Compartilhar via


.NET Core Framework

Vá de plataforma cruzada com o .NET Framework

Cheryl Simmons

A maioria dos desenvolvedores prefere escrever seu código de lógica comercial uma vez e reutilizá-lo posteriormente. Essa é uma abordagem muito mais fácil do que criar aplicativos diferentes para várias plataformas de destino. Lançamentos recentes sobre o .NET Core — uma versão dividida em componentes do Microsoft .NET Framework — e a próxima parceria da Microsoft e Xamarin significa que, se você criar Bibliotecas de Classes Portáteis (PCLs) compatíveis com .NET Core, estará mais próximo dessa realidade do que nunca.

E enquanto suas bibliotecas do .NET Framework existentes? Quanto trabalho levará para torná-las compatíveis entre plataformas e convertê-las em PCLs? Entre no .NET Portability Analyzer. Usar algumas técnicas simples e fazer algumas alterações no arquivo do projeto pode ajudar a facilitar o processo.

A ferramenta .NET Portability Analyzer é uma extensão do Visual Studio criada pela equipe do .NET Framework. Você pode usá-la com qualquer versão recente do Visual Studio que oferece suporte às extensões. Basta apontar o Portability Analyzer em seus assemblies ou projetos e a ferramenta fornece um relatório de resumo detalhado e recomendações sobre as APIs que você deve usar para aumentar a compatibilidade. Para projetos, a ferramenta lista mensagens de erro e leva você para as linhas de código que você precisa alterar. A ferramenta também fornece resultados para as principais plataformas da Microsoft e você pode configurá-la para fornecer resultados de outras plataformas, como Mono e Xamarin.

O .NET Portability Analyzer tem um aplicativo de console irmão chamado API Portability Analyzer (você pode baixá-lo em aka.ms/w1vcle) que gera resultados semelhantes aos que o Portability Analyzer gera. Neste artigo, falarei sobre como usar a extensão do Visual Studio. Também é importante observar que pode haver algumas atualizações para a extensão do .NET Portability Analyzer entre quando este artigo foi escrito e sua data de publicação, portanto, a aparência da ferramenta pode diferir entre as imagens vistas aqui.

Preparar-se para o sucesso

Para uma biblioteca ser executada com êxito entre plataformas, ela deve ser bem fatorada e conter principalmente a lógica de negócios. O código da interface do usuário deve ser separado em outros projetos. No entanto, como o .NET COre é um subconjunto do .NET Framework, mesmo que seu código for bem fatorado, suas bibliotecas talvez estejam usando APIs que não têm suporte no .NET Core.

Em alguns casos, há APIs alternativas que realizam a mesma coisa. Nesses casos, o Portability Analyzer sugerirá uma API alternativa. Em outros casos, não há nenhum substituto e você precisará fatorar o código específico da plataforma. Finalmente, mesmo se você não tiver ideia do quanto um assembly é fatorado, é possível usar o Portability Analyzer para realizar uma avaliação rápida.

Para usar a extensão, você precisará do Visual Studio 2013 ou 2014. A próxima etapa é instalar a extensão. Você pode encontrá-la pesquisando o .NET Portability Analyzer na Galeria do Visual Studio ou ir diretamente para aka.ms/lah74y.

Clique no botão Baixar e selecione Abrir. A próxima caixa de diálogo permite que você escolha a versão do Visual Studio na qual você deseja aplicar a extensão. Clique em Instalar, que inicia a instalação e em Fechar para fechar a caixa de diálogo. Agora você está pronto para escolher as plataformas de destino e analisar assemblies ou projetos.

Escolha as plataformas de destino

O Portability Analyzer fornece resultados para o .NET Framework, ASP.NET vNext (também conhecido como .NET Core), Windows e Windows Phone, por padrão. Você pode especificar opções adicionais acessando a entrada do .NET Portability Analyzer no menu Ferramentas | Opções no Visual Studio e selecionando o conjunto de plataformas você gostaria de orientar, conforme mostrado na Figura 1.

Selecione as plataformas de destino para o seu projeto
Figura 1 Selecione as plataformas de destino para o seu projeto

Executar o Portability Analyzer

Há duas maneiras que você pode analisar seus projetos e assemblies:

  • Para analisar assemblies já construídos ou arquivos executáveis, acesse o Portability Analyzer no menu Analisar do Visual Studio e navegue até o local do assembly. Com essa opção, a ferramenta gera um relatório resumido e detalhado.
  • Para analisar os projetos, clique com botão direito do mouse no projeto de destino no Gerenciador de Soluções. Escolha Analisar | Analisar Portabilidade do Assembly (veja a Figura 2), que é específico para o projeto selecionado. Com essa opção, a ferramenta gera um resumo, um relatório detalhado e uma mensagem para a Lista de Erros que fornece um nome de arquivo e o número de linha onde o problema ocorre. Você pode também clicar duas vezes em cada mensagem e a ferramenta navega para a linha de código especificada.

Selecionando Analisar Portabilidade do Assembly para um projeto específico
Figura 2 Selecionando Analisar Portabilidade do Assembly para um projeto específico

Para testar a ferramenta, abri um projeto em que eu trabalhei cerca de um ano atrás, um jogo de palavras que tem como alvo o Windows Phone Silverlight 8. Eu comecei com minha lógica de negócios em uma Biblioteca de Classe Portátil (PCL) voltada para Windows Phone 8 e Windows 8. A ideia era reutilizar a biblioteca para implementar o mesmo aplicativo para Windows. No entanto, eu enfrentei alguns problemas e estava com pressa, portanto, mudei minha abordagem e minha biblioteca agora é destinada somente para o Windows Phone Silverlight 8.

Meu plano é analisar a portabilidade da biblioteca, fazer as alterações de código necessárias, converter o projeto para um projeto PCL e redirecioná-lo para Windows 8.1, Windows Phone 8.1 e Windows Phone Silverlight 8.1. Também desejo testar sua compatibilidade com o .NET Core. O Portability Analyzer me dá uma visão do trabalho que preciso fazer sem realmente converter o projeto, alterando os destinos e tentando classificar os erros de compilação. Também estou curioso para saber se posso usar minha biblioteca para criar um aplicativo Android, portanto, eu configurei a ferramenta para fornecer resultados também para Xamarin.Android.

Eu executo a ferramenta e os resultados são incentivadores. A Figura 3 mostra o relatório de resumo detalhado, as mensagens de erro e a URL do relatório. De acordo com o resumo, posso ver que minha biblioteca é bastante compatível com todas as plataformas. É totalmente compatível com o Windows Phone Silverlight 8.1, o que não é surpreendente, considerando o que Windows Phone Silverlight 8 foi o destino original.

O relatório de compatibilidade detalhado mostrando plataformas compatíveis
Figura 3 O relatório de compatibilidade detalhado mostrando plataformas compatíveis

Os resultados detalhados são uma exibição do tipo planilha apenas das APIs que não oferecem suporte a uma ou mais das minhas plataformas de destino. É fácil verificar os detalhes. Eles estão marcados com um X vermelho para indicada onde uma API não é suportada e uma marca de seleção verde para indicar suporte. É importante observar as APIs com suporte em todas as plataformas e que, portanto, não exigem qualquer refatoração, não será exibido no relatório.

Os detalhes também incluem uma coluna de alterações recomendadas, que aponta para APIs alternativas que funcionam em várias plataformas. Na parte inferior dos detalhes, o relatório inclui um link Voltar para o Resumo. Isso navega de volta para o resumo na parte superior. Meus resultados são muito curtos, mas para mais relatórios mais longos, essa funcionalidade "retorno ao início" é útil.

Como analisei um projeto, meu relatório contém mensagens da Lista de Erros que indicam o arquivo e o número da linha onde ocorre o uso. Se eu clicar na mensagem, a ferramenta me leva para o arquivo e a linha indicada pela mensagem.

Se você deseja acessar os resultados fora do Visual Studio, eles são armazenados em um arquivo HTML (ApiPortability­Analysis.htm) localizado no mesmo diretório de projeto do assembly de destino. O local é indicado na seção da URL na parte superior do relatório, conforme mostrado na Figura 4.

Resultados do Portability Analysis armazenados para acesso externo do Visual Studio
Figura 4 Resultados do Portability Analysis armazenados para acesso externo do Visual Studio

Trabalho em andamento

O .NET Portability Analysis, seus resultados e orientações devem alterar conforme a equipe .NET reúne mais informações (consulte a Figura 5). A equipe de coleta dados anônimos sobre o uso da API quando você usa a ferramenta ou seu equivalente do aplicativo de console e é resumido em bit.ly/14vciaD.

Esse site mostra os níveis de uso da API do .NET
Figura 5 Esse site mostra os níveis de uso da API do .NET

Esse site é padrão para mostrar as APIs que exigem a maioria das alterações de código. Você pode mudar isso alterando o valor na lista suspensa Mostrar (não mostrado na imagem). Você também pode passar o mouse sobre os ícones "R" ou "S" e ver as mesmas recomendações de código mostradas pelo Portability Analyzer.

Cada nome de API na lista é um link que leva você para uma página de relatório na qual as plataformas dessa API são suportadas. A equipe planeja continuar a atualizar o site e abri-lo nas contribuições de cliente. Portanto, verifique periodicamente.

Executar a biblioteca de plataforma cruzada

Agora é hora de corrigir minha biblioteca. Sei que eu quero que minha biblioteca funcione com o Windows Phone 8.1 e Windows 8.1 e vejo alguns problemas. Usarei uma abordagem diferente para cada um dos problemas.

Usar abstração de plataforma Há duas entradas relacionados ao fluxo do recurso. De acordo com o relatório, essas APIs não são suportadas no Windows 8.1 ou Windows Phone 8.1. A ferramenta não recomenda qualquer API que eu possa substituir, portanto, preciso remover esse código da minha biblioteca. O relatório informa que esses dois membros são usados nas mesmas poucas linhas de código, que carrega um arquivo de dicionário estático:

WordList = new ObservableCollection<string>();
StreamResourceInfo info =
  Application.GetResourceStream(new
  Uri("/WordLibWP;component/US.dic", UriKind.Relative));
StreamReader reader = new StreamReader(info.Stream);
string line;
while ((line = reader.ReadLine()) != null)
{
  WordList.Add(line);
}
reader.close();

Eu sei que posso usar as APIs do Windows.Storage no Windows 8.1 e Windows Phone 8.1 para carregar um arquivo de recurso, mas minha biblioteca não seria compatível com o Windows Phone Silverlight. Para um alcance mais amplo, eu decidi abstrair este trecho de código específico da plataforma. A abstração de plataforma é uma técnica útil para fornecer uma biblioteca que define o comportamento, mas implemente esse comportamento de forma diferente no código específico da plataforma. Se desejar que seu código seja compatível entre plataformas, é uma técnica com os quais você deve estar familiarizado.

Aqui estão as etapas básicas que percorri para fazer isso:

  • Defina o comportamento da biblioteca entre plataformas: Para fazer isso, eu criei uma classe abstrata na biblioteca que define um método para ler o arquivo de dicionário. Também defini uma propriedade que é uma instância da minha classe DictionaryReader. Algo parecido com isto:
public abstract class DictionaryReader
{
  public abstract Task<ObservableCollection<string>>
    ReadDictionaryAsync(string path);
  public static DictionaryReader Instance { get; set; }
}
  • Implemente o comportamento no código específico da plataforma: Para fazer isso, eu derivo da classe DictionaryReader no projeto do Windows Phone Silverlight. Vou fornecer uma implementação do método ReadDictionaryAsync que carrega e lê o arquivo de dicionário como um recurso de aplicativo. Observe que esse código é basicamente o mesmo que o código em minha biblioteca, com alguma verificação de erro no caminho do recurso porque eu preciso de um formato específico para que meu código de telefone funcione. Minha implementação para outras plataformas será diferente dependendo das técnicas para leitura de um recurso de aplicativo local para essas plataformas. No entanto, com a abstração que eu adicionei — conforme mostrado na Figura 6— isso não deve ser um problema.
  • Inicializar a instância definida pela biblioteca para a implementação especifica da plataforma: Para fazer isso, eu adiciono código para a classe App do meu projeto do Windows Phone. Esse código inicializa a instância de DictionaryReader para minha implementação específica do telefone que lê o arquivo como um recurso. Novamente, esse código está no meu projeto específico da plataforma e não no projeto analisado:
public App()
{
  DictionaryReader.Instance = new DictionaryReaderPhone();
...
}

Figura 6 Implementação de telefone para carregar e ler dicionário

class DictionaryReaderPhone : DictionaryReader
{
  public override async Task<ObservableCollection<string>>
  ReadDictionaryAsync(string resourcePath)
{
  ObservableCollection<string> wordList =
    new ObservableCollection<string>();
  StreamResourceInfo info =
    Application.GetResourceStream(new Uri(resourcePath,
    UriKind.Relative));
  if (info == null)
    throw new ArgumentException("Could not load resource: " +
      resourcePath +
      ". For Windows Phone this should be in the
      Format:[project];component/[filename]");
  else
  {
    StreamReader reader = new StreamReader(info.Stream);
    string line;
    while ((line = await reader.ReadLineAsync()) != null)
    {
    wordList.Add(line);
    }
    reader.Close();
    return wordList;
    }
  }
}

Outro exemplo que mostra como abstrair código específico da plataforma, consulte o artigo da biblioteca MSDN, "Abstração de plataforma com a biblioteca de classe portátil", em aka.ms/q4sq7l.

Usar uma API diferente Em seguida, posso avaliar a entrada para obter o nome da cultura atual. Eu cliquei duas vezes na mensagem de erro e encontrei esse método:

public string CheckLanguage()
{
  return Thread.CurrentThread.CurrentCulture.Name.Split('-')[0];
}

De acordo com o Portability Analyzer, posso usar CultureInfo.CurrentCulture. Como CurrentCulture é uma propriedade estática de CultureInfo e fornece as mesmas informações obtidas do thread atual, deve funcionar bem. Posso substituir o código que depende da obtenção da classe Thread com o código a seguir, que usa CultureInfo:

public string CheckLanguage()
{
  return System.Globalization.CultureInfo.CurrentCulture.Name.Split('-')[0];
}

Até aqui tudo bem.

Eu testo minhas alterações e tudo parece certo. Em seguida, eu executo novamente o Portability Analyzer. Meu relatório está limpo, com apenas algumas alterações de código, e eu selecionei o suporte para Xamarin.Android além dos meus destinos de plataforma originais, conforme mostrado na Figura 7.

Execute novamente o relatório de análise após as alterações de código
Figura 7 Execute novamente o relatório de análise após as alterações de código

A etapa final para meu conversão de plataformas cruzada é converter o projeto de biblioteca de um projeto de biblioteca específico de telefone para um PCL que posso referenciar por vários aplicativos. Inicialmente, pensei que a maneira mais fácil e rápida de fazer isso seria fazer uma conversão "local" ao modificar manualmente o arquivo de projeto.

Depois de fazer algumas pesquisas e experimentar algumas das etapas descobertas, cheguei à conclusão que não há nenhuma vantagem visível para modificar o arquivo de projeto manualmente. Eu verifiquei novamente com um membro da equipe do .NET e ele concordou. Grande parte da ajuda que você encontrará para modificar manualmente um projeto pressupõe um determinado ponto de partida.

Dependendo de seu histórico de projetos e quaisquer outras atualizações realizadas, você pode acabar com um projeto quebrado. É provável que você precise criar um novo projeto PCL depois de gastar tempo tentando convertê-lo manualmente. Além disso, mesmo que seu projeto convertido manualmente funcione inicialmente, ele pode ser desfeito se você fizer outras alterações.

Como resultado, criei um novo projeto PCL e recomendo que você faça o mesmo. Eu copiei meus arquivos de código para o novo projeto. Depois que eu copiei o código, recebi alguns erros de compilação devido ao uso de instruções que não são mais aplicadas ao novo PCL. Eu as removi e minha biblioteca estava pronta. Alternei meu aplicativo Windows Phone Silverlight para fazer referência a minha nova PCL e meu aplicativo estava funcionando novamente.

Experimente

Usar o Portability Analyzer não só me ajudou a avaliar rapidamente o trabalho que eu precisava fazer para tornar minha biblioteca de plataforma cruzada, mas identificou qualquer problema específico da plataforma para minhas chamadas de método e uso de propriedade. Também fez sugestões de API onde as alternativas estavam disponíveis.

Também mostrei técnicas para fatorar o código específico da plataforma. Meus novos resultados do Portability Analyzer indicam que minha biblioteca será executada em outras plataformas que gostaria, bem como Xamarin.Android. Finalmente, consegui criar uma nova PCL com os novos destinos e fazer referência a essa PCL do meu aplicativo existente. O novo .NET Portability Analyzer lhe ajudará a levar suas bibliotecas para novas plataformas.


Cheryl Simmons tem sido uma escritora de programação na Microsoft há dez anos e escreveu sobre as bibliotecas de classe Base .NET, Windows Forms, Windows Presentation Foundation, Silverlight, Windows Phone e ferramentas relacionadas.

Agradecemos aos seguintes especialistas técnicos da Microsoft pela revisão deste artigo: Matt Galbraith, Daniel Plaisted e Taylor Southwick