Allowing Custom XML in Web API Data Contract - asp.net-web-api

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.

Related

Web api map request parameter with a hyphen to a Pascal cased complex model property

I am trying to figure out a way to map POSTED form parameters that have hyphens in them to a WEB-API method that takes a complex object.
Some context:
We are using Mailgun to forward a processed email to our own custom Web API Controller method.
Mailgun POSTS to our API and some of the parameters it uses have hyphens in them - for example: body-plain.
My C# complex model will have a property to match in Pascal Case (can't use hyphens in property names)
so if these parameters are generated by Mailgun and posted to our WEB API controller:
from
subject
body-plain
body-stripped
timestamp
and our complex object looks like this:
public class Response{
public string From{get; set;}
public string Subject{get; set;}
public string BodyPlain{get; set;}
public string BodyStripped{get; set;
public int Timestamp{get; set;}
}
Then From, Subject, and Timestamp all map correctly - but BodyPlain and BodyStripped do not - they are null since the model binding can't translate the hyphenated parameters to Camelcase.
Is there a way to do this?
I have seen some posts referring to different ways to achieve this with MVC but we are not using MVC, just strictly WEB API.
You can use the Request object in the controller, which will make the parameters available key/value style.
In the case of Mailgun forwarding (which was the same problem I ran into), the Request.ReadFormAsync() method will expose the IFormCollection, from which you can access the parameters you need via:
IFormCollection.TryGetValue("my-parameter", out StringValues myParameter)
Since the parameters are sent through form submission and not JSON, using [JsonProperty(PropertyName = "my-param")] won't help and you'll have to resort to having your action receiving a parameter of type FormDataCollection and then inside your action you'll map it to your complex object. An alternative is to implement a custom model binder.
In this post there are details about those two options.

Is it valid to apply JsonConverter for query string arguments

All,
My team has recently encountered with a roadblock of using JsonConverter with HttpRequest arguments.
My API method definition is as below
[HttpGet]
[GET("Values/Data/{inputString}/{inputDateTime:datetime}")]
public HttpResponseMessage GetResponseForData(string inputString, [JsonConverter(typeof(DateTimeToTicksConverter))] DateTime inputDateTime)
{
// do something here
}
The DateTimeToTicksConverter is to intercept the DateTime attributes and then transform as defined. When this attribute is applied on the attributes of a model it works fine. However when the attribute is defined as in the API above it doesn't intercept during request.
I would like to know if it is valid to expect JsonConverter to intercept the request parameters?
Any help is much appreciated. Thanks
That's not meant to be used there, that attribute is just metada which json.net looks for when serializing a class to JSON, but webapi has no knowledge of it.
You can achieve what you want using a custom httpparameterbinding. You can find more info here http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

Custom validation message

I have a problem with validating some data types.
There are int, short, DateTime and so on except string.
Suppose i have following property in my view model class
public int? LineNumber { get; set; }
When i input incorrect value i get mvc error "The value 'balblabl' is not valid for LineNumber."
But what if i want just out something like "Value incorrect"? Or what if i want to use other language? I have no idea how to do it(of course i can use string instead of int but it is painfull workaround)
i already tried dataannotationsextensions [DataAnnotationsExtensions.Integer(ErrorMessage = "Please enter a valid number.")] attribute. It is not working. I cannt to use custom validation attribute because of after binder convertation i get null value in all cases with incorrect value. I just cannt to do my own validation. I can to write my own binder but it looks like a joke. Really i think custom validation message is one of must have featerus and i cannt belive asp.net mvc doesnt has a simple way to do it.
I would like to add another, in my opinion, easy way to add and maintain custom error messages.
using the FluentValidation NuGet package.
It hooks up with mvc pretty easy have a look here
You can easily specify numerous rules for your models and display custom error messages that can use a resource file an example:
public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
{
public CreateAgendaPointCommandValidator()
{
RuleFor(cmd => cmd.price)
.NotEmpty()
.WithMessage(Translations.CreateProduct_Price)
}
}
}
Documentation: FluentValidationDocumentation
Those errors are automatically added by the default model binder when it cannot parse the input string into its destination type. They are not like data annotations, where you can specify a resource instead of a harcoded string error message.
However you can use your own resource files, see this other question. Once you have created the resource file, you will update the global.asax for the default model binder to use it:
DefaultModelBinder.ResourceClassKey = "MyResources";
After a custom resource file has been set in the property ResourceClassKey of the default model binder, values will be resolved according to the following criteria (as per the MSDN):
If the property is not set, MVC uses the standard MVC resources.
If the property is set to an invalid class key (such as a resource
file that does not exist), MVC throws an exception.
If the property is set and the class key exists but the resource
names in the file do not exist in the application, MVC uses the
standard MVC resources.
If the property is set and the specified resources are available,
MVC uses the resources in the file.
If you need to know the key values for a particular message check this. For the message The value '{0}' is not valid for {1}., you will need to add a value with the key DefaultModelBinder_ValueInvalid

ASP.NET Web API Deserialize Query Parameters into Nested POCO Action Parameter

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.

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
}

Resources