Pages

I've migrated my blog

Thanks for visiting my blog. I am no longer maintaining this and I've migrated the blog to my personal domain . If you would like to follow my blog kindly use my new RSS feed

Friday, April 13, 2012

An interesting JSON Model Binding behaviour in ASP.NET MVC3

Introduction

Model Binding is one of the coolest feature in ASP.NET MVC3. Like a magic wand, your form element values, JSON values, also query string values automatically get converted to the equivalent C# object and makes the life of the developer easier.

The default behaviour of MVC3 model binding works well in more common scenarios. But in certain cases it wont work as expected, and in such situations we need to write custom model binders. Two weeks before while I was working with model binding on JSON values, I’ve encountered an interesting behaviour of JSON model binding.

If a JSON property contains a string, it get bind to a string property of the equivalent C# object. But if that same JSON property contains a empty string, while model binding, the equivalent C# object’s property is assigned to null and not to empty string! The same happened with arrays. If it contains elements, it get bind without any problems. But if the array is empty it get bind to null!!

In this blog post, we are going to get rid of this intriguing behaviour by writing a Custom JSON model binder. Hope it would be useful and save you some hairs Smile 

The Sample Application – “MyMobileStore”

In this blog post we are going to see a small application called “MyMobileStore”. This sample app has two features. One will help you to search the mobiles in the “MyMobileStore” by using the company name and the mobile types. An another feature will help you to find out the sales details of the mobiles from a given company for the specified mobile types.

Show me the code

Core classes

MobileStore.Models 

As mentioned earlier, the two features of “MyMobileStore” are exposed as controller action methods as below

MobileStore.Controller

Both action methods uses a parameter of type “MobileFilter” which actually holds the filter criteria for finding out the mobiles. It has two properties, the companyname of the mobile and the collection of mobile types (Normal, DualSim or SmartPhone)

MobileStore.MobileFilter

The SearchMobiles action method retrieves all the mobiles from the repository and filter it first by the company name and then by the mobile types. One small tweak, if the mobile types count is more than 3, it would take only the first 3 types (Added for demo purpose). I just left the logic of SalesDetails action method blank to keep it simple. Both actions returns a JSON result to make them consumed by ajax.

(Note: I’ve violated some design principles in the sample code as I just wanted to make this blog post as simple as possible)

The Problem (Opportunity in my language)

In a good world, if the user selected either or both the company name and the mobiles types to be filtered, then our controller in “MyMobileStore” will happily accepts them as a parameter and continue its work without any mishaps.

GoodWorld

But in the bad world, if the user missed out either the company names or the mobiles types or both, ASP.NET MVC3 treat them as nulls which might cause null reference exception and breaks the functionality!!

BadWorld

NullException

(Now you might have understood why I added a tweak in the number of mobile types Smile)

Possible Solutions

  1. Perform null check inside the “SearchMobiles” action method and assign empty array.
  2. Write a Custom Model Binder for “MobileFilter” and perform the null check inside the model binding logic

Though the option 1 is a simple and straightforward thing, what would you do if the “SalesDetails” action method works with the mobile types collection. You certainly need to duplicate the null checking inside it also. Let us assume that we have some more action methods in our “MyMobileStore” which has “MobileFilter” as their parameter. Do you still duplicate the null check there ?. Think!!

If you do so, I am sorry my dear friend, you are violating the DRY principle and creating a broken window in your codebase! So, lets go ahead and write clean code by making use of Custom Model Binder for our “MobileFilter”.

The Pragmatic Solution – MobileFilterModelBinder

MobileFilterModelBinder

Our custom model binder is very simple, it just makes use of Default Model binding behaviour. After the default behaviour has been done, it checks for null values using Null-Coalescing operator and assign empty values if the values are null.

Don’t forget add the custom model binder in the Global.asax.cs file.

Global

Now our “MyAppStore” is robust enough to tackle the bad world!!

NoMoreBadWorld

Conclusion

In this blog post you have seen an exciting problematic behaviour of JSON model binding in ASP.NET MVC3 and a simple way to get rid of the default model binding problems. In my next blog post I would share my experiences in how to unit test this custom model binders. You can download the source code that I have used in this blog post from here.  

10 comments:

  1. good stuff buddy. Appreciate your attitute towards programming.

    ReplyDelete
  2. Hello, good and interesting article you have posted.

    I have a question thought: isn't it better to use the MobileFilter's default constructor to initialize default values, in order not to have null properties? I am saying this because I believe that the model is the most appropriate context where values are being initially handled.

    I believe that the ModelBinder's main role is not handling value-related constrains, and it can add a bit of a complexity in your code, as a whole.

    ReplyDelete
    Replies
    1. Thanks Andrei. Its a very good catch and it really makes sense to add the value-related constraints in the model itself.

      I have preferred this approach over what you have mentioned, as it is targeted to address the leakiness in the model binding behavior of the MVC3.

      Even we used default value assignment in Model's default constructor, A string property will be assigned to null when model binding happens. To accommodate this we may need to add a separate getter for the string property which check for the null value and return a valid value.

      With these changes, now the model is polluted with some additional code just to overcome the limitation of model binding. I believe model has to be meaningful on its own, it should don't do anything just because its consumer has some limitations.

      Thanks for your feedback. Correct me if I am wrong.

      Delete
  3. Usually, I visit your blogs and get updated with the information you include but today’s blog would be the most appreciable...

    Thanks
    Cpa offers

    ReplyDelete
  4. Nice! you are sharing such helpful and easy to understandable blog. i have no words for say i just say thanks because it is helpful for me.

    Dot Net Training in Chennai | Dot Net Training in anna nagar | Dot Net Training in omr | Dot Net Training in porur | Dot Net Training in tambaram | Dot Net Training in velachery







    ReplyDelete
  5. Thanks for sharing I really loved this article the way you presented is really amazing
    Best Software training institues

    ReplyDelete
  6. very charming case. i've basically found your blog and cherished considering your weblog posts entirely bounty. I'm searching out new presents on get safeguard of more prominent bombastic data. large thank you for the advantageous information. Microsoft Office 2019 Crack

    ReplyDelete
  7. Goodness, super make regarded. i'd once to draft rearward of this too - taking period and genuine chafing achievement to make a massive article. This verification has asked me to consider unequivocal presents that i'm going on record quickly. Tally ERP 9 With GST Crack Full Version Zip

    ReplyDelete