Udostępnij za pomocą


Akcje i funkcje w usłudze OData w wersji 4 przy użyciu ASP.NET internetowego interfejsu API 2.2

Autor: Mike Wasson

W usłudze OData akcje i funkcje są sposobem dodawania zachowań po stronie serwera, które nie są łatwo zdefiniowane jako operacje CRUD na jednostkach. W tym samouczku pokazano, jak dodawać akcje i funkcje do punktu końcowego OData w wersji 4 przy użyciu internetowego interfejsu API 2.2. Samouczek opiera się na samouczku Tworzenie punktu końcowego OData w wersji 4 przy użyciu ASP.NET internetowego interfejsu API 2

Wersje oprogramowania używane w samouczku

  • Internetowy interfejs API 2.2
  • OData 4
  • Visual Studio 2013 (pobierz program Visual Studio 2017 tutaj)
  • .NET 4.5

Wersje samouczków

Aby uzyskać informacje odata w wersji 3, zobacz OData Actions in ASP.NET Web API 2 (Akcje OData w interfejsie API sieci Web 2).

Różnica między akcjami i funkcjami polega na tym, że działania mogą mieć skutki uboczne, a funkcje nie. Zarówno akcje, jak i funkcje mogą zwracać dane. Niektóre zastosowania dla akcji to:

  • Złożone transakcje.
  • Manipulowanie kilkoma jednostkami jednocześnie.
  • Zezwalanie na aktualizacje tylko do niektórych właściwości jednostki.
  • Wysyłanie danych, które nie są jednostką.

Funkcje są przydatne do zwracania informacji, które nie odpowiadają bezpośrednio jednostce ani kolekcji.

Akcja (lub funkcja) może dotyczyć pojedynczej jednostki lub kolekcji. W terminologii OData jest to powiązanie. Możesz również mieć akcje/funkcje", które są nazywane operacjami statycznym w usłudze.

Przykład: dodawanie akcji

Zdefiniujmy akcję, aby ocenić produkt.

Najpierw dodaj ProductRating model do reprezentowania klasyfikacji.

namespace ProductService.Models
{
    public class ProductRating
    {
        public int ID { get; set; }
        public int Rating { get; set; }
        public int ProductID { get; set; }
        public virtual Product Product { get; set; }  
    }
}

Dodaj również zestaw DbSet do ProductsContext klasy, aby program EF utworzył tabelę Ratings w bazie danych.

public class ProductsContext : DbContext
{
    public ProductsContext() 
            : base("name=ProductsContext")
    {
    }

    public DbSet<Product> Products { get; set; }
    public DbSet<Supplier> Suppliers { get; set; }
    // New code:
    public DbSet<ProductRating> Ratings { get; set; }
}

Dodawanie akcji do EDM

W pliku WebApiConfig.cs dodaj następujący kod:

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");

// New code:
builder.Namespace = "ProductService";
builder.EntityType<Product>()
    .Action("Rate")
    .Parameter<int>("Rating");

Metoda EntityTypeConfiguration.Action dodaje akcję do modelu danych jednostki (EDM). Metoda Parametr określa typowy parametr akcji.

Ten kod ustawia również przestrzeń nazw dla EDM. Przestrzeń nazw ma znaczenie, ponieważ identyfikator URI akcji zawiera w pełni kwalifikowaną nazwę akcji:

http://localhost/Products(1)/ProductService.Rate

Uwaga

W typowej konfiguracji usług IIS kropka w tym adresie URL spowoduje zwrócenie błędu 404 przez usługi IIS. Możesz rozwiązać ten problem, dodając następującą sekcję do pliku Web.Config:

<system.webServer>
    <handlers>
      <clear/>
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="/*" 
          verb="*" type="System.Web.Handlers.TransferRequestHandler" 
          preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

Dodawanie metody kontrolera dla akcji

Aby włączyć akcję "Rate", dodaj następującą metodę do ProductsController:

[HttpPost]
public async Task<IHttpActionResult> Rate([FromODataUri] int key, ODataActionParameters parameters)
{
    if (!ModelState.IsValid)
    {
        return BadRequest();
    }

    int rating = (int)parameters["Rating"];
    db.Ratings.Add(new ProductRating
    {
        ProductID = key,
        Rating = rating
    });

    try
    {
        await db.SaveChangesAsync();
    }
    catch (DbUpdateException e)
    {
        if (!ProductExists(key))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return StatusCode(HttpStatusCode.NoContent);
}

Zwróć uwagę, że nazwa metody jest zgodna z nazwą akcji. Atrybut [HttpPost] określa metodę jest metodą HTTP POST.

Aby wywołać akcję, klient wysyła żądanie HTTP POST w następujący sposób:

POST http://localhost/Products(1)/ProductService.Rate HTTP/1.1
Content-Type: application/json
Content-Length: 12

{"Rating":5}

Akcja "Oceń" jest powiązana z wystąpieniami produktu, więc identyfikator URI akcji jest w pełni kwalifikowaną nazwą akcji dołączona do identyfikatora URI jednostki. (Pamiętaj, że ustawiliśmy przestrzeń nazw EDM na "ProductService", więc w pełni kwalifikowana nazwa akcji to "ProductService.Rate".

Treść żądania zawiera parametry akcji jako ładunek JSON. Internetowy interfejs API automatycznie konwertuje ładunek JSON na obiekt ODataActionParameters , który jest tylko słownikiem wartości parametrów. Użyj tego słownika, aby uzyskać dostęp do parametrów w metodzie kontrolera.

Jeśli klient wyśle parametry akcji w niewłaściwym formacie, wartość parametru ModelState.IsValid ma wartość false. Sprawdź tę flagę w metodzie kontrolera i zwróć błąd, jeśli isValid ma wartość false.

if (!ModelState.IsValid)
{
    return BadRequest();
}

Przykład: dodawanie funkcji

Teraz dodajmy funkcję OData, która zwraca najdroższy produkt. Tak jak wcześniej, pierwszym krokiem jest dodanie funkcji do EDM. W pliku WebApiConfig.cs dodaj następujący kod.

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
builder.EntitySet<Supplier>("Suppliers");

// New code:
builder.Namespace = "ProductService";
builder.EntityType<Product>().Collection
    .Function("MostExpensive")
    .Returns<double>();

W takim przypadku funkcja jest powiązana z kolekcją Products, a nie poszczególnymi wystąpieniami produktu. Klienci wywołują funkcję, wysyłając żądanie GET:

GET http://localhost:38479/Products/ProductService.MostExpensive

Oto metoda kontrolera dla tej funkcji:

public class ProductsController : ODataController
{
    [HttpGet]
    public IHttpActionResult MostExpensive()
    {
        var product = db.Products.Max(x => x.Price);
        return Ok(product);
    }

    // Other controller methods not shown.
}

Zwróć uwagę, że nazwa metody jest zgodna z nazwą funkcji. Atrybut [HttpGet] określa metodę HTTP GET.

Oto odpowiedź HTTP:

HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true
OData-Version: 4.0
Date: Sat, 28 Jun 2014 00:44:07 GMT
Content-Length: 85

{
  "@odata.context":"http://localhost:38479/$metadata#Edm.Decimal","value":50.00
}

Przykład: dodawanie funkcji unbound

Poprzedni przykład był funkcją powiązaną z kolekcją. W następnym przykładzie utworzymy funkcję bez ruchu przychodzącego . Funkcje niezwiązane są nazywane operacjami statycznym w usłudze. Funkcja w tym przykładzie zwróci podatek od sprzedaży dla danego kodu pocztowego.

W pliku WebApiConfig dodaj funkcję do modułu EDM:

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");

// New code:
builder.Function("GetSalesTaxRate")
    .Returns<double>()
    .Parameter<int>("PostalCode");

Zwróć uwagę, że wywołujemy funkcję bezpośrednio w obiekcie ODataModelBuilder zamiast typu jednostki lub kolekcji. Informuje to konstruktora modelu, że funkcja jest niezwiązana.

Oto metoda kontrolera, która implementuje funkcję:

[HttpGet]
[ODataRoute("GetSalesTaxRate(PostalCode={postalCode})")]
public IHttpActionResult GetSalesTaxRate([FromODataUri] int postalCode)
{
    double rate = 5.6;  // Use a fake number for the sample.
    return Ok(rate);
}

Nie ma znaczenia, w którym kontrolerze internetowego interfejsu API umieścisz tę metodę. Można go umieścić w ProductsControllerobiekcie lub zdefiniować oddzielny kontroler. Atrybut [ODataRoute] definiuje szablon identyfikatora URI dla funkcji.

Oto przykładowe żądanie klienta:

GET http://localhost:38479/GetSalesTaxRate(PostalCode=10) HTTP/1.1

Odpowiedź HTTP:

HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true
OData-Version: 4.0
Date: Sat, 28 Jun 2014 01:05:32 GMT
Content-Length: 82

{
  "@odata.context":"http://localhost:38479/$metadata#Edm.Double","value":5.6
}