模型绑定时获取参数的自定义属性

时间:2013-08-16 10:35:19

标签: asp.net-mvc c#-4.0 model-binding

我在这上面看过很多类似的帖子,但没有找到特定于控制器parameters的答案。

我编写了一个名为AliasAttribute的自定义属性,允许我在模型绑定期间为参数定义别名。例如,如果我在服务器上有public JsonResult EmailCheck(string email),我希望将email参数绑定到名为 PrimaryEmail SomeCrazyEmail 的字段,我可以使用alias属性“映射”这样:public JsonResult EmailCheck([Alias(Suffix = "Email")]string email)

问题:在我的自定义模型绑定器中,我无法保持应用于AliasAttribute参数的email类。它总是返回null。 我已经看到 DefaultModelBinder 类正在做什么来在反射器中获取 BindAttribute 并且它相同但不适用于我。

问题:如何在绑定过程中获取此属性?

AliasModelBinder:

public class AliasModelBinder : DefaultModelBinder
{
    public static ICustomTypeDescriptor GetTypeDescriptor(Type type)
    {
        return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = base.BindModel(controllerContext, bindingContext);

        var descriptor = GetTypeDescriptor(bindingContext.ModelType);
        /*************************/
        // this next statement returns null!
        /*************************/
        AliasAttribute attr = (AliasAttribute)descriptor.GetAttributes()[typeof(AliasAttribute)];

        if (attr == null)
            return null;

        HttpRequestBase request = controllerContext.HttpContext.Request;

        foreach (var key in request.Form.AllKeys)
        {
            if (string.IsNullOrEmpty(attr.Prefix) == false)
            {
                if (key.StartsWith(attr.Prefix, StringComparison.InvariantCultureIgnoreCase))
                {
                    if (string.IsNullOrEmpty(attr.Suffix) == false)
                    {
                        if (key.EndsWith(attr.Suffix, StringComparison.InvariantCultureIgnoreCase))
                        {
                            return request.Form.Get(key);
                        }
                    }
                    return request.Form.Get(key);
                }
            }
            else if (string.IsNullOrEmpty(attr.Suffix) == false)
            {
                if (key.EndsWith(attr.Suffix, StringComparison.InvariantCultureIgnoreCase))
                {
                    return request.Form.Get(key);
                }
            }
            if (attr.HasIncludes)
            {
                foreach (var include in attr.InlcludeSplit)
                {
                    if (key.Equals(include, StringComparison.InvariantCultureIgnoreCase))
                    {
                        return request.Form.Get(include);
                    }
                }
            }
        }
        return null;
    }
}

AliasAttribute:

[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class AliasAttribute : Attribute
{
    private string _include;
    private string[] _inlcludeSplit = new string[0];

    public string Prefix { get; set; }
    public string Suffix { get; set; }
    public string Include
    {
        get
        {
            return _include;
        }
        set
        {
            _include = value;
            _inlcludeSplit = SplitString(_include);
        }
    }
    public string[] InlcludeSplit
    {
        get
        {
            return _inlcludeSplit;
        }
    }
    public bool HasIncludes { get { return InlcludeSplit.Length > 0; } }


    internal static string[] SplitString(string original)
    {
        if (string.IsNullOrEmpty(original))
        {
            return new string[0];
        }
        return (from piece in original.Split(new char[] { ',' })
                let trimmed = piece.Trim()
                where !string.IsNullOrEmpty(trimmed)
                select trimmed).ToArray<string>();
    }
}

用法:

public JsonResult EmailCheck([ModelBinder(typeof(AliasModelBinder)), Alias(Suffix = "Email")]string email)
{
    // email will be assigned to any field suffixed with "Email". e.g. PrimaryEmail, SecondaryEmail and so on
}

2 个答案:

答案 0 :(得分:0)

放弃这个,然后偶然发现了可能允许我这样做的Action Parameter Alias代码库。它不像我开始编写的那样灵活,但可能会被修改为允许使用外卡。

答案 1 :(得分:0)

我所做的是创建我的属性子类System.Web.Mvc.CustomModelBinderAttribute,然后允许您返回使用别名修改的自定义模型绑定器的版本。

示例:

public class AliasAttribute : System.Web.Mvc.CustomModelBinderAttribute
{
    public AliasAttribute()
    {
    }

    public AliasAttribute( string alias )
    {
        Alias = alias;
    }

    public string Alias { get; set; }

    public override IModelBinder GetBinder()
    {
        var binder = new AliasModelBinder();

        if ( !string.IsNullOrEmpty( Alias ) )
            binder.Alias = Alias;

        return binder;
    }
}

然后允许这种用法:

public ActionResult Edit( [Alias( "somethingElse" )] string email )
{
    // ...
}