Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
di Mike Wasson
In OData le azioni e le funzioni sono un modo per aggiungere comportamenti lato server che non sono facilmente definiti come operazioni CRUD sulle entità. Questa esercitazione illustra come aggiungere azioni e funzioni a un endpoint OData v4 usando l'API Web 2.2. L'esercitazione si basa sull'esercitazione Creare un endpoint OData v4 usando ASP.NET API Web 2
Versioni software usate nell'esercitazione
- API Web 2.2
- OData v4
- Visual Studio 2013 (scaricare Visual Studio 2017 qui)
- .NET 4.5
Versioni del tutorial
Per OData versione 3, vedere Azioni OData in ASP.NET API Web 2.
La differenza tra azioni e funzioni è che le azioni possono avere effetti collaterali e le funzioni non lo fanno. Sia le azioni che le funzioni possono restituire dati. Alcuni usi per le azioni includono:
- Transazioni complesse.
- Manipolazione di più entità contemporaneamente.
- Consentire gli aggiornamenti solo a determinate proprietà di un'entità.
- Invio di dati che non sono un'entità.
Le funzioni sono utili per restituire informazioni che non corrispondono direttamente a un'entità o a una raccolta.
Un'azione (o funzione) può essere usata come destinazione di una singola entità o di una raccolta. Nella terminologia di OData, questo è il binding. È anche possibile avere azioni/funzioni "non associate", chiamate come operazioni statiche sul servizio.
Esempio: Aggiunta di un'azione
Definiamo un'azione per valutare un prodotto.
Annotazioni
Questa esercitazione si basa sull'esercitazione Creare un endpoint OData v4 usando ASP.NET'API Web 2
Aggiungere prima di tutto un ProductRating modello per rappresentare le classificazioni.
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; }
}
}
Aggiungere anche un DbSet alla classe ProductsContext, in modo che EF crei una tabella Ratings nel database.
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; }
}
Aggiungere l'azione a EDM
In WebApiConfig.cs aggiungere il codice seguente:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
// New code:
builder.Namespace = "ProductService";
builder.EntityType<Product>()
.Action("Rate")
.Parameter<int>("Rating");
Il metodo EntityTypeConfiguration.Action aggiunge un'azione al modello di dati dell'entità (EDM). Il metodo Parameter specifica un parametro tipizzato per l'azione.
Questo codice imposta anche lo spazio dei nomi per l'EDM. Lo spazio dei nomi è importante perché l'URI per l'azione include il nome completo dell'azione:
http://localhost/Products(1)/ProductService.Rate
Annotazioni
In una configurazione IIS tipica, il punto in questo URL porterà a un errore 404 restituito da IIS. Per risolvere questo problema, aggiungere la sezione seguente al file 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>
Aggiungere un metodo controller per l'azione
Per abilitare l'azione "Rate", aggiungere il metodo seguente a 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);
}
Si noti che il nome del metodo corrisponde al nome dell'azione. L'attributo [HttpPost] specifica che il metodo è un metodo HTTP POST.
Per richiamare l'azione, il client invia una richiesta HTTP POST simile alla seguente:
POST http://localhost/Products(1)/ProductService.Rate HTTP/1.1
Content-Type: application/json
Content-Length: 12
{"Rating":5}
L'azione "Rate" è associata alle istanze di Product, quindi l'URI per l'azione è il nome dell'azione completo aggiunto all'URI dell'entità. Tenere presente che lo spazio dei nomi EDM viene impostato su "ProductService", quindi il nome dell'azione completo è "ProductService.Rate".
Il corpo della richiesta contiene i parametri di azione come payload JSON. L'API Web converte automaticamente il payload JSON in un oggetto ODataActionParameters , che è semplicemente un dizionario di valori dei parametri. Usare questo dizionario per accedere ai parametri nel metodo del controller.
Se il client invia i parametri azione nel formato errato, il valore di ModelState.IsValid è false. Verifica questo flag nel metodo del controller e restituisci un errore se IsValid è false.
if (!ModelState.IsValid)
{
return BadRequest();
}
Esempio: Aggiunta di una funzione
Aggiungere ora una funzione OData che restituisce il prodotto più costoso. Come in precedenza, il primo passaggio aggiunge la funzione a EDM. In WebApiConfig.cs aggiungere il codice seguente.
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>();
In questo caso, la funzione è associata alla raccolta Prodotti, anziché alle singole istanze di Prodotto. I client richiamano la funzione inviando una richiesta GET:
GET http://localhost:38479/Products/ProductService.MostExpensive
Ecco il metodo controller per questa funzione:
public class ProductsController : ODataController
{
[HttpGet]
public IHttpActionResult MostExpensive()
{
var product = db.Products.Max(x => x.Price);
return Ok(product);
}
// Other controller methods not shown.
}
Si noti che il nome del metodo corrisponde al nome della funzione. L'attributo [HttpGet] specifica che il metodo è un metodo HTTP GET.
Ecco la risposta 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
}
Esempio: Aggiunta di una funzione non associata
L'esempio precedente era una funzione associata a una raccolta. In questo esempio successivo si creerà una funzione non vincolata. Le funzioni non associate vengono chiamate operazioni statiche sul servizio. La funzione in questo esempio restituirà l'iva per un determinato codice postale.
Nel file WebApiConfig aggiungere la funzione a EDM:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
// New code:
builder.Function("GetSalesTaxRate")
.Returns<double>()
.Parameter<int>("PostalCode");
Si noti che la funzione viene chiamata direttamente su ODataModelBuilder invece di sul tipo di entità o sulla raccolta. Ciò indica al costruttore di modelli che la funzione non è associata.
Di seguito è riportato il metodo controller che implementa la funzione :
[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);
}
Non importa in quale controller API Web inserire questo metodo. È possibile inserirlo in ProductsControllero definire un controller separato. L'attributo [ODataRoute] definisce il modello URI per la funzione.
Ecco una richiesta client di esempio:
GET http://localhost:38479/GetSalesTaxRate(PostalCode=10) HTTP/1.1
Risposta 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
}