ASP.NET WebApi modelbinding to a complex type containing DateTime - asp.net-web-api

This question regards ASP.NET WebApi in MVC 4, not ASP.NET MVC.
Consider the following WebApi Model
public class MyComplex
{
public DateTime? Date { get; set; }
}
bound by model binding as parameter to the following ApiController method
public class MyController : ApiController
{
[HttpPost]
public HttpResponseMessage PostMyComplex(MyComplex id){ .. }
}
How do I declare what format the model binder should expect for MyComplex.Date? As I see it, Modelbinders in WebApi does the trick when the parameter is of type DateTime itself, but I haven't seen a good way of handling date formats when they are part of a complex type and I want to restrict what is acceptable for the api. I have gone down the route of experimenting with both Modelbinders and ValueProviders, none of which seems suitable.
I want to explicitly restrict acceptable HttpPosts on format dd-MM-yyyy.

Related

WebAPI OData v4 - Using a class to represent an action's parameters

I want to add an action to my OData controller. I'll be calling this action with the request body matching the following structure, and with the following validation requirements:
public class PublishModel
{
[Required, EnumDataType(typeof(JobEventType))]
public JobEventType Type { get; set; }
[Required, StringLength(100)]
public string ExternalRef { get; set; }
public DateTimeOffset? DateTime { get; set; }
}
With a normal ApiController, I'd normally have my controller method simply take an argument of this type, and it'd work. With OData, it seems I have to implement my method using a ODataActionParameters argument.
I can't figure out how I'm supposed to tell OData that the body of the request should match the above. The closest I've got is to have it expect it in a parameter:
var pa = mb.EntityType<Edm.JobEvent>().Collection.Action("publish");
pa.ReturnsFromEntitySet<Edm.JobEvent>("jobevent");
pa.Parameter<PublishModel>("evt");
But this requires me to send
{"evt":{"type":"...","externalRef":"...","dateTime":"..."}}
When what I want to send is just
{"type":"...","externalRef":"...","dateTime":"..."}
I understand that I can just specify the properties of my class as individual parameters, but that'll be harder to maintain and I'll lose the data annotation validation. Is there a way to handle this?

Doctrine: Validate Model Data using Annotations

In doctrine, is there a way that I could validate model data using annotations? Like the bellow example in c#
public class ProductMD {
[StringLength(50),Required]
public object Name { get; set; }
[StringLength(15)]
public object Color { get; set; }
[Range(0, 9999)]
public object Weight { get; set; }
}
So when the property Name is empty then it will give you error.
Unfortunately, starting from Doctrine2 there is no validation component integrated into the ORM itself anymore.
If, for example, you're using Doctrine2 with Symfony2, you can take advantage of the validation framework component by using #Assert annotations in the Doctrine entities.
If you don't use any framework, or if the framework you use does not provide a validation component, you can always use Doctrine's lifecycle callbacks to provide custom validation in #PrePersist and #PreUpdate (for more information, take a look here). In this case, there's more manual work to be done but it still sounds like a reasonable solution.

read Asp.Net Web api GET values from url

I am trying to map /{Controller}/{Variable1}/{Variable2}/{Variable3} to a GET method in controller
public TestController{
public ActionResult Get([FromUrl] Entity instance){}
}
So I need to map variables to the entity.
To put it into an example
/Product/{category}/{filter1}/{filter2}/
Entity
public class ProductSearchRequest
{
public string Category{get;set;}
public string filter1 {get;set;}
public string filter2 {get;set;}
}
Controller
public ProductController: Controller {
public ActionResult GET([FromUri] ProductSearchRequest productSearchRequest){
}
}
[EDITED]
Had to do following changes to get this working
Instead of RouteCollection.MapHttpRoute use HttpConfiguration.Routes.MapHttpRoute as this is API routing not MVC routing.
Inherit controller from ApiController rather than Controller which I was before.
Basically you are not going to be able to do that. Complex types are not compatible with the routing mechanism.
Take a read of this article. But this paragraph explains why the routing mechanism cannot do what you are asking.
A complex type can only bind to the URI through a custom binding. But
in that case, the framework cannot know in advance whether the
parameter would bind to a particular URI. To find out, it would need
to invoke the binding. The goal of the selection algorithm is to
select an action from the static description, before invoking any
bindings. Therefore, complex types are excluded from the matching
algorithm.
Therefore the basic rule is:
For every parameter of the action, if the parameter is taken from the
URI, then the parameter name must be found either in the route
dictionary or in the URI query string. (Optional parameters and
parameters with complex types are excluded.)
Which means you need to define your action like so:
public ActionResult GET(string Category, string filter1, string filter2){
}
And your route template:
/{controller}/{category}/{filter1}/{filter2}/

How does one bind the value of a field to a property with a different name using ASP.NET MVC 3?

Consider the following model which uses XmlSerializer and JSON.net to serialize the object to and from the respective formats.
[XmlRoot("my_model")]
[JsonObject("my_model")]
public class MyModel {
[JsonProperty("property1")]
[XmlElement("property1")]
public string Property1 { get; set; }
[JsonProperty("important")]
[XmlElement("important")]
public string IsReallyImportant { get; set; }
}
Now consider the following ASP.NET MVC 3 action that accept JSON or XML requests and returns model in the respective format (based on the accept header).
public class MyController {
public ActionResult Post(MyModel model) {
// process model
string acceptType = Request.AcceptTypes[0];
int index = acceptType.IndexOf(';');
if (index > 0)
{
acceptType = item.Substring(0, index);
}
switch(acceptType) {
case "application/xml":
case "text/xml":
return new XmlResult(model);
case "application/json":
return new JsonNetResult(model);
default:
return View();
}
}
}
Custom ValueProviderFactory implementations exist for JSON and XML inputs. As it stands the IsReallyImportant is being ignored when the input is being mapped to MyModel. However, if I define the attributes of IsReallyImportant to use "isreallyimportant", then information is correctly serialized.
[JsonProperty("isreallyimportant")]
[XmlElement("isreallyimportant")]
public string IsReallyImportant { get; set; }
As expected the default binder uses the property name when mapping incoming values to the model. I had a look at the BindAttribute, however its not supported on properties.
How does one tell ASP.NET MVC 3 that the property IsReallyImportant should be bound to "important" in the incoming request?
I have too many models to write a custom binder for each. Note that I don't use ASP.NET Web API.
You can do only one custom ModelBinder which will look for JSonProperty and XMLElement attributes to map the right properties. This way you could use it everywhere and you won't have to develop a modelbinder for each model. Unfortunately, there is no other option to modify the property bindings than custom modelbinders.

ASP.Net Web API - How can I make it so that prefixes are not required when model binding from the query string?

In ASP.Net Web API (RC) I have a test model class like so:
[ModelBinder]
public class TestRequest
{
public string Foo { get; set; }
public string Bar { get; set; }
}
My controller looks like this:
public class TestController : ApiController
{
public TestRequest Get(TestRequest model)
{
return model;
}
}
Now if I invoke the action via:
http://.../test?foo=abc&bar=xyz
neither values bind, because the model binder is expecting model prefixes, such that I actually need to call:
http://.../test?model.foo=abc&model.bar=xyz
I can understand that this is so that other action parameters can bind correctly, but in my case the model is a clean way of encapsulating all the possible action parameters so that I don't need to have a nasty action method signature with a whole lot of optional parameters. It also allows for easy model validation.
Is there any easy way to cause model binding to behave the same way as it would in MVC, or in a POST request?
Removing the ModelBinder attribute from your model class should work in the example you've posted. You'll run into issues for more complex method signatures, see Rick Strahl's comment: http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx#10302750

Resources