web-dev-qa-db-ja.com

パラメータ名の変更WebApiモデルバインディング

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
}
_
14
user1763965

FromUriバインディング属性のNameプロパティを使用して、メソッド引数とは異なる名前のクエリ文字列パラメーターを使用できます。

QueryParameters型ではなく単純なパラメーターを渡す場合は、次のように値をバインドできます。

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

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

Web APIは、ASP.NETMVCとは少し異なるメカニズムをモデルバインディングに使用します。本文に渡されるデータにはフォーマッターを使用し、クエリ文字列に渡されるデータにはモデルバインダーを使用します(あなたの場合のように)。フォーマッターは追加のメタデータ属性を尊重しますが、モデルバインダーは尊重しません。

したがって、クエリ文字列ではなくメッセージ本文でモデルを渡した場合、次のようにデータに注釈を付けることができ、それは機能します。

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)
13
Sebastian K

私はこれに遭遇し、パラメータクラスでゲッターを使用してバインドされたプロパティを返しました。

だからあなたの例では:

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プロパティが含まれます。しかし、なぜ誰かがクエリパラメータでそれを行う必要があるのか​​わかりません。

0
pholly

私は同じ問題の堅牢な解決策に数時間を費やしましたが、ワンライナーでうまくいく場合は次のようになります。

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