InstallShield LE ou WiX ?

Recentemente tivemos a notícia que a Microsoft irá descontinuar os templates de projetos de instalação (Setup Project e outros) nas próximas versões do Visual Studio. A seguinte informação existe na documentação do MSDN.

Future versions of Visual Studio will not include the Visual Studio Installer project templates. To preserve existing customer investments in Visual Studio Installer projects, Microsoft will continue to support the Visual Studio Installer projects that shipped with Visual Studio 2010 per the product life-cycle strategy.

De acordo com a Flexera Software Jazon Zander, vice-presidente corporativo do Visual Studio, disse que o InstallShield deve ser a escolha para o ambiente de desenvolvimento de usuários do Visual Studio.

No Visual Studio 2010 podemos criar projetos de instalação utilizando uma versão gratuita do InstallShield que é chamada de InstallShield LE (Limited Edition). Mais informações sobre como utilizar essa versão você pode encontrar aqui e aqui.

Na semana passada tive a oportunidade de avaliar esse produto na criação de um instalador simples para uma aplicação C++ 64-bit que deveria incluir o merge module do MFC 10.0 (x64). Criar um instalador para uma aplicação desse tipo usando o Setup Project é relativamente simples, não tem muito segredo.

Bom, depois de alguma pesquisa e de alguns erros estranhos descobri que a versão LE não possui suporte a criação de instaladores de aplicações 64-bit. Pior, a versão Express que custa em torno de U$ 500 também não. O que resta então é a versão Professional, que possui esse suporte mas que custa U$ 1999.

Uma outra opção é o WiX (Windows Installer XML) que é um projeto open-source hospedado no Codeplex e que possui um conjunto de ferramentas para criar pacotes de instalação com base em código XML. De acordo com esse artigo, o WiX é utilizado nos instaladores do Visual Studio e do Microsoft Office. Considerando que o WiX estava cotado para ser entregue juntamente com o Visual Studio 2010 em abril e isso não aconteceu, fico com dúvidas sobre se devo investir algum tempo estudando essa tecnologia.

Considerando o preço da versão Professional do InstallShield e da falta de apoio da Microsoft quanto ao WiX, fico na dúvida sobre qual das opções devo utilizar.

Update

Recentemente estive um pouco longe do blog e das minhas atividades no fórum do MSDN. Estou retornando aos poucos e espero ter mais tempo para poder compartilhar e adquirir mais conhecimento com a comunidade de desenvolvedores.

Só para atualizar…

1 – Em setembro estive presente no TechEd em São Paulo e devo admitir que foi uma experiência fantástica. Estar perto de tantos desenvolvedores e assistir a palestras muito interessantes foi realmente muito bom. Não vou falar muita coisa sobre o evento pois muitos outros já disseram (aqui, aqui, aqui e aqui são alguns exemplos).

2 – Sou oficialmente Moderador de alguns fóruns do MSDN Brasil (.NET, C#, Windows Forms, Silverlight e WPF). Tive a felicidade de ser convidado para exercer esse papel e espero poder contribuir da melhor forma possível.

3 – No final de outubro aconteceu o PDC 2010 e tivemos várias apresentações interessantes. Vale destacar a apresentação do Anders Hejslberg que demonstrou algumas funcionalidades de programação assíncrona e do compilador como um serviço. Além disso, tivemos várias apresentações e informações sobre o Windows Phone 7 (WPF), Windows Azure e também a famosa polêmica do Silverlight.

Uma outra informação…

Fiquei um pouco longe pois estive estudando recentemente o DirectX 11 (não gerenciado) e fiquei perplexo com a péssima qualidade da documentação do MSDN sobre o Direct3D. É extremamente confuso e também faltam alguns exemplos e informações mais objetivas de como e onde utilizar determinadas classes. A documentação do Direct2D é bem completa.

Mas porquê estou estudando DirectX não gerenciado? Porque infelizmente para determinadas aplicações o .NET não oferece a performance desejada.

É um tanto difícil voltar a desenvolver em C/C++ depois de muitos anos com o .NET mas estou gostando da experiência.

Microsoft TechEd Brasil 2010

Este ano terei o privilégio de participar Microsoft TechEd Brasil 2010 que acontecerá em São Paulo nos dias 13 a 15 de setembro. O TechEd é um evento para desenvolvedores e profissionais de TI que utilizam tecnologia Microsoft em seu dia-a-dia. Serão 3 dias de palestras, novidades e encontros com os maiores “nomes” da comunidade e funcionários da própria Microsoft.

teched_250x250Não participei das outras edições do evento e também nunca participei de um evento tão grande como esse. Normalmente acompanho os grandes eventos pela internet assistindo aos vídeos ou por meio do Twitter. Esse ano estarei presente e terei a oportunidade de chegar mais perto da comunidade, ou seja, aquelas pessoas que conhecemos pelos fóruns do MSDN ou cujo blog seguimos.

Devo também destacar que fui convidado pela Microsoft para participar pela primeira vez do Community Zone, que é um evento voltado para profissionais que atuam na comunidade. Esse evento irá se realizar nos dias 16 e 17 de setembro.

Fiquei muito feliz pelo convite mas também triste por não poder participar, espero poder estar presente em futuras edições.

Segue abaixo a minha agenda para o TechEd.

Programação do dia 13/09/2010

13:45 - 15:00  ASP.NET MVC para desenvolvedores Web Forms
15:30 - 16:45  Arquitetura de Soluções com o Windows Server AppFabric, WCF e WF - Patterns de Aplicações, Serviços e Workflows
17:15 - 18:30  Scrum Process Template para TFS 2010: Seja ágil de verdade!

Programação do dia 14/09/2010

09:00 - 10:15  Windows Server AppFabric Caching - construindo aplicações com alto desempenho na plataforma Microsoft
10:45 - 12:00  Tudo que você sempre quis saber sobre o Windows Presentation Foundation (WPF) 4
13:45 - 15:00  Primeiros passos no Team Foundation Server 2010
15:30 - 16:45  Implementando Serviços RESTful usando o Microsoft .NET Framework
17:15 - 18:30  Aplicações WEB com Silverlight 4 fora do Browser

Programação do dia 15/09/2010

09:00 - 10:15  Usando o pattern MVVM (Model-View-ViewModel) para desenvolvimento em WPF e Silverlight
10:45 - 12:00  Como e onde devo utilizar o Managed Extensibility Framework (MEF) 
13:45 - 15:00  Criando Rich Internet Applications (RIA) com Silverlight 4 e WCF RIA Services
15:30 - 16:45  Paralelismo no .Net 4.0: Patterns, dicas e truques

Obs: Acho que não poderei participar da última palestra do dia 15 devido ao horário do meu voo.

Aguardo vocês lá.

Extendendo a ESRI ArcGIS API For Microsoft Silverlight/WPF – Parte 2

Na segunda parte desse post irei demonstrar como utilizar o método de extensão.

How can I use it?

Para utilizar o método de extensão vamos criar uma aplicação Silverlight simples que irá mostrar a informação de um layer oriundo de um serviço da ESRI.

Criamos então uma nova aplicação Silverlight 4 no Visual Studio 2010.

Adicione uma referência ao projeto que contém o método de extensão e também ao assembly ESRI.ArcGIS.Client.

Coloque o seguinte código no arquivo MainPage.xaml.

<UserControl x:Class="ArcGISServerAPIExtensionSample.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
             mc:Ignorable="d">

    <Grid x:Name="LayoutRoot">

        <esri:Map x:Name="MainMap">
            <esri:ArcGISDynamicMapServiceLayer ID="DynamicLayer"
                                               Url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer"
                                               Initialized="ArcGISDynamicMapServiceLayer_Initialized" />
        </esri:Map>

        <Grid Background="Black"
              Margin="10"
              Width="450"
              VerticalAlignment="Top"
              HorizontalAlignment="Left">

            <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="250" />
            </Grid.RowDefinitions>

            <ComboBox x:Name="cmbLayers"
                      HorizontalAlignment="Left"
                      Width="180"
                      Margin="2"
                      Grid.Row="0" />

            <Button x:Name="btnTeste"
                    Width="180"
                    Margin="2"
                    HorizontalAlignment="Left"
                    Content="Testar Método de Extensão"
                    Grid.Row="1"
                    Click="btnTeste_Click" />

            <TextBox x:Name="txtResultado"
                     Margin="2"
                     Grid.Row="2"
                     TextWrapping="Wrap" />

        </Grid>

    </Grid>
    
</UserControl>

O código XAML é bem simples e o objetivo é o usuário selecionar um layer no ComboBox e então clicar no Button, que realiza a chamada ao método de extensão.

No code-behind da página realize a inclusão dos namespaces abaixo:

using System.Text;
using ArcGISServerAPIExtension;
using ESRI.ArcGIS.Client;

Ainda no code-behind da página realize o data binding dos layers existentes no serviço DynamicLayer do mapa após o mesmo ser inicializado (evento Initialized).

private void ArcGISDynamicMapServiceLayer_Initialized(object sender, EventArgs e)
{
    // recupera layer
    var dynamicLayer = sender as ArcGISDynamicMapServiceLayer;

    // data binding
    this.cmbLayers.SelectedValuePath = "ID";
    this.cmbLayers.DisplayMemberPath = "Name";
    this.cmbLayers.ItemsSource = dynamicLayer.Layers;
}

Também faça a implementação do evento Click do Button para mostrar as informações do layer selecionado.

private void btnTeste_Click(object sender, RoutedEventArgs e)
{
    // verifica se algum layer foi selecionado
    if (this.cmbLayers.SelectedValue == null)
        return;

    // referência ao layer dinâmico que está no mapa
    var dynamicLayer = this.MainMap.Layers["DynamicLayer"] as ArcGISDynamicMapServiceLayer;

    dynamicLayer.GetLayerDetails((int)this.cmbLayers.SelectedValue, 
        (r) =>
        {
            // verifica erro
            if (r.Error != null)
            {
                this.txtResultado.Text = r.Error.Message;
                return;
            }

            // recupera resultado do método
            var layerDetails = r.Result;

            // cria string que contém as informações do layer
            var stringBuilder = new StringBuilder();

            // adiciona informações
            stringBuilder.AppendFormat("ID: {0}\n", layerDetails.ID);
            stringBuilder.AppendFormat("Name: {0}\n", layerDetails.Name);
            stringBuilder.AppendFormat("Description: {0}\n", layerDetails.Description);
            stringBuilder.AppendFormat("GeometryType: {0}\n", layerDetails.GeometryType);
            stringBuilder.AppendFormat("MinScale: {0}\n", layerDetails.MinScale);
            stringBuilder.AppendFormat("MaxScale: {0}\n", layerDetails.MaxScale);

            // adiciona campos (fields)
            stringBuilder.AppendLine("-----------------------");
            stringBuilder.AppendLine("Fields");
            stringBuilder.AppendLine("-----------------------");

            foreach (var field in layerDetails.Fields)
                stringBuilder.AppendLine(field.Name);

            this.txtResultado.Text = stringBuilder.ToString();
        }
    );
}

Esse método realiza o tratamento do método callback por meio de uma expressão lambda ( (r) =>) e mostra algumas das informações recuperadas do serviço.

Done !

O código-fonte do exemplo e do método de extensão você encontra aqui.

Espero que tenham gostado.

Extendendo a ESRI ArcGIS API For Microsoft Silverlight/WPF – Parte 1

Venho trabalhando com a ESRI ArcGIS For Microsoft Silverlight/WPF já há algum tempo (+- 5 meses) e percebi que diversas funcionalidades que existem em suas APIs irmãs (ArcGIS Server API For Flex e ArcGIS Server API For JavaScript) não estão disponíveis. Esse post irá demonstrar uma maneira de estender a API da ESRI para Silverlight/WPF com o objetivo de adquirir maiores informações sobre os serviços de mapas dinâmicos, ou seja, serviços de mapa que não possuem cache.

Observação: Esse post leva em consideração que o leitor possua conhecimento de desenvolvimento de aplicações de mapeamento na plataforma ESRI e que já possua um conhecimento mínimo da ArcGIS API For Microsoft Silverlight/WPF. No final do post vou indicar alguns links com maiores informações.

Introdução

O objetivo da ArcGIS API For Microsoft Silverlight/WPF é integrar serviços de mapa publicados no ArcGIS Server, dados espaciais armazenados no SQL Server 2008 (ESRI MapIt) ou até mesmo serviços do Bing Maps com aplicações desenvolvidas em Silverlight ou WPF.

O ArcGIS Server é um software servidor desenvolvido pela ESRI que permite a criação e a distribuição de dados espaciais por meio de serviços web. Uma característica interessante do ArcGIS Server é que este possui uma API que disponibiliza os serviços de mapas por meio de uma interface REST, ou seja, podemos utilizar os recursos e operações de cada serviço por meio de URLs.

A idéia então é criar um método de extensão na classe ArcGISDynamicMapServiceLayer que recupera essas informações usando a ArcGIS Server REST API e deserialização de dados no formato JSON.

Instalação e Requisitos Mínimos

Primeiramente temos que fazer o download da versão 2.0 Beta da ArcGIS Server API For Microsoft Silverlight/WPF, que somente funciona com o Silverlight 4 e consequentemente com o Visual Studio 2010 e Expression Blend 4. Para utilizar essa API você deve possuir um login na ESRI e então fazer o download do instalador neste link.

Por questões práticas irei pular as instruções de instalação e os requisitos mínimos para utilizar a API. Para mais informações veja esse vídeo.

Hands-On

A classe ArcGISDynamicMapServiceLayer possui uma propriedade que é um array de layers refresentados pela classe LayerInfo, que representa informações relativas a um layer. Infelizmente existem poucas informações disponíveis (ID, Name, DefaultVisibility e SubLayerIds). A ArcGIS REST API disponibiliza além dessas informações diversas outras, tais como: escala de visualização (minScale, maxScale), atributos, tipo de geometria e muitos outros.

Observação: As APIs do ArcGIS Server para Flex e JavaScript possuem essas informações, mas a API do Silverlight/WPF não. É bem possível que o que irei demonstrar aqui possa surgir em versões futuras da API.

Um exemplo desse recurso em formato JSON pode ser encontrado no exemplo da ESRI do link abaixo.
http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/1?f=json&pretty=true

Vejam uma parte desse recurso abaixo.

{
  "id" : 1, 
  "name" : "states", 
  "type" : "Feature Layer", 
  "geometryType" : "esriGeometryPolygon", 
  "description" : "This service provides ... ", 
  "definitionExpression" : "", 
  "copyrightText" : "(c) ESRI and its data partners", 
  "minScale" : 0, 
  "maxScale" : 0, 
  "extent" : {
    "xmin" : -178.217598362366, 
    "ymin" : 18.9247817993165, 
    "xmax" : -66.9692710360024, 
    "ymax" : 71.4062353532711, 
    "spatialReference" : {
      "wkid" : 4326
    }
  }, 
  "displayField" : "STATE_NAME", 
  "fields" : [
    {"name" : "OBJECTID", "type" : "esriFieldTypeOID", "alias" : "OBJECTID"}, 
    ...
    {"name" : "Shape_Area", "type" : "esriFieldTypeDouble", "alias" : "Shape_Area"}
  ], 
  "parentLayer" : null, 
  "subLayers" : []
}

Silverlight Class Library

Vamos agora criar o nosso projeto no Visual Studio 2010. No Startup Page clique em New Project, escolha o template Silverlight Class Library e dê o nome ArcGISServerAPIExtension.

Escolha a versão 4 do Silverlight como target da class library.

Helper Classes

Vamos agora criar algumas classes que irão representar as informações que iremos recuperar do serviço dinâmico de mapa.

Para isso primeiramente devemos fazer referência ao assembly System.Runtime.Serialization e System.ServiceModel.Web. O primeiro possibilita a criação ou implementação de contratos usando os atributos DataContractAttribute e DataMemberAttribute, já o segundo possui a classe DataContractJsonSerializer que realiza serialização em objetos no formato JSON.

Observação: A classe DataContractJsonSerializer encontra-se no assembly System.ServiceModel.Web mas no namespace System.Runtime.Serialization.Json. Não me perguntem o porquê.

Vamos fazer a referência também do assembly ESRI.ArcGIS.Client que contém a classe ArcGISDynamicMapServiceLayer.

A classe FieldDetails irá representar algumas informações referentes a um dos atributos de um layer.

[DataContract]
public class FieldDetails
{
    [DataMember(Name="name")]
    public string Name { get; set; }

    [DataMember(Name = "type")]
    public string Type { get; set; }

    [DataMember(Name = "alias")]
    public string Alias { get; set; }
}

O parâmetro Name do DataMember mapeia a propriedade à informação correspondente disponibilizada no serviço de mapa. Perceba que os nomes mapeados encontram-se no array fields do exemplo do recurso REST mostrado anteriormente.

A classe LayerDetails irá representar algumas informações de um layer e seu conjunto de atributos em forma de um array

[DataContract]
public class LayerDetails
{
    [DataMember(Name = "id")]
    public int ID { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }

    [DataMember(Name = "description")]
    public string Description { get; set; }

    [DataMember(Name = "geometryType")]
    public string GeometryType { get; set; }

    [DataMember(Name = "minScale")]
    public double MinScale { get; set; }

    [DataMember(Name = "maxScale")]
    public double MaxScale { get; set; }

    [DataMember(Name = "fields")]
    public FieldDetails[] Fields { get; set; }
}

Observação: Por praticidade não irei mapear todas as informações do layer. Se necessário, realize o mapeamento na classe acima.

Uma outra classe chamada GetLayerDetailsResult também será criada com o objetivo de retornar as informações para um método callback, que será explicado posteriormente.

public class GetLayerDetailsResult
{
    public LayerDetails Result { get; set; }
    public Exception Error { get; set; }
    public object UserState { get; set; }
}

Extension Method

Vamos então criar uma nova classe em nosso projeto com um método chamado GetLayerDetails que será o método de extensão da classe ArcGISDynamicMapServiceLayer.

public static void GetLayerDetails(this ArcGISDynamicMapServiceLayer dynamicLayer, 
    int layerId, object userState, 
    Action<GetLayerDetailsResult> resultCallback)
{
    var webClient = new WebClient();
    webClient.DownloadStringCompleted += (s, a) =>;
    {
        // verifica erro
        if (a.Error != null)
        {
            // executa método callback (retorna null, se erro)
            resultCallback(
                new GetLayerDetailsResult {
                    Error = a.Error, 
                    Result = null, 
                    UserState = userState }
            );
            return;
        }

        // transforma string em uma stream na memória
        var bytes = Encoding.Unicode.GetBytes(a.Result);
        var memStream = new MemoryStream(bytes);

        // deserializa a stream com base no contrato definido na classe LayerDetails
        var dataContractJson = new DataContractJsonSerializer(typeof(LayerDetails));
        var layerDetails = (LayerDetails)dataContractJson.ReadObject(memStream);

        // executa método callback
        resultCallback(
            new GetLayerDetailsResult { 
                Error = null, 
                Result = layerDetails, 
                UserState = userState }
        );
    };

    // realiza download da string conforme URL padrão
    // [url do serviço]/[id do layer]?f=json }
    webClient.DownloadStringAsync(new Uri(dynamicLayer.Url + @"/" + layerId + "?f=json"));
}

Os comentários são auto-explicativos, mas vou explicar algumas partes do código.

O método possui os seguintes parâmetros:
  • layerId – o ID do layer cujas informações serão recuperadas.
  • userState – um objeto que representa o estado do usuário.
  • resultCallback – método que será chamado quando o método GetLayerDetails terminar o processamento.
Utilizamos a classe WebClient para realizar uma requisição na URL do serviço de forma assíncrona e recuperar uma string com o conteúdo da requisição, ou seja, um conteúdo tal como o que foi apresentado no exemplo da ESRI de um recurso REST.

Com a string, transformamos a mesma em um objeto MemoryStream e utilizamos a classe DataContractJsonSerializer para deserializar a string com conteúdo JSON em um objeto da classe LayerDetails.

O método resultCallback é executado e entrega para o cliente da classe informações sobre o processamento por meio da classe GetLayerDetailsResult. Com essa classe podemos verificar se ocorreu um erro (propriedade Error) ou recuperar as informações do layer (propriedade LayerDetails), que é o resultado do processamento do método.

A implementação desse método surgiu com a necessidade em um projeto de recuperar as escalas máxima e mínima de visualização de um layer para habilitar ou desabilitar o mesmo em uma legenda de acordo com o zoom atual do mapa. O único plágio foi copiar o nome do método da API do Flex, que você encontra aqui.

Em uma segunda parte desse post, explicarei como utilizar essa classe.

Links diversos:

ArcGIS Server
http://bit.ly/pLj3T

ArcGIS Server REST API
http://bit.ly/8KLgfe

ESRI Products
http://bit.ly/cyduyV

ArcGIS API for Microsoft Silverlight/WPF
http://bit.ly/cgUZ5o

DataContractAttribute Class
http://bit.ly/9286VZ

DataContractJsonSerializer Class
http://bit.ly/bobuuI

WebClient Class
http://bit.ly/aDEK9N