making a web services query using gSoap with query arguments - c++

I'm attempting to convert a soap query written for C# into a gSoap query in Visual C++.
The C# query adds an XML node's to the query call, in order to pass parameters to the query:
XmlNode queryOpts = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
queryOpts.InnerXml = "<DateInUtc>TRUE</DateInUtc>";
Here's the C# query, passing various args (some args are specified as XmlNode objects)
XmlNode nodeListItems = listService.GetListItems("Announcements", null, query, viewFields, null, queryOpts, null);
The C++ / gSoap query allows me to pass a query and response object:
listService.__ns10__GetListItems(&announcementQuery, &announcementResponse)
The query object has various properties that can be set that relate to the arguments in the C# call:
announcementQuery.listName
announcementQuery.query
announcementQuery.queryOptions
announcementQuery.viewFields
The first argument there is a string, no problem.
The query, queryOptions and viewFields are a bit confusing.
"query" is a class of type _ns2__GetListItems_query, and it has the following functions & members:
soap_default()
soap_get()
soap_in()
soap_out()
soap_put()
soap_serialize()
soap_type()
__any
__mixed
for query, queryOptions and viewFields, I'd simply like to specify an xml formatted string, like the C# code does, but I'm not sure how this is done.
Can someone cast some experience on this?
thanks!

I'm assuming you've already discovered the answer to this, but I'll post some notes for posterity.
Here's a simple C++ demo for sending and XML doc to a ASP.NET web method.
int _tmain(int argc, _TCHAR* argv[])
{
Service1SoapProxy proxy;
_WebServiceNS1__HelloWorld helloWorld;
_WebServiceNS1__HelloWorld_xml xml;
_WebServiceNS1__HelloWorldResponse response;
xml.__any = "<doc><x>hi</x></doc>";
helloWorld.xml = &xml;
int result = proxy.HelloWorld(&helloWorld, &response);
fprintf(stdout, "result: %i\n", result);
switch(result)
{
case SOAP_OK:
fprintf(stdout, "Response: %s\n", response.HelloWorldResult);
break;
default:
break;
}
return 0;
}
Here's the trivial web method in the .NET service:
[WebMethod]
public string HelloWorld(XmlNode xml)
{
return string.Format("Your XML: {0}", xml.OuterXml);
}
If everything works, you'll see "Response: hi" on your console.

Related

Not able to get values from JSON in Casablanca, C++

I'm using Casablanca, cpprestsdk to consume REST APIs in C++, in Visual Studio 2015 Professional. I'm trying to develop a simple example here hitting an API and parsing the response as JSON. The URL I'm using, actually returns all the parameters sent to the API.
I've hit the API and got response as well, extracted json from the response successfully. But when i try to read a value at any key from json, it crashes. Hence i put a check whether that key is available or not, and it always says json does not have the field. As an example i printed the data i.e. json. It has the key/field "name" but when i check it via has_field, it returns false.
Please help.
Complete code is below :
json::value postData;
postData[L"name"] = json::value::string(L"Joe Smith");
postData[L"sport"] = json::value::string(L"Baseball");
http_client client(L"https://httpbin.org/post);
http_request request(methods::POST);
request.set_body(postData);
client.request(request).then([](web::http::http_response response) {
json::value j = response.extract_json().get();
json::value data = j.at(U("data"));
std::wcout << "Json : " << data;
// Prints "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}"
if (data.has_field(U("name"))) {
std::cout << "Name Found";
}
else {
std::cout << "Name key not Found";
}
});
It seems that your response looks like this:
{ "data": "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}" }`
i.e. the actual data is not a JSon object but escaped JSon passed as string. I guess you need to return a payload that looks like this to do what you want to do the way you are doing it:
{
"data": {
"name": "John Smith",
"sport": "Baseball"
}
}

How Can I Call PL/pgSQL Function From C++ Code

I am trying to call a function which is declared in PostgreSQL with PL/pgSQL. For that I write the code below. My function is working but after that I am taking a "PGRES_FATAL_ERROR". Also when I changed "select removestopwords()" with an sql query like "DELETE * FROM TABLE1" it's working successfully.
I am considering, that error can cause some big problem in future even if now working. How can I call a PL/pgSQL function without taking error?
void removeStopWordsDB(PGconn* conn) {
PGresult *res = PQexec(conn, "select removestopwords()");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
printf("removestopwords failed");
cout<<PQresultStatus(res);
PQclear(res);
exit_nicely(conn);
}
printf("removestopwords - OK\n");
PQclear(res);
}
If you get PGRES_FATAL_ERROR from PQresultStatus you should use PQresultErrorField to get all the error data from the result set to provide a useful error message. This will allow you to determine what the actual error is here (quite likely an error being sent over from the server).
Consider creating a class to hold PostgreSQL error details that can be constructed from q PQresult pointer, e.g.:
PgError(const PGresult *rs)
{
severity = GetErrorField(rs, PG_DIAG_SEVERITY);
sqlstate = GetErrorField(rs, PG_DIAG_SQLSTATE);
primary = GetErrorField(rs, PG_DIAG_MESSAGE_PRIMARY);
// ...
}
static std::string GetErrorField(const PGresult *rs, int fieldCode)
{
const char *message = PQresultErrorField(rs, fieldCode);
if (message == NULL) return "";
return std::string(message);
}
Then you can, for example, encapsulate dumping out the error to a stream in this object to provide details just like psql and friends do (although strictly speaking, you'd need the input SQL as well for all of that)
PostgreSQL API doesn't support some flag like "ignore all errors". If you would to ignore result, then just don't check result in host environment. But it is bad strategy.

Unable to set Reporting Services Parameters

I'm generating a reporting services report from an ASP.NET (MVC) based application but am having problems setting the parameters for the report.
I believe the issue has only occurred since we upgraded SQL Server from 2005 to 2008 R2 (and Reporting Services along with it).
The original error encountered was from calling rsExec.Render:
Procedure or function 'pCommunication_ReturnRegistrationLetterDetails'
expects parameter '#guid', which was not supplied.
Debugging the code I noticed that rsExec.SetExecutionParameters is returning the following response:
Cannot call 'NameOfApp.SQLRSExec.ReportExecutionService.SetExecutionParameters(NameOfApp.SQLRSExec.ParameterValue[],
string)' because it is a web method.
Here is the function in it's entirety:
public static bool ProduceReportToFile(string reportname, string filename, string[,] reportparams,
string fileformat)
{
bool successful = false;
SQLRS.ReportingService2005 rs = new SQLRS.ReportingService2005();
SQLRSExec.ReportExecutionService rsExec = new NameOfApp.SQLRSExec.ReportExecutionService();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
rsExec.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Prepare Render arguments
string historyID = null;
string deviceInfo = null;
// Prepare format - available options are "PDF","Word","CSV","TIFF","XML","EXCEL"
string format = fileformat;
Byte[] results;
string encoding = String.Empty;
string mimeType = String.Empty;
string extension = String.Empty;
SQLRSExec.Warning[] warnings = null;
string[] streamIDs = null;
// Define variables needed for GetParameters() method
// Get the report name
string _reportName = reportname;
string _historyID = null;
bool _forRendering = false;
SQLRS.ParameterValue[] _values = null;
SQLRS.DataSourceCredentials[] _credentials = null;
SQLRS.ReportParameter[] _parameters = null;
// Get if any parameters needed.
_parameters = rs.GetReportParameters(_reportName, _historyID,
_forRendering, _values, _credentials);
// Load the selected report.
SQLRSExec.ExecutionInfo ei =
rsExec.LoadReport(_reportName, historyID);
// Prepare report parameter.
// Set the parameters for the report needed.
SQLRSExec.ParameterValue[] parameters =
new SQLRSExec.ParameterValue[1];
// Place to include the parameter.
if (_parameters.Length > 0)
{
for (int i = 0; i < _parameters.Length; i++)
{
parameters[i] = new SQLRSExec.ParameterValue();
parameters[i].Label = reportparams[i,0];
parameters[i].Name = reportparams[i, 0];
parameters[i].Value = reportparams[i, 1];
}
}
rsExec.SetExecutionParameters(parameters, "en-us");
results = rsExec.Render(format, deviceInfo,
out extension, out encoding,
out mimeType, out warnings, out streamIDs);
// Create a file stream and write the report to it
using (FileStream stream = System.IO.File.OpenWrite(filename))
{
stream.Write(results, 0, results.Length);
}
successful = true;
return successful;
}
Any ideas why I'm now unable to set parameters? The report generation works without issue if parameters aren't required.
Looks like it may have been an issue with how reporting services passes parameters through to the stored procedure providing the data. A string guid was being passed through to the report and the stored procedure expected a varchar guid. I suspect reporting services may have been noticing the string followed the guid format pattern and so passed it through as a uniqueidentifier to the stored procedure.
I changed the data source for the report from "stored procedure" to "text" and set the SQL as "EXEC pMyStoredOProcName #guid".
Please note the guid being passed in as a string to the stored procedure is probably not best practice... I was simply debugging an issue with another developers code.
Parameter _reportName cannot be null or empty. The [CLASSNAME].[METHODNAME]() reflection API could not create and return the SrsReportNameAttribute object
In this specific case it looks like an earlier full compile did not finish.
If you encounter this problem I would suggest that you first compile the class mentioned in the error message and see if this solves the problem.
go to AOT (get Ctrl+D)
in classes find CLASSNAME
3.compile it (F7)

Reading SQL table in C++

I am trying to read a SQL Server table in C++ using a function like this..
CCommand<CDynamicAccessor>* Read(char* tblName)
{
wostringstream query;
query << "SELECT * FROM " << tblName;
return dataSource -> Query (query);
}
which calls this other function
CCommand<CDynamicAccessor>* Query(wostringstream& query)
{
HRESULT hr;
hr = _cmd.Open(_sess, _T(query.str().c_str()));
if (FAILED(hr))
{
std::wcout<<query.str().c_str() << "\n";
THROW_EXCEPTION("Command not executed.");
}
return &_cmd;
}
The problem is when I try to retrieve the column values using something like this
char* column20= (char*)cmd->GetValue("column20");
char* column21= (char*)cmd->GetValue("column21"); //Error
Because in the column20 I get the full string ex. "Value1"
But in the column21 I only get the first character ex. "V", when I should get "Value2"
Is there any limitation in size or something like that which do not allow me to retrieve the full string for column21?
If so, what is the best way to solve this issue?
Most probably the result is a wchar_t * string and you cast it to char *

SharePoint web services: test if file exists

I'm using SharePoint web services in C#. I have my code working to check files and check them out using the Lists web service. I need to test to see if a file exists; I can find lots of examples for doing this using the object model API, but I can't seem to find a straightforward way of doing this using web services.
Try the Lists.GetListItems with a suitable CAML query.
A CAML query like
<Query><Where><Eq><FieldRef Name="FileLeafRef" /><Value Type="Text">Filename.rtf</Value></Eq></Where></Query>
should work; the field 'FileLeafRef' is where the filename is stored.
This code may do, it's a little rough, but demonstrates how to get a list of files based on the title.
public static bool PageExists(string listName, string webPath, string pageTitle)
{
string pageId = "";
IntranetLists.Lists lists = new IntranetLists.Lists();
lists.UseDefaultCredentials = true;
lists.Url = webPath + "/_vti_bin/lists.asmx";
XmlDocument doc = new XmlDocument();
doc.LoadXml("<Document><Query><Where><Contains><FieldRef Name=\"Title\" /><Value Type=\"Text\">" + pageTitle + "</Value></Contains></Where></Query><ViewFields /><QueryOptions /></Document>");
XmlNode listQuery = doc.SelectSingleNode("//Query");
XmlNode listViewFields = doc.SelectSingleNode("//ViewFields");
XmlNode listQueryOptions = doc.SelectSingleNode("//QueryOptions");
Guid g = GetWebID(webPath);
XmlNode items = lists.GetListItems(listName, string.Empty, listQuery, listViewFields, string.Empty, listQueryOptions, g.ToString());
}
return items.Count > 0;
}
public static XmlNodeList XpathQuery(XmlNode xmlToQuery, string xPathQuery)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlToQuery.OuterXml);
XmlNamespaceManager mg = new XmlNamespaceManager(doc.NameTable);
mg.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/soap/");
mg.AddNamespace("z", "#RowsetSchema");
mg.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
mg.AddNamespace("y", "http://schemas.microsoft.com/sharepoint/soap/ois");
mg.AddNamespace("w", "http://schemas.microsoft.com/WebPart/v2");
mg.AddNamespace("d", "http://schemas.microsoft.com/sharepoint/soap/directory");
return doc.SelectNodes(xPathQuery, mg);
}
I also had similiar problems with this.
I have tried the following FieldRefs without success: "Name", "FileLeafRef" and "LinkFilenameNoMenu".
The post located at http://www.johanolivier.blogspot.com details what I had to do to get it working.