Saturday, September 06, 2008
#
O WCF fornece, não por padrão, a possibilidade de invocar as operações de um serviço de forma assíncrona. Quando efetuamos a referencia para um serviço via IDE do Visual Studio 2008 ou através do utilitário svcutil.exe (com a opção /async) automaticamente, além da versão síncrona do método, dois métodos chamados BeginXXX/EndXXX (onde XXX é o nome do método síncrono) são adicionados, permitindo que voce invoque assincronamente uma determinada operação.
Além do tradicional modelo de chamadas assíncronas (APM), temos a possibilidade da chamada assíncrona baseada em eventos. A idéia aqui é, antes de invocar a operação, voce poderá assinar à um evento que será disparado somente quando o processo assíncrono finalizar. Isso evitará de ter um trabalho manual para analisar se o processo finalizou ou não (poll, waiting, etc.). Internamente durante a geração do proxy, o código que é auto-gerado já inclui a implementação necessária para o modelo baseado em eventos.
Basicamente é criado mais uma versão do método, agora com o sufixo XXXAsync que, internamente, faz a chamada para os métodos BeginXXX/EndXXX que, como já sabemos, dispararam a operação de forma assíncrona. Além disso, um delegate do tipo EventHandler<T> também será criado para representar o callback que, quando disparado, invocará o evento do lado de quem está consumindo o serviço. Abaixo um exemplo de como efetuar a chamada assíncrona baseada em eventos:
using (ClienteClient p = new ClienteClient())
{
p.CalcularComissaoCompleted +=
new EventHandler<CalcularComissaoCompletedEventArgs>(p_CalcularComissaoCompleted);
p.CalcularComissaoAsync("2");
Console.ReadLine();
}
static void p_CalcularComissaoCompleted(object sender,
CalcularComissaoCompletedEventArgs e)
{
Console.WriteLine("Fim.");
}
Se notarmos a implementação interna do proxy, veremos que o método XXXAsync faz o uso do método InvokeAsync, da classe ClientBase<T>. Este método está disponível somente a partir do .NET Framework 3.5. Sendo assim, alguns detalhes durante a geração do proxy precisam ser analisados:
-
Via "Add Service Reference": se voce estiver fazendo a referencia em um projeto que esteja utilizando o .NET Framework 3.5 e voce opta pela geração dos métodos que dão suporte ao processamento assíncrono, ele também criará os tipos necessários para suportar o modelo de eventos.
-
Via svcutil.exe: neste caso voce precisará especificar através do parametro /async e, além disso, especificar a versão do .NET Framework através do parametro /targetClientVersion, apontando para Version30 ou, se quiser utilizar o modelo baseado em eventos, utilizar a opção Version35.
Friday, September 05, 2008
#
Em alguns momentos durante a escrita de um projeto para servir de exemplo para um artigo, eu gostaria de colocar uma diretiva no código para forçar o leitor a antes de executar o mesmo, configurar algo que seja necessário para que o projeto funcione como o esperado. Depois de algumas pesquisa no MSDN Library, a solução que encontrei foi a diretiva #error, que podemos aplicar ao código da seguinte forma:
#error Altere o valor da connectionstring apontando para uma base válida
private const string SQL_CONN_STRING = "Data Source=.;Initial Catalog=DBTest;Integrated Security=SSPI;";
Isso impedirá o usuário de compilar a aplicação sem antes alterar essa informação ou, ao menos, comentá-la. :P
Tuesday, September 02, 2008
#
Há algum tempo eu comentei sobre a evolução dos delegates, passando pelas versões 1.0, 2.0 e 3.0 do C#. Sabemos que a partir da versão 3.0 temos uma nova forma de expressar os delegates: expressões lambda. Neste modelo, não há mais necessidade de criar um método adicional ou um método anonimo para executar uma determinada tarefa.
Com a vinda do LINQ, novos delegates também foram introduzidos dentro do namespace System, através do Assembly System.Core.dll:
public delegate TR Func<TR>();
public delegate TR Func<T0, TR>(T0 a0);
public delegate TR Func<T0, T1, TR>(T0 a0, T1 a1);
public delegate TR Func<T0, T1, T2, TR>(T0 a0, T1 a1, T2 a2);
public delegate TR Func<T0, T1, T2, T3, TR>(T0 a0, T1 a1, T2 a2, T3 a3);
Esta família de delegates genéricos servem para construir delegates "on-the-fly", eliminando a necessidade de criá-los explicitamente. TR representa o resultado do delegate (nunca podendo ser void); depois temos outras versões do mesmo podendo, no máximo, termos quatro parametros de entrada. Em uma operação de soma, poderíamos utilizar o terceiro delegate, como por exemplo:
Func<int, int, int> exemplo = (v1, v2) => v1 + v2;
int resultado = exemplo(2, 3);
Ao compilar este código, o compilador do C# criará: um método que retorna um número inteiro e, no corpo do mesmo, terá o cálculo a ser realizado (v1 + v2) e um delegate que apontará para esse método recém criado; além disso, ele converterá a expressão lambda em um método anonimo, fazendo o uso do delegate criado anteriormente que, neste momento, apontará para o método que fará a soma dos números. O código acima é compilado para:
private static void Main(string[] args)
{
Func<int, int, int> exemplo1 = delegate (int v1, int v2) {
return v1 + v2;
};
int resultado = exemplo1(2, 3);
}
[CompilerGenerated]
private static Func<int, int, int> CS$<>9__CachedAnonymousMethodDelegate1;
[CompilerGenerated]
private static int <Main>b__0(int v1, int v2)
{
return (v1 + v2);
}
Uma outra alternativa é a utilização da classe Expression<TDelegate>, contida dentro do namespace System.Linq.Expressions. Essa classe deve ser tipificada com o mesmo delegate que utilizamos acima e, ao invés de converter a expressão lambda em um código IL que avalia a expressão, irá transformá-la em uma árvore de objetos IL, representando a expressão. Se utilizarmos o mesmo exemplo, veremos que o código mudará:
Expression<Func<int, int, int>> exemplo1 = (v1, v2) => v1 + v2;
int resultado = exemplo1.Compile()(2, 3);
Neste caso, não podemos invocar diretamente o delegate por ele não é um delegate. Essa classe fornece um método chamado Compile que, ao invocá-lo, retorna o delegate especificado na sua criação (Func<int, int, int>) e, a partir daí, podemos utilizá-lo da forma tradicional. Como o compilador lida de forma diferente quando utilizamos a classe Expression<TDelegate>, o código IL gerado para ele corresponde à:
private static void Main(string[] args)
{
ParameterExpression CS$0$0000;
ParameterExpression CS$0$0001;
int resultado =
Expression.Lambda<Func<int, int, int>>(
Expression.Add(
CS$0$0000 = Expression.Parameter(typeof(int), "v1")
, CS$0$0001 = Expression.Parameter(typeof(int), "v2")
)
, new ParameterExpression[] { CS$0$0000, CS$0$0001 })
.Compile()(2, 3);
}
Como podemos ver, as expressões lambdas podem ser representadas como código (delegates) ou como dados (árvore de expressões). É importante lembrar que uma expressão é um tipo de Abstract Syntax Tree (AST), que é uma estrutura de dados que representa um código já analisado. Essa técnica nos dá a habilidade de converter/traduzir um determinado código em outro, como é o caso do LINQ to SQL, que transforma essas árvores de expressão em linguagem T-SQL.
Thursday, August 28, 2008
#
O utilitário WcfTestClient.exe que está integrado ao Visual Studio .NET não precisa ser necessariamente incializado a partir de um projeto do tipo WCF Service Library que, por sua vez, tem a finalidade de gerar uma DLL contendo o contrato e implementação do serviço e, o utilitário é utilizado para testá-los, sem a necessidade de criar um host, pois ele já faz isso.
É importante dizer que podemos iniciá-lo a partir do prompt de comando do Visual Studio, passando como parametro uma Url já existente para que possamos testá-lo, sem a necessidade de criar um projeto dummy para isso. Abaixo está o exemplo:
C:\>WcfTestClient http://IADevServer/ServicoDePublicacaoDeArquivos/
Wednesday, August 27, 2008
#
Como todos sabem, o Windows Live ID é a evolução do Passport. Antigamente, para integrar uma aplicação ASP.NET ao sistema de autenticação do Passport, além de uma SDK que voce precisa entender e customizar, havia custos envolvidos, o que fez com que a terceira forma de autenticação suportada pelo ASP.NET não vingasse.
Atualmente, o Windows Live ID torna-se muito menos complexo e mais simples de acoplar à aplicações ASP.NET e, além disso, não é mais necessário pagar para utilizá-lo. Tudo o que precisa ser feito é um cadastro prévio, que consiste nas informações a respeito da aplicação que fará o uso do Windows Live ID. Para um passo à passo de como configurá-lo, podemos seguir o um artigo que neste endereço.
Além disso, ainda temos (ainda em CTP) o Windows Live Tools, que adiciona alguns controles na barra de ferramentas do Visual Studio .NET. Este CTP contempla, entre vários controles, os controles IDLoginView, IDLoginStatus e a classe LiveMembershipProvider. Esta última, herda diretamente da classe SqlMembershipProvider e traz a possibilidade de integrar uma credencial Live a um usuário dentro da estrutura de segurança do ASP.NET.
Wednesday, August 20, 2008
#
Quando estamos fazendo testes com serviços WCF, a idéia é sempre criar um serviço e consumí-lo em alguma aplicação cliente para testar se tudo corre como esperado. Mas quando o exemplo é simples, onde queremos testar apenas algumas funcionalidades, podemos utilizar uma técnica para criar o host e também, no mesmo projeto, poderíamos consumir o serviço sem a necessidade de criar um projeto dummy para isso.
As primeiras linhas consistem na criação e configuração do host e, depois que ele estiver aberto, então podemos recorrer ao uso da classe genérica ChannelFactory<TChannel> que podemos informar o contrato que estamos utilizando/testando, o ponto de acesso (endpoint) e o binding. O método CreateChannel utiliza o endpoint e o binding especificado no construtor para criar e estabelecer o canal de comunicação.
string address = "http://localhost:9388";
using (ServiceHost host = new ServiceHost(typeof(Servico), new Uri[] { new Uri(address) }))
{
host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding(), string.Empty);
host.Open();
using (ChannelFactory<IContrato> srv =
new ChannelFactory<IContrato>(new BasicHttpBinding(), new EndpointAddress(address)))
{
Console.WriteLine(srv.CreateChannel().Metodo("Israel Aece"));
}
}
Thursday, August 14, 2008
#
Thomas Marquardt mostra aqui uma nova funcionalidade da API de Caching do ASP.NET 3.5. Basicamente a idéia aqui é interceptar o momento antes do item ser efetivamente removido do cache.
O Service Pack 1 do .NET Framework 3.5 incluiu um novo recurso, onde voce poderá definir qual será a forma de redirecionamento quando estiver com o customErrors habilitado. Agora temos um atributo chamado RedirectMode, onde voce poderá definir dois valores:
Abaixo um simples exemplo:
<customErrors mode="On" redirectMode="ResponseRewrite">
<error statusCode="500" redirect="Erro.aspx"/>
</customErrors>
Alguém havia me
solicitado isso em algum momento e agora é possível.
O Service Pack 1 do .NET Framework 3.5 e o Serviço Pack 1 do Visual Studio 2008 trouxeram algumas melhorias interessantes no WCF:
-
UriTemplate: agora podemos incluir um valor padrão para algum parametro que será invocado
via REST. Algo como: [WebGet(UriTemplate = "RecuperarUsuarios/{quantidade
=5}")].
-
Atributo DataContract/DataMember: a partir de agora não precisamos explicitamente definir quais são os objetos e propriedades que serão expostos para serviços quando estamos trabalhando com tipos complexos. Ele entende que tudo será exposto. Temos apenas que nos preocuparmos em marcar o que não queremos que seja serializado.
-
-
Hosting Wizard: basicamente é a mesma funcionalidade do "Publish Web Site", mas para um serviço WCF.
-
WCF Options: quando tem um projeto do tipo
Wcf Service Library na solução, nas propriedades deste projeto temos uma aba chamada
WCF Options. Dentro da mesma, há uma opção chamada:
Start WCF Service Host when debugging another project in the same solution. Ao marcá-la, ao rodar qualquer projeto em modo de depuração, o
WCF Test Client irá iniciar para tornar o serviço disponível para que outras aplicações na mesma solução o utilizem.