Konvence směrování ve službě ASP.NET Web API 2 Odata
Tento článek popisuje konvence směrování, které webové rozhraní API 2 v ASP.NET 4.x používá pro koncové body OData.
Když webové rozhraní API obdrží požadavek OData, namapuje požadavek na název kontroleru a název akce. Mapování je založené na metodě HTTP a identifikátoru URI. Například mapuje GET /odata/Products(1)
na ProductsController.GetProduct
.
V 1. části tohoto článku popíšu integrované konvence směrování OData. Tyto konvence jsou navržené speciálně pro koncové body OData a nahrazují výchozí systém směrování webového rozhraní API. (K nahrazení dojde při volání MapODataRoute.)
V části 2 vám ukážu, jak přidat vlastní konvence směrování. Předdefinované konvence v současné době nepokrývají celý rozsah identifikátorů URI OData, ale můžete je rozšířit o další případy.
Integrované konvence směrování
Než popíšeme konvence směrování OData ve webovém rozhraní API, je užitečné pochopit identifikátory URI OData. Identifikátor URI OData se skládá z těchto součástí:
- Kořenový adresář služby
- Cesta k prostředku
- Možnosti proxy
Důležitou součástí směrování je cesta k prostředku. Cesta k prostředku je rozdělená na segmenty. Například /Products(1)/Supplier
má tři segmenty:
Products
odkazuje na sadu entit s názvem "Produkty".1
je klíč entity, který ze sady vybírá jednu entitu.Supplier
je navigační vlastnost, která vybere související entitu.
Tato cesta tedy vybere dodavatele produktu 1.
Poznámka
Segmenty cest OData nemusí vždy odpovídat segmentům identifikátoru URI. Například "1" se považuje za segment cesty.
Názvy kontroleru. Název kontroleru je vždy odvozený od entity nastavené v kořenovém adresáři cesty k prostředku. Pokud je /Products(1)/Supplier
například cesta k prostředku , webové rozhraní API vyhledá kontroler s názvem ProductsController
.
Názvy akcí. Názvy akcí jsou odvozené ze segmentů cesty a modelu EDM (Entity Data Model), jak je uvedeno v následujících tabulkách. V některých případech máte pro název akce dvě možnosti. Například "Get" nebo "GetProducts".
Dotazování entit
Žádost | Příklad identifikátoru URI | Název akce | Příklad akce |
---|---|---|---|
GET /entityset | /Produkty | GetEntitySet nebo Get | GetProducts |
GET /entityset(klíč) | /Produkty(1) | GetEntityType nebo Get | GetProduct |
GET /entityset(klíč)/cast | /Products(1)/Models.Book | GetEntityType nebo Get | GetBook |
Další informace najdete v tématu Vytvoření koncového bodu Read-Only OData.
Vytváření, aktualizace a odstraňování entit
Žádost | Příklad identifikátoru URI | Název akce | Příklad akce |
---|---|---|---|
POST /entityset | /Produkty | PostEntityType nebo Post | Produktová náčiní |
PUT /entityset(klíč) | /Produkty(1) | PutEntityType nebo Put | PutProduct |
PUT /entityset(klíč)/cast | /Products(1)/Models.Book | PutEntityType nebo Put | PutBook |
PATCH /entityset(klíč) | /Produkty(1) | PatchEntityType nebo Patch | PatchProduct |
PATCH /entityset(klíč)/cast | /Products(1)/Models.Book | PatchEntityType nebo Patch | PatchBook |
DELETE /entityset(klíč) | /Produkty(1) | DeleteEntityType nebo Delete | DeleteProduct |
DELETE /entityset(klíč)/cast | /Products(1)/Models.Book | DeleteEntityType nebo Delete | Odstranitbook |
Dotazování navigační vlastnosti
Žádost | Příklad identifikátoru URI | Název akce | Příklad akce |
---|---|---|---|
GET /entityset(klíč)/navigation | /Products(1)/Supplier | GetNavigationFromEntityType nebo GetNavigation | GetSupplierFromProduct |
GET /entityset(klíč)/cast/navigation | /Products(1)/Models.Book/Author | GetNavigationFromEntityType nebo GetNavigation | GetAuthorFromBook |
Další informace najdete v tématu Práce s relacemi entit.
Vytváření a odstraňování odkazů
Žádost | Příklad identifikátoru URI | Název akce |
---|---|---|
POST /entityset(key)/$links/navigation | /Products(1)/$links/Supplier | Vytvořit odkaz |
PUT /entityset(key)/$links/navigation | /Products(1)/$links/Supplier | Vytvořit odkaz |
DELETE /entityset(key)/$links/navigation | /Products(1)/$links/Supplier | Odstranit odkaz |
DELETE /entityset(key)/$links/navigation(relatedKey) | /Products/(1)/$links/Suppliers(1) | Odstranit odkaz |
Další informace najdete v tématu Práce s relacemi entit.
Vlastnosti
Vyžaduje webové rozhraní API 2.
Žádost | Příklad identifikátoru URI | Název akce | Příklad akce |
---|---|---|---|
GET /entityset(klíč)/property | /Products(1)/Name | GetPropertyFromEntityType nebo GetProperty | GetNameFromProduct |
GET /entityset(key)/cast/property | /Products(1)/Models.Book/Author | GetPropertyFromEntityType nebo GetProperty | GetTitleFromBook |
Akce
Žádost | Příklad identifikátoru URI | Název akce | Příklad akce |
---|---|---|---|
POST /entityset(key)/action | /Products(1)/Rate | ActionNameOnEntityType nebo ActionName | RateOnProduct |
POST /entityset(key)/cast/action | /Products(1)/Models.Book/CheckOut | ActionNameOnEntityType nebo ActionName | CheckOutOnBook |
Další informace najdete v tématu Akce OData.
Signatury metod
Tady jsou některá pravidla pro podpisy metod:
- Pokud cesta obsahuje klíč, měla by mít akce parametr s názvem key.
- Pokud cesta obsahuje klíč do navigační vlastnosti, měla by mít akce parametr relatedKey.
- Parametry klíče a relatedKey můžete zdobit parametrem [FromODataUri].
- Požadavky POST a PUT přebírají parametr typu entity.
- Požadavky PATCH přebírají parametr typu Delta<T>, kde T je typ entity.
Tady je příklad, který ukazuje podpisy metod pro každou integrovanou konvenci směrování OData.
public class ProductsController : ODataController
{
// GET /odata/Products
public IQueryable<Product> Get()
// GET /odata/Products(1)
public Product Get([FromODataUri] int key)
// GET /odata/Products(1)/ODataRouting.Models.Book
public Book GetBook([FromODataUri] int key)
// POST /odata/Products
public HttpResponseMessage Post(Product item)
// PUT /odata/Products(1)
public HttpResponseMessage Put([FromODataUri] int key, Product item)
// PATCH /odata/Products(1)
public HttpResponseMessage Patch([FromODataUri] int key, Delta<Product> item)
// DELETE /odata/Products(1)
public HttpResponseMessage Delete([FromODataUri] int key)
// PUT /odata/Products(1)/ODataRouting.Models.Book
public HttpResponseMessage PutBook([FromODataUri] int key, Book item)
// PATCH /odata/Products(1)/ODataRouting.Models.Book
public HttpResponseMessage PatchBook([FromODataUri] int key, Delta<Book> item)
// DELETE /odata/Products(1)/ODataRouting.Models.Book
public HttpResponseMessage DeleteBook([FromODataUri] int key)
// GET /odata/Products(1)/Supplier
public Supplier GetSupplierFromProduct([FromODataUri] int key)
// GET /odata/Products(1)/ODataRouting.Models.Book/Author
public Author GetAuthorFromBook([FromODataUri] int key)
// POST /odata/Products(1)/$links/Supplier
public HttpResponseMessage CreateLink([FromODataUri] int key,
string navigationProperty, [FromBody] Uri link)
// DELETE /odata/Products(1)/$links/Supplier
public HttpResponseMessage DeleteLink([FromODataUri] int key,
string navigationProperty, [FromBody] Uri link)
// DELETE /odata/Products(1)/$links/Parts(1)
public HttpResponseMessage DeleteLink([FromODataUri] int key, string relatedKey, string navigationProperty)
// GET odata/Products(1)/Name
// GET odata/Products(1)/Name/$value
public HttpResponseMessage GetNameFromProduct([FromODataUri] int key)
// GET /odata/Products(1)/ODataRouting.Models.Book/Title
// GET /odata/Products(1)/ODataRouting.Models.Book/Title/$value
public HttpResponseMessage GetTitleFromBook([FromODataUri] int key)
}
Vlastní konvence směrování
Předdefinované konvence v současné době nepokrývají všechny možné identifikátory URI OData. Nové konvence můžete přidat implementací rozhraní IODataRoutingConvention . Toto rozhraní má dvě metody:
string SelectController(ODataPath odataPath, HttpRequestMessage request);
string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext,
ILookup<string, HttpActionDescriptor> actionMap);
- SelectController vrátí název kontroleru.
- SelectAction vrátí název akce.
Pokud se pro obě metody konvence nevztahuje na tento požadavek, měla by metoda vrátit hodnotu null.
Parametr ODataPath představuje analyzovanou cestu k prostředku OData. Obsahuje seznam instancí ODataPathSegment , jeden pro každý segment cesty k prostředku. ODataPathSegment je abstraktní třída; každý typ segmentu je reprezentován třídou, která je odvozena z ODataPathSegment.
Vlastnost ODataPath.TemplatePath je řetězec, který představuje zřetězení všech segmentů cesty. Pokud je /Products(1)/Supplier
například identifikátor URI , šablona cesty je ~/entityset/key/navigation. Všimněte si, že segmenty přímo neodpovídají segmentům identifikátoru URI. Například klíč entity (1) je reprezentován jako vlastní ODataPathSegment.
Implementace IODataRoutingConvention obvykle provede následující:
- Porovnejte šablonu cesty a zjistěte, jestli se tato konvence vztahuje na aktuální požadavek. Pokud se nepoužije, vrátí hodnotu null.
- Pokud platí konvence, použijte vlastnosti instancí ODataPathSegment k odvození názvů kontrolerů a akcí.
- U akcí přidejte do slovníku tras všechny hodnoty, které by se měly svázat s parametry akce (obvykle klíče entit).
Podívejme se na konkrétní příklad. Integrované konvence směrování nepodporují indexování do navigační kolekce. Jinými slovy, neexistuje žádná konvence pro identifikátory URI, jako je následující:
/odata/Products(1)/Suppliers(1)
Tady je vlastní konvence směrování pro zpracování tohoto typu dotazu.
using Microsoft.Data.Edm;
using System.Linq;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;
namespace ODataRouting
{
public class NavigationIndexRoutingConvention : EntitySetRoutingConvention
{
public override string SelectAction(ODataPath odataPath, HttpControllerContext context,
ILookup<string, HttpActionDescriptor> actionMap)
{
if (context.Request.Method == HttpMethod.Get &&
odataPath.PathTemplate == "~/entityset/key/navigation/key")
{
NavigationPathSegment navigationSegment = odataPath.Segments[2] as NavigationPathSegment;
IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty.Partner;
IEdmEntityType declaringType = navigationProperty.DeclaringType as IEdmEntityType;
string actionName = "Get" + declaringType.Name;
if (actionMap.Contains(actionName))
{
// Add keys to route data, so they will bind to action parameters.
KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment;
context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;
KeyValuePathSegment relatedKeySegment = odataPath.Segments[3] as KeyValuePathSegment;
context.RouteData.Values[ODataRouteConstants.RelatedKey] = relatedKeySegment.Value;
return actionName;
}
}
// Not a match.
return null;
}
}
}
Poznámky:
- Odvozeno z EntitySetRoutingConvention, protože SelectController metoda v této třídě je vhodná pro tuto novou konvenci směrování. To znamená, že nemusím znovu implementovat SelectController.
- Konvence se vztahuje pouze na požadavky GET a pouze v případě, že je šablona cesty "~/entityset/key/navigation/key".
- Název akce je Get{EntityType}, kde {EntityType} je typ navigační kolekce. Například GetSupplier. Můžete použít libovolnou konvenci vytváření názvů, které se vám líbí – stačí se ujistit, že akce kontroleru odpovídají.
- Akce přijímá dva parametry s názvem key a relatedKey. (Seznam některých předdefinovaných názvů parametrů najdete v tématu ODataRouteConstants.)
Dalším krokem je přidání nové konvence do seznamu konvencí směrování. K tomu dochází během konfigurace, jak je znázorněno v následujícím kódu:
using ODataRouting.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;
namespace ODataRouting
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
// Create EDM (not shown).
// Create the default collection of built-in conventions.
var conventions = ODataRoutingConventions.CreateDefault();
// Insert the custom convention at the start of the collection.
conventions.Insert(0, new NavigationIndexRoutingConvention());
config.Routes.MapODataRoute(routeName: "ODataRoute",
routePrefix: "odata",
model: modelBuilder.GetEdmModel(),
pathHandler: new DefaultODataPathHandler(),
routingConventions: conventions);
}
}
}
Tady jsou některé další ukázkové konvence směrování, které je užitečné studovat:
A samotné webové rozhraní API je samozřejmě opensourcové, takže můžete vidět zdrojový kód pro integrované konvence směrování. Jsou definovány v oboru názvů System.Web.Http.OData.Routing.Conventions .