没有公共属性的类型上的自定义 MVC 模型绑定

本文关键字:自定义 MVC 模型 绑定 类型 属性 | 更新日期: 2023-09-27 18:37:17

我已经在我的项目中创建了强类型的ID类,因为目前与可互换的字符串ID存在混淆,这导致了容易错过的错误。

我已将操作方法中的所有string id参数更改为新的强类型,以实现 MVC 模型绑定器现在无法将字符串绑定到新类型(尽管此类型存在隐式字符串转换运算符)。

例如

public ActionResult Index(JobId jobId)
{
  //...
}

我已经阅读了有关创建自定义模型绑定器的信息,但是当我们知道查询参数/表单值的名称时,所有教程都是关于绑定POCO类的。

我只是希望能够告诉框架"如果参数是强类型 id 类型,则使用此构造函数进行实例化",因此无论参数的名称是什么,它都将始终有效。

谁能指出我正确的方向?

编辑

这是强类型 ID 继承自的基类:

public class StronglyTypedId
{    
    private readonly string _id;
    public StronglyTypedId(string id)
    {
        _id = id;
    }
    public static bool operator ==(StronglyTypedId a, StronglyTypedId b)
    {
        if (ReferenceEquals(a, b))
        {
            return true;
        }
        if (((object)a != null) && ((object)b == null) || ((object)a == null))
        {
            return false;
        }
        return a._id == b._id;
    }
    public static bool operator !=(StronglyTypedId a, StronglyTypedId b)
    {
        return !(a == b);
    }
    public override string ToString()
    {
        return _id;
    }
    public override bool Equals(object obj)
    {
        if (!(obj is StronglyTypedId))
        {
            return false;
        }
        return ((StronglyTypedId)obj)._id == _id;
    }
    public Guid ToGuid()
    {
        return Guid.Parse(_id);
    }
    public bool HasValue()
    {
        return !string.IsNullOrEmpty(_id);
    }
}

没有公共属性的类型上的自定义 MVC 模型绑定

我刚刚想出了一种方法来使用自定义模型绑定器来做到这一点。无论需要绑定的参数名称如何,这种方式都将起作用:

public class JobIdModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(JobId))
        {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            string id = value.AttemptedValue;
            return new JobId(id);
        }
        else
        {
            return base.BindModel(controllerContext, bindingContext);
        }
    }
}

因此,这与为特定模型类型实现自定义绑定器几乎相同,只是这是魔术var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName)这意味着无论参数命名如何,它都可以工作。

然后,您只需在Global.cs中注册活页夹,如下所示:

ModelBinders.Binders.Add(typeof(JobId), new JobIdModelBinder());