Creación de un punto de conexión de OData v4 mediante ASP.NET WEB API
Open Data Protocol (OData) es un protocolo de acceso a datos para la web. OData proporciona una manera uniforme de consultar y manipular conjuntos de datos mediante operaciones CRUD (crear, leer, actualizar y eliminar).
ASP.NET WEB API admite tanto v3 como v4 del protocolo. Incluso puede tener un punto de conexión v4 que se ejecute en paralelo con un punto de conexión v3.
En este tutorial se muestra cómo crear un punto de conexión de OData v4 que admita operaciones CRUD.
Versiones de software usadas en el tutorial
- Web API 5.2
- OData v4
- Visual Studio 2017 (descargar Visual Studio 2017 aquí)
- Entity Framework 6
- .NET 4.7.2
Versiones del tutorial
Para la versión 3 de OData, consulte Creación de un punto de conexión de OData v3.
Creación del proyecto de Visual Studio
En Visual Studio, en el menú Archivo, seleccione Nuevo> Proyecto .
Expanda Instalado>Visual C#>Weby seleccione la plantilla ASP.NET Aplicación web (.NET Framework). Asigne al proyecto el nombre "ProductService".
Seleccione Aceptar.
Seleccione la plantilla Vacía. En Agregar carpetas y referencias principales para:, seleccione Web API. Seleccione Aceptar.
Instalación de los paquetes de OData
En el menú Herramientas, seleccione Administrador de paquetes NuGet>Consola del Administrador de paquetes. En la ventana Consola del Administrador de paquetes, escriba:
Install-Package Microsoft.AspNet.Odata
Este comando instala los paquetes NuGet de OData más recientes.
Incorporación de una clase de modelo
Un modelo es un objeto que representa una entidad de datos en la aplicación.
En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Models. En el menú contextual, seleccione Agregar>Clase.
Nota:
Por convención, las clases de modelo se colocan en la carpeta Models, pero no es necesario seguir esta convención en sus propios proyectos.
Asigne Product
como nombre de la clase. En el archivo Product.cs, reemplace el código reutilizable por lo siguiente:
namespace ProductService.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
}
La propiedad Id
es la clave de entidad. Los clientes pueden consultar entidades por clave. Por ejemplo, para obtener el producto con el identificador 5, el URI es /Products(5)
. La propiedad Id
también será la clave principal de la base de datos back-end.
Habilitación de Entity Framework
En este tutorial, usaremos Entity Framework (EF) Code First para crear la base de datos de back-end.
Nota:
La API web OData no requiere EF. Use cualquier capa de acceso a datos que pueda traducir entidades de base de datos en modelos.
En primer lugar, instale el paquete NuGet para EF. En el menú Herramientas, seleccione Administrador de paquetes NuGet>Consola del Administrador de paquetes. En la ventana Consola del Administrador de paquetes, escriba:
Install-Package EntityFramework
Abra el archivo Web.config y agregue la siguiente sección dentro del elemento de configuración, después del elementoconfigSections.
<configuration>
<configSections>
<!-- ... -->
</configSections>
<!-- Add this: -->
<connectionStrings>
<add name="ProductsContext" connectionString="Data Source=(localdb)\mssqllocaldb;
Initial Catalog=ProductsContext; Integrated Security=True; MultipleActiveResultSets=True;
AttachDbFilename=|DataDirectory|ProductsContext.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
Esta configuración agrega una cadena de conexión para una base de datos LocalDB. Esta base de datos se usará al ejecutar la aplicación localmente.
A continuación, agregue una clase denominada ProductsContext
a la carpeta Models:
using System.Data.Entity;
namespace ProductService.Models
{
public class ProductsContext : DbContext
{
public ProductsContext()
: base("name=ProductsContext")
{
}
public DbSet<Product> Products { get; set; }
}
}
En el constructor, "name=ProductsContext"
proporciona el nombre de la cadena de conexión.
Configuración del punto de conexión de OData
Abra el archivo App_Start/WebApiConfig.cs. Agregue los siguientes mediante instrucciones:
using ProductService.Models;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;
A continuación, agregue el código siguiente al método Registro :
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
}
}
Este código hace dos cosas:
- Crea un modelo de datos de entidad (EDM).
- Agrega una ruta.
Un EDM es un modelo abstracto de los datos. El EDM se usa para crear el documento de metadatos del servicio. La clase ODataConventionModelBuilder crea un EDM mediante convenciones de nomenclatura predeterminadas. Este enfoque requiere el código mínimo. Si desea tener más control sobre el EDM, puede usar la clase ODataModelBuilder para crear el EDM agregando propiedades, claves y propiedades de navegación explícitamente.
Una ruta indica a la API web cómo enrutar las solicitudes HTTP al punto de conexión. Para crear una ruta de OData v4, llame al método de extensión MapODataServiceRoute.
Si la aplicación tiene varios puntos de conexión de OData, cree una ruta independiente para cada uno. Asigne a cada ruta un nombre y prefijo de ruta únicos.
Agregar el controlador OData
Un controlador es una clase que controla las solicitudes HTTP. Cree un controlador independiente para cada conjunto de entidades en el servicio OData. En este tutorial, creará un controlador para la Product
entidad.
En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Controladores y seleccione Agregar>Clase. Asigne ProductsController
como nombre de la clase.
Nota:
La versión de este tutorial para OData v3 usa el Agregar controladorandamiaje. Actualmente, no hay andamiaje para OData v4.
Reemplace el código reutilizable en ProductsController.cs por lo siguiente.
using ProductService.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
namespace ProductService.Controllers
{
public class ProductsController : ODataController
{
ProductsContext db = new ProductsContext();
private bool ProductExists(int key)
{
return db.Products.Any(p => p.Id == key);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
El controlador usa la ProductsContext
clase para acceder a la base de datos mediante EF. Observe que el controlador invalida el método Dispose para eliminar ProductsContext.
Este es el punto de partida del controlador. A continuación, agregaremos métodos para todas las operaciones CRUD.
Consulta del conjunto de entidades
Agregue los métodos siguientes a ProductsController
.
[EnableQuery]
public IQueryable<Product> Get()
{
return db.Products;
}
[EnableQuery]
public SingleResult<Product> Get([FromODataUri] int key)
{
IQueryable<Product> result = db.Products.Where(p => p.Id == key);
return SingleResult.Create(result);
}
La versión sin parámetros del método Get
devuelve toda la colección Products. El método Get
con una clave parámetro busca un producto por su clave (en este caso, la propiedad Id
).
El atributo [EnableQuery] permite a los clientes modificar la consulta mediante opciones de consulta como $filter, $sort y $page. Para obtener más información, consulte Compatibilidad con las opciones de consulta de OData.
Adición de una entidad al conjunto de entidades
Para permitir que los clientes agreguen un nuevo producto a la base de datos, agregue el método siguiente a ProductsController
.
public async Task<IHttpActionResult> Post(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
await db.SaveChangesAsync();
return Created(product);
}
Actualización de una entidad
OData admite dos semánticas diferentes para actualizar una entidad, PATCH y PUT.
- PATCH realiza una actualización parcial. El cliente especifica solo las propiedades que se van a actualizar.
- PUT reemplaza a toda la entidad.
La desventaja de PUT es que el cliente debe enviar valores para todas las propiedades de la entidad, incluidos los valores que no cambian. La especificación de OData indica que se prefiere PATCH.
En cualquier caso, este es el código para los métodos PATCH y PUT:
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var entity = await db.Products.FindAsync(key);
if (entity == null)
{
return NotFound();
}
product.Patch(entity);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(entity);
}
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != update.Id)
{
return BadRequest();
}
db.Entry(update).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
En el caso de PATCH, el controlador usa el tipo Delta<T> para realizar un seguimiento de los cambios.
Eliminación de una entidad
Para permitir que los clientes eliminen un producto de la base de datos, agregue el método siguiente a ProductsController
.
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
var product = await db.Products.FindAsync(key);
if (product == null)
{
return NotFound();
}
db.Products.Remove(product);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}