ASP.NET Web API 'sinde parametre bağlamaParameter Binding in ASP.NET Web API

, Mike te sonby Mike Wasson

ASP.NET Core Web API 'sinikullanmayı düşünün.Consider using ASP.NET Core web API. ASP.NET 4. x Web API 'sine göre aşağıdaki avantajları vardır:It has the following advantages over ASP.NET 4.x Web API:

  • ASP.NET Core, Windows, macOS ve Linux 'ta modern, bulut tabanlı Web uygulamaları oluşturmaya yönelik açık kaynaklı, platformlar arası bir çerçevedir.ASP.NET Core is an open-source, cross-platform framework for building modern, cloud-based web apps on Windows, macOS, and Linux.
  • ASP.NET Core MVC denetleyicileri ve Web API denetleyicileri birleştirilmiştir.The ASP.NET Core MVC controllers and web API controllers are unified.
  • , Test edilebilirlik için tasarlanmıştır.Architected for testability.
  • Windows, macOS ve Linux 'ta geliştirme ve çalıştırma özelliği.Ability to develop and run on Windows, macOS, and Linux.
  • Açık kaynak ve topluluk odaklı.Open-source and community-focused.
  • Modern, istemci tarafı çerçeveleri ve geliştirme iş akışlarının tümleştirilmesi.Integration of modern, client-side frameworks and development workflows.
  • Buluta hazırlanma, ortam tabanlı bir yapılandırma sistemi.A cloud-ready, environment-based configuration system.
  • Yerleşik bağımlılık ekleme.Built-in dependency injection.
  • Basit, yüksek performanslı ve modüler bir HTTP istek işlem hattı.A lightweight, high-performance, and modular HTTP request pipeline.
  • Kestrel, IIS, http. sys, NGINX, Apacheve Dockerüzerinde barındırma özelliği.Ability to host on Kestrel, IIS, HTTP.sys, Nginx, Apache, and Docker.
  • Yan yana sürüm oluşturma.Side-by-side versioning.
  • Modern web geliştirmeyi basitleştiren araçlar.Tooling that simplifies modern web development.

Bu makale, Web API 'sinin parametreleri nasıl bağlamakta olduğunu ve bağlama işlemini nasıl özelleştirebileceğinizi açıklamaktadır.This article describes how Web API binds parameters, and how you can customize the binding process. Web API 'SI bir denetleyicide bir yöntemi çağırdığında,, bağlamaadlı bir işlem olan parametrelerin değerlerini ayarlaması gerekir.When Web API calls a method on a controller, it must set values for the parameters, a process called binding.

Varsayılan olarak, Web API parametreleri bağlamak için aşağıdaki kuralları kullanır:By default, Web API uses the following rules to bind parameters:

  • Parametre "basit" bir tür ise, Web API 'SI URI 'den değeri almaya çalışır.If the parameter is a "simple" type, Web API tries to get the value from the URI. Basit türler, .NET ilkel türlerini (int, bool, Double, vb.), artı TimeSpan, DateTime, Guid, Decimal, ve Stringve bir dizeden dönüştürebileceğiniz tür dönüştürücüsü olan herhangi bir türü içerir.Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (Daha sonra tür dönüştürücüler hakkında daha fazla bilgi.)(More about type converters later.)
  • Karmaşık türler için Web API 'SI, bir medya türü biçimlendiricikullanarak ileti gövdesinden değeri okumaya çalışır.For complex types, Web API tries to read the value from the message body, using a media-type formatter.

Örneğin, tipik bir Web API denetleyici yöntemi aşağıda verilmiştir:For example, here is a typical Web API controller method:

HttpResponseMessage Put(int id, Product item) { ... }

ID parametresi "basit bir" türüdür, bu nedenle Web API 'SI istek URI 'sinden değeri almaya çalışır.The id parameter is a "simple" type, so Web API tries to get the value from the request URI. Öğe parametresi karmaşık bir türdür, bu nedenle Web API 'si, istek gövdesinden değeri okumak için bir medya türü biçimlendirici kullanır.The item parameter is a complex type, so Web API uses a media-type formatter to read the value from the request body.

URI 'den bir değer almak için Web API 'si yol verilerine ve URI sorgu dizesine bakar.To get a value from the URI, Web API looks in the route data and the URI query string. Yönlendirme sistemi URI 'yi ayrıştırdığında ve bir rota ile eşleştiğinde rota verileri doldurulur.The route data is populated when the routing system parses the URI and matches it to a route. Daha fazla bilgi için bkz. Yönlendirme ve eylem seçimi.For more information, see Routing and Action Selection.

Bu makalenin geri kalanında, model bağlama işlemini nasıl özelleştirebileceğinizi göstereceğiz.In the rest of this article, I'll show how you can customize the model binding process. Ancak karmaşık türler için, mümkün olduğunda medya türü formatlayıcıları kullanmayı düşünün.For complex types, however, consider using media-type formatters whenever possible. HTTP 'nin önemli prensibi, kaynak gösterimini belirtmek için içerik görüşmesi kullanılarak ileti gövdesinde kaynakların gönderilmektir.A key principle of HTTP is that resources are sent in the message body, using content negotiation to specify the representation of the resource. Medya türü formatlayıcıları tam olarak bu amaçla tasarlanmıştı.Media-type formatters were designed for exactly this purpose.

[FromUri] kullanmaUsing [FromUri]

Web API 'sini URI 'den karmaşık bir tür okuyacak şekilde zorlamak için, parametresine [Fromuri] özniteliğini ekleyin.To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter. Aşağıdaki örnek, URI 'den GeoPoint alan bir denetleyici yöntemiyle birlikte GeoPoint türünü tanımlar.The following example defines a GeoPoint type, along with a controller method that gets the GeoPoint from the URI.

public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }
}

public ValuesController : ApiController
{
    public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}

İstemci, enlem ve boylam değerlerini sorgu dizesine yerleştirebilir ve Web API 'SI bunları bir GeoPointoluşturmak için kullanır.The client can put the Latitude and Longitude values in the query string and Web API will use them to construct a GeoPoint. Örneğin:For example:

http://localhost/api/values/?Latitude=47.678558&Longitude=-122.130989

[FromBody] kullanmaUsing [FromBody]

Web API 'sini istek gövdesinden basit bir tür okuyacak şekilde zorlamak için, [Frombody] özniteliğini parametresine ekleyin:To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter:

public HttpResponseMessage Post([FromBody] string name) { ... }

Bu örnekte, Web API 'SI, istek gövdesinden adı değerini okumak için bir medya türü biçimlendirici kullanacaktır.In this example, Web API will use a media-type formatter to read the value of name from the request body. Örnek bir istemci isteği aşağıda verilmiştir.Here is an example client request.

POST http://localhost:5076/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:5076
Content-Type: application/json
Content-Length: 7

"Alice"

Bir parametre [FromBody] olduğunda, Web API 'SI bir biçimlendirici seçmek için Content-Type üst bilgisini kullanır.When a parameter has [FromBody], Web API uses the Content-Type header to select a formatter. Bu örnekte, içerik türü "Application/JSON" ve istek gövdesi ham JSON dizesidir (JSON nesnesi değil).In this example, the content type is "application/json" and the request body is a raw JSON string (not a JSON object).

İleti gövdesinden en fazla bir parametrenin okumasına izin verilir.At most one parameter is allowed to read from the message body. Bu nedenle, bu çalışmaz:So this will not work:

// Caution: Will not work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Bu kuralın nedeni, istek gövdesinin yalnızca bir kez okunabilecek, arabelleğe alınmamış bir akışa depolanabileceği bir akışdır.The reason for this rule is that the request body might be stored in a non-buffered stream that can only be read once.

Tür dönüştürücülerType Converters

Bir TypeConverter 'ı oluşturarak ve bir dize dönüştürmesi sağlayarak Web API 'sinin bir sınıfı basit bir tür olarak (Web API 'sini URI 'den bağlamaya çalışacak şekilde) görmesini sağlayabilirsiniz.You can make Web API treat a class as a simple type (so that Web API will try to bind it from the URI) by creating a TypeConverter and providing a string conversion.

Aşağıdaki kod, bir coğrafi noktayı temsil eden bir GeoPoint sınıfını ve dizelerden GeoPoint örneklerine dönüştüren bir TypeConverter 'ı gösterir.The following code shows a GeoPoint class that represents a geographical point, plus a TypeConverter that converts from strings to GeoPoint instances. GeoPoint sınıfı, tür dönüştürücüsünü belirtmek için bir [TypeConverter] özniteliğiyle donatılmalıdır.The GeoPoint class is decorated with a [TypeConverter] attribute to specify the type converter. (Bu örnek, Mike Stall 'ın Web günlüğü gönderisini MVC/WebAPI içindeki eylem imzalarındaki özel nesnelere bağlama.)(This example was inspired by Mike Stall's blog post How to bind to custom objects in action signatures in MVC/WebAPI.)

[TypeConverter(typeof(GeoPointConverter))]
public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }

    public static bool TryParse(string s, out GeoPoint result)
    {
        result = null;

        var parts = s.Split(',');
        if (parts.Length != 2)
        {
            return false;
        }

        double latitude, longitude;
        if (double.TryParse(parts[0], out latitude) &&
            double.TryParse(parts[1], out longitude))
        {
            result = new GeoPoint() { Longitude = longitude, Latitude = latitude };
            return true;
        }
        return false;
    }
}

class GeoPointConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof(string))
        {
            return true;
        }
        return base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, 
        CultureInfo culture, object value)
    {
        if (value is string)
        {
            GeoPoint point;
            if (GeoPoint.TryParse((string)value, out point))
            {
                return point;
            }
        }
        return base.ConvertFrom(context, culture, value);
    }
}

Şimdi Web API 'SI GeoPoint basit bir tür olarak değerlendirir, yani GeoPoint parametrelerini URI 'den bağlamaya çalışacaktır.Now Web API will treat GeoPoint as a simple type, meaning it will try to bind GeoPoint parameters from the URI. Parametreye [Fromuri] eklemeniz gerekmez.You don't need to include [FromUri] on the parameter.

public HttpResponseMessage Get(GeoPoint location) { ... }

İstemci, yöntemi aşağıdaki gibi bir URI ile çağırabilir:The client can invoke the method with a URI like this:

http://localhost/api/values/?location=47.678558,-122.130989

Model ciltleriModel Binders

Tür dönüştürücüden daha esnek bir seçenek, özel model Bağlayıcısı oluşturmaktır.A more flexible option than a type converter is to create a custom model binder. Model Ciltçi ile HTTP isteği, eylem açıklaması ve rota verilerinden ham değerler gibi şeylere erişebilirsiniz.With a model binder, you have access to things like the HTTP request, the action description, and the raw values from the route data.

Bir model Bağlayıcısı oluşturmak için ımodelciltçi arabirimini uygulayın.To create a model binder, implement the IModelBinder interface. Bu arabirim tek bir yöntemi tanımlar, BindModel:This interface defines a single method, BindModel:

bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext);

GeoPoint nesneler için bir model Bağlayıcısı aşağıda verilmiştir.Here is a model binder for GeoPoint objects.

public class GeoPointModelBinder : IModelBinder
{
    // List of known locations.
    private static ConcurrentDictionary<string, GeoPoint> _locations
        = new ConcurrentDictionary<string, GeoPoint>(StringComparer.OrdinalIgnoreCase);

    static GeoPointModelBinder()
    {
        _locations["redmond"] = new GeoPoint() { Latitude = 47.67856, Longitude = -122.131 };
        _locations["paris"] = new GeoPoint() { Latitude = 48.856930, Longitude = 2.3412 };
        _locations["tokyo"] = new GeoPoint() { Latitude = 35.683208, Longitude = 139.80894 };
    }

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(GeoPoint))
        {
            return false;
        }

        ValueProviderResult val = bindingContext.ValueProvider.GetValue(
            bindingContext.ModelName);
        if (val == null)
        {
            return false;
        }

        string key = val.RawValue as string;
        if (key == null)
        {
            bindingContext.ModelState.AddModelError(
                bindingContext.ModelName, "Wrong value type");
            return false;
        }

        GeoPoint result;
        if (_locations.TryGetValue(key, out result) || GeoPoint.TryParse(key, out result))
        {
            bindingContext.Model = result;
            return true;
        }

        bindingContext.ModelState.AddModelError(
            bindingContext.ModelName, "Cannot convert value to GeoPoint");
        return false;
    }
}

Model Ciltçi, bir değer sağlayıcısındanham giriş değerleri alır.A model binder gets raw input values from a value provider. Bu tasarım iki ayrı işlevi ayırır:This design separates two distinct functions:

  • Değer sağlayıcısı, HTTP isteğini alır ve anahtar-değer çiftlerinin bir sözlüğünü doldurur.The value provider takes the HTTP request and populates a dictionary of key-value pairs.
  • Model Ciltçi, modeli doldurmak için bu sözlüğü kullanır.The model binder uses this dictionary to populate the model.

Web API 'sindeki varsayılan değer sağlayıcısı, rota verilerinden ve sorgu dizesinden değerleri alır.The default value provider in Web API gets values from the route data and the query string. Örneğin, URI http://localhost/api/values/1?location=48,-122ise, değer sağlayıcı aşağıdaki anahtar-değer çiftlerini oluşturur:For example, if the URI is http://localhost/api/values/1?location=48,-122, the value provider creates the following key-value pairs:

  • kimlik = "1"id = "1"
  • Konum = "48.122"location = "48,122"

("API/{Controller}/{ID}"varsayılan yol şablonunu kabul ediyorum.)(I'm assuming the default route template, which is "api/{controller}/{id}".)

Bağlanacak parametrenin adı, ModelBindingContext. ModelName özelliğinde depolanır.The name of the parameter to bind is stored in the ModelBindingContext.ModelName property. Model Ciltçi, sözlükte bu değere sahip bir anahtar arar.The model binder looks for a key with this value in the dictionary. Değer varsa ve bir GeoPointdönüştürülebiliyorsanız model Ciltçi, bağlantılı değeri ModelBindingContext. model özelliğine atar.If the value exists and can be converted into a GeoPoint, the model binder assigns the bound value to the ModelBindingContext.Model property.

Model cildin basit bir tür dönüştürmesi ile sınırlı olmadığına dikkat edin.Notice that the model binder is not limited to a simple type conversion. Bu örnekte, model cildi ilk olarak bilinen konumların bir tablosuna bakar ve bu başarısız olursa, tür dönüştürme kullanır.In this example, the model binder first looks in a table of known locations, and if that fails, it uses type conversion.

Model cildi ayarlamaSetting the Model Binder

Model cildi ayarlamak için çeşitli yollar vardır.There are several ways to set a model binder. İlk olarak, parametresine bir [Modelciltçi] özniteliği ekleyebilirsiniz.First, you can add a [ModelBinder] attribute to the parameter.

public HttpResponseMessage Get([ModelBinder(typeof(GeoPointModelBinder))] GeoPoint location)

Ayrıca, türüne bir [Modelciltçi] özniteliği ekleyebilirsiniz.You can also add a [ModelBinder] attribute to the type. Web API 'SI, bu türün tüm parametreleri için belirtilen model cildi kullanır.Web API will use the specified model binder for all parameters of that type.

[ModelBinder(typeof(GeoPointModelBinder))]
public class GeoPoint
{
    // ....
}

Son olarak, bir model Ciltçi sağlayıcısını HttpConfiguration'a ekleyebilirsiniz.Finally, you can add a model-binder provider to the HttpConfiguration. Model Ciltçi sağlayıcısı, model cildi oluşturan bir fabrika sınıfıdır.A model-binder provider is simply a factory class that creates a model binder. ModelBinderProvider sınıfından türeterek bir sağlayıcı oluşturabilirsiniz.You can create a provider by deriving from the ModelBinderProvider class. Ancak, model Ciltçi tek bir tür işlediğinde, bu amaçla tasarlanan yerleşik SimpleModelBinderProviderkullanımı daha kolay olur.However, if your model binder handles a single type, it's easier to use the built-in SimpleModelBinderProvider, which is designed for this purpose. Aşağıdaki kod bunun nasıl yapılacağını gösterir.The following code shows how to do this.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var provider = new SimpleModelBinderProvider(
            typeof(GeoPoint), new GeoPointModelBinder());
        config.Services.Insert(typeof(ModelBinderProvider), 0, provider);

        // ...
    }
}

Model bağlama sağlayıcısıyla, Web API 'sini bir medya türü biçimlendirici değil, model cildi kullanması gerektiğini söylemek için, [modelciltçi] özniteliğini parametreye eklemeniz gerekir.With a model-binding provider, you still need to add the [ModelBinder] attribute to the parameter, to tell Web API that it should use a model binder and not a media-type formatter. Ancak şimdi özniteliğinde model cildin türünü belirtmeniz gerekmez:But now you don't need to specify the type of model binder in the attribute:

public HttpResponseMessage Get([ModelBinder] GeoPoint location) { ... }

Değer sağlayıcılarıValue Providers

Model cildin bir değer sağlayıcısından değerler aldığından bahsetdim.I mentioned that a model binder gets values from a value provider. Özel bir değer sağlayıcısı yazmak için IValueProvider arabirimini uygulayın.To write a custom value provider, implement the IValueProvider interface. İşte, istekteki tanımlama bilgilerinden değer çeken bir örnek:Here is an example that pulls values from the cookies in the request:

public class CookieValueProvider : IValueProvider
{
    private Dictionary<string, string> _values;

    public CookieValueProvider(HttpActionContext actionContext)
    {
        if (actionContext == null)
        {
            throw new ArgumentNullException("actionContext");
        }

        _values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        foreach (var cookie in actionContext.Request.Headers.GetCookies())
        {
            foreach (CookieState state in cookie.Cookies)
            {
                _values[state.Name] = state.Value;
            }
        }
    }

    public bool ContainsPrefix(string prefix)
    {
        return _values.Keys.Contains(prefix);
    }

    public ValueProviderResult GetValue(string key)
    {
        string value;
        if (_values.TryGetValue(key, out value))
        {
            return new ValueProviderResult(value, value, CultureInfo.InvariantCulture);
        }
        return null;
    }
}

Ayrıca, ValueProviderFactory sınıfından türeterek bir değer sağlayıcısı fabrikası oluşturmanız gerekir.You also need to create a value provider factory by deriving from the ValueProviderFactory class.

public class CookieValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(HttpActionContext actionContext)
    {
        return new CookieValueProvider(actionContext);
    }
}

Değer sağlayıcısı fabrikasını HttpConfiguration öğesine aşağıdaki şekilde ekleyin.Add the value provider factory to the HttpConfiguration as follows.

public static void Register(HttpConfiguration config)
{
    config.Services.Add(typeof(ValueProviderFactory), new CookieValueProviderFactory());

    // ...
}

Web API 'SI, tüm değer sağlayıcılarını oluşturur, bu nedenle model Ciltçi ValueProvider. GetValue' yi çağırdığında, model cildi onu üretebilecek ilk değer sağlayıcısından değeri alır.Web API composes all of the value providers, so when a model binder calls ValueProvider.GetValue, the model binder receives the value from the first value provider that is able to produce it.

Alternatif olarak, değer sağlayıcı fabrikasını parametre düzeyinde, ValueProvider özniteliğini kullanarak aşağıdaki gibi ayarlayabilirsiniz:Alternatively, you can set the value provider factory at the parameter level by using the ValueProvider attribute, as follows:

public HttpResponseMessage Get(
    [ValueProvider(typeof(CookieValueProviderFactory))] GeoPoint location)

Bu, Web API 'sinin belirtilen değer sağlayıcı fabrikası ile model bağlamayı kullanmasını söyler ve diğer kayıtlı değer sağlayıcılarının hiçbirini kullanmaz.This tells Web API to use model binding with the specified value provider factory, and not to use any of the other registered value providers.

HttpParameterBindingHttpParameterBinding

Model ciltleri, daha genel bir mekanizmanın belirli bir örneğidir.Model binders are a specific instance of a more general mechanism. [Modelciltçi] özniteliğine bakarsanız, onun soyut ParameterBindingAttribute sınıfından türetildiğinden emin olursunuz.If you look at the [ModelBinder] attribute, you will see that it derives from the abstract ParameterBindingAttribute class. Bu sınıf, bir Httpparameterbinding nesnesi döndüren GetBindingtek bir yöntemini tanımlar:This class defines a single method, GetBinding, which returns an HttpParameterBinding object:

public abstract class ParameterBindingAttribute : Attribute
{
    public abstract HttpParameterBinding GetBinding(HttpParameterDescriptor parameter);
}

Bir Httpparameterbinding , bir parametreyi bir değere bağlamaktan sorumludur.An HttpParameterBinding is responsible for binding a parameter to a value. [Modelciltçi] söz konusu olduğunda, öznitelik gerçek bağlamayı gerçekleştirmek Için ımodelciltçi kullanan bir httpparameterbinding uygulaması döndürür.In the case of [ModelBinder], the attribute returns an HttpParameterBinding implementation that uses an IModelBinder to perform the actual binding. Ayrıca kendi Httpparameterbinding'nizi de uygulayabilirsiniz.You can also implement your own HttpParameterBinding.

Örneğin, istekteki if-match ve if-none-match üst bilgilerden ETags almak istediğinizi varsayalım.For example, suppose you want to get ETags from if-match and if-none-match headers in the request. ETags temsil eden bir sınıf tanımlayarak başlayacağız.We'll start by defining a class to represent ETags.

public class ETag
{
    public string Tag { get; set; }
}

Ayrıca, if-match üst bilgisinden veya if-none-match üst bilgisinden ETag 'in mi alınacağını göstermek için bir sabit listesi tanımlayacağız.We'll also define an enumeration to indicate whether to get the ETag from the if-match header or the if-none-match header.

public enum ETagMatch
{
    IfMatch,
    IfNoneMatch
}

Burada, istenen üst bilgiden ETag 'i alan ve ETag türü bir parametreye bağlayan bir Httpparameterbinding yer alır:Here is an HttpParameterBinding that gets the ETag from the desired header and binds it to a parameter of type ETag:

public class ETagParameterBinding : HttpParameterBinding
{
    ETagMatch _match;

    public ETagParameterBinding(HttpParameterDescriptor parameter, ETagMatch match) 
        : base(parameter)
    {
        _match = match;
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, 
        HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        EntityTagHeaderValue etagHeader = null;
        switch (_match)
        {
            case ETagMatch.IfNoneMatch:
                etagHeader = actionContext.Request.Headers.IfNoneMatch.FirstOrDefault();
                break;

            case ETagMatch.IfMatch:
                etagHeader = actionContext.Request.Headers.IfMatch.FirstOrDefault();
                break;
        }

        ETag etag = null;
        if (etagHeader != null)
        {
            etag = new ETag { Tag = etagHeader.Tag };
        }
        actionContext.ActionArguments[Descriptor.ParameterName] = etag;

        var tsc = new TaskCompletionSource<object>();
        tsc.SetResult(null);
        return tsc.Task;
    }
}

Executebindingasync yöntemi bağlamayı yapar.The ExecuteBindingAsync method does the binding. Bu yöntemde, bir bağlama parametre değerini HttpactioncontextIçindeki actionargument sözlüğüne ekleyin.Within this method, add the bound parameter value to the ActionArgument dictionary in the HttpActionContext.

Note

Executebindingasync yönteminiz istek iletisinin gövdesini okuyorsa, true döndürecek şekilde willreadbody özelliğini geçersiz kılın.If your ExecuteBindingAsync method reads the body of the request message, override the WillReadBody property to return true. İstek gövdesi, yalnızca bir kez okunabilecek, arabelleğe alınmamış bir akış olabilir, bu nedenle Web API 'SI en çok bir bağlamanın ileti gövdesini okuyabilecek bir kuralı zorlar.The request body might be an unbuffered stream that can only be read once, so Web API enforces a rule that at most one binding can read the message body.

Özel bir Httpparameterbindinguygulamak Için ParameterBindingAttributeöğesinden türetilen bir öznitelik tanımlayabilirsiniz.To apply a custom HttpParameterBinding, you can define an attribute that derives from ParameterBindingAttribute. ETagParameterBindingiçin biri if-match üst bilgileri ve bir if-none-match üst bilgisi için olmak üzere iki öznitelik tanımlayacağız.For ETagParameterBinding, we'll define two attributes, one for if-match headers and one for if-none-match headers. Her ikisi de soyut bir temel sınıftan türetir.Both derive from an abstract base class.

public abstract class ETagMatchAttribute : ParameterBindingAttribute
{
    private ETagMatch _match;

    public ETagMatchAttribute(ETagMatch match)
    {
        _match = match;
    }

    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
    {
        if (parameter.ParameterType == typeof(ETag))
        {
            return new ETagParameterBinding(parameter, _match);
        }
        return parameter.BindAsError("Wrong parameter type");
    }
}

public class IfMatchAttribute : ETagMatchAttribute
{
    public IfMatchAttribute()
        : base(ETagMatch.IfMatch)
    {
    }
}

public class IfNoneMatchAttribute : ETagMatchAttribute
{
    public IfNoneMatchAttribute()
        : base(ETagMatch.IfNoneMatch)
    {
    }
}

[IfNoneMatch] özniteliğini kullanan bir Controller yöntemi aşağıda verilmiştir.Here is a controller method that uses the [IfNoneMatch] attribute.

public HttpResponseMessage Get([IfNoneMatch] ETag etag) { ... }

ParameterBindingAttribute'un yanı sıra özel bir httpparameterbindingeklemek için başka bir kanca vardır.Besides ParameterBindingAttribute, there is another hook for adding a custom HttpParameterBinding. HttpConfiguration nesnesinde parameterbindingrules özelliği, (HttpParameterDescriptor -> httpparameterbinding) türündeki anonim işlevlerin bir koleksiyonudur.On the HttpConfiguration object, the ParameterBindingRules property is a collection of anonymous functions of type (HttpParameterDescriptor -> HttpParameterBinding). Örneğin, GET yöntemindeki herhangi bir ETag parametresinin if-none-match``ETagParameterBinding kullandığı bir kural ekleyebilirsiniz:For example, you could add a rule that any ETag parameter on a GET method uses ETagParameterBinding with if-none-match:

config.ParameterBindingRules.Add(p =>
{
    if (p.ParameterType == typeof(ETag) && 
        p.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Get))
    {
        return new ETagParameterBinding(p, ETagMatch.IfNoneMatch);
    }
    else
    {
        return null;
    }
});

İşlev, bağlamanın geçerli olmadığı parametreler için null döndürmelidir.The function should return null for parameters where the binding is not applicable.

IactionvalueciltçiIActionValueBinder

Tüm parametre bağlama işlemi takılabilir bir hizmet olan ıactionvalueciltçitarafından denetlenir.The entire parameter-binding process is controlled by a pluggable service, IActionValueBinder. Iactionvalueciltçi 'nin varsayılan uygulaması aşağıdakileri yapar:The default implementation of IActionValueBinder does the following:

  1. Parametresinde bir ParameterBindingAttribute bulun.Look for a ParameterBindingAttribute on the parameter. Buna [Frombody] , [fromuri] ve [modelciltçi] ya da özel öznitelikler dahildir.This includes [FromBody], [FromUri], and [ModelBinder], or custom attributes.

  2. Aksi halde, null olmayan bir Httpparameterbindingdöndüren bir Işlev Için HttpConfiguration. parameterbindingrules bölümüne bakın.Otherwise, look in HttpConfiguration.ParameterBindingRules for a function that returns a non-null HttpParameterBinding.

  3. Aksi takdirde, daha önce açıklananlardan varsayılan kuralları kullanın.Otherwise, use the default rules that I described previously.

    • Parametre türü "basittir" ise veya tür dönüştürücüsüyle, URI 'den bağlayın.If the parameter type is "simple"or has a type converter, bind from the URI. Bu, [Fromuri] özniteliğini parametreye koymaya eşdeğerdir.This is equivalent to putting the [FromUri] attribute on the parameter.
    • Aksi takdirde, ileti gövdesinden parametresini okumayı deneyin.Otherwise, try to read the parameter from the message body. Bu parametre üzerine [Frombody] koymaya eşdeğerdir.This is equivalent to putting [FromBody] on the parameter.

İsterseniz, tüm ıactionvalueciltçi hizmetini özel bir uygulamayla değiştirebilirsiniz.If you wanted, you could replace the entire IActionValueBinder service with a custom implementation.

Ek KaynaklarAdditional Resources

Özel parametre bağlama örneğiCustom Parameter Binding Sample

Mike Stall, Web API parametresi bağlaması hakkında iyi bir blog gönderisi serisi yazdı:Mike Stall wrote a good series of blog posts about Web API parameter binding: