Get custom attribute for parameter when model binding

折月煮酒 提交于 2019-12-11 02:46:38

问题


I've seen a lot of similar posts on this, but haven't found the answer specific to controller parameters.

I've written a custom attribute called AliasAttribute that allows me to define aliases for parameters during model binding. So for example if I have: public JsonResult EmailCheck(string email) on the server and I want the email parameter to be bound to fields named PrimaryEmail or SomeCrazyEmail I can "map" this using the aliasattribute like this: public JsonResult EmailCheck([Alias(Suffix = "Email")]string email).

The problem: In my custom model binder I can't get a hold of the AliasAttribute class applied to the email parameter. It always returns null. I've seen what the DefaultModelBinder class is doing to get the BindAttribute in reflector and its the same but doesn't work for me.

Question: How do I get this attribute during binding?

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

Usage:

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
}

回答1:


Gave up on this and then stumbled across the Action Parameter Alias code base that will probably allow me to do this. It's not as flexible as what I started out to write but probably can be modified to allow wild cards.




回答2:


what I did was make my attribute subclass System.Web.Mvc.CustomModelBinderAttribute which then allows you to return a version of your custom model binder modified with the aliases.

example:

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

which then allows this usage:

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


来源:https://stackoverflow.com/questions/18271307/get-custom-attribute-for-parameter-when-model-binding

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!