Web API 2.2 Kullanarak OData v4'te Sınırlama

tarafından Jinfu Tan

Geleneksel olarak, bir varlığa yalnızca bir varlık kümesi içinde kapsüllenmişse erişilebilirdi. Ancak OData v4, Her ikisi de WebAPI 2.2'nin desteklediği Singleton ve Containment adlı iki ek seçenek sunar.

Bu konuda, WebApi 2.2'deki bir OData uç noktasında kapsamanın nasıl tanımlanacağı gösterilmektedir. Kapsama hakkında daha fazla bilgi için bkz. Kapsama OData v4 ile geliyor. Web API'sinde OData V4 uç noktası oluşturmak için bkz. ASP.NET Web API 2.2 Kullanarak OData v4 Uç Noktası Oluşturma.

İlk olarak, şu veri modelini kullanarak OData hizmetinde bir kapsama etki alanı modeli oluşturacağız:

Veri modeli

Hesapta birçok PaymentInstruments (PI) bulunur, ancak PI için bir varlık kümesi tanımlamayız. Bunun yerine, API'lere yalnızca bir Hesap üzerinden erişilebilir.

Veri modelini tanımlama

  1. CLR türlerini tanımlayın.

    public class Account     
    {         
        public int AccountID { get; set; }         
        public string Name { get; set; }         
        [Contained]         
        public IList<PaymentInstrument> PayinPIs { get; set; }     
    }     
    
    public class PaymentInstrument     
    {         
        public int PaymentInstrumentID { get; set; }        
        public string FriendlyName { get; set; }     
    }
    

    Contained özniteliği, kapsama navigasyon özellikleri için kullanılır.

  2. CLR türlerini temel alarak EDM modelini oluşturun.

    public static IEdmModel GetModel()         
    {             
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();             
        builder.EntitySet<Account>("Accounts");             
        var paymentInstrumentType = builder.EntityType<PaymentInstrument>();             
        var functionConfiguration = 
            paymentInstrumentType.Collection.Function("GetCount");             
        functionConfiguration.Parameter<string>("NameContains");             
        functionConfiguration.Returns<int>();             
        builder.Namespace = typeof(Account).Namespace;             
        return builder.GetEdmModel();         
    }
    

    ODataConventionModelBuilder özniteliği ilgili gezinti özelliğine eklenirse Contained EDM modelinin oluşturulmasını işler. Özelliği bir koleksiyon türüyse, bir GetCount(string NameContains) işlev de oluşturulur.

    Oluşturulan meta veriler aşağıdaki gibi görünür:

    <EntityType Name="Account">   
      <Key>     
        <PropertyRef Name="AccountID" />   
      </Key>   
      <Property Name="AccountID" Type="Edm.Int32" Nullable="false" />   
      <Property Name="Name" Type="Edm.String" />   
      <NavigationProperty 
        Name="PayinPIs" 
        Type="Collection(ODataContrainmentSample.PaymentInstrument)" 
        ContainsTarget="true" /> 
    </EntityType>
    

    ContainsTarget özniteliği, gezinti özelliğinin bir kapsama olduğunu gösterir.

İçeren varlık kümesi denetleyicisini tanımlama

Kapsanan varlıkların kendi denetleyicisi yoktur; eylemi, içeren varlık kümesi denetleyicisinde tanımlanır. Bu örnekte bir AccountsController vardır, ancak PaymentInstrumentsController yoktur.

public class AccountsController : ODataController     
{         
    private static IList<Account> _accounts = null;         
    public AccountsController()         
    {             
        if (_accounts == null)             
        {                 
            _accounts = InitAccounts();             
        }         
    }         
    // PUT ~/Accounts(100)/PayinPIs         
    [EnableQuery] 
    public IHttpActionResult GetPayinPIs(int key)         
    {             
        var payinPIs = _accounts.Single(a => a.AccountID == key).PayinPIs;             
        return Ok(payinPIs);         
    }         
    [EnableQuery]         
    [ODataRoute("Accounts({accountId})/PayinPIs({paymentInstrumentId})")]         
    public IHttpActionResult GetSinglePayinPI(int accountId, int paymentInstrumentId)         
    {             
        var payinPIs = _accounts.Single(a => a.AccountID == accountId).PayinPIs;             
        var payinPI = payinPIs.Single(pi => pi.PaymentInstrumentID == paymentInstrumentId);             
        return Ok(payinPI);         
    }         
    // PUT ~/Accounts(100)/PayinPIs(101)         
    [ODataRoute("Accounts({accountId})/PayinPIs({paymentInstrumentId})")]         
    public IHttpActionResult PutToPayinPI(int accountId, int paymentInstrumentId, [FromBody]PaymentInstrument paymentInstrument)         
    {             
        var account = _accounts.Single(a => a.AccountID == accountId);             
        var originalPi = account.PayinPIs.Single(p => p.PaymentInstrumentID == paymentInstrumentId);             
        originalPi.FriendlyName = paymentInstrument.FriendlyName;             
        return Ok(paymentInstrument);         
    }         
    // DELETE ~/Accounts(100)/PayinPIs(101)         
    [ODataRoute("Accounts({accountId})/PayinPIs({paymentInstrumentId})")]         
    public IHttpActionResult DeletePayinPIFromAccount(int accountId, int paymentInstrumentId)         
    {             
        var account = _accounts.Single(a => a.AccountID == accountId);             
        var originalPi = account.PayinPIs.Single(p => p.PaymentInstrumentID == paymentInstrumentId);             
        if (account.PayinPIs.Remove(originalPi))             
        {                 
            return StatusCode(HttpStatusCode.NoContent);             
        }             
        else             
        {                 
            return StatusCode(HttpStatusCode.InternalServerError);             
        }         
    }         
    // GET ~/Accounts(100)/PayinPIs/Namespace.GetCount() 
    [ODataRoute("Accounts({accountId})/PayinPIs/ODataContrainmentSample.GetCount(NameContains={name})")]         
    public IHttpActionResult GetPayinPIsCountWhoseNameContainsGivenValue(int accountId, [FromODataUri]string name)         
    {             
        var account = _accounts.Single(a => a.AccountID == accountId);             
        var count = account.PayinPIs.Where(pi => pi.FriendlyName.Contains(name)).Count();             
        return Ok(count);         
    }         
    private static IList<Account> InitAccounts()         
    {             
        var accounts = new List<Account>() 
        { 
            new Account()                 
            {                    
                AccountID = 100,                    
                Name="Name100",                    
                PayinPIs = new List<PaymentInstrument>()                     
                {                         
                    new PaymentInstrument()                         
                    {                             
                        PaymentInstrumentID = 101,                             
                        FriendlyName = "101 first PI",                         
                    },                         
                    new PaymentInstrument()                         
                    {                             
                        PaymentInstrumentID = 102,                             
                        FriendlyName = "102 second PI",                         
                    },                     
                },                 
            },             
        };            
        return accounts;         
    }     
}

OData yolu 4 veya daha fazla kesimse, yukarıdaki denetleyicide olduğu gibi [ODataRoute("Accounts({accountId})/PayinPIs({paymentInstrumentId})")] yalnızca öznitelik yönlendirmesi çalışır. Aksi takdirde hem öznitelik hem de geleneksel yönlendirme çalışır: örneğin, GetPayInPIs(int key) ile eşleşir GET ~/Accounts(1)/PayinPIs.

Bu makalenin orijinal içeriği için Leo Hu'ya teşekkür ederiz.