Capitulo 7 : WCF Data Services (Parte 1)

Lección 1: ¿Qué es WCF Data Services?


WCF Data Services es la implementación de Microsoft de OData, que es una especificación de formato abierto para acceder a datos. Microsoft Visual Studio. NETfacilita la creación de un servicio de WCF de datos mediante un ADO.NET Entity Framework data model.

Introducción a OData
OData es un protocolo abierto para el el intercambio de datos que se basa en el protocolo de publicación Atom (AtomPub), que se usa con feeds, como los blogs. Proporciona una forma de acceder y, esencialmente, derribar los silos de datos para aumentar el valor compartido de datos para que los consumidores pueden interactuar con los productores de datos de una manera muy poderosa.
Las interacciones con un canal OData se llevan a cabo mediante el uso de URI para hacer frente a los recursos y verbos HTTP estándar (GET, POST, PUT, DELETE) para actuar en esos recursos. En comparación con SQL, el verbo GET selecciona, POST inserta , PUT actualiza, y el verbo DELETE borra.
Creando un WCF Data Service
WCF Data Services permite el intercambio de datos a través de Internet de una manera simplista. Los datos pueden estar en un archivo XML o en otro lugar.
Por ejemplo:
Se tiene una lista de autos que se desea mostrar en Internet. No importa su origen, los objetos podrían haber venido de una base de datos de SQL Server:
Esta demostración se inicia mediante la creación de una solución vacía denominada WcfDataServicesSolution, y una aplicación web ASP.NET, llamada WcfDataServicesLibrary.
Una clase llamada Car se añade a la WcfDataServiceLibrary:
-------------------------------------VB-------------------------------------------
VIN")> _
Public Class Car
Public Property VIN As String
Public Property Make As String
Public Property Model As String
Public Property Year As Integer
End Class
-------------------------------------CS-------------------------------------------
[DataServiceKey("VIN")]
public class Car
{
public string VIN { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }
}

La clase Car contiene las propiedades: VIN, make, model, y year. El atributo DataServiceKey, que OData utiliza para acceder a un elemento específico, espera una cadena que contiene el nombre de una propiedad que con valores únicos.

Se debe agregar una referencia al ensamblado System.Data.Services.Client.dll y el uso del espacio de nombres System.Data.Services.Common.
En el proyecto WcfDataServicesLibrary, se debe agregar el servicio de WCF , clic derecho en el proyecto WcfDataServicesLibrary y luego elegir Agregar | Nuevo elemento. Seleccionar WCF Data Service y de nombre CarService.svc


clip_image001[4]


Este archivo contiene una sola línea que hace referencia a una clase, donde se encuentra en el archivo code-behind, que puede ser o CarService.svc.cs CarService.svc.vb. (en mi caso .cs) El archivo contiene el siguiente código, esta clase hereda de DataService:
 
public class CarService :
DataService< /* TODO: put your data source class name here */ >
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service
operations are visible, updatable, etc.
// Examples:
// config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
// config.SetServiceOperationAccessRule("MyServiceOperation",
ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
}
}


Configurando WCF Data Services (ADO.NET Data Services)
La clase CarService contiene un método InitializeService con el que se setea la configuración del servicio, utilizando como parámetro un DataServiceConfiguration.
Esta clase tiene un método SetEntitySetAccessRule que acepta dos parámetros. El primer parámetro representa el nombre del conjunto de entidades en las que desea establecer permisos. Este parámetro también se acepta el asterisco (*) comodín para establecer permisos en todos los conjuntos de entidades. El segundo parámetro es un valor de enumeración EntitySetRights que representa los permisos que desea asignar al conjunto de entidades.

Nombre de miembro
Descripción
None
Deniega todos los derechos de acceso a los datos.
ReadSingle
Autorización para leer elementos de datos individuales.
ReadMultiple
Autorización para leer conjuntos de datos.
WriteAppend
Autorización para crear nuevos elementos de datos en los conjuntos de datos.
WriteReplace
Autorización para reemplazar los datos.
WriteDelete
Autorización para eliminar elementos de datos de los conjuntos de datos.
WriteMerge
Autorización para combinar datos.
AllRead
Autorización para leer datos.
AllWrite
Autorización para escribir datos.
All
Autorización para crear, leer, actualizar y eliminar datos.

El objeto de configuración establece permisos en las operaciones, proporcionando un valor de enumeración ServiceOperationRights al método SetServiceOperationAccessRule.
Valores de la enumeración ServiceOperationRights:
Nombre de miembro
Descripción
None
Sin autorización para acceder a la operación del servicio (service operation).
ReadSingle
Autorización para leer elementos de datos individuales. Usando service operation.
ReadMultiple
Autorización para leer conjuntos de datos  usando service operation.
AllRead
Autorización para leer datos. En service operation.
All
Autorización para crear, leer, actualizar y eliminar datos  en service operation..
OverrideEntitySetRights
Sobrescribe los derechos del  entity

La clase CarService debe contener propiedades para mostrar los datos, por lo que una propiedad de Car se agrega a CarService. Esta propiedad obtiene los datos de una lista codificada de autos, pero sin duda podría obtener sus datos desde un servidor back-end SQL u otra fuente. El siguiente ejemplo muestra la clase CarService completa.
-------------------------------------VB-------------------------------------------
Public Class CarService
Inherits DataService(Of CarService)
Public ReadOnly Property Cars As IQueryable(Of Car)
Get
Return (New List(Of Car) From
{
New Car() With {.VIN = "ABC123", .Make = "Ford",
.Model = "F-250", .Year = 2000},
New Car() With {.VIN = "DEF123", .Make = "BMW",
.Model = "Z-3", .Year = 2005},
New Car() With {.VIN = "ABC456", .Make = "Audi",
.Model = "TT", .Year = 2008},
New Car() With {.VIN = "HIJ123", .Make = "VW",
.Model = "Bug", .Year = 1956},
New Car() With {.VIN = "DEF456", .Make = "Ford",
.Model = "F-150", .Year = 1998}
}).AsQueryable()
End Get
End Property
Public Shared Sub InitializeService( _
ByVal config As DataServiceConfiguration)
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead)
config.DataServiceBehavior.MaxProtocolVersion = _
DataServiceProtocolVersion.V2
End Sub
End Class
-------------------------------------CS------------------------------------------- 
public class CarService : DataService
{
public IQueryable Cars
{
get
{
return (new List
{
new Car {VIN = "ABC123",Make = "Ford",
Model = "F-250", Year = 2000},
new Car {VIN = "DEF123",Make = "BMW",
Model = "Z-3", Year = 2005},
new Car {VIN = "ABC456",Make = "Audi",
Model = "TT", Year = 2008},
new Car {VIN = "HIJ123",Make = "VW",
Model = "Bug", Year = 1956},
new Car {VIN = "DEF456",Make = "Ford",
Model = "F-150", Year = 1998}
}).AsQueryable();
}
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
 
Antes de ejecutar este ejemplo, se debe abrir Microsoft Internet Explorer y desactivar  Feed Viewing (Herramientas | Opciones de Internet | Contenido, en la sección Feeds and Web Slices).De esta forma el navegador muestra una representación XML de los servicios. La colección de coches se define como una ubicación URI relativo, por lo que la adición de coches hasta el final de la URI se mostrará un feed XML que contiene la lista de los coches

clip_image002[4]

Es posible que también recuperar la información del esquema que describe las entidades expuestas por el servicio.

clip_image003[4]

Con WCF Data Services, se agrega /$metadata al final de la URI.
El elemento raíz está utilizando el espacio de nombres EDMX. Los metadatos describen la entidad Car con sus propiedades. También se describe el EntityContainer, llamado CarService, que tiene un EntitySet llamado Cars.


Accediendo a los datos de la base de datos
Se debe agregar un ADO.NET Entity Data Model  (NorthwindModel) al proyecto generando el modelo desde la base de datos Northwind (como se explico anteriormente).

Se debe agregar un servicio de WCF de datos (clic derecho en el proyecto en el Explorador de soluciones y elegir Agregar | Nuevo elemento--> WCF Data Service, con el nombre del archivo a NorthwindService.svc. La clase NorthwindService debe estar configurada para heredar del DataService de NorthwindEntities.

No se puede acceder a la función de importación CustOrderHist desde servicio WCF de datos, pero se puede agregar un método a la clase NorthwindService que permita el acceso a este. Los Métodos que se agregan a la clase de servicio se denominan operaciones de servicio. Las operaciones de servicio pueden aceptar parámetros, pero los parámetros deben ser de entrada (Visual Basic ByVal)  y deben ser tipos primitivos. Las operaciones de servicio deben devolver un tipo primitivo, IEnumerable IQueryable o void.

Las operaciones de servicio deben tener un atributo WebGet o WebInvoke. El atributo WebGet trabaja con el HTTP GET, y el atributo WebInvoke trabaja con el HTTP POST. En este ejemplo se utiliza el atributo WebGet, para ejecutar la operación del servicio desde el URI.
-------------------------------------VB-------------------------------------------
Public Class NorthwindService
Inherits DataService(Of NorthwindEntities)
Public Shared Sub InitializeService( _
ByVal config As DataServiceConfiguration)
config.SetEntitySetAccessRule("*", EntitySetRights.All)
config.SetServiceOperationAccessRule("*", _
ServiceOperationRights.All)
config.DataServiceBehavior.MaxProtocolVersion = _
DataServiceProtocolVersion.V2
End Sub
 _
Public Function CustOrderHist(ByVal customerID As String) _
As IQueryable(Of CustOrderHist_Result)
Using db As New NorthwindEntities()
Return db.CustOrderHist(customerID).ToList().AsQueryable()
End Using
End Function
End Class
-------------------------------------CS------------------------------------------- 
public class NorthwindService : DataService
{
// Este método es llamado solo una vez para iniciar las políticas de todo el servicio.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*",EntitySetRights.All);
config.SetServiceOperationAccessRule("*",
ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
}
[WebGet]
public IQueryable CustOrderHist(string customerID)
{
using(NorthwindEntities db = new NorthwindEntities())
{
return db.CustOrderHist(customerID).ToList().AsQueryable();
}
}
}
 
Ejemplos de URIs para acceder a las Entidades


http://localhost:65363/NorthwindService.svc/Customershttp://localhost:65363/NorthwindService.svc/Employees
http://localhost:65363/NorthwindService.svc/Orders
 
 
Ejemplo de URI para ejecutar el Service Operation http://localhost:65363/NorthwindService.svc/CustOrderHist?customerID='ALFKI'

Consultando datos a través de WCF Data Services
Algunas consultas requieren filtros, mientras que otras consultas requieren unirse a las operaciones.

Accediendo al WCF Data Service
Un URI utilizado por un servicio OData tiene hasta tres partes importantes: la URI raíz de servicio, la ruta del recurso, y las opciones de consulta. el siguiente ejemplo muestra la implementación de un filtro para recuperar a los clientes donde el país es igual a EE.UU.


clip_image004[4]


Propiedades de direccionamiento para recuperar
También se puede estar interesado en la recuperación de una sola propiedad de una consulta. Para eso se debe especificar propiedades individuales, así como otras palabras clave al final de la URI, por ejemplo:
Devuelve el nombre de la compañía de un cliente donde su customerID es “QUICK” http://localhost:57087/NorthwindService.svc/Customers('QUICK')/CompanyName
Devuelve las ordenes de un cliente donde su customerID es “QUICK”
http://localhost:57087/NorthwindService.svc/Customers('QUICK')/Orders
Devuelve el nombre de la compañía del Proveedor del producto 1  de la tabla supplier (proveedor)
http://localhost:57087/NorthwindService.svc/Products(1)/Supplier/CompanyName
También puede utilizar la palabra clave $count para recuperar el número de entidades en la consulta, como se muestra en el siguiente ejemplo:
Devuelve la cantidad de ordenes de un cliente donde su customerID es “QUICK” http://localhost:57087/NorthwindService.svc/Customers('QUICK')/Orders/$count
Se puede utilizar la palabra clave $value para recuperar el valor de una propiedad de forma explícita, aunque $value es implícito si no se especifica:
Devuelve el nombre de la compañía de un cliente donde su customerID es “QUICK”
http://localhost:57087/NorthwindService.svc/Customers('QUICK')/CompanyName/$value.
Además de los ejemplos anteriores que recuperar un valor de una propiedad, también se pueden especificar múltiples propiedades para devolver mediante el uso de la palabra clave $select, como se muestra en los siguientes ejemplos.
Devuelve el ProductID, ProductName y UnitPrice para el producto con ProductID (clave principal) =1
http://localhost:57087/NorthwindService.svc/Products(1)?$select=ProductID,ProductName,UnitPrice
Devuelve el CustomerID y el CompanyName para todos los clientes http://localhost:57087/NorthwindService.svc/Customers?$select=CustomerID,CompanyName


Estableciendo el orden de los resultados
Se puede utilizar la palabra clave $orderby para ordenar el conjunto de las entidades identificadas por la sección de ruta del recurso de la URI. La palabra clave $orderby sólo se admite cuando la ruta del recurso identifica un conjunto de entidades:
Devuelve los clientes ordenados por ContactName http://localhost:57087/NorthwindService.svc/Customers?$orderby=ContactName
Devuelve los productos ordenados de forma descendiente por UnitPrice
http://localhost:57087/NorthwindService.svc/Products?$orderby=UnitPrice desc


Recuperando un Top X de las Entidades
La palabra clave $top puede limitar la cantidad de entidades a regresar de una consulta.
Este subgrupo está formado por la selección de sólo los primeros n elementos de las entidades que han sido devueltos, donde n es un entero positivo especificado.
Si la URI del servicio de datos no contiene la palabra clave $orderby, las entidades del primer grupo tienen que ser plenamente ordenadas por el servicio de datos. La palabra clave $orderby no es obligatoria, pero, para obtener resultados repetibles, un servicio de datos debe utilizar siempre la misma semántica.
Devuelve los primeros 3 clientes http://localhost:57087/NorthwindService.svc/Customers?$top=3
Devuelve los primeros 3 precios de productos mas altos
http://localhost:57087/NorthwindService.svc/Products?$orderby=UnitPrice desc&$top=3

Omitiendo entidades
Puede utilizar la palabra clave $skip, para saltar un subconjunto de entidades que se han devuelto. Probablemente el uso más beneficioso de la palabra clave $skip es en la implementación de  paginación, en la que se salta n y se toma las entidades x para mostrar una página de datos.
Devuelve los primeros 3 clientes despues de saltearse 18 http://localhost:57087/NorthwindService.svc/Customers?$orderby=CustomerID&$skip=18&$top=3

Trabajando con filtros
Se puede utilizar la palabra clave $filter en la consulta para identificar un subconjunto de los elementos que desea recuperar. El subconjunto se determina mediante la selección de las entidades que satisfacen la expresión de predicado especificado.
Operador lógico
Descripción
eq
Igual
gt
Mayor que
ge
Mayor o igual que
lt
Menor que
le
Menor o igual que
ne
No igual
and
Y
or
O
not
No
Add
suma
Sub
resta
mul
multiplicación
div
división
mod
modulo
( )
agrupar


Por ej:
Devuelve los Productos donde su Unit Price es mayor a 10 http://localhost:65363/NorthwindService.svc/Products?$filter=UnitPrice gt 10
Devuelve las Ordenes donde el CustomerID es igual a ALFKI http://localhost:65363/NorthwindService.svc/Orders?$filter=CustomerID eq 'ALFKI'
Devuelve los Productos discontinuados donde su UnitPrice es mayor o igual a 50
http://localhost:65363/NorthwindService.svc/Products?
$filter=Discontinued eq true
and UnitPrice ge 50


Además de utilizar los operadores de filtro, también puede tomar ventaja de las funciones de string.
Miembro de la clase String
Función de OData admitida
string concat(string p0, string p1)
bool substringof(string p0, string p1)
bool endswith(string p0, string p1)
int indexof(string p0, string p1)
int length(string p0)
string replace(string p0, string find, string replace)
string substring(string p0, int pos)
string substring(string p0, int pos, int length)
string tolower(string p0)
string toupper(string p0)
string trim(string p0)

Devuelve los Productos donde el ProductName comienza con C http://localhost:65363/NorthwindService.svc/Products?$filter=startswith(ProductName,'C')
Devuelve los Productos donde su  CompanyName contiene restaurant
http://localhost:65363/NorthwindService.svc/Customers?$filter=substringof('restaurant',CompanyName
)

Las funciones de fecha y hora también están disponibles para su uso con las operaciones de $filter.
Miembro de la estructura DateTime
Función de OData admitida
int day(DateTime p0)
int hour(DateTime p0)
int minute(DateTime p0)
int month(DateTime p0)
int second(DateTime p0)
int year(DateTime p0)

Devuelve las ordenes de 1998 http://localhost:65363/NorthwindService.svc/Orders?$filter=year(OrderDate) eq 1998
Devuelve las ordenes de Febrero del 1998
http://localhost:65363/NorthwindService.svc/Orders?$filter=year(OrderDate) eq 1998
and month(OrderDate) eq 2

Funciones matemáticas disponibles para su uso con las operaciones de $filter:
Miembro de la clase Math
Función de OData admitida
decimal ceiling(decimal p0)
double ceiling(double p0)
decimal floor(decimal p0)
double floor(double p0)
decimal round(decimal p0)
double round(double p0)

Devuelve los Productos donde UnitPrice Floor es 19http://localhost:65363/NorthwindService.svc/Products?$filter=floor(UnitPrice) eq 19
Devuelve los Productos donde UnitPrice redondeado es 29
http://localhost:65363/NorthwindService.svc/Products?$filter=round(UnitPrice) eq 29
Devuelve los Productos donde UnitPrice termina con .5
http://localhost:65363/NorthwindService.svc/Products?$filter=
UnitPrice sub floor(UnitPrice) eq 0.5

Las funciones de tipo también se pueden usar con $filter:
Miembro de la clase Expression
Función de OData admitida
bool isof(type p0)
bool IsOf(expresion p0, type p1)


Carga ansiosa (Eager Loading) de Entidades
Cuando se quiere recuperar un cliente y las Ordenes de este, en lugar de ejecutar dos consultas, se puede ejecutar una sola consulta mediante el uso de la palabra clave $expand. Una URI con una palabra clave $expand indica que las entidades asociadas a la entidad o conjunto de entidades identificadas  en la URI deben ser cargadas ansiosamente.
Devuelve el cliente con el CustomerID = QUICK y sus ordenes http://localhost:57087/NorthwindService.svc/Customers('QUICK')?$expand=Orders
Devuelve el cliente con el CustomerID = ALFKI y sus ordenes y sus detalles de ordenes.
http://localhost:57087/NorthwindService.svc/Customers('ALFKI')
?$expand=Orders/Order_Details

Resumen de la lección
  • WCF Data Services se conocían anteriormente como ADO.NET Data Services.
  • Utiliza el protocolo Atom Publishing y Open Data protocol (OData).
  • WCF Data Services utiliza la semántica de transferencia de estado representacional(REST)​​.
  • Se puede introducir un URI la barra de direcciones del navegador para realizar un GET HTTP, que permite consultar los datos.
  • Se puede utilizar la enumeración EntitySetRights para establecer permisos de acceso a los datos.
  • Se puede utilizar la enumeración ServiceOperationRights para establecer los permisos de acceso a las operaciones de servicio.
  • La palabra clave $metadata recupera todo el esquema, que define todos los datos expuestos.
  • No se pueden llamar a un procedimiento almacenado directamente, se debe crear una operación de servicio para tener acceso a un procedimiento almacenado a través de una importación de la función.
  • Al llamar a una operación del servicio, los parámetros se pasan en la cadena de consulta y separados por el signo (&).
  • La palabra clave $count puede recuperar un recuento de las entidades que cumplen con un criterio de consulta.
  • La palabra clave $orderby puede especificar un orden de clasificación.
  • La palabra clave $top puede recuperar las primeros n entidades de un resultado de la consulta.
  • La palabra clave $skip  se puede utilizar en la paginación, para saltar sobre las entidades de n antes de devolver un resultado de la consulta.
  • La palabra clave $ filter limita a las entidades a ser devueltos por una consulta.
  • La palabra clave $expand permite realizar una carga ansiosa de entidades al ejecutar una consulta.

No hay comentarios:

Publicar un comentario