0

I m trying to create a custom model binder with below code:

public class TransactionModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext)
    {
        Object Model = bindingContext.Model;

        //Do custom logic

        return Model;
    }
}

In global.asax, I m adding:

ModelBinders.Binders.Add(typeof(TransViewModel), new TransactionModelBinder());

Issue: I m not sure how to get Model. I tried bindingContext.Model but it is null. Please also guide if my line of code in Global.asax is fine.

Toubi
  • 2,469
  • 10
  • 33
  • 49

2 Answers2

2

See this article:

public class HomeCustomDataBinder : DefaultModelBinder
{

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(HomePageModels))
        {
            HttpRequestBase request = controllerContext.HttpContext.Request;

            string title = request.Form.Get("Title");
            string day = request.Form.Get("Day");
            string month = request.Form.Get("Month");
            string year = request.Form.Get("Year");

            return new HomePageModels
            {
                Title = title,
                Date = day + "/" + month + "/" + year
            };

            //// call the default model binder this new binding context
            //return base.BindModel(controllerContext, newBindingContext);
        }
        else
        {
            return base.BindModel(controllerContext, bindingContext);
        }
    }

} 
1

Well, if you intend to write the entire binder from scratch, you will not have a model. Instead you'd actually be the one creating the model (since that's what the binder is for), from the form data. Such as:

return new SomeModel 
{
    OneProp = request.Form["OneProp"],
    AnotherProp = request.Form["AnotherProp"]
}

Alternatively you can inherit from DefaultModelBinder instead of IModelBinder, which you can use to extend only certain behavior instead of actually handling the construction of the model.

EDIT:

From your comments I'm understanding that you are only wanting to process one property in several viewmodels you might have (possibly multiple viewmodels have decimals that come from the view in a different format than what MVC expects for decimals.

In that case I'd actually use a different approach. Instead of registering the ModelBinder in global.asax, I'd remove it from there and do it declaratively on the actual properties that need that special format.

Such as:

[PropertyBinder(typeof(MyDecimalBinder))]
public decimal SomePropInAViewModel {get; set;}

This is based on a common approach of creating the PropertyBindingAttribute: http://www.prideparrot.com/blog/archive/2012/6/customizing_property_binding_through_attributes or https://stackoverflow.com/a/12683210/1373170

And with a ModelBinder similar to this:

public class MyDecimalBinder :  DefaultModelBinder {
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) {

        // use the propertyDescriptor to make your modifications, by calling SetProperty()
        ...

        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }

}

Now, if this is something you want applied to ALL decimals, you might also want to check out Phil Haack's full implementation on handling decimals using a custom binder:

http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx/

Community
  • 1
  • 1
Pablo Romeo
  • 11,298
  • 2
  • 30
  • 58
  • agreed. Will be highly appreciate if you please can guide a little more. What you are saying is from Model, I should modify a property and return property and not complete model right ? Before I tried it before. Need to modify just a decimal property. Problem: Unfortunately in Global.asax, I already have a customer binder with decimal. I tried : ModelBinders.Binders.Add(typeof(decimal), new CurrencyModelBinder()); ModelBinders.Binders.Add(typeof(decimal), new TxTransactionModelBinder()); but was error "An item with the same key has already been added." – Toubi Feb 12 '14 at 04:24
  • Please see this for details http://stackoverflow.com/questions/21717757/cant-add-new-custom-model-binder-error-an-item-with-the-same-key-has-already-b?noredirect=1#comment32841219_21717757 – Toubi Feb 12 '14 at 04:25
  • does it means In global.asax I can register 2 custom model binders of same typeof (in this case typeof(decimal)) ? I appreciate your approach but just want to ask, is it not possible ? how you will do if you have to do from global.asax ? – Toubi Feb 12 '14 at 04:45
  • I don't think you can have multiple custom binders for the same type, wouldn't make much sense (it would be similar to having two functions with the same parameters but different return type), however you only seem to need one, for decimals. If you want to allow for separators in your decimals in all your viewmodels, I'd go for Phil Haack's implementation ;) – Pablo Romeo Feb 12 '14 at 04:49
  • I cant access [PropertyBinder(typeof(MyDecimalBinder))] what namespace I should add for it ? Is it from MS ? I musing MVC4. Please guide – Toubi Feb 12 '14 at 05:14
  • I cant access [PropertyBinder(typeof(MyDecimalBinder))] what namespace I should add for it ? Is it from MS ? I musing MVC4. Please guide – Toubi Feb 12 '14 at 05:23
  • 1
    I added a few links on a few PropertyBinder implementations. However, I think in your scenario Phil's implementation may be simpler. – Pablo Romeo Feb 12 '14 at 05:27