HttpClient response ReadAsAsync() doesn't fully deserialize object - c#-4.0

I'm trying to consume a web service with the Web API client library. My problem is that the ReadAsAsync doesn't seem to want to fully deserailize the returned object when the submitting function uses a POST method.
If I get the response as a string and manually deserailize it works. (I get a apmsgMessage with all the fields populated)
HttpClient client = GetClient();
var response = client.PostAsJsonAsync("api/robot/Preview", ad).Result;
var msg = response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<apmsgMessage>(msg.Result);
I originally tried the code below which returns an apmsgMessage Object, but all the fields are null.
HttpClient client = GetClient();
var response = client.PostAsJsonAsync("api/robot/Preview", ad).Result;
var msg = response.Content.ReadAsAsync<apmsgMessage>().Result;
return msg;
My question is why dosn't my orginal (the PostAsJsonAsync) return a apmsgMessage fully populated. Am I doing somethign wrong with the ReadAsAsync?

I just had the same issue, and in my case I solved it by removing the [Serializable] attribute from the class.
I don't know why this attribute conflicts with the deserialization process, but as soon as I took that out, the ReadAsAsync method worked as expected.

Related

Microsoft.Azure.Cosmos SDK Paginated Queries with Continuation Token

I'm migrating from the Microsoft.Azure.Documents SDK to the new Microsoft.Azure.Cosmos (v3.2.0) and am having an issue getting a continuation token back for paginated queries. In the previous SDK when you had the FeedResponse object it returned a bool for HasMoreResults as well as a ContinuationToken which I pass off to my users should they want to make a call for the next page (via an API endpoint). In the new SDK I am trying to use the GetItemQueryIterator method on my container and the only examples I see are using a while loop to get all the pages using the HasMoreResults value with no way for me to extract a ContinuationToken and just pass back the first set of results.
Here is how my code looks so far:
var feedIterator = _documentContext.Container.GetItemQueryIterator<MyDocumentModel>(query, request.ContinuationToken, options);
if (feedIterator.HasMoreResults)
{
listViewModel.HasMoreResults = true;
//listViewModel.ContinuationToken = feedIterator.ContinuationToken; (DOES NOT EXIST!)
}
The commented out line is where I would usually expect to extract the ContinuationToken from but it does not exist.
Most examples show using the iterator like so:
while (feedIterator.HasMoreResults)
{
listViewModel.MyModels.AddRange(_mapper.Map<List<MyModelListViewItem>>(await results.ReadNextAsync()));
}
But I only want to return a single page of results and pass in a continuation token if I want to get the next page.
The ContinuationToken is part of the ReadNextAsync response:
FeedResponse<MyDocumentModel> response = await feedIterator.ReadNextAsync();
var continuation = response.ContinuationToken;
The reason is that the ReadNextAsync is the moment where the service call is made, representing a page of data, and the continuation is for that particular page.
I have not tried the code but looking through the documentation, ReadNextAsync() method on FeedIterator returns you an object of type FeedResponse and that has a ContinuationToken property.

Swagger generated API for the Microsoft Cognative Services Recommendations

I can't seem to figure out how to include the CSV file content when calling the Swagger API generated methods for the Microsoft Cognitive Services Recommendations API method Uploadacatalogfiletoamodel(modelID, catalogDisplayName, accountKey);. I've tried setting the catalogDisplayName to the full path to the catalog file, however I'm getting "(EXT-0108) Passed argument is invalid."
When calling any of the Cog Svcs APIs that require HTTP body content, how do I include the body content when the exposed API doesn't have a parameter for the body?
I guess, Swagger can't help you testing functions that need to pass data thru a form. And I guess sending the CSV content in the form data shall do the trick, if you know the proper headers.
I work with nuGet called "Microsoft.Net.Http" and code looks like
HttpContent stringContent = new StringContent(someStringYouWannaSend);
HttpContent bytesContent = new ByteArrayContent(someBytesYouWannaSend);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(stringContent, "metadata", "metadata");
formData.Add(bytesContent, "bytes", "bytes");
HttpResponseMessage response = client.PostAsync(someWebApiEndPoint.ToString(), formData).Result;
if (!response.IsSuccessStatusCode)
{
return false; //LOG
}
string responseContent = response.Content.ReadAsStringAsync().Result;
jsonResult= JsonConvert.DeserializeObject<someCoolClass>(responseContent);
return true;
}
Sorry about that someVariables that can't compile. Hope you'll figure this out.
When you are basing your code on the Swagger definition you depend on the good will of the person that created that Swagger definition. Maybe it is not complete yet.
If you are working on C#, try looking at the Samples repo.
Particularly for the Uploading of the catalog there are several functions on the ApiWrapper class that might be helpful, one has this signature: public CatalogImportStats UploadCatalog(string modelId, string catalogFilePath, string catalogDisplayName), another has this other signature public UsageImportStats UploadUsage(string modelId, string usageFilePath, string usageDisplayName) (where it seems like you can point to a public url).
In your case I'd probably try the second one.
Download the sample and use the Wrapper code defined there in your project.

Self referencing loop detected using HttpClient PutAsJsonAsync Extension

Using the PutAsJsonAsync extension method for HttpClient in an asp.net mvc 5 returns a Self referencing loop detected exception.
Here is the calling code:
httpClient.BaseAddress = _uri;
HttpResponseMessage response = await httpClient.PutAsJsonAsync<b>("index/1",b);
response.EnsureSuccessStatusCode();
The object b does have a self reference.
So my question is how do I set SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore in an asp.net mvc 5 application.
One way to solve this problem is to change from using the PutAsJsonAsync extension method to using the PutAsync extension method and setting the MediaTypeformatter explicitly.
var jsonformatter = new JsonMediaTypeFormatter();
jsonformatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
HttpResponseMessage response = await httpClient.PutAsync<b>("index/1",b,jsonformatter);
response.EnsureSuccessStatusCode();
This allows you to use whatever setting you need.

ServiceStack: Send JSON string instead DTO via POST

I would like to send a string (JSON formatted) to my webservice instead using a DTO.
var client = new JsonServiceClient(absoluteUrl);
client.Post<T>(absoluteUrl, data);
But, after to do change my data (DTO object) to a JSON string, I'm getting a ServiceStack Exception: Internal Server Error. Looks like the ServiceStack Post/Send method changes my JSON request.
Is it possible or is there any way to avoid it? Someone else had the same issue?
UPDATE 1: I'm using this approach because of the OAuth authentication. I'm generating a HMAC by request.
Thanks.
You can use HTTP Utils to send raw JSON, e.g:
var response = absoluteUrl.PostJsonToUrl(data)
.FromJson<T>();
ServiceStack's .NET Service Clients provide Typed API's to send Typed Request DTO's, it's not meant for POST'ing raw strings but I've just added support for sending raw string, byte[] and Stream in this commit so now you can send raw data with:
var requestPath = request.ToPostUrl();
string json = request.ToJson();
var response = client.Post<GetCustomerResponse>(requestPath, json);
byte[] bytes = json.ToUtf8Bytes();
response = client.Post<GetCustomerResponse>(requestPath, bytes);
Stream ms = new MemoryStream(bytes);
response = client.Post<GetCustomerResponse>(requestPath, ms);
This change is available from v4.0.43+ that's now available on MyGet.
Sharing Cookies with HttpWebRequest
To have different HttpWebRequests share the same "Session" you just need to share the clients Cookies, e.g. after authenticating with a JsonServiceClient you can share the cookies with HTTP Utils by assigning it's CookieContainer, e.g:
var response = absoluteUrl.PostJsonToUrl(data,
requestFilter: req => req.CookieContainer = client.CookieContainer)
.FromJson<T>();

how to pass in paramters to a post request using the servicestack json client

I'm having trouble getting my servicestack json client to format a REST Post request.
I'm trying to post to my login service with a raw json body of
{"Uname":"joe", "Password":"test"}
but the post methods is actually mistakenly sending this
{"login":""}
Here's the code I'm using.
JsonServiceClient.HttpWebRequestFilter = filter =>
{
filter.Headers.Add(string.Format("X-API-Key: {0}", "test"));
};
var client = new JsonServiceClient(url);
var url = "/login";
var login = new LoginModel { Uname = uname, Password = pwd };
return client.Post<UserCredentials>(url, login);
How should I structure the parameter object so that it serializes to the correctly to the intended raw value in the post request? Additionally, can I just pass in a dictionary or a more generic object so that I don't have to create a LoginModel class or struct?
It turns out the issue was that I was using public fields instead of public properties in my LoginModel. Changing it to properties fixed it.

Resources