2

In my MVC 3 solution I want to have all Ids in querystring to be crypted. To decrypt URLs I inherited from DefaultModelBinder and overrided BindProperty method:

 public class CryptedIdBinder : DefaultModelBinder
{   

    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
    {
        if (propertyDescriptor.Name.ToLower() == "id")
        {
            propertyDescriptor.SetValue(bindingContext.Model, CryptoHelper.Decrypt(controllerContext.HttpContext.Request.Form["id"]));
            return;
        }

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

After that I set new DefaultBinder in global.asax on Application_Start:

System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new CryptedIdBinder();

I didn't inherit from IModelBinder because I want to change binding logic only for id fields in solution.

The issue is that BindProperty method is never called. What am I doning wrong?

PS. In order to be sure that I call at least BindModel method I added a peace of this code inside my custom binder, and it was hit by the debugger:

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        return base.BindModel(controllerContext, bindingContext);
    }
2
  • Can you post some sample model code? Maybe the DefaultModelBinder filtered out some of your properties... Commented Nov 4, 2011 at 18:52
  • Sorry, I didn't catch your idea. Isn't it a global binder, that should run for every model? This Id parameter is not defined in model - it's inside the default route Commented Nov 4, 2011 at 18:59

1 Answer 1

2

If your models don't have Id properties of course the BindProperty won't be called. Because it called on the model properties. If I understood your question what you need is to transform each Id named query string parameter. In this case you need a custom value provider instead of a modelbinder. This is good article about the value providers. And it's quite easy to write one:

public class MyValueProviderFacotry : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        return new MyValueProvider(controllerContext);
    }
}

public class MyValueProvider : IValueProvider
{
    private ControllerContext controllerContext;

    public MyValueProvider(ControllerContext controllerContext)
    {
        this.controllerContext = controllerContext;
    }

    public bool ContainsPrefix(string prefix)
    {
        return true;
    }

    public ValueProviderResult GetValue(string key)
    {
        if (key.ToLower() == "id")
        {
           var originalValue =  controllerContext.HttpContext.Request.QueryString[key]; 
           var transformedValue = CryptoHelper.Decrypt(orignalValue );
           var result = new ValueProviderResult(transformedValue,originalValue,CultureInfo.CurrentCulture);
            return result;
        }
        return null;
    }
}

In global.asax:

 protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            ValueProviderFactories.Factories.Insert(4, new MyValueProviderFacotry()); //Its need to be inserted before the QueryStringValueProviderFactory
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much for the answer. It looks like this is the thing I was looking for.I will try this in the morning
This works almost great. The only thing I had to do is to implement ContainsPrefix (so it really returns value indicating, whether I need to search for value or not) and place it not before QueryStringValueProviderFactory, but before RouteValueProviderFactory. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.