Mapping Web API Incoming Form Field Names to my class? - asp.net-web-api

I have written a Web API to be used as a webhook with a 3rd party service so they can send me data when an event occurs in their service. They have dictated what the posted data coming in will be. So I created a class for the incoming data such that each property name matches the field names coming from the posted form urlencoded data.
What I would LIKE to do is name things in my class in a more user-friendly manner than the names they are sending in their POST request. I cannot find if there is a way, maybe using attributes, that will tell the ModelBinder which form data to put into which property. Is there a way to do this?
Incidentally, when I thought they were sending JSON as the POSTED data, I was able to do this with JSON.NET and their JsonProperty attribute. But now that it's coming as application/x-www-form-urlencoded, I don't know how to do this same thing.
Thanks for your help!

please try something like this
[DataContract]
public class TestSerialization
{
[DataMember(Name = "field_one")]
public string ItemOne { get; set; }
[DataMember(Name = "field_two")]
public string ItemTwo { get; set; }
}

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?

Web API Form - Url Encoded Complex Parameter

Deserializing a complex type in WebAPI is giving me serious grief.
The data contains keys that are syntactically invalid in c# as property names.
How can I translate the key names?
Relevant: Web API form-urlencoded binding to different property names
You can use JSON.NET's JsonProperty to do the trick:
public class SomeModel {
[JsonProperty("YourCustomName")]
public string SomeProperty { get; set; }
}
I wrote my own url encoded object deserializer that made use of the JsonProperty attribute. Then I used it with a custom modelbinder.

How to make fields on ViewModel required for Web API call?

I want to know if it is possible or how can I mark fields on my class used as a parameter on my Web API call to be required? I obviously can do this manually once I have received the message, but I was hoping there was something built in the pipeline (like in MVC in combination with jQuery that uses required field annotations to automatically kick back to UI showing required field notations) so I don't have to check everything manually.
Let's say I have the following ViewModel class:
public class PersonViewModel
{
public string FirstName {get; set;}
public string MiddleName {get; set;}
public string LastName {get; set;}
}
Here is my simple Post method on a PersonController
public HttpResponseMessage Post(PersonViewModel person)
{
}
Let's say the FirstName and LastName fields are required but not MiddleName. What I want to know is will the call automatically respond back to the client with a HTTP 400 Bad Request or similar if the Person object does not have one of the required fields populated?
Essentially do I have to do all of this work manually, or is there a way to have the framework handle notated fields automatically, so I don't have a lot of boilerplate validation code for required fields?
Manual Way I'm trying to avoid:
if (ModelState.IsValid)
{
if (person.LastName == string.empty)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
Any help is appreciated, thanks!
WebAPI does have a validation feature. You should be able to mark the FirstName and LastName properties as [Required] and then use the action filter at the bottom of this blog post to send back an appropriate response:
http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
You can read more about WebAPI validation here:
http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api

Polymorphism in Web API: Single endpoint possible?

I realize that the Web API is REST focused, but I would still like to configure a single controller method that can handle a Command/Response scenario. So far I haven't been successful... is there a way to have the following class structure recognized by a single API endpoint?
[Serializable]
public abstract class Command{
public int CommandId{get; set;}
}
[Serializable]
public class RegisterNewPersonCommand:Command{
public string Name{get; set;}
}
//etc... various Command subclasses. Similar thing for Responses.
//now have a single endpoint to Handle Commands
public class CommandsController : ApiController{
public Response HandleCommand(Command command){
//handle Command based on which subclass it is
//return appropriate Response subclass
}
}
Thus far it doesn't seem the serialization system can handle this scenario, but I hope someone out there has found a way to do it :)
In order for polymorphism to work in Web API, you will need to enable type name handling and the data has to contain the type information.
You'll need to turn on TypeNameHandling in WebApiConfig.cs if you're using JSON in your scenario:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling =
Newtonsoft.Json.TypeNameHandling.All;
Then, the content body that you are sending to your HandleCommand(...) action must contain the type information:
{"$type":"MvcApplication.Models.RegisterNewPersonCommand, MvcApplication", ... }
For XML, you'll need to use DataContract's KnownType...
By the way, is there any specific reason why you are using [Serializable] (since POCO types and [DataContract] types are also supported...)?

How to find properties are not modified or change?

I have viewmodel which i am binding with my view call "EditProfile". Now once the user click on the "EditProfile" link from the menu bar I load all the profile information by calling get restful service and user can see his/her profile.
User can change any field they want but I want to post only fields that are changed by User.
I know how to compare two properties but don't know how to pull only modified properties from the viewmodel. Have anybody arrived to this situation before?
Properties in my viewmodel are:
public class UserViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Profession { get; set; }
}
In the past I implemented INotifyPropertyChanged for the ViewModel. And I logged which property's changed after the PropertyChanged event fired.
Why not take an alternative approach - post everything (so the model is available) and simply have "IsDirty" properties on your objects that are smart enough to submit only changes to the database (like the entity framework does by default)
You can simply form your own jQuery .post() parameters, but unless you have a ton of data - why? It makes for a difficult to read view model (how do you know what is posted under what scenarios) so the typical approach is to post separate view models or post everything which in my opinion for basic forms is easier.

Resources