Pontos de Dados

A mistura de EF6, EF7 e ASP.NET 5

Julie Lerman

Julie LermanMinha coluna Pontos de dados de janeiro de 2015”, “Antecipando o Entity Framework 7”, destaquei o que esperar do EF7 examinando o estado do EF7 alfa no momento em que escrevi o artigo. Em dezembro de 2014, assim que a edição da coluna estava sendo publicada, a equipe do EF tomou uma decisão importante sobre a preparação das versões do EF7. Consegui espremer duas frases no artigo no último minuto: “De acordo com a publicação em bit.ly/1ykagF0, ‘EF7 - Priorities, Focus and Initial Release’, a primeira versão do EF7 se concentrará na compatibilidade com o ASP.NET 5. As versões subsequentes adicionarão mais recursos.”

Desde então, procurei descobrir por que, exatamente, isso parece estar um pouco confuso. Quero ter certeza de que você compreende bem para que essa versão inicial do EF7 está destinada, se você deve usá-la e quais são suas opções.

Ele ajudará a discutir a diferença entre a próxima versão do Microsoft .NET Framework e o quais os aplicativos do ASP.NET 5 serão executados nela. Fornecerei uma visão detalhada, mas leia o artigo de Daniel Roth, “Deep Dive into the ASP.NET 5 Runtime”, da edição de março de 2015 para obter uma compreensão mais profunda. Em seguida, explicarei como o EF6 e o EF7 são usados em combinação.

O ASP.NET 5 (também conhecido como o ASP.NET vNext) foi projetado para depender menos do .NET Framework completo e até mesmo do próprio Windows. Sob o guarda-chuva do ASP.NET 5, você pode criar aplicativos e APIs da Web usando o novo recurso combinado definido no ASP.NET MVC 6, bibliotecas de classes e até mesmo um aplicativo de console. Se você pensar no ASP.NET como uma maneira de criar sites da Web, o aplicativo de console é um mistério. Mas o ASP.NET 5 está realmente fornecendo uma nova “versão” do .NET Framework, nos quais os aplicativos podem ser colocados. Na verdade, essa nova versão tem atualmente dois tipos: um que é executado sobre o Common Language Runtime (Tempo de Execução do Linguagem Comum - CLR) e outro que é executado no novo CoreCLR. Um terceiro, que será executado em uma plataforma cruzada CLR, será adicionado em breve. A versão mais simplificada é chamada de .NET Core, que é executada em um tempo de execução otimizado, o CoreCLR. Se você lembrar das primeiras lições sobre o .NET Framework, você deve se lembrar que a Microsoft definiu a Common Language Infrastructure (Infraestrutura de linguagem comum - CLI), que é uma especificação. Em seguida, a Microsoft criou o CLR baseado na CLI. O Mono é outra implementação da CLI que é executada no Linux e Mac OS X. Aplicativos .NET sempre dependeram da disponibilidade de uma implementação de CLI. A maioria de nós usou o Visual Studio e o Windows para criar aplicativos .NET que dependem do CLR. O Xamarin tornou-se cada vez mais popular para desenvolvimento de aplicativos que podem ser executados em Mono.

O CoreCLR e o Entity Framework

Agora, a Microsoft criou uma implementação simplificada da CLI chamado o CoreCLR que não é apenas um código-fonte aberto, mas também pode ser distribuído pelo NuGet e outros gerenciadores de pacote. Isso proporciona aos desenvolvedores a capacidade de criar aplicativos leves que são excelentes para dispositivos móveis e aplicativos de servidor baseados em nuvem. E também remove a restrição para implantar aplicativos apenas em máquinas Windows.

O Entity Framework 6 (e versões anteriores) se baseiam no .NET Framework completo e o CLR completo e não serão executados em aplicativos visando o CoreCLR. Mas o EF7 foi projetado como um conjunto de APIs menores, combináveis que podem ser misturadas e combinadas com base no conjunto de recursos que você precisa. Por exemplo, se você estiver visando um repositório de dados não relacional, você não precisa dos recursos relacionais ou de migrações que são projetados para bancos de dados relacionais. Com o EF7, essa lógica está em uma DLL separada que você não precisará recuperar e carregar na memória.

Quando você escolhe direcionar o CoreCLR, você pode fazer isso selecionando o ambiente de tempo de execução correto. Junto com o ASP.NET 5, a Microsoft criou o Ambiente de Tempo de Execução K (KRE) o qual, conforme descrito pelo ASP.NET MVP Gunnar Peipman, “... é o código necessário para inicializar e executar um aplicativo do ASP.NET vNext. O Tempo de Execução K será renomeado em algum ponto antes do lançamento. Fique atento a esta mudança. Por exemplo, o KVM (Gerenciador de versão) se tornará o DNVM (Gerenciador de versão do .NET). O tempo de execução inclui coisas como o sistema de compilação, as ferramentas do SDK e os hosts CLR nativos”(bit.ly/1x9rpOn). Existem versões de 32 bits e 64 bits do KRE que suportam o CoreCLR. Você pode vê-las como opções de destino do aplicativo ASP.NET 5 na Figura 1.

Selecionando o KRE de destino em um aplicativo ASP.NET 5
Figura 1 Selecionando o KRE de destino em um aplicativo ASP.NET 5

A maneira mais fácil de ver o EF7 em um aplicativo, fora assistir ao vídeo de demonstração no meu curso Pluralsight, “Antecipando o Entity Framework 7” (bit.ly/18ct13F), é usar o modelo de projeto ASP.NET 5, que lhe dará uma solução com o EF7 já conectado para fornecer uma autenticação baseada em identidade em seu aplicativo.

Comece escolhendo um aplicativo Web ASP.NET e, em seguida, o modelo da Web do ASP.NET 5 Starter, conforme mostrado na Figura 2.

Criando um novo aplicativo ASP.NET 5 com o Entity Framework 7 pré-configurado
Figura 2 Criando um novo aplicativo ASP.NET 5 com o Entity Framework 7 pré-configurado

Você descobrirá que os pacotes do EF7 EntityFramework.SqlServer e EntityFramework.Commands já estão selecionados. O pacote SqlServer fará com que suas dependências (EntityFramework.Core, EntityFramework.Relational) sejam incorporadas.

Você pode ver isso no arquivo project.json, que lista os pacotes para o NuGet recuperar na sua seção de dependências. Aqui estão algumas linhas de seção:

"dependencies": {
  "EntityFramework.SqlServer": "7.0.0-beta2",
  "EntityFramework.Commands": "7.0.0-beta2",
  "Microsoft.AspNet.Mvc": "6.0.0-beta2",

Você também pode ver o que acaba na seção referências, que lista as referências para o ASP.NET 5.0 e versões do ASP.NET Core 5.0 do aplicativo por padrão. Figura 3 mostra a listagem com as referências do ASP.NET Core 5.0 expandidas. Observe que porque o modelo atualmente tem como alvo a versão beta2, você verá o pacote de migrações referenciado, embora em uma versão posterior, as migrações tornaram-se parte da API relacional.

ASP.NET 5.0 e referências do ASP.NET Core 5.0 que contém os pacotes do Entity Framework 7 e APIs
Figura 3 ASP.NET 5.0 e referências do ASP.NET Core 5.0 que contém os pacotes do Entity Framework 7 e APIs

O ASP.NET 5 e EF7 adotam e dependem muito de injeção de dependência (DI). Você pode ver na Startup.cs do projeto na Figura 4 que há lógica para informar o aplicativo que deve usar o Entity Framework, sua API do SQL Server e o DbContext predefinido único usado para segurança, ApplicationDbContext. Você pode ver este mesmo contexto conectado como o serviço de identidade para o aplicativo. A cadeia de conexão é armazenada no arquivo config.json e conecta o construtor de Inicialização desse arquivo para que o aplicativo possa encontrá-lo quando necessário.

Figura 4 Listagem parcial do Startup.cs padrão

public class Startup {
  public Startup(IHostingEnvironment env) {
    Configuration = new Configuration()
      .AddJsonFile("config.json")
      .AddEnvironmentVariables();
  }
  public IConfiguration Configuration { get; set; }
  public void ConfigureServices(IServiceCollection services) {
    services.AddEntityFramework(Configuration)
      .AddSqlServer()
      .AddDbContext<ApplicationDbContext>();
    services.AddIdentity<ApplicationUser, IdentityRole>(Configuration)
      .AddEntityFrameworkStores<ApplicationDbContext>();
       services.AddMvc();  }

O modelo de projeto agora é configurado por padrão para usar EF7 e usar sua lógica se estiver destinado ao CoreCLR simplificado ou ao .NET Framework completo. Na verdade, por padrão, o projeto não está definido para ser executado com o CoreCLR, mas para usar o .NET Framework completo. Vamos examinar onde essa opção se encaixa.

O CLR completo do ASP.NET 5 (e o Entity Framework)

Há uma atualização para o surgimento do .NET Framework, o .NET Framework 4.6, e permitirá que você continue a criar todos os estilos de software que você já conseguiu, do Windows Forms e Web Forms para aplicativos do Windows Presentation Foundation (WPF) e do ASP.NET MVC 5. Graças a outras versões KRE mostradas na Figura 1, o KRE do CLR do amd64 e KRE do CLR do x86, também é possível executar um aplicativo ASP.NET 5 sobre o .NET Framework completo. Isso permite fazer o bolo e comê-lo, se você quiser se beneficiar de outros novos recursos do ASP.NET 5, como MVC 6 ou a nova API da Web, que é uma fusão de controladores do MVC e a API da Web. Ela também fornece compatibilidade com versões anteriores porque você está visando o .NET Framework e o CLR completos e pode acessar o conjunto completo de recursos. Por padrão, o arquivo project.json indica que você deseja ser capaz de executar o aplicativo em qualquer versão do CLR:

"frameworks": {
      "aspnet50": { },
      "aspnetcore50": { }
    },

Você pode remover a linha “aspnetcore50” completamente (com a vírgula no final da linha anterior) e o efeito seria por dois motivos. Primeiro, a seção do ASP.NET Core 5.0 desapareceria das Referências no Gerenciador de soluções. Em segundo lugar, os destinos KRE exibidos na Figura 1 seriam reduzidos a apenas as opções de KRE CLR.

Você ainda estaria direcionando o EF7 e obtendo todos as vantagens dessa nova versão. Mas, o que não era óbvio é que, como o CLR KRE tem como alvo o .NET Framework completo, ele é compatível com o Entity Framework 6. Isso significa que se você tiver a lógica do EF6 existente, é possível usá-lo em combinação com ASP.NET 5 (embora não a versão do CoreCLR) e aproveitar os benefícios dos novos recursos do ASP.NET 5 sem ter que refazer seu código do EF6 para alinhar com o EF7.

ASP.NET 5 (CLR completo) com o EF6

Sabendo que isso era possível, naturalmente tive tentar obter o EF6 em uma solução ASP.NET 5. Tenha em mente que a abordagem que usei para alcançar esse resultado pode muito bem precisar ser alterada entre a versão inicial que estou usando no momento (em fevereiro de 2015) e quando o ASP.NET 5 e o Visual Studio 2015 forem liberados.

Descobri que o fator mais importante para fazer isso foi manter a lógica do Entity Framework e as dependências em um projeto separado do projeto ASP.NET 5. Normalmente desenvolvo meus aplicativos dessa forma de qualquer jeito, em vez de todas as camadas do meu aplicativo em um único projeto. Com um projeto separado dedicado ao EF, você não precisa se preocupar sobre o aplicativo ASP.NET 5 extraindo as APIs do EF7 imediatamente.

Em vez de começar com o projeto da Web inicial do ASP.NET 5, é melhor usar o modelo de projeto vazio do ASP.NET. O arquivo project.json tem somente uma dependência especificada, o Microsoft.Asp.NET.Server.IIS.

Em seguida, você pode criar um segundo projeto. Escolhi um projeto de biblioteca de classes do .NET 4.6. Em seguida, eu poderia usar o Package Manager Console (Console do Gerenciador de Pacotes) para instalar o EF6, garantindo que estava apontando para nuget.org como origem do pacote e à biblioteca de classes do projeto padrão. Nesse ponto eu pude chamar o pacote de instalação do entityframework como sempre foi feito. Isso trouxe a entityframework.dll e a entityframework.sqlserver.dll para o projeto.

Para testar, criei uma classe simples, Ninja.cs (porque eu considero o EF6 a edição Ninja, enquanto o EF7 é a edição Samurai):

public class Ninja {
    public int Id { get; set; }
    public string Name { get; set; }
  }

e um DbContext exposto a um DbSet de Ninjas:

public class NinjaContext : DbContext {
  public NinjaContext()
    :base(@"Data Source=(localdb)\mssqllocaldb;
          Initial Catalog=NinjaContext;
          Integrated Security=True;"){ }
  public DbSet<Ninja> Ninjas { get; set; }
}

Para manter a simplicidade no teste, codifiquei a cadeia de caracteres de conexão do SQL Server diretamente em minha classe DbContext.

Com meu modelo definido, posso habilitar migrações, adicionar uma nova migração e criar o banco de dados, como sempre foi feito. Observe que quando instalei o EF6 para o projeto de dados, deixei o arquivo app.config que o pacote criou de forma que poderia definir o projeto como o projeto de inicialização e, em seguida, os comandos de migração funcionariam corretamente. Também usei o método DbMigrationsConfiguration Seed para propagar previamente o banco de dados com alguns Ninjas.

Não quero fazer chamadas EF diretamente do aplicativo ASP.NET 5 e criar confusão de versão, de forma que eu tenha uma classe no meu projeto do EF6 que encapsula as consultas que precisarei. Denominei-o de Repositório porque ele se ajusta meu objetivo, mas isso não é uma classe que segue o padrão de repositório. Isso não é um desafio com um aplicativo de demonstração e uma única consulta, mas você pode usar o padrão favorito para separação de assuntos para aplicativos mais complexos:

public class Repository  {
  public List<Ninja> GetAllNinjas() {
    using (var context=new NinjaContext())
    {
      return context.Ninjas.ToList();
    }
  }
}

Com o acesso a dados do projeto definidos, posso retornar ao projeto ASP.NET 5. Criei um controlador simples para recuperar e retornar uma View:

public class NinjaController : Controller
  {
    public IActionResult Index()
    {
      var repo = new Repository();
        return View(repo.GetAllNinjas());
      }
    }
  }

Também criei um index.cshtml simples que listará os Ninjas passados pelo controlador:

@model List<EF6Model.Ninja>
@{
  ViewBag.Title = "EF6 Ninjas";
}
@foreach (var item in Model)
{
  @Html.Label(item.Name);
}

Por fim, Figura 5 mostra um código adicionado ao arquivo startup.cs, para inserir os serviços do MVC e especificar o roteamento para o controlador Ninja.

Figura 5 Classe de inicialização para configurar o aplicativo do ASP.NET 5 que usa o Entity Framework 6

public class Startup  {
  public void Configure(IApplicationBuilder app) {
    app.UseMvc(routes =>
    {
      routes.MapRoute(
      name: "default",
      template: "{controller}/{action}/{id?}",
      defaults: new { controller = "Ninja", action = "Index" });
     });
  }
  public void ConfigureServices(IServiceCollection services)  {
    services.AddMvc();
  }
}

Removi também a estrutura aspnetcore50 do arquivo project.json, garantindo que apenas se destinam ao CLR completo.

Com o banco de dados e alguns dados de propagação criados pelas migrações, sou capaz de ver o aplicativo ASP.NET 5 trabalhando com o projeto baseado no EF6, exibindo os dados que foram recuperados com o EF6 (consulte a Figura 6).

Aplicativo do ASP.NET 5 exibindo dados por meio do Entity Framework 6
Figura 6 Aplicativo do ASP.NET 5 exibindo dados por meio do Entity Framework 6

Usarei o EF7 e o ASP.NET 5 imediatamente?

Estou muito interessado nos novos recursos do EF7 e aprender como aproveitá-los melhor. Também estou procurando entender esse novo canal de programação que o ASP.NET 5 abre. O CoreCLR se tornará mais sofisticado na medida que evoluir, assim como o EF7. Estou impressionado com o estado do EF7 como ele será lançado com o ASP.NET 5. Mas, como eu não sou um desenvolvedor da Web, não tenho um motivo para trabalhar no código de produção na incógnita do ASP.NET, e a equipe do EF foi clara que ela recomenda usar a versão inicial do EF7, que será marcada como uma versão de pré-lançamento, somente com aplicativos ASP.NET 5. Caso contrário, a orientação da equipe é aguardar até que o EF7 seja lançado como uma versão final. Portanto, posso aguardar as versões subsequentes do EF7, mas continuar a seguir e experimentar o projeto à medida que ele evolui para obter mais paridade com os recursos do EF6 que, caso contrário, poderá perder.

O CoreCLR ainda é uma incógnita no momento para minhas preferências. Se encontrar um cenário que se ajusta ao que estará disponível na versão CLR completa do ASP.NET 5, bem como o conjunto de recursos de pré-lançamento do EF7, estarei ansioso para tomar esse caminho. No entanto, é mais provável, que vou acabar aguardando as versões subsequentes. E, em seguida, o ASP.NET 5 e o CoreCLR também ficarão mais sofisticados. Para mim, pessoalmente, o tempo até então fornecerá a oportunidade de explorar e saber mais sobre essas ferramentas em preparação para a versão posterior.

Enquanto isso, é altamente recomendável ler a postagem do blog de Scott Guthrie, “Introdução ao ASP.NET 5”, em bit.ly/1wV4zzm para ter uma compreensão melhor de todos os novos recursos que o ASP.NET 5 traz. As APIs combináveis são apenas um dos muitos aprimoramentos empolgantes que os desenvolvedores ganharão nesta mudança.


Julie Lerman é MVP da Microsoft, mentora e consultora do .NET, que reside nas colinas de Vermont. Você pode encontrar ela apresentando sobre o acesso a dados e outros tópicos do .NET em grupos de usuário e conferências pelo mundo todo. Ela bloga em thedatafarm.com/blog e é a autora do “Programming Entity Framework” (2010), bem como de Code First edition (2011) e DbContext edition (2012), todos de O’Reilly Media. Siga Julie no Twitter em twitter.com/julielerman e confira seus cursos da Pluralsight em juliel.me/PS-Videos.

Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Rick Strahl
Rick Strahl é o Grande Kahuna na West Wind Technologies, localizada na bela ilha de Mauí, no Havaí. Entre sessões de windsurf e aventuras de arrepiar os cabelos, Rick tem sido um desenvolvedor de software há mais de 25 anos, criando aplicativos Web e de negócios desde os primórdios da Web quando era necessário uma manivela disponível (ou um par de conectores) para conectar-se. Hoje Rick cria aplicativos e serviços web para clientes com o HTML5, JavaScript e tecnologias da Web móveis, usando o AngularJS no front-end e a pilha do ASP.NET e tecnologias da Microsoft no back end. A empresa de Rick, a West Wind Technologies, também produz uma série de ferramentas relacionadas ao desenvolvedor, incluindo West Wind WebSurge, West Wind Web Monitor e o Construtor da Ajuda em Html. Rick também mantém um host de bibliotecas de código-fonte aberto em github.com/RickStrahl e você pode visitar seu blog em weblog.west-wind.com ou entrar em contato diretamente pelo rstrahl@west-wind.com.