自定义模型绑定问题

发布于 2024-12-13 21:27:39 字数 1248 浏览 2 评论 0原文

在我的 MVC 3 解决方案中,我希望对查询字符串中的所有 Id 进行加密。要解密我从 DefaultModelBinder 继承并重写 BindProperty 方法的 URL:

 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;
    }

之后,我在 Application_Start 上的 global.asax 中设置新的 DefaultBinder:

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

我没有从 IModelBinder 继承,因为我想更改 id 字段的绑定逻辑在溶液中。

问题是 BindProperty 方法从未被调用。我做错了什么?

附言。为了确保我至少调用 BindModel 方法,我在自定义绑定器中添加了这段代码,并且它被调试器命中:

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        return base.BindModel(controllerContext, bindingContext);
    }

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);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

弄潮 2024-12-20 21:27:39

如果您的模型没有 Id 属性,当然不会调用 BindProperty。因为它调用了模型属性。如果我理解你的问题,你需要的是转换每个 Id 命名查询字符串参数。在这种情况下,您需要一个自定义值提供程序而不是模型绑定程序。这是关于价值的好文章提供商。编写一个非常容易:

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;
    }
}

在 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);
        }

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);
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文