更改参数名称Web Api模型绑定
本文关键字:Api 模型 绑定 Web 参数 | 更新日期: 2023-09-27 18:28:00
我使用Web API模型绑定来解析URL中的查询参数。例如,这里有一个模型类:
public class QueryParameters
{
[Required]
public string Cap { get; set; }
[Required]
public string Id { get; set; }
}
当我调用类似/api/values/5?cap=somecap&id=1
的东西时,这很好。
有没有什么方法可以更改模型类中属性的名称,但保持查询参数名称不变——例如:
public class QueryParameters
{
[Required]
public string Capability { get; set; }
[Required]
public string Id { get; set; }
}
我原以为将[Display(Name="cap")]
添加到Capability
属性中会起作用,但事实并非如此。是否有我应该使用的某种类型的数据注释?
控制器将有一个看起来像这样的方法:
public IHttpActionResult GetValue([FromUri]QueryParameters param)
{
// Do Something with param.Cap and param.id
}
您可以使用FromUri绑定属性的Name属性来使用与方法参数名称不同的查询字符串参数。
如果您传递的是简单的参数而不是QueryParameters
类型,则可以像这样绑定值:
/api/values/5?cap=somecap&id=1
public IHttpActionResult GetValue([FromUri(Name = "cap")] string capabilities, int id)
{
}
Web API使用与ASP.NET MVC稍有不同的模型绑定机制。它为主体中传递的数据使用格式化程序,为查询字符串中传递的信息使用模型绑定器(在您的情况下)。格式化程序尊重附加的元数据属性,而模型绑定器则不尊重。
因此,如果您在消息体而不是查询字符串中传递模型,您可以如下注释数据,它就会起作用:
public class QueryParameters
{
[DataMember(Name="Cap")]
public string Capability { get; set; }
public string Id { get; set; }
}
你可能已经知道了。为了让它与查询字符串参数以及模型绑定器一起工作,您必须使用自己的自定义模型绑定器,该绑定器将实际检查和使用DataMember属性。
下面的一段代码可以做到这一点(尽管它与生产质量相去甚远):
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;
}
}
你还需要在你的控制器方法中表明你想使用这个模型绑定器:
public IHttpActionResult GetValue([ModelBinder(typeof(MemberModelBinder))]QueryParameters param)
- EDIT-添加了更多代码以转换为类型
如果你想在你的类上使用更多的类型,我只添加了一些最常见的类型(int、bool、DateTime等)解析。字符串是默认值。
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);
var propertyType = property.PropertyType;
object convertedValueObject;
switch (Type.GetTypeCode(propertyType))
{
case TypeCode.Empty:
case TypeCode.Object:
case TypeCode.DBNull:
case TypeCode.Char:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Single:
throw new NotImplementedException($"This model binder does not support this type. {propertyType} ");
case TypeCode.Int16:
case TypeCode.UInt16:
convertedValueObject = ushort.Parse(value);
break;
case TypeCode.Int32:
case TypeCode.UInt32:
convertedValueObject = int.Parse(value);
break;
case TypeCode.Int64:
case TypeCode.UInt64:
convertedValueObject = long.Parse(value);
break;
case TypeCode.Double:
convertedValueObject = double.Parse(value);
break;
case TypeCode.Decimal:
convertedValueObject = decimal.Parse(value);
break;
case TypeCode.DateTime:
convertedValueObject = DateTime.Parse(value);
break;
case TypeCode.Boolean:
convertedValueObject = bool.Parse(value);
break;
default:
convertedValueObject = value;
break;
}
property.SetValue(model, convertedValueObject);
}
bindingContext.Model = model;
return true;
}
我刚刚遇到这个问题,并在参数类中使用getter返回绑定属性。
所以在你的例子中:
public class QueryParameters
{
public string cap {get; set;}
public string Capability
{
get { return cap; }
}
public string Id { get; set; }
}
现在,在控制器中,您可以引用Capability
属性。
public IHttpActionResult GetValue([FromUri]QueryParameters param)
{
// Do Something with param.Capability,
// except assign it a new value because it's only a getter
}
当然,如果对param
对象使用反射或对其进行序列化,则会包含cap
属性。但不确定为什么任何人都需要对查询参数执行此操作。
我花了几个小时为同一个问题制定了一个稳健的解决方案,而一行代码可以很好地解决这个问题:
myModel.Capability = HttpContext.Current.Request["cap"];