Uma classe que pode ajudar – Executando evento de tempos em tempos

Boas brotherhood, no post de hoje, vou compartilhar com voces uma classe que eu bolei e achei que ficou bacaninha. Let’s rock.

Bom tudo começou com uma necessidade la no meu trampo. Existe um processo que deve ficar rodando de tempos em tempos executando uma tarefa X. A partir dessa ideia, eu resolvi bolar uma classe que me permitisse executar essa tarefa. Claro que dava pra fazer de varias formas esse tipo de logica, mas eu quis encapsular essa inteligencia em uma classe de modo a permitir o reuso dessa mesma, sem repetecos de loops e nada do genero. Bom, a ideia era construir uma classe que ficaria repetindo um processo de tempos em tempo. Bom, nisso identificamos que precisaremos de uma propriedade onde sera definido o intervalo de tempo de execução entre uma tarefa e outra. Alem disso, vamos precisar iniciar,parar,pausar,continuar,reiniciar o processo. Nisso, tambem devemos ter uma segunda propriedade que indica o status do processo. Abaixo voces podem ver a definição de um enum com os possiveis status do processo:

public enum FactoryProcessStatus
{
    Stopped = 0,
    Stopping = 1,
    Starting = 2,
    Running = 3,
    Pausing = 4,
    Paused = 5,
    Resuming = 6,
}

Como o nosso processo vai estar em constante execução, os metodos mencionados acima irão apenas alterar os estados, ficando por conta do processo realizar determinado comando de acordo com o estado que fora alterado. Abaixo voce poderão ver a definição da classe:

    public delegate void TimeoutReachedHandler();
    public delegate void StatusChangedHandler(FactoryProcessStatus status);
    public delegate void ProcessFinishedHandler();
    public delegate void ProcessPausedHandler();
    public delegate void ProcessStartedHandler();
    public delegate void RunProcessDelegate();
    public class FactoryProcess
    {
        private bool _mustRestart;
        private bool _stopProcess;
        public int Timeout { get; set; }

        private FactoryProcessStatus _status;
        public FactoryProcessStatus Status
        {
            get
            {
                return this._status;
            }
            set
            {
                this._status = value;
                if (OnStatusChanged != null)
                    OnStatusChanged(this.Status);
            }
        }
        public event TimeoutReachedHandler OnTimeoutReached;
        public event StatusChangedHandler OnStatusChanged;
        public event ProcessFinishedHandler OnProcessFinished;
        public event ProcessPausedHandler OnProcessPaused;
        public event ProcessStartedHandler OnProcessStarted;

        public FactoryProcess(int timeout = 300000)
        {
            this._stopProcess = false;
            this.Timeout = timeout;
        }
        public void Pause()
        {
            this.Status = FactoryProcessStatus.Pausing;
        }
        public void Restart()
        {
            this._mustRestart = true;
            this.Stop();
        }
        public void Resume()
        {
            this.Status = FactoryProcessStatus.Resuming;
        }
        public void Start()
        {
            this.Status = FactoryProcessStatus.Starting;
            this.RunProcessAsync();
        }
        public void Stop()
        {
            this.Status = FactoryProcessStatus.Stopping;
        }
        private void RunProcess()
        {
            while (!_stopProcess)
            {
                if (this.Status == FactoryProcessStatus.Stopping)
                {
                    this._stopProcess = true;
                    this.Status = FactoryProcessStatus.Stopped;
                }
                else if (this.Status == FactoryProcessStatus.Starting)
                {
                    this.Status = FactoryProcessStatus.Running;
                    this._stopProcess = false;
                }
                else if (this.Status == FactoryProcessStatus.Pausing)
                {
                    this.Status = FactoryProcessStatus.Paused;
                    this._stopProcess = false;
                    if (OnProcessPaused != null)
                        OnProcessPaused();
                }
                else if (this.Status == FactoryProcessStatus.Resuming)
                {
                    this.Status = FactoryProcessStatus.Running;
                    this._stopProcess = false;
                }

                if (this.Status == FactoryProcessStatus.Running)
                {
                    if (this.OnTimeoutReached != null)
                        this.OnTimeoutReached();
                }

                if (this.Status == FactoryProcessStatus.Running || this.Status == FactoryProcessStatus.Paused)
                {
                    Thread.Sleep(this.Timeout);
                }
            }
        }
        private void RunProcessAsync()
        {
            RunProcessDelegate process = new RunProcessDelegate(RunProcess);
            AsyncCallback callback = delegate
            {
                this._stopProcess = false;
                if (OnProcessFinished != null)
                    OnProcessFinished();

                if (this._mustRestart)
                {
                    this._mustRestart = false;
                    this.Start();
                }
            };

            process.BeginInvoke(callback, null);

            if (OnProcessStarted != null)
                OnProcessStarted();
        }
    }

Antes que voces me xinguem, o codigo acima tem de fato mais coisas do que as que mencionei. O que mencionei acima, foram as necessidades iniciais que levantei. Para que tudo funcionasse, tive que adicionar algumas coisas. Mas calma, eu irei explicar tudinho :) . Bom, das linhas 1 a 6, temos a definição dos nossos delegates. Esses delegates serão utilizados quando estivermos definindo nossos eventos que serão disparados para informar progressos do nosso processo. Ha um evento que é o evento chave da classe. O cliente que estiver utilizando a classe, devera implementar a logica que ele desejar ser executada de tempos em tempos. Mais a frente, na utilização dessa classe, as coisas ficarão mais claras (pelo menos eu espero :P ). A declaração dos eventos esta das linhas 27 a 31. Alem das duas propriedades mencionadas, tambem temos duas variaveis privadas para controle interno do processo. A partir da linha 33, temos as implementações dos metodos mencionados anteriormente. A maioria deles apenas altera o Status para que mais pra fente, o processo efetue os comandos conforme o status corrente. Ja da linha 60 em diante, temos dois metodos privados, onde um é o metodo assincrono que é invocado quando executamos o metodo Start definido acima. O outro, é o metodo core da nossa classe. É nele que toda a magica acontece. Ele faz uso de uma das nossas variaveis de controle para poder rodar o processo. Alem disso, ele faz as devidas verificações para que possa executar as devidas ações relacionadas ao processo. Bom, chega de falar, eu não gosto de falar muito, então vamos mostrar a implementação da classe acima criada.

public partial class MainWindow : Window
{
    private FactoryProcess factory = new FactoryProcess(5000);
    public MainWindow()
    {
        InitializeComponent();

        factory.OnTimeoutReached += new TimeoutReachedHandler(Factory_OnTimeoutReached);
        factory.OnStatusChanged += new StatusChangedHandler(Factory_OnStatusChanged);
        factory.OnProcessFinished += new ProcessFinishedHandler(Factory_OnProcessFinished);
    }
    void Factory_OnProcessFinished()
    {
        //Implementação da logica quando o processo for finalizado.
    }
    void Factory_OnStatusChanged(FactoryProcessStatus status)
    {
        //Implementação da logica quando o status do processo for alterado. De em execução para pausado, por exemplo.
    }
    void Factory_OnTimeoutReached()
    {
        //Implementação da rotina que deverá ser executada de tempos em tempos.
        //Esse é o evento core que eu mencionei. Basta colocar a logica que desejar executar e
        //quando voce der o start, esse metodo sera executado, baseado no timeout definido.
    }
    private void buttonStart_Click(object sender, RoutedEventArgs e)
    {
        factory.Start();
    }

    private void buttonPause_Click(object sender, RoutedEventArgs e)
    {
        factory.Pause();
    }
    private void buttonResume_Click(object sender, RoutedEventArgs e)
    {
        factory.Resume();
    }

    private void buttonStop_Click(object sender, RoutedEventArgs e)
    {
        factory.Stop();
    }
    private void buttonRestart_Click(object sender, RoutedEventArgs e)
    {
        factory.Restart();
    }
}

Acho que agora deu pra entender (espero que sim). A ideia é abstrair a complexidade(que na verdade nem é tão grande) das verificações e controles, para que quem for implementar, o faça de forma simples e elegante :) . Bom por hoje é isso galera, até o proximo post! \m/

Mixed mode assembly is built against version…

Boas pessoal, no post de hoje, uma situação que eu passei e consegui resolver de uma forma muito simples, isso é claro, depois de muito tempo gasto pesquisando. Let’s rock.

Bom, alguns de voces ja devem ter passado pelo seguinte erro:

Mixed mode assembly is built against version ‘v1.1.4322′ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.

Depois de uma googlada basica, muitos posts na internet me diziam que eu deveria adicionar a seguinte seção de configuração no meu arquivo *.config.


<startup useLegacyV2RuntimeActivationPolicy="true">
     <supportedRuntime version="v4.0" />
 </startup>

Pois bem, essa seção de configuração foi o que eu achei em varios locais e muitos diziam que após incluir essa linha no arquivo de configuração da aplicação, de fato passava a funcionar. Porém as coisas pra mim não podiam ser fáceis assim, certo? Bom, mesmo após adicionar essa configuração no meu arquivo *.config, continuei obtendo o mesmo erro. Bom pra explicar o cenario que eu estava passando, era o seguinte: Eu tinha um serviço em WCF que tinha a referencia de um assembly X (Business Conector) e esse serviço era consumido por um outro serviço. Eu conseguia hostear o serviço normalmente (utilizando o WcfService Host), porém quando entrava em debug, na linha que fazia referencia a uma classe do Business Conector, eu obtinha o erro mencionado. Tentei adicionar a referencia em todos os *.configs envolvidos, porem continuou o erro. Ja meio sem esperanças, resolvi fazer o publish do serviço no IIS e consumir diretamente do IIS. Para minha surpresa, funcionou e não disparava a exception. Isso foi muito ruim, porque como ainda estava desenvolvendo o serviço, eu precisava debugar o codigo pra continuar a codificação. Quase perdendo as esperanças, um amigo meu que estava me ajudando nesse projeto, me enviou um link que salvaria minha vida :) . O link é esse e nele, explica como resolver o problema que eu estava enfrentando. Resumidamente, devemos adicionar a seção de configuração mencionada acima, porem ao invés de adicionarmos apenas no nosso arquivo de configuração, devemos adicionar tambem no arquivo de configuração do Wcf Service Host. Como um amigo meu diria, THINK. Pois é, não sei explicar ao certo, mas aparentemente essa configuração é necessaria no aplicativo que faz o hosting do serviço. Talvez se eu tivesse criado um self-host eu não teria obtido esse problema. O fato é que após adicionar essa configuração no arquivo de configuração do Wcf Service Host, consegui hostear meu serviço nele e também consegui debugar sem obter a exception anteriormente mencionada :) . O arquivo de configuração fica no caminho “C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE” e o nome dele é WcfSvcHost.exe.config. Bom por hoje é isso galera, até o proximo post! \m/

Consumindo um WCF Service no Windows Phone 7

Boas galera, no post de hoje vou falar sobre o consumo de um serviço WCF em uma aplicação windows phone 7. Let’s rock!

De fato, o consumo de um serviço não tem segredo. Da mesma forma que voce trabalha com uma aplicação em windows ou web, voce tambem adiciona a referencia do seu serviço normalmente. Uma coisa que muda é que as chamadas serão realizadas de forma assincrona. Hoje um exemplo bem simples. Vou usar a ideia de uma aplicação que consulta uma determinada informação a partir de um ID. Bom, vamos ao codigo da aplicação. Primeiro o codigo do nosso serviço:

[ServiceContract]
public interface IConsultaContrato
{
    [OperationContract]
    Funcionario RecuperaFuncionario(int id);
}

Como voces podem ver, o codigo acima define o contrato do nosso serviço. Este contrato é bem simples e disponibiliza somente uma operação que retorna um funcionario. Abaixo a implementação do contrato na nossa classe de serviço:

public class ConsultaServico : IConsultaContrato
{
    public Funcionario RecuperaFuncionario(int id)
    {
        try
        {
            return new FuncionarioController().RetornaFuncionario(id);
        }
        catch (FaultException ex)
        {
            throw;
        }
    }
}

A implementação do serviço ficou vaga, confesso :P … Como eu encapsulei a inteligencia dentro de um controller, na nossa classe, apenas fazemos a chamada de um metodo do nosso controller. Antes que voces comecem a me xingar, segue abaixo a implementação desse controller:

internal class FuncionarioController
{
    internal Funcionario RetornaFuncionario(int id)
    {
        try
        {
            var query = from tbl in XDocument.Load(@"c:\users\daniel.torres\documents\visual studio 2010\Projects\DanielTTorres.Wp7App\AlertService\Funcionarios.xml").Elements("root")
                            .Elements("arrayOfFuncionarios")
                            .Elements("funcionario")
                        where int.Parse(tbl.Element("id").Value) == id
                        select new Funcionario()
                        {
                            Id = int.Parse(tbl.Element("id").Value),
                            Nome = tbl.Element("nome").Value,
                            Email = tbl.Element("email").Value,
                            Ramal = int.Parse(tbl.Element("ramal").Value),
                            Departamento = tbl.Element("departamento").Value,
                            Foto = this.LoadImage(tbl.Element("foto").Value)
                        };

            return query.FirstOrDefault();
        }
        catch (Exception ex)
        {
            throw;
        }
    }
    private byte[] LoadImage(string path)
    {
        return File.ReadAllBytes(path);
    }
}

Pronto. Sem xingamentos :) . O metodo invocado, RetornaFuncionario, busca o funcionario pelo id. No nosso caso, o repositório é um arquivo xml, mas poderiamos utilizar um banco de dados. Bom, ja da pra ver a estrutura da nossa classe funcionario no codigo anterior, e ela segue abaixo:

[DataContract]
public class Funcionario
{
    [DataMember]
    public int Id { get; set; }
    [DataMember]
    public string Nome { get; set; }
    [DataMember]
    public string Departamento { get; set; }
    [DataMember]
    public int Ramal { get; set; }
    [DataMember]
    public string Email { get; set; }
    [DataMember]
    public byte[] Foto { get; set; }
}

Como voces podem ver é um contrato de dados simples, porem devemos prestar atenção em uma das propriedades do nosso contrato de dados. A propriedade Foto é do tipo array de bytes e isso pode prejudicar na comunicação entre client e service, dependendo do tamanho dela. No meu caso, estou utilizando uma imagem pequena, porem se for preciso adicionar uma imagem maior, é necessario adicionar uma configuração no seu arquivo *.config. Abaixo segue o arquivo de configuração do serviço (apenas a seção referente a configuração do serviço):

<system.serviceModel>
    <services>
      <service name="Servico.ConsultaServico" behaviorConfiguration="bhvr">
        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="Servico.IConsultaContrato"
                  >
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="bhvr">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Caso voce se encaixe no caso descrito acima, voce deve adicionar a seguinte seção de configuração no seu *.config:

<bindings>
  <basicHttpBinding>
    <binding name="basicBindingConfigs"
             maxReceivedMessageSize="2147483647"
             maxBufferSize="2147483647"
             maxBufferPoolSize="2147483647"
             receiveTimeout="01:00:00"
             openTimeout="01:00:00"
             closeTimeout="01:00:00"
             sendTimeout="01:00:00">
      <readerQuotas maxDepth="2147483647"
                    maxArrayLength="2147483647"
                    maxBytesPerRead="2147483647"
                    maxStringContentLength="2147483647"
                    maxNameTableCharCount="2147483647"/>
    </binding>
  </basicHttpBinding>
</bindings>

Os valores inseridos nessa seção de configuração deverão ser definidos com cuidado. No caso, o tamanho definido é o int.MaxValue, o que em ambiente de desenvolvimento não tem problema. Porem quando estiver rodando em produção, voce devera alterar para o valor que realmente for necessário. Com isso, terminamos a codificação e configuração por parte do serviço. Agora vamos ao cliente que é uma aplicação em WP7. Criei um projeto do tipo Windows Phone Application e adicionei duas Windows Phone Portrait Pages uma para a tela de consulta  e outra para a tela de resultado. Elas devem ficar como nas imagens abaixo:

Como voces podem ver, essa tela é bem simples. No corpo, temos um textblock contendo o texto código, uma textbox onde será digitado o código e um botão consultar. Abaixo segue o código do layout da tela:

<phone:PhoneApplicationPage
    x:Class="PhoneApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="CONSULTA POR ID" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="Pesquisa" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="22,25,0,0" Name="textBlock1" Text="Codigo: " VerticalAlignment="Top" />
            <Button Content="Consultar" Height="72" HorizontalAlignment="Left" Margin="290,143,0,0" Name="buttonConsultar" VerticalAlignment="Top" Width="160" Click="buttonConsultar_Click" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="9,47,0,0" Name="textBox1" VerticalAlignment="Top" Width="444" />
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>

Ao clicar no botão consultar, iremos abrir a pagina com o resultado da consulta. Para isso, adicionamos um event handler ao click do botão. O code behind contendo o handler segue abaixo:


public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();
    }

    private void buttonConsultar_Click(object sender, RoutedEventArgs e)
    {
        this.Content = new Resultado(int.Parse(textBox1.Text));
    }
}

E agora a imagem e o código  da segunda tela que exibe o resultado da consulta ao serviço:

O layout dessa tela  tambem é simples, contendo 8 textblocks referentes aos dados a serem exibidos, um textblock para a mensagem a ser exibida, um hyperlink button e uma image onde sera exibida a foto da pessoa. E abaixo o código da segunda tela:

<phone:PhoneApplicationPage
    x:Class="PhoneApp.Resultado"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="CONSULTA POR ID" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="Resultado" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <HyperlinkButton Content="Voltar" Height="30" HorizontalAlignment="Left" Margin="363,18,0,0" Name="hyperlinkButton1" VerticalAlignment="Top" Width="87" Click="HyperlinkButton_Click" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,69,0,0" Name="textBlockMensagem" Text="" VerticalAlignment="Top" Width="438" TextAlignment="Center" />
            <Image Height="129" HorizontalAlignment="Left" Margin="12,130,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="139" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,281,0,0" Name="textBlockLabelNome" Text="Nome:" VerticalAlignment="Top" Width="70" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,331,0,0" Name="textBlockLabelDepto" Text="Depto: " VerticalAlignment="Top" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,387,0,0" Name="textBlockLabelRamal" Text="Ramal: " VerticalAlignment="Top" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,436,0,0" Name="textBlockLabelEmail" Text="Email: " VerticalAlignment="Top" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="88,281,0,0" Name="textBlockNome" VerticalAlignment="Top" Width="348" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="88,331,0,0" Name="textBlockDepto" VerticalAlignment="Top" Width="348" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="88,387,0,0" Name="textBlockRamal" VerticalAlignment="Top" Width="348" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="88,436,0,0" Name="textBlockEmail" VerticalAlignment="Top" Width="348" />
        </Grid>

    </Grid>

</phone:PhoneApplicationPage>

E agora o code behind que contem toda a inteligencia de criação do proxy e montagem do layout com os dados de retorno. Segue abaixo o código:

public partial class Resultado : PhoneApplicationPage
{
    public Resultado(int codigo)
    {
        InitializeComponent();
        this.PreencheResultado(codigo);
    }

    private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
    {
        this.Content = new MainPage();
    }

    private void PreencheResultado(int codigo)
    {
        ServicoDeConsulta.ConsultaContratoClient proxy = new ServicoDeConsulta.ConsultaContratoClient();
        try
        {
            proxy.RecuperaFuncionarioAsync(codigo);
            proxy.RecuperaFuncionarioCompleted += new EventHandler<ServicoDeConsulta.RecuperaFuncionarioCompletedEventArgs>(Proxy_RecuperaFuncionarioCompleted);
        }
        catch (Exception)
        {
            throw;
        }
    }

    void Proxy_RecuperaFuncionarioCompleted(object sender, ServicoDeConsulta.RecuperaFuncionarioCompletedEventArgs e)
    {
        if (e.Result != null)
        {
            this.textBlockMensagem.Text = "Dados do funcionario";
            this.textBlockDepto.Text = e.Result.Departamento;
            this.textBlockEmail.Text = e.Result.Email;
            this.textBlockNome.Text = e.Result.Nome;
            this.textBlockRamal.Text = e.Result.Ramal.ToString();
            System.Windows.Media.Imaging.BitmapImage image = new System.Windows.Media.Imaging.BitmapImage();
            image.SetSource(new System.IO.MemoryStream(e.Result.Foto));
            this.image1.Source = image;
        }
        else
        {
            this.textBlockLabelDepto.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockLabelEmail.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockLabelRamal.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockLabelNome.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockDepto.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockEmail.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockNome.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockRamal.Visibility = System.Windows.Visibility.Collapsed;
            this.image1.Visibility = System.Windows.Visibility.Collapsed;
            this.textBlockMensagem.Text = "Nenhum registro encontrado";
        }
    }
}

Pronto agora temos tudo pronto para rodar nosso aplicativo. Abaixos a sequencia de prints da execução do aplicativo no emulador do windows phone 7:
1- Consulta com retorno de registros:

E o resultado:

2 – Agora seguindo a seguindo a linha sem retorno de registros:

E a tela de resultado informando que não foi encontrado registro com o id consultado:

Com isso, finalizamos o post de hoje. Estou disponibilizando o link do download do projeto. Baixem e analizem o código, melhorem ele, alterem… a minha intenção é divulgar o conhecimento e aprender tambem. Bom por hoje é isso galera, até o proximo post! \m/

Mudanças no blog

Boas pessoal, esse post não tem nenhum conteudo técnico. Decidi fazer umas mudanças no blog e estou postando aqui o que foi alterado. Agora eu coloquei uma area de contato, assim voce pode entrar em contato comigo direto pelo blog. Tambem alterei o layout do blog. Aquele outro era legalzinha, mas um colega meu me alertou que em alguns casos, os codigos ficavam bagunçados. Gostei bastante desse novo tema do blog, porque ele é bem simples e limpo. O RSS do blog tambem ficou visivel, coisa que no tema antigo ficava meio dificil de localizar. Adicionei tambem tags nos posts, coisa que eu não fazia. Adicionei o widget do twitter e tambem um widget das tags. Enfim, algumas melhorias pra o blog ficar mais legal :) . Tambem adicionei uns links de uns blogs que eu achei bacana na seção indico. Bom é isso galera, espero o feedback de voces não somente no layout e melhorias, como tambem nos posts tecnicos. Abraços.

Brincando de interoperabilidade com WCF e VB6

Boas galera, no post de hoje um pouco de interoperabilidade. Ja adianto. Essa não deve ser a melhor forma de se fazer esse tipo de consumo. Eu apenas estava um pouco entediado e resolvi testar pra ver se funcionava. Então tenham em mente de que o que vou fazer no post de hoje é apenas um teste. Neste post, eu presumo que voces saibam como criar um serviço em WCF e tambem uma dll com interop. Let’s rock.

Bom pra poder fazer o que eu tenho em mente, precisaremos de

  • Microsoft Visual Studio 2010
  • Microsoft Visual Basic 6
  • Utilitario svcutil
  • Utilitario regasm
  • Utilitario sn

E com isso podemos iniciar nosso laboratório :) .

Abra o Visual Studio 2010 e crie um serviço em WCF (pra agilizar o processo, podemos utilizar o template WCF Service Library). O serviço que estou utilizando é o que vem no template, então não irei postar o código aqui. Agora vem um momento de reflexão. Uma vez em uma oportunidade, tive que fazer interoperabilidade de um componente em .NET com uma aplicação em VB6. Dai eu parei e pensei: “Se eu consegui com uma dll escrita em C#, com um serviço deve funcionar.”. A partir dai, Criei um projetinho (Class Library) em C# e adicionei a referencia do serviço, e criei  uma especie de ponte para o consumo do VB6. A ideia era criar uma classe que expusesse os mesmos metodos do serviço. Uma observação importante. Para fazer a referencia, eu gerei o proxy atraves do svcutil, não utilizando o visual studio, mas o prompt de comando e adicionei a classe proxy ao meu projeto. Tambem gerei um strong name para o assembly do meu projetinho e associei ele ao meu projeto. Após isso, comecei a codificação. Para desenvolver um assembly interoperavel, precisamos definir um contrato para ele, então segue abaixo a definição do contrato:

[Guid("71f329f4-f190-4701-a475-79e257a66877")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface ICOMDummy
{
    [ComVisible(true)]
    [DispId(1)]
    string DoSomeFuckinStuff(int a);
}

Gostaria de pedir desculpas pelo palavrão no nome do metodo, mas o importante é a ideia :) . E abaixo a implementação dessa interface:

[Guid("d12fe59b-2a63-4a5c-9924-2b892cd23e5c")]
[ComSourceInterfaces(typeof(ICOMDummy))]
[ComVisible(true)]
public class COMDummy : ICOMDummy
{
    [ComVisible(true)]
    public string DoSomeFuckinStuff(int a)
    {
        try
        {
            ChannelFactory<IService1> factory =
                new ChannelFactory<IService1>(new WSHttpBinding(),
                new EndpointAddress("http://localhost:8732/Design_Time_Addresses/ServiceDummy/Service1/"));
            IService1 proxy = (IService1)factory.CreateChannel();
            string t = proxy.GetData(a);
            return t;
        }
        catch (COMException ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message);
            return "";
        }
    }
}

Agora abrimos o Visual Basic 6 e criamos um aplicação Standard EXE que nos traz um formulario windows normal. Nele, adicionamos um botão   Agora, o codigo VB6 para o consumo desse serviço:

Private test As COMDummy.COMDummy

Private Sub Command1_Click()
    Dim s As String

    Set test = New COMDummy.COMDummy
    s = test.DoSomeFuckinStuff(4)
    MsgBox s

End Sub

Lembrando que para que seja possivel executar, é necessario registrar esse assembly interoperavel. É possivel fazer isso com o uso do utilitario regasm. Agora se executarmos a o nosso projeto em VB6, veremos que ele executa com sucesso a chamada ao serviço :) .

Bom por hoje é isso galera. Até o proximo post! \m/

Brincando de novo com LINQ to XML

Boas galera, no post de ontem, eu mostrei como utilizar o LINQ to XML pra poder ler um xml e preencher um objeto ou collection de objetos. Mas dae voce vira e fala: “Po, mas o meu xml ta num formato diferente e usando o que voce passou não to conseguindo ler.”. Calma calma, não priemos canico. Alem daquela forma de montar o xml, tambem tem uma segunda possibilidade de se montar o xml, que seria assim:

<?xml version="1.0" encoding="utf-8" ?>
<root>
    <clientes>
        <cliente id="13" nome="Daniel Torres" conta="6136136" />
    </clientes>
</root>

Agora, ao invés de utilizar varios elementos para armazenar os valores, estou utilizando os atributos de um unico elemento para fazer essa tarefa. O codigo para o consumo muda um pouco, mas nada muito grande. Segue abaixo o código:


static IEnumerable<Cliente> GetCliente(string xml)
{
    return (from tbl in XDocument.Parse(xml).Elements("root").
                Elements("clientes").
                Elements("cliente")
            select new Cliente()
            {
                Id = int.Parse(tbl.Attribute("id").Value),
                Nome = tbl.Attribute("nome").Value,
                Conta = long.Parse(tbl.Attribute("conta").Value)
            });
}

Pronto. Como voces devem ter notado, não mudou quase nada do codigo anterior, apenas ao invés de usar o metodo Elements do objeto tbl, agora estamos utilizando o metodo Attribute. Simples assim :) .

Bom por hoje é isso galera. Até o proximo post! \m/

Brincando um pouco com LINQ to XML

Boas galera, no post de hoje, um pouco de LINQ to XML. Let’s rock.

O xml é um formato que de fato facilita nossa vida. Como ele não é padrão de uma empresa, mas aberto, podemos utilizar ele para efetuar a interoperabilidade entre aplicações. Por exemplo, temos uma classe X em nossa aplicação 1 e desejamos trafega-la para uma outra aplicação 2 que não conhece a nossa classe. Para fazer isso, podemos utilizar o xml, permitindo que a aplicação 2 leia esse xml e obtenha os dados desejados. Sem mais delongas, vamos ao codigo:


class Cliente
{
    int Id { get; set; }
    string Nome { get; set; }
    long Conta { get; set; }
}

Como voces podem ver, na classe acima, definimos uma estrutura bem simples,  contendo apenas 3 atributos. A representação xml dessa estrutura poderia ficar assim:

<?xml version="1.0" encoding="utf-8" ?>
<root>
    <clientes>
        <cliente>
            <id>13</id>
            <nome>Daniel Torres</nome>
            <conta>6136136</conta>
        </cliente>
    </clientes>
</root>

Essa seria a representação em xml da nossa classe. Imaginem agora o seguinte cenario. Temos uma classe cliente com a estrutura definida anteriormente e receberemos os dados de um sistema  qualquer escrito numa linguagem qualquer naquela estrutura xml. Como fariamos para ler esse xml e preencher nossa classe?? Bom existem varias formas, mas como eu gosto de LINQ, vamos usar o LINQ para preencher nossa classe. Abaixo o codigo utilizado para preencher nossa classe.

static Cliente GetCliente(string xml)
{
    return (from tbl in XDocument.Parse(xml).Elements("root").
                Elements("clientes").
                Elements("cliente")
           select new Cliente()
           {
               Id = int.Parse(tbl.Element("id").Value),
               Nome = tbl.Element("nome").Value,
               Conta = long.Parse(tbl.Element("conta").Value)
           }).First<Cliente>();
}

Aqui vai a explicação. O XDocument é a classe utilizada para trabalhar com o xml. O metodo Parse() recebe como parametro uma string que ele tenta carregar como um xml valido e caso não esteja no formato correto, uma exceção é disparada. Ele retorna um XDocument que contem o metodo Elements que recebe como parametro um xname. No nosso caso, estamos invovando 3 vezes, mapeando o root, depois o clientes e por fim o node cliente. Depois de mapear os 3 nodes, chegamos no node que desejamos que é o cliente. Agora podemos fazer o select e preencher as propriedades do nosso objeto cliente. Para isso, utilizamos a variavel tbl declarada no começo da nossa expressão. Atraves dela, mapeamos para o elemento desejado e obtemos o Value deste elemento. Apos fazer isso, devemos fazer a chamada do metodo First<T>() pois caso contrario, ele ira retornar um IEnumerable<Cliente> o que nesse caso não é o esperado. Abaixo o codigo referente ao metodo Main():

static void Main(string[] args)
{
    string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
                   <root>
                       <clientes>
                           <cliente>
                               <id>13</id>
                               <nome>Daniel Torres</nome>
                               <conta>6136136</conta>
                           </cliente>
                       </clientes>
                   </root>";
    Cliente c = GetCliente(xml);
    Console.WriteLine("{0} - {1} - {2}",c.Id, c.Nome, c.Conta);
}

Pronto. Se executarmos o output será semelhante ao seguinte:

O mais legal, é que se quisermos retornar uma lista de clientes, basta alterar o tipo de retorno para IEnumerable<Cliente> e retirar a chamada do metodo First<Cliente>(), não é o maximo ?? :)

Bom por hoje é isso galera. Como voces viram, não tem segredo é bem simples. Até o proximo post! \m/

03 – Criando meu primeiro serviço (basico) em WCF. – Contrato de Dados

Boas galera, vamos continuar hoje a nossa serie. Hoje, conforme eu prometi no ultimo post, vou falar sobre contrato de dados. Let’s rock!

Lembram-se do ultimo post onde eu falei sobre o contrato de serviço? No exemplo que eu passei, eu criei um contrato que expunha 3 operações: InsereProduto, RecuperaProdutos e RecuperaProduto. Em todas as operações, trafegava entre o cliente e o serviço um objeto Produto. Esse objeto é o nosso contrato de dados. Segue abaixo a definição do contrato:

[DataContract]
public class Produto
{
    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public string Nome { get; set; }

    [DataMember]
    public string Descricao { get; set; }

    [DataMember]
    public decimal Valor { get; set; }
}

Da mesma forma que com o serviço, para trafegar um tipo customizado, precisamos definir o contrato de dados. Na realidade, até o framework 3.5 era necessario utilizar esses atributos. A partir do SP1 do 3.5 o uso dos atributos  DataContractAttribute e DataMemberAttribute são opcionais. Eu particularmente sempre decoro as classes com esses atributos, porque acho que fica mais legivel e de facil entendimento, alem de organizado. O DataContractAttribute é utilizado em cima da classe que representa o contrato de dados. Ja o DataMemberAttribute deve ser utilizado em cima das propriedades da classe.  Seguem abaixo os parametros do DataContractAttribute:

  • IsReference
  • Name
  • Namespace
As propriedades Name e Namespace tem a mesma finalidade das do contrato de serviço. O Name define qual será o nome do contrato de dados e o Namespace define a namespace do contrato de dados. Ja o IsReference é um booleano que quando setado pra true, informa ao DataContractSerializer que deve ser inserido no xml informações que preservem a referencia do objeto. Abaixo as propriedades do DataMemberAttribute:
  • EmitDefaultValue
  • IsRequired
  • Name
  • Order
A propriedade Name como ja foi dito define o nome do membro exposto. A IsRequired tem uma funcionalidade muito interessante. Ela define se a propriedade tem que estar preenchida quando for serializada para envio e recebimento da mensagem. A Order define a ordem em que os campos serão serializados e a EmitDefaultValue Define que se o valor não for informado, o valor default é serializado na mensagem. Bom por hoje é isso galera. Como voces viram, não tem segredo :) . Até o proximo post! \m/

02 – Criando meu primeiro serviço (basico) em WCF. – Contrato de Serviço

Boas galera, vamos continuar com a serie de posts de WCF. No post de hoje vou falar um pouco sobre Contrato de Serviço. Let’s rock!

Como disse no post passado, um dos itens da estrutura do WCF é o contrato do serviço. No contrato do serviço são definidas quais operações serão disponibilizadas para os clientes do serviço. Alem de definir as operações, tambem é possivel definir comportamentos a nivel de operação e tambem a nivel de serviço. Abaixo um exemplo de um contrato:

[ServiceContract]
public interface IContrato
{
    [OperationContract]
    void InsereProduto(Produto p);
    [OperationContract]
    Produto[] RecuperaProdutos();
    [OperationContract]
    Produto RecuperaProduto(int id);
}

Ok, vamos as explicações:

- ServiceContractAttribute: Este atributo, como o nome diz, define que a interface/classe decorada com ele será o contrato do nosso serviço. Este atributo pode ser colocado tanto  em uma classe quanto em uma interface, porem eu particularmente sempre coloco na interface. Por que? Bom porque eu gosto de manter meus projetos organizados e facilitar minha vida na hora de mexer. Eu acho que colocar diretamente na classe, deixa o codigo porco, mas sinta-se a vontade se quiser colocar. :P

- OperationContractAttribute: Este atributo como o proprio nome diz, define que o metodo decorado com ele será uma operação do nosso serviço. Somente os metodos que estiverem decorados com este atributo serão disponibilizados, ou seja, se voce quiser ter N metodos definidos na sua interface de contrato do serviço mas somente quiser disponibilizar 1 ou 2, somente decore esse(s) metodo(s) com o atributo. O fato de eu decorar uma interface com o ServiceContractAttribute não me obriga a decorar todos os metodos definidos nessa interface com o atributo OperationContractAttribute. Porem um detalhe importante deve ser observado. Caso voce decore a interface com o atributo ServiceContractAttribute e não decorar nenhum metodo com o atributo OperationContractAttribute, uma exceção do tipo InvalidOperationException será disparada com a mensagem de que não ha operações definidas no contrato do serviço.

Ambos os atributos tem algumas propriedades que podem ser utilizadas dependendo da ocasião. Segue abaixo a lista de propriedades, lembrando que não irei me aprofundar em todas as propriedades nesse post:

- ServiceContractAttribute:

  • CallbackContract:
  • ConfigurationName:
  • Name:
  • Namespace:
  • ProtectionLevel:
  • SessionMode:

- OperationContractAttribute:

  • Action:
  • AsyncPattern:
  • IsInitiating:
  • IsOneWay:
  • IsTerminating:
  • Name:
  • ProtectionLevel:
  • ReplyAction:
Desses apresentados vou focar apenas em: Name e Namespace para o ServiceContractAttribute e Name e IsOneWay para o OperationContractAttribute. Quanto aos outros, abordarei em outros artigos nos quais eles forem utilizados.
O atributo Name, como o proprio nome diz, define qual sera o nome do serviço disponibilizado. Não tem segredo :) . Da mesma forma, o atributo Namespace define qual sera a namespace do serviço. A namespace de um serviço tem o mesmo tipo de finalidade de uma namespace em um assembly, evitar o conflito de duas classes (no caso serviços) com o mesmo nome. Veja abaixo o codigo alterado para utilizar essas propriedades:
[ServiceContract(Name = "WCFSerieContract", Namespace = "http://localhost/svc/2011/05/")]
public interface IContrato
{
//...
}

Caso voces tentem visualizar o wsdl, ele tera inserido tanto o nome quanto a namespace que nos informamos:
<wsdl:import namespace="http://localhost/svc/2011/05/" location="http://localhost:8080/?wsdl=wsdl0"/>

E tambem o nome:
<wsdl:binding name="NetTcpBinding_WCFSerieContract" type="i0:WCFSerieContract">

Agora vamos as propriedades do OperationContractAttribute. Da mesma forma que no ServiceContractAttribute, no OperationContractAttribute o Name define o nome da operação a ser disponibilizada. Essa propriedade é de grande valia quando temos overloads de metodos no nosso contrato. Devido a uma limitação do WSDL, não é possivel disponibilizar no seu contrato de serviço 2 metodos/operações com o mesmo nome. Para contornar essa limitação, podemos codificar os nossos overloads normalmente no contrato do nosso serviço e fazer uso da propriedade Name para disponibilizar os overloads com nomes diferentes. Ja o atributo IsOneWay tem uma funcionalidade muito importante. No WCF, podemos ter 3 tipos de comunicação: One-Way, Request-Reply e Duplex. Mensagens One-Way são todas aquelas em que não é necessario saber o retorno da execução do metodo. As Request-Reply são aquelas em que é necessario saber qual o retorno da execução de uma operação. E as Duplex, são aquelas onde o cliente envia mensagens para o serviço, bem como o serviço manda mensagens assincronas para o cliente. Futuramente vou publicar um post ensinando como criar uma solução duplex ( eu ja to escrevendo ele em paralelo :P ). Dada essa explicação, fica mais claro entender qual o uso dessa propriedade. No caso do nosso contrato, temos 1 operação one-way e 2 request-reply. Toda operação one-way deve ter o tipo de retorno void. Segue abaixo o codigo alterado para a utilização das propriedades citadas:
[ServiceContract(Name = "WCFSerieContract", Namespace = "http://localhost/svc/2011/05/")]
public interface IContrato
{
    [OperationContract(Name = "AdicionaProdutos", IsOneWay = true)]
    void InsereProduto(Produto p);

    [OperationContract(Name = "RecuperaProdutos", IsOneWay = false)]
    Produto[] RecuperaProdutos();

    [OperationContract(Name = "RecuperaProdutoPorId", IsOneWay = false)]
    Produto RecuperaProduto(int id);
}

Como se ve no codigo acima, a propriedade IsOneWay é booleana e se setada como true, a comunicação será one-way, caso contrario sera request-reply. Vamos ao wsdl gerado e vemos que ele alterou o nome das operações tambem:
...
<wsdl:operation name="AdicionaProdutos">
...
<wsdl:operation name="RecuperaProdutos">
...
<wsdl:operation name="RecuperaProdutoPorId">
...

Bom por hoje é isso galera, Acho que consegui dar um overview em Contratos de Serviço. No proximo post vou falar sobre Contrato de Dados. Até o proximo post! \m/

01 – Criando meu primeiro serviço (basico) em WCF. – Overview

Boas galera, devido aos pedido vou a partir deste post, escrever uma serie de posts sobre WCF para quem ainda não teve contato com essa tecnologia. O post de hoje tende a ser somente teorico e sem codigos pra poder passar alguns conceitos e informações do WCF e serviços. Let’s rock.

O WCF é uma tecnologia que veio para unir as formas de comunicação distribuidas. Antigamente, tinhamos o COM+, ASP.NET Webservices, .NET Remoting… o WCF une essas tecnologias nele de forma a padronizar a forma de comunicação orientada a serviços. O Evilazaro Alves está com uma serie de webcasts sobre WCF bem bacana, aconselho voces acompanharem tambem, pois esta muito legal :) . Alem dessa serie, ele esta com outra serie, uma de posts rapidos sobre WCF. Nela, ele foca nos pontos especificos e da as explicações sobre o tema de forma bem objetiva, tambem aconselho acompanharem. Bom chega de fala-fala, vamos ao que interessa :) .

Preciso mesmo de um serviço?

Quando se vai criar um serviço, precisamos ter em mente se realmente existe a necessidade de utilizar um serviço como forma de comunicação. Outro dia, estava conversando com um amigo, e falavamos justamente sobre a necessidade de usar ou não uma tecnologia em determinada situação. Eu sou um grande entusiasta do WCF (meus amigos sabem muito bem disso :) ), porem nem sempre é viavel utilizar um serviço pra tudo. Por exemplo, temos uma aplicação A onde um unico departamento da empresa utiliza e essa aplicação precisa Consultar dados, inserir dados e atualizar dados. Nesse caso, não vejo a necessidade de se utilizar um serviço. A propria aplicação pode acessar o banco de dados diretamente e fazer as operações. Ja em um outro cenario, onde varias aplicações precisam, por exemplo, consultar um determinado dado, faz mais sentido criar um serviço que consulte esse dado, porque no caso de uma manutenção, dependendo do nivel, a alteração passara despercebida pelos clientes. A intenção dessa explanação é conscientizar que voce escolhera quando sera melhor utilizar um serviço ou não, tudo vai depender do cenario em questão.

Serviço é a melhor alternativa, e agora o que faço?

Com base nisso, agora vamos as informações sobre a plataforma. O WCF foi criado a partir do .NET Framework 3.0. As classes mais importantes pra se trabalhar com o WCF estão contidas no assembly System.ServiceModel. Alem dele, temos outros assemblies que são importantes no uso do WCF que são System.Runtime.Serialization, System.ServiceModel.Web entre outros. Eu tenho por costume criar meus serviços de forma bem manual, então nos artigos na maioria das vezes optarei por criar o serviço a partir de um template Class Library e não pelos templates do WCF. Como eu disse, isso é uma preferencia minha :D . Porque eu comentei isso? Bom, é porque nos templates do WCF, esses assmblies ja estão adicionados por default, ja no caso de um class library deveremos adicionar manualmente essas referencias. Como o nosso amigo Evilazaro disse nesse post , a estrutura basica de um serviço consiste em:

- Host

- Contrato do serviço

- Contrato de Metadados

Alem deles, temos tambem os Endpoints.

Host

Pra quem não sabe, o WCF é bem flexivel quando o assunto é hosting. Como host, podemos utilizar o IIS, um Windows Service, um Console Application, um Windows Forms. Essa flexibilidade é bem legal, mas devemos saber escolher qual o melhor cenario para utilizalas. Até o IIS 6, apenas um protocolo era possivel de se utilizar nele, que é o HTTP. A partir do IIS 7, pode ser utilizado os demais protocolos. Ou seja, antigamente, se quisessemos utilizar um protocolo TCP por exemplo, teriamos que hostear nosso serviço em outro host que não o IIS, ja a partir do IIS 7, podemos hostear um serviço disponibilizado via TCP, MSMQ no proprio IIS. Isso é possivel devido a um componente, o WAS (Windows Activation Services). Dessa forma, o IIS não é mais somente um servidor Web e sim um servidor de aplicações. Qual host eu recomendo? Bom o IIS é uma otima escolha, principalmente com a integração com o App Fabric, os outros hosts, somente utilizados em cenarios especificos ou para teste tambem.

Contrato de metadados

O contrato de metadados é implementado pela interface/contrato IMetadataExchange. Ele permite a visualização dos metadados do seu serviço. Quando disponibilizamos o metadados do nosso serviço, fazemos uso do IMetadaExchange atraves de um endpoint especifico. O contrato de metadados pode ser disponibilizado por http ou tcp por exemplo.

Endpoint

Um endpoint é o canal de comunicação pelo qual o serviço é disponibilizado. A estrutura dele contem 3 informações basicas que são:

Address

O address é o endereço em si, por exemplo http://localhost:8080/MeuServico/. Quando o cliente for consumir o serviço, ele devera acessar ataves desse address.

Binding

Basicamente, o binding define o protocolo pelo qual voce ira disponibilizar o consumo do serviço, por exemplo via HTTP ou TCP. Existem outras caracteristicas do Binding que serão abordadas no futuro.

Contract

O contrato do seu serviço. Aqui deve ser especificado o fullname do seu contrato de serviço.

Um detalhe importante é que se voce esta expondo seu serviço via HTTP, o address dele tem que ser uma URI utilizando o protocolo HTTP (http://localhost:8080/, por exemplo).

Bom por hoje é isso galera prometo que no proximo post, vai ter codigo :) . Até o proximo post! \m/

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.