asp.net web api having trouble sending objects - asp.net-mvc-4

I've just switched to using the new web api for MVC 4, and I am having great difficulty in deserializing the response from my webservice.
This is my server code:
IEnumerable<Fish> myList = GetFish();
return Request.CreateResponse(HttpStatusCode.OK, myList,"application/xml");
This is serialised as:
<ArrayOfFish xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.datacontract.org/2004/07/MySolution.NameSpace.Resources\" />
As there are no results returned.
When I try to parse this using the XmlMediaTypeFormatter, I get an error saying it wasn't expecting what it got.
My code to deserialise it hasn't changed from before I started using web api, and is simply:
return content.ReadAsAsync<T>(formatters).Result;
formatters is a List of formatters, containing only the XmlMediaTypeFormatter
T is a generic list of Fish
If I omit the "application/xml" type then it appears to send in JSon (as the result is []) however the client expects xml, and will not use a JSon serialiser on it for some reason, even if I explicitly put the type as text/json.
It should be fairly simple to deserialise objects as it's exactly what I was doing before, I've just changed my server very slightly to use CreateResponse to make a HttpResponseMessage instead of using HttpResponseMessage<T> directly, because the generic version isn't supported anymore. I can't find a single client/server example online of someone decoding the result into objects which is frustrating.
Any ideas?

An XmlSerializer can't serialize an interface (IEnumerable). Convert to a List before returning.
return Request.CreateResponse(HttpStatusCode.OK, myList.ToList(),"application/xml");
simlar question with references here - XmlSerializer won't serialize IEnumerable

I ended up discovering that the serialization method web api uses is very slightly different to the former, standard way. I added this to my global.asax and it resolved the issue:
GlobalConfiguration.Configuration.Formatters.Insert(0, new XmlMediaTypeFormatter() { UseXmlSerializer = true });

Related

Is there an issue with the custom object JSON serialization implementation of System.IdentityModel.Tokens.Jwt for .Net 6?

We migrated from .Net Core (dotnet core) 3.1 to .Net 6. We were using the System.IdentityModel.Tokens.Jwt to create a payload and generate a security token with that payload.
Our application has yet to be migrated from Newtonsoft.Json to System.Text.Json due to a lot of nonstandard property serialization that is currently favoring the former. The custom claim value contains an object that was previously serialized properly by adhering to the camelCase contract resolver that was specified in the Startup.cs configuration with regards to JSON serialization.
We upgraded from version 5.5.0 of System.IdentityModel.Tokens.Jwt to version 6.16.0 and the serialization is behaving differently.
We are using a mixture of IdentityModel well-known claims along with a custom claim. The custom claim is the only one that is an object and also the only one behaving this way. All other claims are primitive types and are written to the token as specified and expected.
This is an example of the code that is not working:
var payload = new JwtPayload()
{
{JwtRegisteredClaimNames.Iss, issuer},
{JwtRegisteredClaimNames.Iat, now},
{JwtRegisteredClaimNames.Nbf, now},
{JwtRegisteredClaimNames.Exp, exp},
{JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")},
{"role", user.UserType},
{"customClaim", customClaimObjectInstance }
};
var jwt = new JwtSecurityToken(_jwtHeader, payload);
/* Token below contains a valid base64 encoded JWT Token with
the customClaim property containing pascal values that match
the properties of the C# Poco object and not at all following
either default convention or even any JsonProperty description
attributes such as [JsonProperty("name")] that may decorate each
property of the custom object */
var token = _jwtSecurityTokenHandler.WriteToken(jwt);
My first hunch was such that it may be related to a conflict with default library of System.Text.Json. I proceeded to troubleshoot by adding the [JsonPropertyName("name")] attribute to some of the properties but did not succeed. I expected that if System.Text.Json was being used that at least those description attributes would be respected or consulted during the serialization of the claim object.
I also tried serializing the value with Newtonsoft JsonConverter.Serialize function and use the serialized value as the value of the claim key-value-pair. However, the stringified object quotes were escaped and found plenty of escaping characters ("****") all over the value which was undesired.
After some time searching online and trying to come up with the right keywords to search google and GitHub and I finally got to what I, for now, consider a workaround and not a long-term solution.
The clue was provided by this open issue on Github. I simply, to my interpretation, forced the use of the Newtonsoft serializing and deserializing delegates by specifying the following lines before instantiation of payload variable posted in the question:
JsonExtensions.Serializer = JsonConvert.SerializeObject;
JsonExtensions.Deserializer = JsonConvert.DeserializeObject;
This was the first indication of potentially System.Text.Json being forced from deep within a library. It may also be an indication that the time has come to prioritize the migration to System.Text.Json from Newtonsoft.Json.
I hope this workaround helps somebody else get to this short-term patch, and not spend as much as I did.
If I find anymore concrete ideas or clues about this matter, I will update this answer.
The code below works
/* This was the key to achieving the prior result, however
temporary it may be. */
JsonExtensions.Serializer = JsonConvert.SerializeObject;
JsonExtensions.Deserializer = JsonConvert.DeserializeObject;
var payload = new JwtPayload()
{
{JwtRegisteredClaimNames.Iss, issuer},
{JwtRegisteredClaimNames.Iat, now},
{JwtRegisteredClaimNames.Nbf, now},
{JwtRegisteredClaimNames.Exp, exp},
{JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")},
{"role", user.UserType},
{ "customClaim", customClaimObjectInstance}
};
var jwt = new JwtSecurityToken(_jwtHeader, payload);
var token = _jwtSecurityTokenHandler.WriteToken(jwt);
I am thankful for the issue on github, but more importantly to the solution suggested here.

JSON.NET MVC 4 WebApi proper return type

I see different examples of different return types for WebApi Controller.Method.
Customizing JSON.NET serialization- Get method returns HttpResponseMessage
using JSON.NET in ASP.NET MVC - shows ActionResult (I understand it is outdated article)
Web Api Tutorial returns Business object
I wonder what are the guidelines when to return what?
Thank you.
That all depends on your requirement.
when you return HttpResponseMessage, it gives you options to return HttpStatusCode with a custom message.
Say for example, in your application, you are saving something through web api (say a new customer for example). you can return that object with the message as well pretty easily and you don't have to worry about the return type (json or xml) at all. And this will be an answer for your 3rd point as well. This is the better way to send a business object to the frontend in web api.
as an answer to the 3rd point, please take a look at this blog post for more info. http://blogs.msdn.com/b/yaohuang1/archive/2012/10/13/asp-net-web-api-help-page-part-2-providing-custom-samples-on-the-help-page.aspx
in a web api action which return an HttpResponseMessage, the return code would look something like this.
return Request.CreateResponse<Customer>(HttpStatusCode.Created, newlyCreatedCustomer);
The second post doesn't mention anything about web api. It shows a way to return json data if you ever want to do it in the Controller Action.

JSON.NET JsonIgnore DeserializeObject

I created a Web API using VS 2012. I have a method with a custom object parameter that I am passing JSON to via Fiddler for testing:
[HttpPost, HttpPut]
public HttpResponseMessage UpsertProject(Projects p)
{
...
}
My Projects object has about a dozen properties marked as JsonIgnore. My assumption was that when my object was serialized into Json those properties would be ignored...which is true. However, when I debug my method I'm noticing that all the object properties marked with JsonIgnore are set to null even if the Json that I pass in from Fiddler is setting them. I also try to get data as Json and deserialize it into a new instance of the object but that also does not set the properties that are marked JsonIngore. I knew JsonIgnore would work for serializing but didn't think it would prevent properties from being set when deserializing. What's frustrating is I know that ScriptIgnore doesn't behave this way, but I want to use JSON.net to handle my serializing/deserializing. I've also created a windows app and tested the same serializing/deserializing functionality and it works in it. So I'm wondering if this is a Web API limitation with the JsonIgnore attribute?
If it works the way you want in the Windows application but not in the Web API, that tells me that the JSON serializer settings are different between the two. What settings are you using in the Windows app that makes it work? You can take those settings and apply them to the Web API serializer in the Register method of the WebApiConfig class (in the App_Start folder of your Web API project). For example:
JsonSerializerSettings jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.NullValueHandling = NullValueHandling.Ignore;
jsonSettings.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate;
...
EDIT
OK, so if I understand you correctly, based on your most recent comments, you want everything to be deserialized if possible, but you only want two specific properties to be serialized and those apparently do not have null or default values. In that case, there are two approaches you can take:
Set the properties that you don't want serialized to null or zero or false (the default value) just before serializing. Because you have DefaultValueHandling set to Ignore, this will cause those properties not to be serialized.
Create several boolean ShouldSerializeXXX() methods in your class where XXX is the name of each property you don't want serialized. These methods should return false. See the first answer of this question for an example.
Don't use JsonIgnore because, as you have seen, this will cause the property to be completely ignored by Json.Net, both for serializing and deserializing.

Custom Xml Serializer for a specific type in asp.net web api

I am in asp.net web api. In an API method, I am calling an external web service, that returns XML response. I don't want to deserialize it. I would rather like to send it to the client as is. Initially, I am storing the response in XDocument object but when my client specifies application/xml as accept header, I see the following exception
Type 'System.Xml.Linq.XDeclaration' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
How do I get around this problem
Great Q,i simple write your problem use in api member:
[HttpGet]
[ActionName("Books")]
public HttpResponseMessage MyBook()
{
var request = new HttpResponseMessage(HttpStatusCode.OK);
var doc = XDocument.Parse(#"<books><book><author>MS</author><name>ASP.NET</name></book></books>");
request.Content = new StringContent(doc.ToString(), Encoding.UTF8, "application/xml");
return request;
}
Try this member source.
You should be able to use some controller specific settings. See here for an example

How to send response using Json object

I am working on a project in which a server page is called through XMLHttp and now I want to retrieve response the called page in json object.
and I never used json so I don't have any idea about it so please tell me how I can make json object in my server side vb.net page.
You can use JSON.NET or use DataContractJsonSerializer built in .NET 3.5.
It isn't too clear what you need to do, as far as I can understand you want to send to the caller JSON responses from a webserver, using VB.NET. I suggest to take a look at JSON.NET project, which makes serializing and deserializing your .NET objects to JSON a breeze!