ASP.NET Web API Deserialize Query Parameters into Nested POCO Action Parameter - asp.net-web-api

Already checked this question but didn't answer.
Background
I have a fully functional RESTful web service written using ASP.NET Web API and it currently supports CORS effectively for cross-origin access from browsers that support CORS. Problem is that current business needs require support of browsers that don't support CORS. I am adding JSON-P support to my web service in addition to supporting CORS and through the magic of action selectors and type formatters, my actual web service code hasn't changed....yet.
Currently I use nested POCO objects (objects that contain other objects) as parameters, for example, for my Post actions. Since I'm supporting XML and JSON incoming, the POST data gets deserialized nicely into the POCO objects, since both XML and JSON support nested deserialization. But to support JSON-P, I have to now emulate a POST through Query Parameters. Getting to the Post action method is successful via an httpMethod Query Parameter and a custom action selector.
Question(s)
First of all, and I ask this after reading responses to other questions, will the registered type formatters even access the Query Parameters for deserializing if I have no request body? The JSON-P request is going to be a simple GET request with no body, so I'm not even sure if it is possible to have a POCO in my action parameter and have it deserialized with a GET request and only Query Parameters.
EDIT: Looks like I may be able to do some MediaTypeFormatter magic with a custom formatter and using the QueryStringMapping. Not sure yet though.
Second, is it possible to deserialize Query Parameters into nested properties of the POCO object? And if so, what is the naming convention for Query Parameters to do this? For example XML of Bob would get deserialized into Message.User.FirstName if the action parameter was of type Message.
EDIT: FormUrlEncodedMediaTypeFormatter has some of the functionality that I want if I could just redirect it to use the Query String instead of the body. But I also don't want a JToken object -- I'd like my POCO, but I think I can deserialize a JToken with JSON.NET. So I'm probably going to steal the code from FormUrlEncodedMediaTypeFormatter and the relate internal class FormUrlEncodedJson to make a custom formatter. Just need to make sure question #1 is possible first.
Example POCOs
public class User
{
public string FirstName { get; set;}
}
public class Message
{
public User User { get; set; }
}
Example "standard" RESTful POST
POST /api/messages
Content-Type: text/xml
<Message><User><FirstName>Bob</FirstName></User></Message>
Example Hypothetical JSON-P Simulated POST
<script type="text/javascript"
src="https://api.mydomain.com/api/messages?callback=MyCallback&httpMethod=Post&User.FirstName=Bob">
</script>
EDIT: Overall Goal: I'm trying to leave the action methods alone right now if possible since they currently handle RESTful CORS-enabled requests. My goal is to add JSON-P support to the calls without changing the method signature. I've got that mostly accomplished; all I have left is being able to deserialize the Query Parameters into the action method parameters when it's a JSON-P request.

Try adding [FromUri] to your action definition, i.e.:
public HttpResponseMessage YourAction([FromUri] YourModel model)
{
...
}

At this point in time it seems that I must create two different paths in the API. Because of the way request parameter deserialization works, and model binding vs. media type formatters, and the lack of a hook in this particular area, I cannot have one single Web API method and have the parameters taken from either the query string or the content based upon various request factors.

Related

Does ModelAndView serialize model before sending response to client

In spring mvc, when we return ModelAndView / Model object, does this get serialized to be sent on HTTP?
Just like it happens in REST API that the #ResponseBody annotated method returned value is serialized.
If not, how is Model object transferred over HTTP in Spring MVC as I have read that objects can't be transferred over HTTP without serialization?
It depends. It depends on the view technology in use. But for most they will be exposed as request attributes and that is done in the View. The AbstractView has code for this which is used by most View implementations.
For something like Freemarker the model is exposed both as request attributes but also added to the Freemarker internal model object. This is so that Freemarker can render the page and you could also use tags in the template to retrieve the request attributes.
Depending on the actual view technology used if something gets serialized depends. For things generating HTML, PDF, Excel etc. nothing will be serialized. All the rendering and processing is done on the server and the end result (the complete view) is being sent to the client.
However, for view technologies like the MappingJackson2JsonView (there are others as well) that will actually serialize the model using Jackson. But in the end, this will be JSON that is sent over HTTP.
So what is sent over HTTP is at least never the actual model but depends on the view technology in use.

Allowing Custom XML in Web API Data Contract

I'm developing an ASP.NET Web API service, which allows users to post metadata.
In one of the data contracts that the users post, they're supposed to be able to post their own custom metadata in XML format. This is an example:
<Delivery>
<Type>Direct</Type>
<Time>12:00:01</Time>
<Format>Segmented</Format>
<CustomMetadata>
<ClientReference>R46375683</ClientReference>
<Contact>Me#There.com</Contact>
</CustomMetadata>
</Delivery>
I'm having trouble creating a data contract that successfully deserializes properly, however. For the CustomMetadata node, I have :
[DataMember(EmitDefaultValue=false)]
public XmlNode CustomMetadata { get; set; }
When it gets deserialized, I receive an exception:
"Collection type 'System.Xml.XmlNode' cannot be deserialized since it
does not have a valid Add method with parameter of type
'System.Object'."
I don't fully understand why it's trying to "Add" anything to the XmlNode, but for whatever reason, it's failing. Is there an alternative for doing this kind of thing, such as deserializing to a different type? I tried deserializing to a string, but that gave an exception too.
Data Contract serialisation only supports primitives and a few special types. You must use XmlElement instead of XmlNode.
Try:
[DataMemeber]
public XmlElement CustomMetadata { get; set; }
See http://msdn.microsoft.com/en-us/library/ms733127.aspx
Can you try using XmlElement instead of XmlNode? I believe the serializer only special cases elements on deserialization. XElement should work too.

What data is sent as part of http response

What is actually sent within a http request response ?
In below simple spring controller a String is sent to client. But this string is wrapped in some html elements that the browser understands ? Is this response always the same but different frameworks just provide different convenient methods/annotations to make the process simpler ?
#RequestMapping(value="myrequest", method = RequestMethod.GET)
public String redirect(#RequestParam String param) {
return "test";
}
In Spring MVC Framework, the lifecycle of an HTTP Request is something like this:
The user makes a request of a resource, and Spring' DispatcherServlet delegates that request to an specific controller method (like redirect). This is made through a Handler Mapping that can use -for example- the annotations (like #RequestMapping) in the controllers to select an appropriate one.
Tipically, Controller methods return instances of ModelAndViews, that are the classes responsible of generating some Markup (HTML, JSON, XLS a.k.a the View) and show some information in that Views (The Model). It is possible also that Controllers return Views Logical Names (like test)that should be later resolver in ModelAndView instances by a View Resolver.
The View Resolver selects and appropriate view based on the Logical Name returned by the Controller, and then the View generates the Markup that is sent to the browser. For example, JstlView generates HTML Markup and AbstractExcelView generates XLS files.
So to answer your question, you must find what View Resolver is configured in your application context and find what markup is produced.

Spring MVC Rest: How to implement partial response in Json and XML?

I need to the ignore the serialization (JSon/Jackson and XML/XStream) of some attributes from my object response based on user input/or Spring security roles (like you don't have permission to see the content of this field, but all others are ok etc). How is the best approach to do this in Spring MVC Rest?
Other approach is show only the attributes that are relevant for the api user, like described here http://googlecode.blogspot.com.br/2010/03/making-apis-faster-introducing-partial.html
If you are using Jackson, here are some possible options to modify the Json serialization:
Use the #JsonIgnore annotation - However, this is static filtering, and will not allow you to implement rule-based filtering as you appear to need
Use #JsonFilter - This will allow you to implement an interface in which you can provide your serialization filtering logic. You may find this to be too heavyweight of a solution.
The way I often solve this is to return a Map from my Controller methods instead of the underlying object. You can write processing code that puts the relevant fields from the object into the Map, therefore giving you complete control over what is serialized. You could include a method on the Object to do the conversion. The method could look something like this:
// RequestObj is whatever 'input' object that indicates what should be filtered
public Map<String,Object> convertToMapForRequest(RequestObj request){
// Build return map based on 'this' and request
}

Jersey - data validation before sending entity object to REST api

I use Jersey framework to communicate (marshalling and unmarshalling object and xml) with REST api. I send data (object has lot attributes) this way:
.
.
ClientResponse response = webResource.type("application/xml").post(ClientResponse.class, object);
.
I would like to ask how can I validate some object attributes (for example private String code in Object should be in format of two numbers etc.)
aYou mean in the service that receives the object? How have you tried? It comes in as an object, or whatever you want it to come in as. We frequently take in Map<String,Object> and then do validation on that map (if we need to decide what subtype to create from the post for example). If you have Jersey unmarshall your request into the POJO for you, you can then do whatever validation you want and return a Response object with the validation error information to your client if the object doesn't pass.
So in other words, the validation is up to you. There are a few validation frameworks out there that you could try to help, such as javax.validation but IMHO it's usually easier to just test each property you need to validate yourself using conditionals, regexps, whatever.
In my opinion the validation comes with a webframework like struts, wicked, jfc... to name some. There the user inputs his data in a form to create the object he wants to post to a service. The webframeworks already got components to validate this data. When there was a positive validation you make the post call to your service.

Resources