Partial Entity Updates in WebAPI PUT/POST - asp.net-mvc-3

Say you have a repository method to update a Document:
public Document UpdateDocument(Document document)
{
Document serverDocument = _db.Documents.Find(document.Id);
serverDocument.Title = document.Title;
serverDocument.Content = document.Content;
_db.SaveChanges();
return serverDocument;
}
In this case, the entity has two properties. When updating a Document, both of these properties are required in the JSON request, so a request to PUT /api/folder with a body of
{
"documentId" = "1",
"title" = "Updated Title"
}
would return an error because "content" was not provided. The reason I'm doing this is because, even for nullable properties and properties that the user doesn't update, it seems safer to force the client to specify these fields in the request to avoid overwriting unspecified fields with nulls serverside.
This has led me to the practice of always requiring every updatable property in PUT and POST requests, even if it means specifying null for those properties.
Is this cool, or is there a pattern/practice that I haven't learned about yet that might facilitate partial updates by sending only what is needed over the wire?

The best practice in API design is to use HTTP PATCH for partial updates.
In fact, use cases like yours are the very reason why IETF introduced it in the first place.
RFC 5789 defines it very precisely:
PATCH is used to apply partial modifications to a resource.
A new method is necessary to improve interoperability and prevent
errors. The PUT method is already defined to overwrite a resource
with a complete new body, and cannot be reused to do partial changes.
Otherwise, proxies and caches, and even clients and servers, may get
confused as to the result of the operation. POST is already used but
without broad interoperability (for one, there is no standard way to
discover patch format support).
Mark Nottingham has written a great article about the use of PATCH in API design - http://www.mnot.net/blog/2012/09/05/patch
In your case, that would be:
[AcceptVerbs("PATCH")]
public Document PatchDocument(Document document)
{
Document serverDocument = _db.Documents.Find(document.Id);
serverDocument.Title = document.Title;
serverDocument.Content = document.Content;
_db.SaveChanges();
return serverDocument;
}

Is this cool, or is there a pattern/practice that I haven't learned
about yet that might facilitate partial updates by sending only what
is needed over the wire?
A good practice of doing a POST or PUT is to only include values that you need for that specific request. In doing the UpdateDocument you should ask yourself what "really should be done here"? If you have a hundred fields on that object do you need to update all of them or only part of them. What "action" are you really trying to do?
Let's have an illustration for those questions, say we have a User object that has the following fields:
public class User {
public int Id {get;set;}
public string Username {get;set;}
public string RealName {get;set;}
public string Password {get;set;}
public string Bio {get;set;}
}
You then have two use cases:
Update the profile of a User
Update the password of a User
When you do each of those you will not, or it's a good idea to, have one update method that will do both. Instead of having a generic UpdateUser method you should have the following methods:
UpdateProfile
UpdatePassword
Methods that accepts fields that they just need, nothing more, nothing less.
public User UpdateProfile(int id, string username, string realname, string bio) {
}
public User UpdatePassword(int id, string password) {
}
Now comes the question:
I have a use case that a "user action" allows for an update on
multiple fields where some of the fields can have "no input" from the
user but I don't want to update that field in my model.
Suppose a user updates his/her profile and provided values for Username, RealName but not for Bio. But you do not want to set Bio as null or empty if it has a value already. Then that becomes a part of your application's business logic and that should be handled explicitly.
public User UpdateProfile(int id, string username, string realname, string bio) {
var user = db.Users.Find(id);
// perhaps a validation here (e.g. if user is not null)
user.Username = username;
user.RealName = realname;
if (!string.IsNullOrEmptyWHiteSpace(bio)) {
user.Bio = bio;
}
}

Related

Why model validation is not working

I have following Model class that is used during the Web API Post. As you can see Id field is annotated as Required.
public class Model
{
[Required]
public Guid Id { get; set; }
}
The Post for API is as follows
[HttpPost]
public IActionResult Post([FromBody]Model value)
{
if (!ModelState.IsValid)
return BadRequest();
Model newModel = new Model() { Id = value.Id };
return Ok(newModel);
}
On a sunny day, this is what I see. All good
enter image description here
On a rainy day, when Id is not provided, I get following.
enter image description here
Given that in the second example, a Required field is not provided, shouldn't a BadRequest is returned rather than a 200 with invalid id guid with 00000000-0000-0000-0000-000000000000?
Using the Required annotation
In the Web API Docs, your issue is known as 'under-posting'.
The issue is that Guid has a default value, so when no value is provided, it is initialized with the default value... which then satisfies the Required constraint.
To prevent this, counter-intuitively you make the Guid nullable using Guid?.
Then if the value is not provided, the deserializer will set the value to null, which will cause the Required constraint to be violated.
If the value is provided, it will be set, and all will be well.
See https://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api for more details, there is an example of a similar issue for a decimal property.
The key distinction to understand is that Guid.Empty is really a valid Guid. The only way to distinguish between the user providing a Guid (which is empty) and not providing one at all is to make it nullable, so null = not provided, and Empty = the user provided the empty Guid.
Using a Custom Annotation
If you really don't want to make your Guid nullable, you need to consider what would you do for a 'normal' value type, e.g. an integer. Rather than making it required, you'd use a Range attribute and specify that it must be > 0.
Similarly for Guids, you'd ideally have an attribute that would simply test that it is != Guid.Empty
See https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation#custom-validation for guidance on creating a custom validation atribute.

Missing HttpParameterBinding and ParameterBindingAttribute

I'm investigating Web Api in ASP.NET vNext using the daily builds. In a web api 2x project, I use HttpParameterBinding and ParameterBindingAttribute in some situations (see http://bit.ly/1sxAxdk); however, I can't seem to find either in vNext. Do/will these classes exist? If not, what are my alternatives?
Edit (1-22-15):
I want to be able to serialize a complex JS object to a JSON string, put the JSON string in a hidden form field (say name="data"), submit the form, and then bind my parameter to that JSON object on the server. This will never be done by a human, but rather by a machine. I also want this very same mechanism to work if the JSON is sent directly in the request body instead of form data. I also need this to work for several different types of objects.
I've been able to accomplish this scenario in Web Api 2.2 in a few different ways, including a custom ModelBinder; however, I remember reading an MSFT blog post that suggested to use a ModelBinder for query string binding, formatters for request body, and HttpParameterBinding for more general scenarios. Is it okay to read the request body in a ModelBinder ASP.NET 5, or is there a better mechanism for that? If so, then case closed and I will port my ModelBinder with a few minor changes.
I'm not sure that IInputFormatter will work for me in this case either.
Here are two rough approaches
Approach 1:
A quick and dirty approach would be to start with a Dto model
public class Dto
{
public Serializable Result { get; set; }
public Serializable FromForm
{
get { return Result; }
set { Result = value; }
}
[FromBody]
public Serializable FromBody
{
get { return Result; }
set { Result = value; }
}
}
public class Serializable
{
}
And an action method
public IActionResult DoSomething(Dto dto)
{
// Do something with Dto.Result
}
Then write a custom model binder for Serializable, that just works with Request.Form this way you never actually read the body yourself, and Form only reads it if it of type Form.
The down side of this is that ApiExplorer will not provide correct details (but I think since this is none-standard you are going to be in trouble here anyways).
Approach 2
You can alternatively just use the code from BodyModelBinder and create a custom binder for Serializable type above, that first tries to get it from the Form, and if it fails tries to get it from the Body. The Dto class in that case is not necessary.
Here is some pseudo code
if (inputType is yourtype)
{
if (request.Form["yourkey"] != null)
{
Use Json.Net to deserialize your object type
}
else
{
fall back to BodyModelBinder code
}
}
With this approach you can make it generic, and ApiExplorer will say the way to bind the type is unknown/custom (we haven't decided on the term yet :) )
Note:
Instead of registering the model binder you can use the [ModelBinder(typeof(customBinder))] attribute to apply it sparingly.
Here is a link to the BodyModelBinder code.
There is a new [FromHeader] attribute that allows you to bind directly to http header values if that is what you need.
https://github.com/aspnet/Mvc/issues/1671
https://github.com/aspnet/Mvc/search?utf8=%E2%9C%93&q=fromheader

Play framework 2: one model approach

The problem:
When programming with play framework I feel that I'm stumbling with same problem than in many times at the past which is creating several models of the same type just because I want to add, update or use different data about certain model in different use cases.
Let me explain, lets consider of a example where I have 2 different views: register and login
I would have following User model:
/**
* Example User class (simple annotations for demo purposes).
*
*/
#Entity
public class User {
#Id
public Long id;
#Required
public String email;
#Required
public String password;
#Required
public String firstName;
#Required
public String lastName;
}
In case of registering: I would have all corresponding fields in register.scala.html : email, password, firstName, lastName - because I will need them all when I register, right?
But also I would want to use repeatPassword field to confirm that user has typed password correctly, so I would add this into User model:
#Required
#Transient
public String repeatPassword;
Ok, then I would extend this model to have repeat password confirmation check in order to correct my "automatic" validations when form is submitted, like this:
public String validate() {
if(!password.equals(repeatPassword)) {
return "Passwords doesn't match.";
}
return null;
}
}
So even now I would have one extra attribute repeatPassword which is not persisted to database but used within registration.
Problem #1: Our model starts to go confusing piece by piece.
In case of login: I would want to use same model because its a User which is trying to sign in, right? But instead of all the fields I would only need email, password.
Problem #2: My User model cant be used in login because its already customized to be used within registration - I would need to move repeatPassword and validate() method to separate UserRegistation model, plus duplicate firstName lastName etc. fields or mix using both User and UserRegistration model within registration and to render two different forms to same registration view = confusing.
Problem #3: My login page cant use User model because it has annotations in place, if I dont add all the necessary fields like firstName, lastName etc. I will get errors. Again, I would need to create separate UserLogin model just because I want to login to work.? Example below:
public class UserLogin {
#Required
public String email;
#Required
public String password;
public String validate() {
if(User.authenticate(email, password) == null) {
return "Invalid user or password";
}
return null;
}
}
So very fast, I would have 3 different models just to represent User, one of them is persisted to database and two others is used to validate errors when we are completing login and registration functionality at template side.
So my question is: How on earth I should begin to solve this mess? code complexity is rising very fast :) Should I create separate models.template and models.database packages where template models are only ones within annotations and in case of no errors I start to fill real model before saving or updating its info to database? I need desperately answers from you guys/girls, Can we make one model approach? thnx in advance.
I'll start from the end: you don't need to use whole model for changing password or loggin-in (also you don't need to create separate, 'non-persisted' sub-models), although Form<YourModel> is useful while filling large objects, you can just avoid them and rely on common DynamicForm.
In such case of course it won't use constraints added with annotations to the model's fields but you can validate them manually.
For an example: in registration form you can check if #Required fields like email, firstName, lastName exists (tip: also add MinLength and MaxLength constraints), but you should remove #Required annotation from password field.
Next after checking if the form hasn't any errors you can check if password and repeatedPassword are the same and it they are identical you can also add some individual (advised) strength check - most probably it wouldn't be possible with the annotations in the model.
In case of logging form the thing is ever easier: using DynamicForm data just try to find existing User with given password if result is null that means, the user doesn't exists or password is invalid.
Finally, tip: There is ready-to-use, full-stack authentication and authorisation module available for Play 2.0 by Joscha Feth (and I'm huge advocate of this solution.)

mvc3 composing page and form element dynamically

I'm developing an MVC3 application and I have a page (well, a view) that let the users edit document's metainfo (a classic #Html.BeginForm usage). For general documents users will see standard fields to fill up, but through a dropdownlist they will be able to specify the type of the document: this, through an ajax call, will load new fields on the edit-document-form.
Whem the user submit the completed form, at last, the controller should read all the standard fields, plus all the fields loaded as being specific to the type of document selected.
Question is, how can I handle all this extra fields in a controller?
Say that I have Document class and a bunch of other classes extendinf Document, like Contract : Document, Invoice : Document, Complaint : Document and so forth, each having specific property (and this fields loaded on the form), how do I write the action in the controller?
I thought to use something like (I'll omitt all the conversions, validations, etc, for brevity)
[HttpPost]
public ActionResult Save(dynamic doc)
{
int docType = doc.type;
switch (docType)
{
case 1:
var invoice = new Invoice(doc);
invoice.amount = Request.Form["amount_field"];
invoice.code = Request.Form["code_field"];
//and so forth for every specific property of Invoice
Repository.Save(invoice);
break;
case 2:
var contract = new Contract(doc);
contract.fromDate = Request.Form["fromDate_field"];
contract.toDate = Request.Form["toDate_field"];
//and so forth for every specific property of Contract
Repository.Save(contract);
break;
..... // and so forth for any document types
default:
break;
}
}
But it seems a very dirty approach to me. Do you have a better idea on how to achive this? Maybe there's a pattern that I don't know nothing about to approach this kind of scenario.
Update
A second idea comes to my mind. After commenting Rob Kent's answer, I thought I could take a different approach, having just one class Document with a property like
public IEnumerable<Field> Tipologie { get; set; }
where
public class Field
{
public int IdField { get; set; }
public String Label { get; set; }
public String Value { get; set; }
public FieldType ValueType { get; set; }
public List<String> PossibleValues { get; set; } // needed for ENUMERATION type
}
public enum FieldType
{
STRING, INT, DECIMAL, DATE, ENUMERATION
}
Is this a better approach? In this case I can have just an action method like
[HttpPost]
public ActionResult Save(Document doc)
But shoud I create the fields in the view in order to make the MVC engine do the binding back to the model?
Given that the class inheriting from Document in the first approach will probably be generated at run-time, would you prefer this second approach?
To keep it all hard-typed on the server, you could use an abstract base type with a custom binder. See my answer here to see how this works: MVC generic ViewModel
The idea is that every time they load a new set of fields, you change the BindingType form variable to the instantiated type of the handler. The custom binder is responsible for creating the correct type on submission and you can then evaluate that in your action, eg:
if (model is Contract) ...
I'm not sure if you will be able to set up different actions each with a different signature, eg,:
public ActionResult Save(Contract contract) ...
public ActionResult Save(Invoice invoice) ...
Pretty sure that won't work because Mvc will have already decided which method to call, or maybe it will firstly see what type it gets back and then decides.
In my linked example, I am checking for overridden base members but if that is not an issue for you, you just need to create the correct type.

MVC3 URL parameters - avoiding malicious attacks/security flaws

When navigating to a new webpage, is there a "Best Practice" for passing Ids around.
For example, a person registers to use a website, they get given an Id, this needs to be passed around the rest of the website/pages where it is used to retrieve relevant data from a database.
If the Id is passed in the url: http://myWebsite.com/User/Details/1234, the user could change it to
http://myWebsite.com/User/Details/4567 and potentially retireve a different user's details.
Putting this value in a hidden field and then POSTing wouldn't be great either as "view source" would display the value.
Many thanks
That's why you should always verify that this id belongs to the currently authenticated user. The currently authenticated user is stored in the forms authentication cookie and is something that the user cannot change because the value is encrypted. This cookie is emitted when the user logs in and you can access it everywhere where you have an instance to HttpContextBase (which is pretty much almost anywhere in the V and C parts of the MVC pattern).
For example, like this:
[Authorize]
public ActionResult Foo(int id)
{
string currentUser = httpContext.User.Identity.Name;
// TODO: go ahead and check in your backed that the id
// belongs to the currently connected user
...
}
Obviously writing those checks over and over again in all controller actions could quickly become boring, not to mention the DRYness of the approach. That's why it is recommended to write a custom Authorize attribute which will perform those checks before even entering into the controller action. Then you will decorate your controller actions with this custom attribute and you will know for sure that if the code has reached inside the action it means that the current user is the owner of the id passed as parameter. The way this id is passed as parameter doesn't really matter. Could be route data, query string, POST, whatever. The user can modify it as much as he likes. The important part is that you ensure that the value he entered is coherent with your domain authorization logic.
So:
public class AuthorizeOwnerAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// the user is either not authenticated or not authorized
// no need to continue any further
return false;
}
// at this stage we know that the user is authenticated and
// authorized (in roles), so let's go ahead and see who this
// user is
string username = httpContext.User.Identity.Name;
// now let's read the id. In this example I fetch it from
// the route data but you could adapt according to your needs
string id = httpContext.Request.RequestContext.RouteData.Values["id"] as string;
// Now that we know the user and the id let's go ahead and
// check in our backend if the user is really the owner
// of this id:
return IsOwner(username, id);
}
private bool IsOwner(string username, string id)
{
// go ahead and hit the backend
throw new NotImplementedException();
}
}
and then:
[AuthorizeOwner]
public ActionResult Foo(int id)
{
...
}

Resources