Content of HttpResponseMessage as JSON - c#

I have an ASP.NET MVC WEB API. For several reasons (redirect because of no authorizations ..), I can't just use a simple object and return it in my controller method. Therefore I need the HttpResponseMessage class which allows me to redirect.
Currently I'm doing this:
var response = new Response { responseCode = Response.ResponseCodes.ItemNotFound };
var formatter = new JsonMediaTypeFormatter();
response.Content = new ObjectContent<Response>(response, formatter, "application/json");
.. to get the object, serialized as JSON, into the content of HttpResponseMessage. Somehow, I have the feeling that there is another, better, way to do this. Any ideas on that?

You can do:
var response = new Response { responseCode = Response.ResponseCodes.ItemNotFound };
Request.CreateResponse<Response>(HttpStatusCode.OK, response);
By default, Web API will set the format of the response based on the Content-Type specified in the HTTP request header but there are some overloads on the CreateResponse method where you can specify the type formatter.
You can also remove the Web API XML serializer to force all responses to be JSON if that's what you want - off the top of my head I think it's a Formatters.Remove method on HttpConfiguration.

Related

HttpClient.SendAsync sending wrong Content-Type

HttpClient httpClient = new HttpClient();
MyRequest request = new MyRequest (data);
var content = new StringContent(System.Text.Json.JsonSerializer.Serialize(request), System.Text.Encoding.UTF8, "application/json");
HttpRequestMessage httpRequestMessage = new HttpRequestMessage
{
RequestUri = new Uri("http://localhost:8000/api/action"),
Content = content,
Method = HttpMethod.Post
};
httpRequestMessage.SetBrowserRequestMode(BrowserRequestMode.NoCors);
await httpClient.SendAsync(httpRequestMessage);
Using HttpClient in Blazor WebAssembly I am trying to send a request to an API.
However, despite specifying application/json as the content type it sends text/plain;charset=UTF-8 (as viewed in the Chrome Network tab). This results in the API throwing an error.
I think you could check these caseļ¼š
case1,case2
read this document,and try with PostAsJsonAsync method
I tested as below and worked well:
var weatherforecast = new WeatherForecast() { Date = DateTime.Now, Summary = "testsummary", TemperatureC = 44 };
var response = await Http.PostAsJsonAsync("https://localhost:44385/WeatherForecast", weatherforecast);
Result:
Related post:
Wrong Content-Type being substituted for fetch http request
HttpClient in WebAssembly calls the standard fetch method.
As per the fetch specification when using no-cors only a limited number of content-types can be used:
https://fetch.spec.whatwg.org/#simple-header
"application/x-www-form-urlencoded"
"multipart/form-data"
"text/plain"
The preferred solution would be to correctly configure the end point you are calling to allow cross origin requests and not to use no-cors e.g:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
Access-Control-Allow-Origin: *
If this is not possible (as in my case) and you must use no-cors the only other option would be to change your end point to map "text/plain" to "application/json"
Whilst many may not consider this a bug it is an inconsistency in how HttpClient behaves and is not obvious (though the NoCors option is only available in WebAssembly)

Unable to deserialize JSON in C# using the same class at both ends

I'm looking for someone to point out the obvious blunder here.
A .NET Core in C# application makes an HTTP call to another such application. Some processing is performed, and a response is sent thus:
Response response = new Response(input)
{
stuff = processedStuff;
};
responseMessage = JsonConvert.SerializeObject(response);
return new OkObjectResult(responseMessage);
This all looks good and responseMessage contains valid JSON (according to an online JSON checker I found).
At the other end, this is received thus:
Response returned = new Response();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
returned = JsonConvert.DeserializeObject<Response>(json);
}
This fails with an Error converting value *the JSON string* to "Response" at line 1
Response is the same class file in both applications. What never obvious and apparently invisible mistake am I making here?
The invisible mistake you are making is double-serializing the result. The contract of OkObjectResult is that it will automatically serialize the result object to the negotiated content type (e.g. JSON or XML) and return an OK status. You are serializing the object first and then passing the serialized string to OkObjectResult so it ends up getting serialized twice.
responseMessage = JsonConvert.SerializeObject(response); // serialize to JSON
return new OkObjectResult(responseMessage); // implicit serialization here
Possible solutions:
Allow the implicit serialization to do its thing (recommended):
return new OkObjectResult(response); // implicit serialization of response object
Use a ContentResult instead (good if you need special serialization handling):
responseMessage = JsonConvert.SerializeObject(response); // serialize to JSON
return new ContentResult()
{
Content = responseMessage,
ContentType = "application/json",
StatusCode = 200
};
Deserialize twice on the receiving end (use as a last resort, i.e. you don't control the server):
var doubleSerializedJson = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<string>(doubleSerializedJson);
returned = JsonConvert.DeserializeObject<Response>(json);
check if the returned string is not wrapped in OkObjectResult object.
As far as I know, you don't need the serialization and deserialization, the framework already takes care of everything. If you need to, you could always deserialize to either an anonymous type or cast it from object.
https://www.newtonsoft.com/json/help/html/DeserializeAnonymousType.htm
I would also help if you could share the response class, since it's most likely part of the problem.
As someone old enough to remember when the Simpsons started, I can only answer in the traditional manner:
D'oh!
Using implicit serialization as described by the kind responder above resolved the issue.

Setting up a REST Client Application (Post) from a Web API

I've been having a few issues in trying to retrieve the results of a POST operation from a Web Service.
I have been using a chrome extension to test the API Services and they are working there. However I've been having problems on implementing it in code.
This is an example of usage of the chrome extension:
What I'm trying to retrieve on code, is the last part, the json array that the POST operation generates, where it says accessToken.
However, in the code that I've been using below, I've only had access to the status (200 OK) etc.
Here's a preview of the code I am using:
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(url.Text);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(header.Text));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url.Text);
request.Content = new StringContent(body.Text, Encoding.UTF8, header.Text);
client.SendAsync(request)
.ContinueWith(responseTask =>
{
MessageBox.Show(responseTask.Result.Content.Headers.ToString());
}
);
}
The Header.Text is exactly "application/json", the body.Text is body which has those various properties such as username and password (in string format) and url.Text contains the complete URL to call the Web service.
I'd like to know what I'm doing wrong with my code, and what can I do to obtain that json array that contains the accessToken
In your code you need to use ReadAsStringAsync method to convert your HttpContent object to string/json. For example:
client.SendAsync(request)
.ContinueWith(responseTask =>
{
var jsonString = responseTask.Result.Content.ReadAsStringAsync().Result;
MessageBox.Show(jsonString);
});
then you can convert you jsonString as you need.

Is there a way to replace the JSON formatter in ASP.Net WebApi only for the return?

We have found that using an attribute on the controller we can have the controllers default json formatter replaced :-
public class WcsControllerConfigAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
var mediaType = ConfigurationManager.AppSettings["WcsMediaType"];
if (mediaType == "application/json")
{
var formatter = controllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Single();
controllerSettings.Formatters.Remove(formatter);
formatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new NullableValueContractResolver(),
NullValueHandling = NullValueHandling.Include,
DefaultValueHandling = DefaultValueHandling.Populate
}
};
controllerSettings.Formatters.Add(formatter);
}
}
}
But this seems to have the effect of replacing the formatter not only for the result we wish to return but also for the json body of the incoming request. Is there a way to replace only the formatter for the response and not the request?
Edit: OK In response the doctors remark I think I should possibly state what my ultimate goal is because then perhaps you can offer an even better solution than using the formatter.
We are implementing a RESTful server with a partner. Their system (based on websphere) sends us perfectly standard JSON except that everything is enclosed in quotes. The standard formatter/parser does not miss a beat and happily converts all the incoming quoted values to dates, decimals, booleans, etc. We are not looking to change this behaviour.
The responses are also standard JSON but they also want all the values to be quoted. So in our data transfer object everything that is not either a child object or an array is a string and gets serialised correctly most of the time. But a further limitation is that all the properties that are null have to be treated differently to how most systems would treat them. Namely:
Null strings are passed as empty string. "property":"" and not "property":null
Null arrays are passed as empty arrays. "array":[] and not "array":null
Null child objects are passed as an empty object. "object":{} and not "object":null
And we are not allowed to simply omit them either. Not that that would be easy I suspect.
I hope that makes the requirement a little clearer. Our solution to use the formatter was based on another question Json Convert empty string instead of null and this works well for what it's worth but stumbles only because it tries to apply the rules in both directions.
You can write a custom MediaTypeFormatter to achieve what you need.
An official tutorial on how to write custom media-type formatters is available in this link http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters
Doing so will allow you to perform an http request using JSON and return a different media-type than JSON.
Keep in mind that when doing so the client needs to send the desired media-type on the request (in the accept header).
ICredentials credentials = CredentialCache.DefaultCredentials;
NetworkCredential credential = credentials.GetCredential(uri, "Basic");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Credentials = credential;
request.Method = "GET";
request.Headers.Add("api-version", "1.0");
request.Headers.Add("customer-code", code);
request.Headers.Add("Authorization", AuthUser);
request.ContentType = "application/json"; //The request is sent in JSON
request.Accept = "text/plain"; //You ask the server to return the response in the format you need it
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
Stream receiveStream = response.GetResponseStream();
YES - You can..
You can define 2 different implementation of MediaTypeFormatter. Set the properties CanReadType() & CanWriteType() as per your choice. Then implement WriteToStream() & ReadFromStream() in both formatters. Finally register both of them for your specific route.

XMl Response from WEB API solution

I have a Web API solution which is configured to respond results always in JSON format as below
config.Formatters.JsonFormatter.SerializerSettings.Formatting =
Newtonsoft.Json.Formatting.Indented;
But now I have a requirement to respond only one of the API calls with XML Response . But if I add the XML formatter to the system
config.Formatters.XmlFormatter.UseXmlSerializer = true;
then all the API calls get affected.
I have a XML string hardcoded which I want to give as reponse .
How can I solve this problem ?
You have to use the Š”onfiguration.Formatters.XmlFormatter at api level. Try below code
public IHttpActionResult ApiMethod()
{
...
return Content(HttpStatusCode.OK, Model, Configuration.Formatters.XmlFormatter);
}
Write the below code in your action:
Class1 c1 = new Class1();//Your Model class
var content = new ObjectContent<Class1>(c1,
GlobalConfiguration.Configuration.Formatters.XmlFormatter);
return new HttpResponseMessage()
{
Content = content
};

Categories

Resources