【问题标题】:Changing the parameter name Web Api model binding更改参数名称 Web Api 模型绑定
【发布时间】:2014-12-23 09:10:10
【问题描述】:

我正在使用 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
}

【问题讨论】:

    标签: c# asp.net-web-api model-binding


    【解决方案1】:

    您可以使用 FromUri 绑定属性的 Name 属性,将具有不同名称的查询字符串参数用于方法参数。

    如果您传递简单参数而不是 QueryParameters 类型,则可以像这样绑定值:

    /api/values/5?cap=somecap&id=1
    
    public IHttpActionResult GetValue([FromUri(Name = "cap")] string capabilities, int id)    
    {
    }
    

    【讨论】:

      【解决方案2】:

      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)
      

      【讨论】:

      • +1 对我有用,尽管我只在参数名称与属性名称不同的属性上标记了 DataMember 属性。因此,我需要将 GetValue 方法调用和 AttemptedValue 引用分开,并对属性进行空检查,否则您将面临 NullReferenceException 的风险。无论如何可能不是一个坏主意:)
      • 必须修复 NullReference 错误并使其适用于字符串以外的其他类型,但它可以工作。
      【解决方案3】:

      我花了几个小时研究同一问题的稳健解决方案,而单线就可以解决问题:

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

      【讨论】:

      • HttpContext.Current.Request["key"] 将始终只返回一个字符串。
      【解决方案4】:

      我刚刚遇到了这个问题,并在我的参数类中使用了一个 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 属性。不知道为什么有人需要使用查询参数来做到这一点。

      【讨论】:

      • 如果参数名称是'$cap'而不是'cap'呢?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      • 2012-06-11
      • 1970-01-01
      相关资源
      最近更新 更多