How to make fields on ViewModel required for Web API call? - asp.net-web-api

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

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?

Mapping Web API Incoming Form Field Names to my class?

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; }
}

Preventing tampering of form fields in ASP.NET MVC EF

The default strongly-typed Edit page in ASP.NET MVC 3 generally exposes all fields for the Entity. While this is often workable, some fields are a security risk. For example a simplified magazine subscription entity might look like:
public void Subscription() {
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public DateTime SubscribedThru { get; set; }
}
If I provide an Edit page to let users change their own address, for example, it's a security risk to include the SubscribedThru field because a knowledgeable and malicious user could give themselves a free 10-year subscription by faking the date (even if I use #Html.HiddenFor(model => model.SubscribedThru). So I am not including that field in any way on the Edit page html (via razor).
I thought the answer might be to prevent binding attempts on SubscribedThru on the Edit method in the controller using something like:
[HttpPost]
public ActionResult Edit([Bind(Exclude="SubscribedThru")] Subscription subscription) {
if (ModelState.IsValid) {
db.Entry(subscription).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(subscription);
}
When I get to the SaveChanges(); line, it throws the error The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value. I believe that the SubscribedThru date (properly?) doesn't exist, and the empty value is less than SQL Server can handle. What surprises me is that it's even trying to update that field when I have Binding excluded for it.
So far my best solution seems to be to create a custom ViewModel that omits the SubscribedThru date, but that seems a lot of duplication of fields, validation, etc.; if possible I'd like to just make the one field SubscribedThru safe from user editing.
I can't say I fully understand the UpdateModel and TryUpdateModel methods and wonder if that's a direction to head? I played with them and EF throws errors for having duplicate objects (same key) which is perplexing.
Also, I'm not clear if the subscription data is preserved from the initial load in public ActionResult Edit(int id) in the controller all the way to the final [HttpPost]
public ActionResult Edit(Subscription subscription)... method, or does the line db.Entry(subscription).State = EntityState.Modified; try and set all the data (I thought it was just setting a flag indicating "edited-so-EF-should-save-this").
I'm a long-time .NET developer, just jumping in to my first ASP.NET MVC project, so I'm probably overlooking something painfully obvious. Thanks for any help!
So far my best solution seems to be to create a custom ViewModel that omits the SubscribedThru date, but that seems a lot of duplication of fields, validation, etc.;
That is exactly what you should do to keep things neat & tidy. AutoMapper eases the ViewModel variation headache.
This page contains an example of updating a model using TryUpdateModel (Listing 4):
http://www.asp.net/mvc/tutorials/older-versions/models-(data)/creating-model-classes-with-the-entity-framework-cs
You can whitelist only the fields that you allow to be edited, which removes the security risk.

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.

MVC DataAnnotations - Require at least one field in a group to be filled

How can I use DataAnnotations to validate that at least one of these fields are filled in?
public string Name { get; set; }
public string State { get; set;}
public string Zip { get; set;}
To do it using DataAnnotations you will need to make a custom attribute because as far as I know there is no built in attribute that will handle this.
To get you started, when you start a new MVC project there is a class called "PropertiesMustMatchAttribute" that is applied at the class level. You could base it off that without much difficulty

Resources