Changing the parameter name Web Api model binding

China☆狼群 提交于 2019-11-28 09:52:20

You can use the Name property of the FromUri binding attribute to use query string parameters with different names to the method arguments.

If you pass simple parameters rather than your QueryParameters type, you can bind the values like this:

/api/values/5?cap=somecap&id=1

public IHttpActionResult GetValue([FromUri(Name = "cap")] string capabilities, int id)    
{
}

Web API uses a bit different mechanism for model binding than ASP.NET MVC. It uses formatters for data passed in the body and model binders for data passed in query string (as in your case). Formatters respect additional metadata attributes whereas model binders do not.

So if you passed your model in message body rather than query string, you could annotate your data as follows and it would work:

public class QueryParameters
{
    [DataMember(Name="Cap")]
    public string Capability { get; set; }

    public string Id { get; set; }
}

You probably know about that already. To get it to work with query string parameters and therefore model binder you would have to use your own custom model binder that would actually inspect and use DataMember attributes.

The following piece of code would do the trick (although it is far from production quality):

public class MemberModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var model = Activator.CreateInstance(bindingContext.ModelType);
        foreach (var prop in bindingContext.PropertyMetadata)
        {
            // Retrieving attribute
            var attr = bindingContext.ModelType.GetProperty(prop.Key)
                                     .GetCustomAttributes(false)
                                     .OfType<DataMemberAttribute>()
                                     .FirstOrDefault();
            // Overwriting name if attribute present
            var qsParam = (attr != null) ? attr.Name : prop.Key;
            // Setting value of model property based on query string value
            var value = bindingContext.ValueProvider.GetValue(qsParam).AttemptedValue;
            var property = bindingContext.ModelType.GetProperty(prop.Key);
            property.SetValue(model, value);
        }
        bindingContext.Model = model;
        return true;
    }
}

You will also need to indicate in your controller method that you want to use this model binder:

public IHttpActionResult GetValue([ModelBinder(typeof(MemberModelBinder))]QueryParameters param)

I spent several hours working on a robust solution to the same problem, when a one-liner will do the trick just fine:

myModel.Capability = HttpContext.Current.Request["cap"];

I just ran into this and used a getter in my parameter class to return the bound property.

So in your example:

public class QueryParameters
{
    public string cap {get; set;}
    public string Capability
    {
      get { return cap; }
    }

    public string Id { get; set; }
}

Now in your Controller you can reference the Capability property.

public IHttpActionResult GetValue([FromUri]QueryParameters param)    
{
    // Do Something with param.Capability,
    // except assign it a new value because it's only a getter
}

Of course if you use reflection on the param object or serialize it the cap property will be included. Not sure why anyone would need to do that with query parameters though.

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