A discussão sobre WCF Data Services no objetivo 1.1 foi curta porque há um objetivo específico para ele, o Create and implement a WCF Data Services service, que será coberto nesse post.
Esse objetivo cobre como endereçar recursos, criar uma query, acessar formatos de carga (incluindo JSON) e trabalhar com interceptores e operadores de serviço. Vamos lá?
Endereçando Recursos
Para criar um WCF Data Service, basicamente você deve seguir os seguintes passos:
- Criar uma aplicação ASP.NET (para hostear o Data Service);
- Usar o EF para criar seu EntityModel;
- Adicionar um WCF Data Service;
- Especificar um tipo para o serviço (que é o nome do model container do projeto do EF);
- Habilitar acesso ao Data Service configurando explicitamente algumas propriedades do DataServiceConfiguration (SetEntitySetAccessRule, SetServiceOperationAccessRule e DataServiceBehavior)
Quando você adicionar um WCF Data Service, você verá classes geradas assim: public class ExamSampleService : DataService
. Essas classes herdam de System.Data. Services.DataService, que recebem um tipo genérico. O código gerado terá também o método InitializeService com alguns comentários que ajudam na sua configuração:
// 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;
}
Como já citado, é importante se familiarizar com os métodos SetEntitySetAccessRule e SetServiceOperationAccessRule e a propriedade DataServiceBehavior.MaxProtocolVersion.
SetEntitySetAccessRule
Esse método recebe dois parâmetros: uma string com o nome do EntitySet e um enum EntitySetRights. Como o enum é decorado com Flags, você pode passar mais de um valor dessa forma: config.SetEntitySetAccessRule("Courses", EntitySetRights.AllRead | EntitySetRights.WriteMerge);
. Os possíveis valores desse enum são:
- None: todos os acessos são revogados;
- ReadSingle: um item pode ser lido;
- ReadMultiple: sets de dados podem ser lidos;
- WriteAppend: novos itens podem ser adicionados;
- WriteReplace: dados podem ser atualizados;
- WriteDelete: dados podem ser deletados;
- WriteMerge: dados podem ser mergeados;
- AllRead: tudo pode ser lido;
- AllWrite: tudo pode ser escrito;
- All: todas as operações são permitidas.
SetServiceOperationAccessRule
Esse método dá permissões para uma ServiceOperation e funciona da mesma forma que o método SetEntitySetAccessRule, mas o enum é um ServiceOperationRights. Os valores desse enum são:
- None: todos os acessos são revogados;
- ReadSingle: um item pode ser lido;
- ReadMultiple: sets de dados podem ser lidos;
- AllRead: um e vários itens podem ser lidos;
- All: todos os direitos são garantidos;
- OverrideEntitySetRights: indica se sobrescreve os valores configurados em SetEntitySetAccessRule.
DataServiceBehavior.MaxProtocolVersion
Essa propriedade indica qual versão do protocolo OData será usado no serviço. Os possíveis valores do enum DataServiceProtocolVersion são V1 e V2.
Criando Uma Query
Uma das principais vantagens do WCF Data Services é que seus recursos são endereçáveis por URIs via OData, e você pode fazer queries nas URIs de uma forma bem simples.
Suponha que você criou um WCF Data Service com o nome ExamPrepService baseado num Entity Model que tem tópicos, questões e respostas como entidades.
Para obter todos os registros de uma entidade, a query Service/EntitySetName pode ser usada. Para obter todos os tópicos do serviço, por exemplo, a seguinte query pode ser usada:
http://servicehost/ExamPrepService.svc/Topics
A query Service/EntitySetName(‘KeyValue’) retorna a entidade que tem uma key com o valor passado. Por exemplo, para obter o tópico que tem o nome First, a query fica http://servicehost/ExamPrepService.svc/Topics('First')
.
Se você precisa somente da propriedade Description, a query fica http://servicehost/ExamPrepService.svc/Topics('First')/Description
. Se quiser somente o valor primitivo e não o XML, basta adicionar /$value no final: http://servicehost/ExamPrepService.svc/Topics('First')/Description/$value
.
As queries funcionam bem com relacionamentos, se esses estiverem definidos no Entity Model. Para obter todas as Answers da Question com a key 1, por exemplo, a seguinte query deve ser usada:
http://servicehost/ExamPrepService.svc/Questions('1')/Answers
O caminho inverso também é possível: http://servicehost/ExamPrepService.svc/Answers('1:4')/Question
.
Até agora, só filtramos os resultados pela key da entidade. Mas o protocolo OData e o WCF Data Service oferecem várias opções de query que se traduzem em queries SQL. É bem importante entender o efeito de todos eles no resultado.
- $orderby: define uma ordem para o resultado. Uma ou mais propriedades podem ser usadas, separadas por vírgula:
/Questions?$orderby=Id,Description
; - $top: define quantos resultados serão retornados:
/Questions?$top=5
- $skip: indica quantos registros devem ser ignorados. Suponha que há 30 tópicos, mas você quer ignorar os 10 primeiros e os 10 últimos. A query fica assim:
/Questions?$skip=10&$top=10
; - $filter: especifica uma ou mais condições:
/Questions?$filter=Id gt 5
; - $expand: indica quais entidades relacionadas serão retornadas:
/Questions?$expand=Answers
; - $select: por padrão, todas as propriedades de uma entidade são retornadas. Usando $select, você pode especificar quais propriedades serão retornadas separando por vírgula:
/Questions&$select=Id,Text,Description,Author
; - $inlinecount: retorna o número de registros retornados no elemento <count>:
/Questions?$inlinecount=allpages
.
Você também pode executar queries por meio de código usando a classe DataServiceQuery:
String ServiceUri = "http://servicehost/ExamPrepService.svc";
ExamServiceContext ExamContext = new ExamServiceContext(new Uri(ServiceUri); DataServiceQuery
.AddQueryOptions("$filter", "id gt 5")
.AddQueryOptions("$expand", "Answers");
Acessando Formatos De Carga
o WCF Data Service dá suporte aos formatos Atom e JSON de forma fácil.
Basta usar a opção $format na query com o valor atom ou json. Caso esteja consultando via WebClient ou queira especificar isso em um request header, funciona da mesma maneira. Para JSON, coloque o header Content-Type para application/json. Para Atom, application/atom+xml.
Trabalhando Com Interceptor e Service Operator
O WCF Data Service permite que você intercepte um request para prover uma lógica customizada.
Há dois tipos de Interceptors: ChangeInterceptor, que serve para interceptar operações NON-Query, e QueryInterceptor, que intercepta operações de Query.
ChangeInterceptors têm retorno nulo e aceitam dois parâmetros: o tipo da entidade e um UpdateOperations, que referencia o request. A definição de um método ChangeInterceptor fica assim:
[ChangeInterceptor("Topics")]
public void OnChangeTopics(Topic topic, UpdateOperations operations)
QueryInterceptors são decorados com QueryInterceptor e retornam uma Expression
[QueryInterceptor("Topics")]
public Expression
A dica para o exame é que, para identificar se um método é ChangeInterceptor ou QueryInterceptor, basta olhar para o tipo do retorno.
Para saber qual Interceptor deve ser implementado para fazer alguma coisa, é necessário saber o comportamento e determinar se é uma operação NON-Query ou Query. Por exemplo, DeleteTopics seria um ChangeInterceptor; já um método GetAdvancedTopics seria um QueryInterceptor.
Qualquer dúvida, fique à vontade para fazê-la nos comentários.
Fique ligado para o post do próximo objetivo, Manipulate XML data structures.
Até mais!