Certificação Microsoft 70-487: Objetivo 4.4 – Host and manage a Web API

Olá pessoal!
O objetivo 4.4 da certificação Microsoft 70-487, Host and manage a Web API, trata dos principais mecanismos de hospedagem de um serviço Web API, como self-hosting, IIS e Azure. Também mostra como limitar o tamanho das mensagens recebidas e configurar a hospedagem para streaming. Vamos lá?

Web API Self-Hosting

Para fazer o self-hosting de uma Web API, você pode usar qualquer template de projeto que crie um executável, como Windows Service, Windows Forms Application, Console Application, etc.

Com o projeto criado, você deve instalar o framework de self-hosting via NuGet com o pacote Microsoft ASP.NET Web API Self Host e referenciar os assemblies System.Web.Http e System.Web.Http.SelfHost:

self host

Depois, há dois passos essenciais: instanciar as classes HttpSelfHostConfiguration e HttpSelfHostServer. O código fica assim:

A primeira verificação se MyWebApi.Controllers.ValuesController é null serve para o framework de self-hosting carregar os controllers do seu projeto Web API. Isso somente é necessário quando os controllers estão num assembly separado.

A classe HttpSelfHostConfiguration recebe o endereço base de onde o serviço vai ser acessado. Um ponto importante aqui é que as rotas precisam ser configuradas diretamente na propriedade Routes.

Por último, a classe HttpSelfHostServer é instanciada recebendo a configuração criada anteriormente. O método OpenAsync toma conta de abrir o servidor com as configurações passadas.

Web API IIS Hosting

Hospedar uma Web API no IIS não tem nada diferente de outras aplicações web.

Você pode primeiro criar uma application pool, conforme abaixo:

application pool

Depois, criar um novo website embaixo do nodo Sites ou adicionar uma aplicação ou diretório virtual:

add application

Com tudo isso no lugar, sua aplicação deve estar hospedada com sucesso.

Web API Windows Azure Hosting

Essa é uma seção conceitual para as 3 formas de hospedar uma Web API no Azure. São elas:

  • Windows Azure Websites: a opção mais rápida. Com Azure Websites você não se importa com a máquina que está hospedando seu serviço, apesar de poder escalar sua aplicação facilmente;
  • Windows Azure Cloud Services: Cloud Services oferecem um controle maior. Você tem mais tamanhos de instância para escolher e pode criar uma arquitetura mais complexa, como uma Web API numa Web Role se comunicando via queue com uma Worker Role, por exemplo. Você pode também configurar o IIS e outras configurações da máquina quando a role começar. Consegue também se conectar via remote com a máquina;
  • Windows Azure Virtual Machines (VMs): usar VMs no Azure te dá controle completo. Você precisa gerenciar sua máquina inteira, de atualizações até configurações.

Fazer o deploy de uma Web API para o Azure Websites ou Cloud Services é bem simples usando o Visual Studio. Isso será coberto com mais detalhes no capítulo 5.

Limitando O Tamanho Das Mensagens

Ao hospedar sua Web API, você com certeza gostaria de limitar o tamanho dos requests para que seu servidor não sofra de ataques DDoS.

Usando self-hosting, você pode fazer isso setando as propriedades MaxReceivedMessageSize e MaxBufferSize do objeto HttpSelfHostConfiguration:

var config = new HttpSelfHostConfiguration(baseAddress);
config.MaxReceivedMessageSize = 1024;
config.MaxBufferSize = 1024;

Hospedando no IIS, isso é possível pela configuração do atributo maxRequestLength no web.config:

<httpRuntime maxRequestLength="1024" />

Configurando Streaming

Às vezes você quer que seu serviço Web API receba arquivos grandes, como algum upload de imagens ou vídeos. Nesses casos, é importante configurar sua Web API para usar streaming ao invés de buffer, já que bufferizar arquivos grandes consome muita memória.

Hospedando sua aplicação no IIS, você consegue implementar sua lógica se usar buffer ou streaming herdando a classe WebHostBufferPolicySelector, a única que implementa a interface IHostBufferPolicySelector, e sobrescrevendo o método UseBufferedInputStream. Por exemplo, você pode habilitar streaming apenas para um controller específico:

Depois disso, você deve configurar o HttpConfiguration para usar sua implementação: config.Services.Replace(typeof(IHostBufferPolicySelector), new StreamingPolicySelector());.

Por último, você precisa configurar as propriedades do ASP.NET como maxAllowedContentLength e maxRequestLength no web.config para que o IIS não rejeite os requests grandes:

Para self-hosting, você só consegue habilitar streaming para todos os controllers. Você faz isso configurando a propriedade TransferMode no objeto HttpSelfHostConfiguration:

// somente requests
selfHostConf.TransferMode = TransferMode.StreamedRequest;
// somente responses
selfHostConf.TransferMode = TransferMode.StreamedResponse;
// ambos
selfHostConf.TransferMode = TransferMode.Streamed;


Isso é tudo para esse objetivo 🙂

Obrigado pela leitura e fique de olho no próximo post, que será o último objetivo sobre Web API: Consume Web API web services.

Até mais!

Leia Mais

Certificação Microsoft 70-487: Objetivo 4.3 – Secure a Web API

Olá pessoal!
O objetivo 4.3 da certificação 70-487, Secure a Web API, trata de forma bem completa sobre as diferentes formas de segurança e autenticação disponíveis para serviços Web API.

Esse objetivo cobre como 1) autenticar e autorizar usuários, 2) implementar a autenticação HTTP Basic com SSL, 3) implementar Windows Authentication, 4) prevenir cross-site request forgery, 5) habilitar requests cross domain e 6) implementar e extender authorization filters.

Autenticar E Autorizar Usuários

Essa seção apenas explica os conceitos de autenticação e autorização.

Autenticação é o processo de identificação do usuário, geralmente por um nome de usuário e senha. O framework da Web API tem uma série de ferramentas para implementação desse processo, o que vamos ver logo mais.

Autorização é o processo que define quais ações o usuário pode fazer no sistema. Por exemplo, você pode permitir que usuários anônimos façam apenas consultas, usuários autenticados façam inserções e usuários administrativos façam atualizações.

Implementando Autenticação HTTP Basic

HTTP Basic é a forma mais simples e fácil de implementar um mecanismo de autenticação. É um formato conhecido e maduro, suportado pela maioria dos browsers e nativamente suportado pelo IIS. A principal desvantagem é que as credenciais são transmitidas em plain text nos headers do request, tornando-se vulnerável a interceptores. Também não há como fazer logout explicitamente a não ser que a sessão do browser se encerre.

O fluxo com HTTP Basic é assim:

Um client faz um request. Se o serviço necessitar autenticação, o server retorna o status code 401 (unauthorized) com o seguinte header: WWW-Authenticate: Basic realm="Realm Name". Esse header especifica que o server suporta a autenticação Basic no domínio especificado (realm).

O client, ao receber um response 401, faz outro request com o header de autenticação. A construção do header começa com o nome de usuário e a senha concatenados por um dois-pontos. Por exemplo, caso o nome de usuário seja JohnQPublic e a senha !*MyPa55w0rd*!, o valor seria JohnQPublic:!*MyPa55w0rd*!. Em seguida esse valor seria encodado por Base64, resultando na string Sm9oblFQdWJsaWM6ISpNeVBhNTV3MHJkKiE=. Por fim, a palavra Basic é adicionada antes dessa string e enviada no header Authorization: Authorization: Basic Sm9oblFQdWJsaWM6ISpNeVBhNTV3MHJkKiE=.

Um ponto importante é que o nome de usuário e senha, apesar de encodados em Base64, não estão encriptados. Qualquer interceptor que tiver acesso aos headers do request vai conseguir decifrar dados sensíveis do usuário facilmente. Por isso, a autenticação Basic não é segura a não ser que feita por HTTPS, onde todo o request é criptografado. Para o exame (e para a vida real), lembre-se: nunca use autenticação Basic sem SSL.

Habilitando SSL

Como a autenticação Basic não deve ser utilizada sem SSL, você deve saber como forçar uma conexão HTTPS para Web API.

Se você viu como implementar Action Filters no objetivo anterior, vai reconhecer como vamos fazer isso agora. De forma simples, basta implementar a classe AuthorizationFilterAttribute e sobrescrever o método OnAuthorization com uma validação. Segue um exemplo:

Depois disso, você deve decorar os controllers desejados com esse atributo ou registrá-lo globalmente no HttpConfiguration.

Não sei se cairá no exame, mas saiba que há uma ferramenta chamada MakeCert.exe para gerar certificados SSL para testes.

Implementando Windows Authentication

Windows Authentication é um processo onde os usuários podem se autenticar pelo seu login no Windows, Kerberos ou NTLM. É ideal para aplicações intranet que serão acessadas somente de dentro do mesmo domínio, em uma empresa por exemplo. Obviamente, não é recomendada para cenários onde usuários “anônimos” vão acessar sua API.

Por ser nativamente suportada pelo IIS, implementar essa autenticação é bem simples. Basta configurar a propriedade Mode do elemento Authentication para “Windows” no web.config, como a seguir:

<system.web>
<authentication mode="Windows" />
</system.web>

Se o client for diretamente um browser, este precisa dar suporte ao esquema de autenticação Negotiation. Não há muito o que se preocupar pois todos os browsers populares têm esse suporte.
Caso seja uma aplicação .NET, a classe HttpClient deve ser usada para fazer o request (como sempre). A única modificação é que ela deve ser instanciada com um HttpClientHandler, que pode ser obtido da seguinte maneira:

HttpClientHandler clientHandler = new HttpClientHandler
{
UseDefaultCredentials = true
};

Prevenindo Cross-Site Request Forgery

Cross-Site Request Forgery (CSRF ou XSRF) é uma forma bastante utilizada por atacantes para acessarem recursos disponíveis para usuários autenticados.

Vamos supor que você está logado no portal do Azure e, no mesmo browser, recebe um e-mail dizendo que você tem desconto de 50% para novos serviços no Azure. Ao clicar no link do e-mail, você é direcionado para a página https://manage.windowsazure.com/api/DeleteAllData sem perceber. É claro que essa página não existe no portal, mas se existisse, você estaria em sérios problemas.

Resumidamente, um ataque XSRF acontece quando você está autenticado em algum sistema e um atacante se aproveita disso para executar alguma ação. Seu sistema está vulnerável a ataques XSFR se você usa um mecanismo de autenticação que mantém o usuário logado (baseado em cookies) ou quando você permite requests cross domain. A autenticação Basic também é vulnerável pois o browser normalmente armazena seu token de autenticação para evitar que o usuário digite o usuário e senha a cada request.

Para se proteger de ataques XSRF, há uma solução pronta em MVC e que os mesmos princípios podem ser aplicados na Web API.

Usando o método Html.AntiForgeryToken na view e o atributo ValidateAntiForgeryToken na action, o MVC primeiro renderiza um input hidden na tela assim: <input name="__RequestVerificationToken" type="hidden" value="saTFWpkKN0BYazFtN6c4YbZAmsEwG0srqlUqqloi/fVgeV2ciIFVmelvzwRZpArs" />. Esse valor é gerado randomicamente e também é colocado num cookie passado para o usuário. Ao fazer um post, por exemplo, o MVC valida se o valor do cookie e o do form data são iguais. Isso é seguro pois o atacante não vai saber o valor do cookie para forjar um request válido.

Para Web API, como dito, o princípio pode ser aplicado. Você manda um valor no cookie e no HTML e depois garante que eles são o mesmo. Você pode mandar o token antiforgery usando o mesmo método Html.AntiForgeryToken.

Para validar o token na Web API, você deve obter o token do cookie; obter do form data; passar ambos para o método AntiForgery.Validate e retornar um response Unauthorized caso a validação falhe. O código ficaria assim:

Habilitando Requests Cross Domain

Por padrão, os browsers proíbem requests cross domain, ou seja, para domínios diferentes do atual. Por exemplo, se você está no site http://www.contoso.com, você não pode fazer uma requisição AJAX para http://www.someotherwebsite.com. Você também não pode fazer requests para o seu domínio com outro protocolo (HTTP ao invés de HTTPS) ou para outra porta. Isso existe para evitar ataques XSRF, já que a maioria das autenticações funcionam por cookie.

Porém você pode querer que sua API seja consumida por vários clients, e isso se tornaria um problema. Isso se chama CORS (cross origin resource sharing), e você pode habilitá-lo facilmente no arquivo web.config:

Isso adiciona um header nos responses, indicando que CORS está habilitado. Com isso, qualquer site pode fazer requisições para sua API, o que pode não ser desejado.

Para resolver esse problema, a Microsoft criou um pacote NuGet chamado Microsoft.AspNet.WebApi.Cors. Após a instalação, você tem um método de extensão no objeto HttpConfiguration: config.EnableCors();.

Chamando esse método no método WebApiConfig.Register, você habilita o suporte a CORS na sua aplicação. Agora você pode adicionar o atributo EnableCors para controllers e actions assim:

Nesse caso, você habilitou CORS somente para esse método na URL especificada em origins.

Implementando E Extendendo Authorization Filters

A Web API oferece o atributo AuthorizeAttribute que por padrão garante que os usuários acessando esse controller ou action estão autenticados e têm as roles necessárias, se especificadas.

Você pode estender a classe AuthorizeAttribute e sobrescrever o método IsAuthorized para implementar sua própria lógica. O exemplo a seguir faz uma implementação de black list, ou seja, usuários com as roles especificadas não podem acessar a action:

Você também pode estender a classe AuthorizationFilterAttribute ou implementar a interface IAuthorizationFilter para realizar alguma lógica customizada. As diferenças entre elas são as seguintes:

  • AuthorizeAttribute: usada para implementar lógica de autorização baseada no usuário e nas roles;
  • AuthorizationFilterAttribute: usada para implementar lógica síncrona de autorização que não está baseada no usuário e nas roles (por exemplo, forçar HTTPS);
  • IAuthorizationFilter: usada para implementar lógica assíncrona de autorização que não está baseada no usuário e nas roles.

Obrigado pela leitura de mais um objetivo!
O próximo post será sobre o objetivo 4.4, Host and manage a Web API.

Até lá!

Leia Mais

Certificação Microsoft 70-487: Objetivo 4.2 – Implement a Web API

O objetivo 4.2, Implement a Web API, é a continuação lógica do objetivo anterior com alguns tópicos mais avançados como content negotiation, HttpMessageHandler, injeção de dependência, Action Filters, streaming, etc. Vamos lá?

Manipulando Dados Em JSON

Com sua Web API retornando os dados, é interessante (e óbvio) que você construa uma interface para seus usuários trabalharem com os dados.

Ao criar uma aplicação Web API, a engine de views Razor é usada por padrão e uma view Index.cshtml é criada na pasta Views/Home, com algum layout pronto. Fazendo as alterações a seguir no HTML, a tela fica mais ou menos assim:

index.cshtml

O plano é listar todos os Customers na ul customers e os que contêm o Last Name informado pelo usuário na ul results. Tudo isso será feito via AJAX (Asynchronous JavaScript and XML), onde o browser consegue fazer requisições ao serviço Web API sem a necessidade de carregar a página inteira novamente.

O seguinte script pode ser utilizado:

O ponto principal dessa seção é que você não precisa alterar nada no serviço Web API para que ele aceite formatos em JSON ou XML. O passo mais importante no client é apenas indicar explicitamente se ele está enviando JSON ou XML pelo request header Content-Type (o método do jQuery getJSON() fez isso).

Content Negotiation

Content Negotiation (negociação de conteúdo) é o processo onde o client indica o tipo do retorno que ele deseja ao fazer uma chamada a um serviço Web API.
Isso é feito por 4 headers no request:

  • Accept: especifica o tipo do retorno do response. Para JSON o valor é application/json e para XML é application/xml ou text/xml;
  • Accept-Charset: especifica o charset. Valores comuns são UTF-8 e ISO-8859-1;
  • Accept-Encoding: indica quais encodings são aceitos;
  • Accept-Language: especifica a linguagem preferida.

Para entender melhor, vamos olhar o request e o response da chamada ao serviço FindCustomers do exemplo anterior:

Request

GET http://localhost:53366/data/Customer/FindCustomers?lastName=r HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*; q=0.01
Referer: http://localhost:53366/
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: localhost:53366
DNT: 1
Connection: Keep-Alive

Response

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcUHJvamVjdHNcTXlTb2x1dGlvblxNeVdlYkFwaVxkYXRhXEN1c3RvbWVyXEZpbmRDdXN0b21lcnM=?=
X-Powered-By: ASP.NET
Date: Mon, 15 Jul 2013 15:52:20 GMT
Content-Length: 290
[{"CustomerId":4,"AccountId":2,"FirstName":"Captain","LastName":"America"},
{"CustomerId":8,"AccountId":3,"FirstName":"Ham","LastName":"Burgler"},
{"CustomerId":11,"AccountId":4,"FirstName":"Betty","LastName":"Rubble"},
{"CustomerId":12,"AccountId":4,"FirstName":"Barney","LastName":"Rubble"}]

Nesse caso, o client fez a requisição solicitando o resultado em JSON (application/json), JavaScript (text/javascript) ou qualquer outra coisa (*/*). O servidor informou que o retorno está em JSON pelo response header Content-Type.

Caso alguma Exception acontecesse, o response estaria com o status code 500 mas o body ainda seria JSON, provavelmente com a Exception serializada.

A execução dessa negociação acontece da seguinte forma: quando o request é recebido pelo servidor, o framework obtém uma instância de IContentNegotiator do HttpConfiguration, que tem a lista dos formatters disponíveis. O método Negotiate de IContentNegotiator é chamado com 3 parâmetros (o tipo do objeto sendo serializado, a lista dos formatters e o request) e retorna o formatter a ser utilizado e o media type para o response. Se nenhum formatter for encontrado, o client recebe um response com o HttpStatusCode NotAcceptable (406).

Data Binding

Um dos aspectos importantes da Web API é o binding dos dados. As actions que você cria recebem parâmetros e é importante entender como o framework “preenche” os valores.

No caso de tipos simples como int, string, bool, DateTime, etc., os valores vêm da URL. No nosso exemplo anterior, o serviço FindCustomers recebe uma string lastName que é passada na URL como query string: /data/Customer/FindCustomers?lastName=r. Para tipo complexos (classes), o framework obtém os dados do body usando um formatter.

Você pode alterar o processo de binding padrão. O atributo FromUri, por exemplo, indica que um tipo complexo deve ser lido da URL ao invés do body:

public HttpResponseMessage Get([FromUri] Person person)

Dessa forma você chamaria esse serviço assim: /api/Persons/?FirstName=John&LastName=Doe. De maneira similar, o atributo FromBody indica que o tipo simples deve ser obtido do body.

HttpMessageHandler

Message handlers fazem parte do pipeline do framework Web API e são responsáveis por interceptar as mensagens que chegam (requests) e as que são retornadas (responses) para os clients.

Você pode implementar um message handler para efetuar alguma lógica ou fazer alguma validação antes que uma action seja chamada. Isso é possível derivando a classe System.Net.Http.DelegatingHandler e implementando o método SendAsync. Por exemplo:

Para interromper o request, basta não chamar o método base e retornar um response de falha.

Seu handler precisa ainda ser registrado no pipeline da Web API. Você pode fazer isso de duas formas.

Na primeira, você adiciona o handler nos MessageHandlers do HttpConfiguration, no método Register da classe WebApiConfig: config.MessageHandlers.Add(new LoggingMessageHandler());
Dessa forma o handler é registrado globalmente, sendo executado para todos os requests.

O outro jeito é adicionar o handler para uma rota específica, fazendo ele ser executado apenas para actions daquela rota:

Implementando Injeção De Dependência

Por motivos fora do escopo do exame, dependências suck. Tome o código a seguir como exemplo:

public string Get()
{
WebClient webClient = new WebClient();
string result = webClient.DownloadString("http://microsoft.com");
return result;
}

Seria bem melhor você ter uma interface IContentRepository com um método GetContent(string uri) e ter uma implementação WebClientContentRepository, que utiliza a classe WebClient. O controller agora ficaria assim:

Com o código desacoplado, você precisa de um mecanismo para preencher a dependência do seu controller. A interface IDependencyResolver pode ser implementada da seguinte forma:

Configurando o DependencyResolver no objeto HttpConfiguration (config.DependencyResolver = new ResolveController();), o framework já consegue resolver a dependência de IContentRepository.

Essa obviamente não é a melhor opção, pois cada nova dependência vai acarretar numa mudança na verificação do tipo do controller no método GetService. Para resolver esse problema, existem vários projetos open source que ajudam nessa implementação, e talvez uma delas caia no exame: Unity.

Ao instalar o Unity pelo NuGet, o arquivo Bootstrapper.cs é adicionado ao projeto. As únicas coisas que você precisa saber é que o método BootStrapper.Initialize deve ser chamado no Global.asax e que você registra uma dependência dessa forma: container.RegisterType();.

Action Filters E Exception Filters

Filters são métodos que podem alterar a action que está sendo executada.
Action Filter é um método que é invocado toda vez que uma action é chamada, enquanto Exception Filter é um método executado quando ocorre uma Exception não tratada.
Para implementar uma Action Filter você implementa a classe ActionFilterAttribute, e para um Exception Filter a classe ExceptionFilterAttribute.

Veja o seguinte exemplo:

Esse filtro pode ser aplicado para forçar a action a retornar XML, sobrescrevendo o comportamento padrão.

Você pode aplicar esse atributo a um controller (que vai aplicar para todas as actions) ou actions específicas. Também é possível configurar esse filtro globalmente pela propriedade HttpConfiguration.Filters.

Streaming Actions

A classe PushStreamContent pode ser usada para uma action retornar um stream, quando você precisa enviar uma quantidade muito grande de dados para um client.

Segue um exemplo de implementação. Esse código usa um timer para enviar alguns dados para os clients conectados a cada segundo. A classe PushStreamContent é inicializada com o método OnStreamAvailable:

Se você executar essa action, o request só vai terminar quando você fechar o browser. Dessa forma, você consegue enviar uma grande quantidade de dados em pacotes para o client.


E chegamos ao final desse objetivo 🙂
Obrigado pela leitura e fique de olho no post do próximo objetivo, Secure a Web API.

Até mais!

Leia Mais

Certificação Microsoft 70-487: Objetivo 4.1 – Design a Web API

Olá pessoal!

Hoje vamos começar o primeiro objetivo do capítulo sobre Web API, Design a Web API. Esse objetivo cobre como escolher um método HTTP apropriado, definir recursos HTTP com actions, usar rotas, escolher formatos e planejar quando usar actions assíncronas. Vamos lá?

Escolhendo Métodos HTTP

Resumindo a introdução, Web API é um serviço REST (Representational State Transfer) baseado em HTTP. Ao invés de chamar um método específico, como no WCF, com Web API você faz uma chamada para uma URL em conjunto com um método HTTP.

Segue uma lista com os métodos HTTP existentes e depois entraremos em detalhes sobre os mais importantes:

  • Delete: deleta a entidade;
  • Get: obtém os dados de uma ou mais entidades;
  • Put: atualiza a entidade inteira;
  • Patch: atualiza parcialmente a entidade;
  • Post: cria uma nova entidade;
  • Head: recupera somente os headers;
  • Options: requisita informações sobre as opções disponíveis de comunicação.

HttpGet

Geralmente o método mais usado, o HttpGet serve para obter dados de uma ou mais entidades. Ou seja, para cada entidade em um modelo, geralmente haverá um Get para obter todos os itens e outro Get para obter os detalhes de um item específico:

"/api/Foos" // obtém lista de todos os Foos
"/api/Foos/keyvalue" // obtém um Foo com a key especificada
"/api/Foos?attributename=attributevalue" // obtém um ou mais Foos com os atributos especificados

Caso nenhum valor seja encontrado, é importante lançar uma HttpResponseException com HttpStatusCode.NotFound (404) ao invés de simplesmente lançar uma Exception.

HttpDelete

Talvez o mais simples de todos, o HttpDelete simplesmente deleta uma entidade com o valor especificado, geralmente a chave. É aconselhável usar o prefixo Delete no nome do método do controller Web API.

Idealmente, há 3 possíveis retornos para um request Delete:

  • HttpStatusCode.OK (200), que indica sucesso;
  • HttpStatusCode.Accepted (202), que indica que o request foi processado e aceito mas está ainda pendente;
  • HttpStatusCode.NoResponse (204), valor padrão para métodos com retorno void

HttpPost

Para criar uma nova entidade, o método HttpPost deve ser usado. Assim como em Delete, o prefixo Post deve ser utilizado.

Em caso de sucesso, o retorno estipulado pelo protocolo HTTP 1.1 é HttpStatusCode.Created (201), mas o status code padrão é 200 (OK). É também aconselhável retornar a localização (URL) de detalhes da nova entidade criada. Seguindo esses padrões, a implementação de um HttpPost para criar uma Account seria assim:

[HttpPost]
public HttpResponseMessage PostAccount(Account account)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, account);
string newUri = Url.Link("NamedApi", new { accountId = account.AccountId });
response.Headers.Location = new Uri(newUri);
return response;
}

HttpPut

HttpPut deve ser utilizado para operações upserts, que inserem novos registros ou atualizam registros existentes. Também devem utilizar o prefixo Put.

Para atualizar uma Account, por exemplo, você deve receber um Id para procurar e uma Account para atualizar os valores. A implementação seria assim:

[HttpPut]
public HttpResponseMessage PutAccount(int id, Account account)
{
// perform insert and/or edit here.
}

Definindo Recursos HTTP Com Actions

Um serviço Web API nada mais é do que uma aplicação que usa controllers e actions para mapear URLs com ações HTTP. Esta seção foca no básico de como construir uma aplicação Web API.

Criando O Model

Voltando um pouco ao capítulo anterior, em WCF era necessário decorar suas classes com os atributos DataContract e DataMember para trafegá-las pelos serviços.

Com Web API, isso não é mais necessário. O próprio framework toma conta de enviar sua classe via HTTP, serializada em JSON ou XML. Isso evita o acoplamento entre seu modelo e o serviço que o expõe, além de facilitar os possíveis clients desse serviço pelo fato de JSON e XML serem praticamente universais.

Para os exemplos a seguir, vamos considerar o seguinte model:

Criando O Controller

Os controllers são as classes que definem os serviços da sua Web API. Eles herdam de ApiController e cada método público vira uma action, como se fosse um método no WCF.

Veja a implementação dos controllers abaixo. Seguindo o padrão REST, é criado um serviço para cada tipo no modelo:

Com isso, você já tem sua Web API funcionando. Basta acessar http://localhost:{porta}/api/Account e a lista de Accounts é retornada. Chamando /api/Account?accountId=1, a Account com o Id 1 é retornada.

Um ponto importante é que, chamando essas URLs diretamente no browser, o comportamento é definido pelo próprio browser. O Chrome e o Firefox, por exemplo, mostrariam um XML na tela, enquanto o Internet Explorer faria o download de um JSON. Isso varia do request header Accept que o browser envia para a Web API.

Definindo Rotas

Toda a mágica da Web API de tornar métodos públicos em um controller acessíveis por clients acontece por causa da Routing Table.

Routing Table é um classe que implementa System.Web.Http.Routing.IHttpRoute e tem a tarefa de mepear um request para um controller e uma action específicos. No caso de Web API, a classe se chama WebApiConfig e fica dentro de App_Start:

Se você mudar o routeTemplate para "data/{controller}/{id}", por exemplo, você agora acessa sua api com http://localhost:{porta}/data/Account.

Quando uma requisição é feita para uma Web API, o framework tenta achar o controller e a action segundo o que está definido na Routing Table. Se não encontra, uma HttpStatusCode 404 é retornado. Caso contrário, o request é encaminhado para o método. As seguintes ações são tomadas pelo framework para encontrar o controller e a action:

  • Para achar o controller, a Web API adiciona a palavra Controller na variável do controller (por isso você chama diretamente Account, por exemplo);
  • Para a action, a Web API examina o método HTTP do request e tenta achar uma action com o nome correspondente;
  • Por padrão, isso só funciona com os métodos GET, POST, PUT e DELETE. Outro métodos são suportados, mas outro mecanismo é utilizado;
  • Por último, as variáveis no routeTemplate são mapeadas para os parâmetros da action (por padrão, id).

Você pode setar explicitamente um método HTTP em uma action. Isso é importante quando você quer que o nome do método seja diferente do método HTTP. Para fazer isso, basta decorar o método com o atributo System.Web.Http.ActionMethodSelectorAttribute. Ele possui 4 valores: HttpGet, HttpPost, HttpDelete e HttpPut. O método ficaria assim:

[HttpGet]
public Account GetAccount(int accountId)

Para definir múltiplos métodos HTTP para uma action ou suportar um método HTTP fora os 4 citados, você usa o atributo System.Web.Http.AcceptVerbsAttribute. O construtor aceita um array de strings que correspondem aos métodos que devem ser mapeados. O uso ficaria assim:

[System.Web.Http.AcceptVerbs("GET", "HEAD")]
public IEnumerable GetCustomers(int accountId)

Alterando Actions

Se você quiser criar as rotas com o nome da ation explícito, basta mudar a Routing Table para isso. O código ficaria assim:

Com isso, ao invés de acessar /api/Customer/1, você acessa /api/Customer/GetCustomers/1.

Você pode alterar o nome da action pelo atributo ActionNameAttribute:

[HttpGet]
[ActionName("FindCustomers")]
public IEnumerable SearchCustomers(string lastName)

Assim, você acessa essa action com a URL /api/Customer/FindCustomers?lastName=r.

O último ponto é que você pode querer que um método público no controller não seja uma action acessível pelo serviço. Para isso, decore o método com o atributo NonAction.

Escolhendo Formatos

O request header Accept indica o formato que o client espera como retorno. Acessando sua Web API pelo browser, geralmente o seguinte header é enviado:

Accept: text/html,application/xhtml+xml,application/xml

Por padrão, a Web API trabalha com JSON e XML. Isso é configurado por um objeto chamado media-type formatter.

Para essa seção, basta você saber isso e que você pode adicionar formatters customizados implementando a classe MediaTypeFormatter ou BufferedMediaTypeFormatter.

Actions Assíncronas

Ao fazer um request para um serviço Web API, uma thread é alocada do servidor para fazer o processamento necessário.
Em cenários de grandes processamentos de I/O (entrada/saída), como acesso a banco de dados e chamadas a outros serviços, é importante liberar a thread atual para que ela processe mais requests enquanto essa entrada/saída longa é executada.

O C# 5 nos deu mecanismos para fazer isso de forma muito simples: as palavras-chave async e await. Tome por exemplo a seguinte action de uma Web API:

public string Get()
{
WebClient webClient = new WebClient();
string result = webClient.DownloadString("http://microsoft.com");
return result;
}

Na maior parte do tempo, a thread alocada fica esperando o processamento I/O de fazer o request para o site da microsoft e buscar o HTML. Olhe essa action com async/await:

public async Task<string> Get()
{
WebClient webClient = new WebClient();
string result = await webClient.DownloadStringTaskAsync("http://microsoft.com");
return result;
}

Na chamada a await webClient.DownloadStringTaskAsync, a thread alocada é liberada para processar outros requests enquanto a requisição ao site da Microsoft é feita.

Um último alerta é que chamadas assíncronas devem ser feitas apenas para processamentos I/O. Se o método assíncrono fizer um processamento de CPU, outra thread terá que ser alocada para fazer esse processamento, o que invalida quaisquer benefícios da programação assíncrona (podendo até piorar devido à troca de threads).


Chegamos ao fim desse objetivo 🙂

Obrigado pela leitura e espere pelo próximo post sobre o objetivo 4.2, Implement a Web API.

Até mais!

Leia Mais

Certificação Microsoft 70-487: Objetivo 3.9 – Host and manage services

Olá!
Esse post será sobre o último objetivo do capítulo de WCF, Host and manage services.
Esse objetivo cobre como gerenciar simultaneidade, escolher um Instance Mode, criar hosts, escolher um mecanismo de hosting, criar serviços transacionais e hostear em um Azure Worker Role.

Gerenciando Simultaneidade

É bem provável que seu serviço seja consumido por mais de um consumidor ao mesmo tempo. Com isso, é necessário tentar prever e gerenciar a simultaneidade que seu serviço suportará.

Dentro de ServiceBehavior, você pode definir o ConcurrencyMode: [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single)]

O enum ConcurrencyMode possui 3 valores:

  • Single: em qualquer momento, somente 1 request tem acesso ao serviço WCF por vez. Caso vários requests sejam feitos simultaneamente, todos vão esperar até que o anterior complete seu processamento;
  • Multiple: como o nome sugere, múltiplos requests podem ser feitos simultaneamente em threads separadas;
  • Reentrant: funciona como o Single, mas se você fizer uma chamada a outro serviço, o lock é liberado para que o próximo request seja processado.

Escolhendo um Instance Mode

Tratando ainda sobre simultaneidade, a configuração InstanceContextMode especifica o número de instâncias do serviço para processar os requests. Também tem 3 valores e, junto com ConcurrencyMode, dão 9 possíveis combinações.

Assim como ConcurrencyMode, você pode setar essa propriedade no atributo ServiceBehavior. Os 3 valores são:

  • Single: uma única instância do serviço é usada para todos os requests;
  • PerSession: cria uma ou mais instâncias para cada client. É a configuração padrão;
  • PerCall: cria uma ou mais instâncias para cada request.

Esse é um assunto bem complexo e o comportamento de cada combinação aparentemente está fora do escopo do exame. Se quiser ir a fundo no tema, há um bom artigo no codeproject.

Criando Hosts

Há várias opções de host para um serviço WCF. Vamos passar pelas opções disponíveis (ou prováveis de estar no exame) resumindo os pontos positivos e negativos.

Self Hosting

Serviços WCF podem ser hospedados em qualquer aplicação .NET. Você especifica a configuração do serviço em um arquivo de configuração ou no código em conjunto com instâncias da classe ServiceHost.

Há vários benefícios dessa forma. Como você pode facilmente trocar de hosts, se sua aplicação não estiver performando bem, você pode fazer upgrade para outro host ou habilitar outros bindings. Fazer debug da aplicação também fica facilitado.

A principal desvantagem é que você deve gerenciar todo o host, consertando quaisquer bugs que apareçam. Mover o host para outra máquina ou fazer um upgrade de hardware, se for necessário, também é doloroso. Por isso são geralmente usados para ambiente de desenvolvimento, e não produção.

Managed Windows Services

Não muito diferentes de outras aplicações .NET, Managed Services são parecidos com Self Hosting, mas com mais poder. Se a máquina reiniciar, por exemplo, o serviço pode startar automaticamente, sem a necessidade de um usuário logado. Também não é necessário usar IIS ou WAS para rodar na máquina.

Como desvantagens, você ainda precisa escrever código para criar o host com a classe ServiceHost e existe limitação para scale up e scale down. Services também tendem a ser mais difíceis para debug.

Internet Information Services (IIS)

O IIS, conhecido por hospedar aplicações ASP.NET, também pode ser usado para hospedar um serviço WCF.

As vantagens são todas as features que o IIS tem, como isolamento de pools de aplicações, recycling, desligamento por ociosidade, monitoramento, etc. Se o serviço precisar de alta disponibilidade e ser escalável, IIS é a escolha ideal.

A desvantagem que pode deixá-lo inutilizável para alguns serviços é que ele só suporta bindings que fazem o transporte por HTTP.

Windows Activation Service (WAS)

WAS, apesar de presente na maioria das grandes organizações, não é tão conhecido como o IIS.

Ele provê todos os benefícios do IIS e suporta outros tipos de transporte, como TCP, named pipes e MSMQ.

A desvantagem é que, por ser uma tecnologia nova, há pouco suporte e material sobre ela.

Windows Azure

Hospedar seu serviço na nuvem possui várias vantagens. A principal é que toda a dor de cabeça de manter um servidor com um serviço rodando fica com a Microsoft, e não com você.

Por enquanto, é suficiente saber que há 3 principais opções no Azure: WebRole, AppFabric service bus e WorkerRole.

A desvantagem pode ser que sua aplicação está hospedada por outras pessoas, o que tira o seu controle de ter um servidor on premise. Usando Azure, você ainda terá que fazer a escolhe entre self-host, IIS ou WAS.

Classe ServiceHost

Criar uma instância de ServiceHost é simples. Você chama o construtor passando o tipo do serviço, que deve estar referenciado. Há vários overloads do construtor, mas não são prováveis de estarem no exame. Após isso, você chama o método Open e por fim Close, ambos num try/catch pois várias coisas podem dar errado nesse tempo.

using (ServiceHost HostInstance = new ServiceHost(typeof(TestServiceType)))
{
HostInstance.Open();
//Put in a Wait Condition so Host stays open
HostInstance.Close();
}

Após o canal ser aberto por um client, o comportamento depende das definições do serviço (ConcurrencyMode, InstancingMode, tipos de endpoint, etc.). Um ponto importante para o client é que, caso haja algum erro não tratado, todo o canal é considerado falho e inválido para novas operações. Sempre deve haver a validação se a conexão está válida.

É importante também entender as opções de host. Como serviços WCF podem ser hospedados em qualquer AppDomain, seja uma aplicação Windows Form ou Console, se o AppDomain não estiver ativo, o host também não estará.

Ao usar um mecanismo de hosting como IIS ou WAS, não é necessário criar um ServiceHost. Basta configurar o serviço e gerenciar pela ferramenta.

Há outro ponto que possivelmente esteja no exame. Antes do .NET 4.0, se você quisesse usar o IIS para hospedar seu serviço, você tinha que criar uma aplicação ASP.NET com uma referência ao seu serviço, colocar as configurações no Web.config e criar um arquivo de texto com a extenção .svc (com uma única linha) para mapear o serviço.

Com a versão 4.0, isso não é mais necessário. Você pode usar a classe ServiceHostingEnvironment, que permite que você referencie o arquivo .svc virtualmente, sem a necessidade de criá-lo fisicamente. A configuração via arquivo fica assim:

<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="ServiceOrInterfaceName.svc" service="FullyQualifiedServiceName"/>
</serviceActivations>
</serviceHostingEnvironment>

Escolhendo Um Mecanismo De Hosting

Resumindo o que vimos até agora, você tem várias opções para hospedar um serviço WCF:

  • Windows Form application
  • Console application
  • Managed Windows Service
  • ASP.NET application
  • IIS
  • WAS
  • Windows Azure

Não existe regra para fazer essa escolha ou uma opção que atenda todos os cenários. Se seu serviço demandar que o transporte não seja feito por HTTP, por exemplo, o IIS não é uma opção. Ou se você precisar usar um binding MSMQ, você vai precisar de um host que dê suporte a isso.

Falando no geral, procure uma solução que te dê menos trabalho. IIS e WAS são produtos confiáveis, com uma base de usuários grande e fáceis de usar em conjunto com WCF. Escrever um novo host fatalmente irá gerar bugs ao longo do caminho.

Criando Serviços Transacionais

No objetivo 1.3, falamos sobre a classe TransactionScope. Ela também funciona de maneira bem simples com serviços WCF.

Você precisa decorar a operação com o atributo TransactionFlow (em conjunto com o atributo OperationContract), que especifica se a operação suporta transações. O construtor aceita 3 valores:

  • [TransactionFlow(TransactionFlowOption.NotAllowed)]: a operação não pode participar de uma transaction;
  • [TransactionFlow(TransactionFlowOption.Allowed)]: a operação pode participar de uma transaction, se o client iniciar uma;
  • [TransactionFlow(TransactionFlowOption.Mandatory)]: obrigatoriamente a chamada deve fazer parte de uma transaction.

Além disso, você deve setar as propriedades TransactionAutoComplete e TransactionScopeRequired do OperationBehavior como true:

[OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)]
public String GetTestSummary(String examId){}

TransactionAutoComplete diz ao runtime para automaticamente completar a transação se nenhuma exceção for lançada. Caso seja, será feito o rollback. O atributo TransactionScopeRequired diz que o método precisa fazer parte de uma TransactionScope.

Hospedando Serviços Em Um Azure WorkerRole

Hospedar seu serviço no Azure em um WorkerRole significa ter mais controle sobre o servidor e as configurações do seu serviço, permitindo que você não use o IIS como hosting, por exemplo.

Com isso, é de sua responsabilidade configurar endpoints, inicializar e abrir um ServiceHost. Isso pode ser feito no método OnStart.

As configurações de endpoint podem estar no arquivo de configuração da role (.csdef). O código fica assim:

É interessante deixar a variável de host fora do método para que o garbage collector não a remova do escopo quando o método terminar.

O último detalhe desse objetivo, não relacionado a nenhum item, é que você deve saber que existe um DiscoveryEndpoint que faz com que seu serviço seja descoberto por clients.


E acabamos o capítulo 3 sobre serviços WCF 😀 Por ser o maior objetivo da certificação, o assunto ficou bem extenso e chato, às vezes.

Mas agora vem o capítulo 4 com os objetivos sobre Web API, que é o mais comum nas aplicações hoje em dia (e bem mais elegante).

O próximo objetivo será o 4.1, Design a Web API.

Até mais!

Leia Mais

Certificação Microsoft 70-487: Objetivo 3.8 – Implement messaging patterns

Olá pessoal!
O objetivo 3.8, Implement messaging patterns, trata de Message Exchange Patterns (ou Padrões de Troca de Mensagem), que são mecanismos que descrevem como o client e o server vão se comunicar.
Vamos cobrir como implementar os tipos one-way, request/reply, streaming e duplex, além de falar sobre alguns mecanismos no Azure. Vamos lá?

Implementando One-Way, Request/Reply, Streaming e Duplex

One-Way

Implementações one-way servem para cenários fire and forget, onde você faz uma chamada e não se importa com a resposta, como escrever alguma coisa em um log.

O WCF suporta implementações one-way de forma simples. Basta setar o parâmetro IsOneWay como true no atributo OperationContract e não ter nenhum tipo de retorno no método:

[OperationContract(IsOneWay = true)]
void LogMessage(String message);

Num cenário comum, um request é feito para o servidor que processa e envia um response. Com OneWay, acontece o seguinte: quando o request é feito, o servidor responde instantaneamente com o StatusCode 202, Accepted. Só depois disso ele vai de fato processar o request, como se fosse uma operação assíncrona.

Apesar de ser uma boa feature, OneWay deve ser usado com cuidado. Operações críticas podem dar errado sem que você saiba, causando problemas. Bons candidatos a OneWay são operações de baixa prioridade e que não retornam valor.

Streaming

Ao implementar streaming com WCF, você tem dois modos para trabalhar: Buffered ou Streaming.

Buffered, o modo default, significa que a mensagem inteira precisa ser enviada para que o recebedor comece a leitura. Em Streaming, o recebedor consegue começar a leitura assim que a informação estiver disponível (cenário ideal para transferência de arquivos grandes, como áudio ou vídeo).

Nesse formato, uma propriedade importante é a maxReceivedMessageSize, que limita o tamanho de mensagens recebidas. Isso é crucial para evitar ataques DDoS.
No nível do contrato, você começa o processo definindo o retorno de um método como Stream. Depois é necessário configurar o binding para que o TransferMode seja Streamed e aí configurar o atributo maxReceivedMessageSize. O arquivo de configuração ficaria assim:

Há 4 valores para o enum TransferMode, com nomes bem sugestivos: Buffered, Streamed, StreamedRequest e StreamedResponse.

Um ponto para se ter em mente é que habilitar streaming para um serviço não vai automaticamente melhorar a performance. É verdade que com streaming não são necessários grandes buffers de memória, mas num contexto comum de transferência de informações a melhora de performance é imperceptível.

Outro aspecto é que nem todos os bindings suportam a propriedade TransferMode. Os únicos bindings padrão que aceitam são BasicHttpBinding, NetTcpBinding e NetNamedPipeBinding.

Por último, há algumas limitações ao se usar streaming. São elas:

  • Operações que usam o transporte Streamed só podem ter um input e um output de parâmetro;
  • Headers SOAP são sempre buffered, mesmo habilitando streaming. Eles não podem ultrapassar o tamanho da propriedade MaxBufferSize;
  • As implementações de segurança Reliable Message e SOAP Message confiam na transmissão buffered. Geralmente você deve usar segurança no nível de transporte (objetivo 3.4).

Request/Reply

É o modo padrão de funcionamento de qualquer web service, onde o client envia um request, o server processa e envia um response. Não há muito a mais o que ser dito 😀 Vamos para o próximo item.

Duplex

Na comunicação duplex, o client se conecta com um serviço provendo um canal de comunicação, onde o server pode mandar mensagens de volta para o client. Para funcionar, tudo isso precisa existir no contexto de uma sessão.

Nesse cenário com WCF, além de definir um contrato de ServiceContract, outra interface é necessária para especificar a propriedade CallbackContract, que serve como callback. Para o exame, não é necessário saber mais que isso existe.

Implementando Azure Service Bus E Azure Queues

Como visto no objetivo anterior, o Azure Service Bus é um componente que conecta serviços WCF (e outras aplicações) pelo Azure.

Usando relay, a comunicação é feita diretamente entre as duas partes. Isso implica que ambas precisam estar online para a comunicação acontecer.
Às vezes, você precisa de uma fila de comunicações ou usar um mecanismo de publish/subscribe. O Azure também oferece essas tipos de comunicações.

Uma Queue (fila) permite que mensagens enviadas por um client sejam armazenadas até que outro client as leia. Um Topic extende o comportamento da queue adicionando subscriptions, onde cada client especifica critérios para filtrar as mensagens que vê. Como Topics não estarão no exame, vamos focar na Queue.

Quando usando uma Queue, você manda uma mensagem para o service bus com um conjunto de propriedades chave/valor e um body binário. A mensagem é armazenada pelo service bus e entregada a um recebedor em um determinado momento, desacoplando as duas (ou mais) aplicações. O recebedor pode remover o item da fila na leitura ou colocar um lock, processar a mensagem e depois removê-la (como o Storage Queue faz).

Questões sobre a implementação não são prováveis de estar no exame, então o conhecimento do mecanismo já é suficiente. Você pode obter mais detalhes aqui.

O conceito importante é o uso da classe QueueClient que permite o envio e recebimento de mensagens da queue. A mensagem é representada pela classe BrokeredMessage.

E chegamos ao final desse objetivo.
O próximo post, sobre o objetivo Host and manage services, será o último do capítulo sobre WCF.

Até mais!

Leia Mais

Certificação Microsoft 70-487: Objetivo 3.7 – Create and configure a WCF service on Windows Azure

O objetivo Create and configure a WCF service on Windows Azure (finalmente sobre Azure) fala principalmente sobre o Azure Service Bus, serviço que permite que você exponha seu serviço WCF (ou qualquer outro) hospedado no seu próprio datacenter. Isso evita os problemas de instalação e configuração de deixar tudo on premises e te dá as vantagens que o Azure pode oferecer. Vamos lá?

Criando E Configurando Bindings

Apenas revisando, um serviço WCF basicamente precisa do ABC (address, binding e contract). Para fazer o deploy de um serviço WCF no Azure em uma Web Role ou Web Site você não precisa fazer nenhuma modificação no código ou nas configurações.

Usando a feature de relay do Azure Service Bus, você pode configurar alguns bindings adicionais no seu projeto adicionando o pacote NuGet Windows Azure Service Bus.

Considere o código a seguir, assumindo que ISecretService e SecretService formam o contrato e a implementação de um serviço:

Nesse exemplo, o serviço está exposto em dois endpoints, um interno (com NetTcpBinding) e um externo, usando a feature de relay do Azure Service Bus (com NetTcpRelayBinding). Ao fechar a aplicação (sh.Close()), o endpoint é removido do Azure.

Você pode configurar também o endpoint no Azure pelo arquivo de configuração:

Nos dois exemplos o binding NetTcpRelayBinding é usado, mas há outros disponíveis.
Tanto por código ou arquivo de configuração, você deve setar o nome do serviço e a Default Key.
Outro ponto interessante é que o Azure Service Bus não requer nenhuma configuração no seu servidor on premise. Normalmente a comunicação é feita por TCP, mas se as portas não estiverem disponíveis, o relay pode usar as portas HTTP ou HTTPS.

Criando Um Azure Service Bus

Para criar um Azure Service Bus, basta ir no portal do Azure, selecionar a criação de um Azure Service Bus, configurar um namespace e selecionar uma região.

O portal vai informar a connection string de conexão, que contém o nome do serviço e a Default Key:

Endpoint=sb://wcfonazure.servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=D1Kmb83CCLrAtz4du9vb3xn99DaM2dH4jQqSec98if4=

Integrando Com O Azure Service Bus Relay

Após criar um novo service bus no Azure e hospedar um serviço WCF, você pode criar um client para se comunicar com seu serviço on premise pelo Azure.

É necessário ter o namespace especificado, o nome do serviço e a Default Key. O código a seguir mostra como o consumo pode ser feito via ChannelFactory:

O método CreateSharedSecretTokenProvider se autentica no service bus pelo owner e a key, mas há outros mecanismos de autenticação como SAML ou SimpleWebToken.

Isso é tudo 🙂
O próximo post será sobre o objetivo 3.8, Implement messaging patterns.

Até lá!

Leia Mais

Certificação Microsoft 70-487: Objetivo 3.6 – Version a WCF service

Olá pessoal!
Continuando a série sobre a certificação Microsoft 70-487, esse post será sobre o objetivo 3.6, Version a WCF service.
Esse objetivo, que é bem curto, cobre os conceitos sobre como versionar diferentes tipos de contratos e informações de bindings.

Várias mudanças podem ocorrer no ciclo de vida de um serviço WCF: no contrato, no endereço (address), nos bindings, na implementação de algum método, etc. Essas mudançar podem ser classificadas em breaking changes ou Nonbreaking changes.

Há 2 tipos de versionamento: strict e lax.

O versionamento strict é quando você tem um ou mais clients que não toleram mudanças no serviço. Nesse caso, todas as mudanças precisam levar isso em conta e você nunca deve modificar algum comportamento; apenas adicionar em outras versões ou namespaces.

No versionamento lax, suportado pelo WCF e até web services .asmx, você pode fazer pequenas alterações sem quebrar o contrato existente. É possível, por exemplo, adicionar um novo membro fazendo com que os dados sejam somente ignorados por clients antigos.

Esse objetivo é bem conceitual e saber quando uma mudança vai quebrar ou não um serviço é suficiente para o exame. Mudanças no contrato são breaking changes; adições no DataContract podem ser ignoradas por clients antigos e não vão quebrar a funcionalidade.

E é isso 🙂
O próximo objetivo, também curto, será o Create and configure a WCF service on Windows Azure.

Até lá!

Leia Mais

Certificação Microsoft 70-487: Objetivo 3.5 – Consume WCF services

Olá!
Hoje vamos falar sobre o objetivo 3.5 da certificação 70-487, Consume WCF services.
Esse objetivo cobre como consumir um serviço WCF de 3 formas: gerando classes proxy com Svcutil.exe, gerando classes proxy adicionando uma referência ao serviço e consumindo via ChannelFactory. Vamos lá?

Gerando Proxies Com Svcutil.exe

É possível consumir serviços WCF gerando uma classe proxy e interagindo com ela como se fosse uma classe comum, deixando o framework fazer toda a comunicação por trás.

O Svcutil.exe, uma ferramenta chamada pela linha de comando, é uma das formas de gerar classes proxy de um serviço WCF. É possível fazer a geração baseado em serviços existentes ou metadata.

A ferramenta também permite que você exporte metadata de um serviço, valide código de um serviço, faça download dos metadatas de serviços existentes e gere código de serialização.

A melhor maneira de estudar para o exame é criar alguns serviços e gerar as proxies chamando o Svcutil.exe com opções diferentes, analisando o que a ferramenta de fato faz. A lista abaixo traz as opções importantes para o exame ao chamar a ferramenta pela linha de comando (atalhos estão entre parênteses):

  • /directory:<directory> (/d): especifica o diretório em que os arquivos gerados serão colocados. Se não for especificado, o diretório atual será usado. Caso o diretório já tenha sido usado, o Svcutil.exe irá sobrescrever os arquivos;
  • /mergeConfig: caso o diretório já tenha sido usado, ao invés de sobrescrever os arquivos, com essa opção o Svcutil.exe irá fazer o merge das configurações;
  • /help (/?): lista as opções disponíveis;
  • /noLogo: tira as informações Logo (copyright e mensagem de banner);
  • /svcutilConfig:<configFile>: coloca as configurações no arquivo especificado. O default é o App.config;
  • /target:<output type> (/t): instrui a ferramenta a criar um output específico. As opções são code, metadata e xmlSerializer;
  • /async (/a): cria todos os métodos das classes proxy com a versão normal e uma Async;
  • /internal (/i): cria todos os métodos das classes proxy como internal, e não public;
  • /serializer (/ser): gera os tipos com um serializer específico. As opções são Auto, DataContractSerializer e XmlSerializer;
  • /out (/o): especifica o nome do arquivo para o código gerado;
  • /language (/l): especifica uma linguagem para o código gerado. As opções são c#, cs, csharp, vb, visualbasic, c++ e cpp.

Gerando Proxies Por Referência

Uma feature do Visual Studio é a possibilidade de gerar classes proxy adicionando uma referência a um serviço.
Basta clicar com o botão direito no seu projeto e ir em Add Service Reference. A seguinte tela é mostrada:

add service

Você pode prover uma URL de um serviço (com metadata habilitado) ou clicar no botão Discover para encontrar services que estão na mesma solution. Após clicar em Go, os serviços são listados e você pode especificar um namespace, o que é recomendado.

Ao clicar em Advanced abaixo, a tela Service Reference Settings é aberta:

service reference settings

No topo você pode especificar o modificador de acesso e se métodos async devem ser gerados, como as opções /internal e /async usando Svcutil.exe.
A opção Always Generate Message Contracts faz o que o nome diz, gera classes para os contratos.

Na seção Data Type, você pode definir o tipo das coleções. Nada te impede de usar generics (List<T>), mas geralmente arrays são utilizados para manter a compatibilidade entre diferentes clients que não sejam .NET.

A última seção, Compatibility, serve se você estiver consumindo um web service antigo .asmx. A tela Add Web Reference é aberta:

add web reference

Criando E Implementando ChannelFactories

A classe ChannelFactory serve para fazer comunicações com endpoints de forma simples. Ela pode atuar em conjunto com o arquivo de configuração da sua aplicação, fazendo com que uma chamada a um serviço tenha 2 linhas de código.

A primeira coisa que você deve saber é que a classe ChannelFactory trabalha com o contrato do serviço, então você deve ter uma referência à interface que especifica o contrato.

Construtores

O construtor padrão não aceita nenhum parâmetro, então informações sobre o endpoint precisam ser especificadas: new ChannelFactory().

O próximo aceita uma string com o nome de configuração do endpoint:

String endpointConfigName = "wsHttp_BindingConfig";
ChannelFactory<ITestService> proxy = new ChannelFactory<ITestService>(endpointConfigName);

Outro aceita um binding, mas funciona da mesma forma:

String endpointConfigName = "wsHttp_BindingConfig";
WSHttpBinding wSBinding = new WSHttpBinding(EndpointConfigName);
ChannelFactory<ITestService> proxy = new ChannelFactory<ITestService>(wSBinding);

O próximo aceita um ServiceEndpoint:

ServiceEndpoint endpoint = new ServiceEndpoint(new ContractDescription("Endpoint"));
ChannelFactory<ITestService> proxy = new ChannelFactory<ITestService>(endpoint);

Há outros construtores que são bem intuitivos. Vamos a um cenário real de uso da classe ChannelFactory, algo bem provável de conter pelo menos 1 questão no exame:

O método CreateChannel inicializa a ChannelFactory, retornando o tipo do contrato especificado no construtor. Depois disso, basta chamar os métodos desejados que estão no contrato. Por fim, chame o método Close. Ele possui uma chamada padrão sem parâmetros e uma recebendo um TimeSpan, onde você indica que se o canal não for fechado nesse tempo uma exceção é lançada.

Por último, é importante destacar que com ChannelFactory você não precisa da classe de definição do serviço, apenas a interface do contrato.

Isso é tudo para esse objetivo 🙂
Obrigado pela leitura e fique de olho no post do próximo objetivo, Version a WCF service.

Até mais!

Leia Mais

Certificação Microsoft 70-487: Objetivo 3.4 – Secure a WCF service

O objetivo 3.4 do exame, Secure a WCF service, cobre as features de segurança que o WCF disponibiliza. Isso inclui 1) como implementar segurança no nível de mensagem, 2) como implementar segurança no nível de transporte e 3) como implementar certificates, que é a combinação dos itens anteriores. Vamos lá?

Implementando Segurança no Nível de Mensagem

Basicamente, implementar segurança no nível da mensagem é “incrementar” as mensagens SOAP com 3 características CIA:

  • Confidencialidade: significa que somente as pessoas que devem ver uma mensagem são as pessoas que de fato vejam a mensagem;
  • Integridade: significa que a mensagem não pode ser alterada;
  • Autenticação: garante a identidade de quem está vendo a mensagem.

Isso significa que a mensagem não é visualizada sem a chave correspondente, mas o texto criptografado pode ser visto na rede.

Na maioria dos bindings, isso é feito por padrão e roda transparentemente, sem intervenção do desenvolvedor. Você pode também especificar via código ou arquivo de configuração.

Por código, basta setar a propriedade Security.Mode do binding desejado, seja por construtor ou setando a propriedade manualmente:

// Set Security Mode to Message in Constructor
WSHttpBinding WsHttpSecurity = new WSHttpBinding(SecurityMode.Message);

// Set the Security property manually
WSHttpBinding wsHttpSecurity2 = new WSHttpBinding();
wsHttpSecurity2.Security.Mode = SecurityMode.Message;

A propriedade Mode para o wsHttpBinding é do tipo SecurityMode. Para o basicHttpBinding o tipo é BasicHttpSecurityMode e para o netNamedPipeBinding é NetNamedPipeSecurityMode.

É possível fazer essa configuração no arquivo de configuração pelo WCF Service Configuration Editor. Para cada binding configurado, há duas abas no editor: Binding e Security. Basta ir na aba Security e setar o Mode para Message:

security mode

Se você for para o arquivo de configuração, verá que nada foi adicionado pois o wsHttpBinding faz essa segurança por padrão. Contudo, é possível declarar também explicitamente dessa forma:

<wsHttpBinding>
<binding name="wsHttpBindingConfigSample" >
<security mode="Message"/>
</binding>
</wsHttpBinding>

Implementando Segurança no Nível de Transporte

Transporte seguro significa que todo o transporte é criptografado, tornando difícil para um interceptor compreender a mensagem. Com isso, o texto da mensagem não precisa ser criptografado; pode ser trafegado em plain text.

Implementar segurança no nível de transporte é virtualmente idêntico ao item anterior. A diferença é que, ao invés de setar o Mode como Message, você deve escolher Transport ou TransportWithMessageCredential

Seja via código ou arquivo de configuração, o funcionamento é exatamente o mesmo.

Implementando Certificates

Para usar certificados, você precisa adicionar uma referência a System.Security.dll. Com o certificado instalado, a configuração no WCF é bem simples.

Assumindo que você tenha um netHttpBinding configurado para o serviço, basta sincronizar os elementos <security> e <message> para que o Mode da propriedade Security seja TransportWithMessageCredential e a propriedade ClientCredentialType da mensagem seja o certificado.

Após essa configuração, basta garantir que certificado está instalado no client, obter uma referência a ele e adicioná-lo na propriedade Credentials.ClientCredentials.Certificate:

var MyFactory = new ChannelFactory("*");
MyFactory.Credentials.ClientCredentials.Certificate = X509.CurrentUser.My.SubjectDistinguishedName.Find("CN=CLIENT").FirstOrDefault();

Isso é tudo para esse objetivo 🙂 O próximo post será sobre o objetivo 3.5, Consume WCF services.

Até lá!

Leia Mais