Reputation: 1841
While experimenting with the WebAPI with regards to creating RESTful web services one thing has been consistently bugging me: What to do with non-nullable types?
Example object:
public class Product {
public Guid Id {get; set;}
public string Name {get; set;}
public decimal Price {get; set;}
public bool InStock {get; set;}
}
Example Controller method:
public void Put (Product product){
productRepository.Update(product);
}
Example json call PUT:
{
"Id": "8E28961C-C99E-4EED-9F33-44D33C107A33",
"Name": "Generic Bottled Water"
}
So we are left with a now with a dilemma, the json call does not include the Price
or the InStock
property in the request so deserialised Price=0
and Instock=false
. At this stage it is now impossible to validate the request because we cannot know the they have intentionally set these values or if they are defaulted because they don't exist.
MAKE THEM NULLABLE! I hear someone from the gallary cry. Yes indeed I could make all my value types nullable by adding that little ?
to the end of each declaration. This to me though is a terrible idea and an abuse of the nullable type. Model View Control are separate for a reason and if your model has to care about how the Controller is going to use it then you have already invalidated your sepration of concerns.
FORCE THEM TO PASS THROUGH ALL PROPERTIES! I hear someone else cry. However this then leads to a waste of bandwidth as superfluous data flies back and fourth.
So what is the answer then.? My 2 cents on the matter are that if you dont want to compromise your core model for the sake of the controllers and you also don't want to force your api consumers to send the full object each and every time then you are left with one solution.
Everything that gets passed through is serialised to a collection and you then validate the collection to decide if all the needed properties exist. So you could end up with the following:
public void Put (Guid productId, Dictionary<string, object> productDictionary){
...retrieve and validate existing product.
if (productDictionary.ContainsKey("Price"))
existingProduct.Price = productDictionary["Price"];
if (productDictionary.ContainsKey("InStock"))
existingProduct.Price = productDictionary["InStock"];
productRepository.Update(existingProduct);
}
I don't particulary like this way either if I'm honest however I don't see a real alternative. I really don't want to make all my object properties nullable nor do I want to force the client to pass through all data.
Does anyone have a better suggestion as to how to get around this issue? Perhaps some validation clause or library that I'm missing? Some architectural pattern that can deal with this?
I truly feel that serialization to object model is a bit of a false economy.
Edit
I've re-opened this question because researching DTO's I really don't think they are the way forward. They increase complexity and reduce maintainability while at the same time not giving you anything over say a dictionary or collection.
Upvotes: 2
Views: 883
Reputation: 2098
This is the time where you should create a separate view model specifically for the controller action. The view model can have the nullable properties and then you can set whatever you need to on an instance of Product that you create in the controller.
Upvotes: 3
Reputation: 3199
Would a custom model binder solve your issue? You can decide how to instantiate a model and what properties to fill and how based on the information passed to you by the request. This is essentially the same solution you provided but done without the serialization and all the extra handling as you would be creating the model yourself.
Upvotes: 0