.NET Core para Desenvolvedores .NET

Disponível também em inglês

Neste artigo analiso uma aplicação MVC em .NET Core, falando a língua de um desenvolvedor .NET. Isso quer dizer que, tudo que irá ler aqui, será um comparativo entre as funcionalidade de ambas tecnologias.

.NET Core para Desenvolvedores .NET

A primeira vez que mexi com o .NET Core foi uma aventura homérica, meu Deus do céu. Tinha um arquivo de configuração JSON, tipo packages.json, e tentaram imitar o NodeJS e quebrava tudo. Até parecia o Xamarin e Android SDK no começo de sua caminhada.

Desisti daquele troço e segui minha vida. Mas já faz algum tempo que novas versões chegaram, muita coisa foi aprimorada e agora sim negócio ficou TOP.

Bom chega de introdução, vamos lá.


#O que faremos?

Vamos criar um novo projeto MVC em .NET Core, de nome FSL.NetCoreBasics, e comparar as principais funcionalidades com o .NET Framework, como as que estão listadas abaixo:

Para esse artigo, utilizei o Visual Studio 2017 Community, .NET Framework 4.7.1 e .NET Core 2.2.

DESIGN PATTERNS vol.1


#Criação do projeto MVC no ASP.NET Core

A criação de um projeto MVC no .NET Core através do Visual Studio 2017 é praticamente idêntica ao MVC do .NET Framework. Para isso basta escolher ASP.NET Core Web Application na primeira tela e na segunda tela, escolher Web Application e pronto.

Criação do projeto MVC no ASP.NET Core


#Estrutura do projeto no ASP.NET Core

A primeira coisa que a gente vê ao criar uma aplicação web MVC em ASP.NET Core é a falta do arquivo web.config. E depois, encontramos duas novas pastas, uma chamada wwwroot e outra Dependencies. Por fim, vemos um novo arquivo chamado appsettings.json.

Estrutura .NET Core

A pasta Dependencies no .NET Core foi fácil entender, é a mesma lógica da pasta References do .NET Framework.

A pasta wwwroot, só clicando nela para saber mais detalhes. Mas aí, também ficou fácil, ela contém os mesmos tipos de arquivos que a pasta Content no .NET Framework. Até agora tudo bem.

Por fim cliquei no arquivo appsettings.json, e por estar acostumado com .NET Framework, ele tem o mesmo nome da classe AppSettings, utilizada para configuração no arquivo web.config.

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
    "AllowedHosts": "*"
}

É possível observar que ao contrário do AppSettings do .NET Framework, o .NET Core trata as configurações em apenas um arquivo JSON.

Cadê meu web.config???


#Diretório Virtual

O próximo passo agora é compilar a aplicação e criar o diretório virtual no IIS. Bora lá, vamos acessar as propriedades do projeto MVC e ir na guia Web.

.NET Core Properties

Se você tentou achar uma guia Web para configurar IIS no .NET Core, caiu na minha pegadinha! No .NET Framework, temos uma guia de propriedades chamada Web para criar o diretório virtual no IIS e outras configurações.

Uma das novidades e principais objetivos do .NET Core é não precisar da dependência do IIS e nem biblioteca System.Web. É por isso que não temos diretório virtual neste caso. É possível desenvolver uma aplicação Web sem esforços que rode no Windows, Linux e Mac.

A primeira tentativa de compilação no MVC .NET Core não demorou tanto tempo assim, então logo já dei F5 para debugar e ver a aplicação rodando no navegador. Abriu… ufa!

.NET Core rodando


#Views e HtmlHelpers

Seguindo a risca uma aplicação MVC .Net Framework, próximo passo é olhar a View Index.cshtml e seu _Layout.cshtml. Nada a comentar na View index.cshtml, mas no _Layout.cshtml as coisas mudam um pouco. Vamos olhar mais de perto.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - FSL.NetCoreBasics.Mvc</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    </environment>
</head>
<body>
    <div class="container">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    @RenderSection("Scripts", required: false)
</body>
</html>

De cara, olhando para o código, já aparecem novas tags em negrito, que mais parecem ser components do Angular e AngularJS. As tags em questão são environment e partial.

Além das tags, alguns atributos, também em negrito, são bem destacados e padronizados com prefixo asp-. Atributos como esses, podemos encontrar no KnockoutJS, Angular e AngularJS, VueJs e em outros frameworks.

No .NET Core, eles chamam de Tag Helpers.

<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>

No .NET Framework, essa responsabilidade fica a cargo dos Html Helpers, que fazem praticamente a mesma coisa, vide abaixo.

@Html.ActionLink("Home", "Index", "Home", new { @class = "nav-link text-dark" })

Com certeza, as Tags Helpers são muito mais harmoniosas e cleans do que os Html Helpers. Mas será que tudo o que funciona em um, funciona no outro? Vamos ver mais a seguir.

Para exemplificar mais um caso, a chamada de uma partial view, respectivamente em .NET Core e .NET Framework é:

<partial name="_CookieConsentPartial" />
@Html.Partial("_CookieConsentPartial")

Ainda bem que o Visual Studio estiliza essas Tag Helpers, senão ia misturar com HTML e viraria uma bagunça para entender.

Por fim, alguns Html Helpers não foram abandonados, percebe-se no código da View _Layout.cshtml os comandos @RenderBody e @RenderSection.


#Controllers

Vamos seguindo, até agora não colocamos a mão no código para mudar uma linha sequer.

É possível analisar que diferente do .NET Framework, não existe mais a herança básica com BaseController, ao invés disto, as classes agora herdam de simplesmente de Controller.

Outro ponto, quase imperceptível, é o tipo de retorno dos métodos das Actions, que no .NET Core, são usadas interfaces IActionResult ao invés de classes abstratas ActionResult no .NET Framework. Inicialmente, nada demais também nessa comparação

public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }

Fazendo um parênteses, a classe Controller no .NET Core, herda de ControllerBase. Ora, pelas boas práticas, deveria herdar de uma com nome de BaseController, pois a classe que está herdando deve carregar seu sufixo, no caso Controller.


#Routes

No MVC .Net Framework, as rotas ficam no arquivo RouteConfig.cs, dentro da pasta App_Start, apesar de tudo isso ser totalmente customizável. A rota básica de uma aplicação MVC é a seguinte:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

No MVC .NET Core é muito parecido, até mesmo a classe que se encontra essa configuração, a Startup.cs.

routes.MapRoute(
    name: "default",
    template: "{controller=Home}/{action=Index}/{id?}");

Bom, nenhuma grande mudança nessa parte de configuração das rotas, salvo apenas que, toda configuração é feita em apenas uma linha na propriedade template.

Eu Apoio Fabio Silva Lima


#Arquivo web.config

Chegamos no tópico mais tenso dentre os tópicos básicos de uma aplicação .NET Core, que é, a falta do arquivo web.config.

Faz sentido não termos um arquivo web.config, já que o .NET Core não depende mais do IIS. Mas e a questão das ConnectionStrings e AppSettings por exemplo?

Para esses casos devemos usar mesmo aquele arquivo appsettings.json e o modo de acessar as tags desse arquivo JSON não é tão difícil. Eu customizeI o arquivo appsettings.json incluindo uma tag FslConfiguration para explificar seu acesso pelo C#.

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
    "AllowedHosts": "*",
    "FslConfiguration": {
        "IsCacheEnabled": true
    },
    "ConnectionStrings": {
        "Default": "Data Source=.\\(local);Initial Catalog=NetCoreBasics;User ID=sa;Password=dsf3432fr823@@2323;Persist Security Info=False;Connect Timeout=200000"
    }
}

Se quisermos acessar a propriedade IsCacheEnabled da tag FslConfiguration, o primeiro passo é criar uma classe e propriedade no C# com o mesmo nome.

public sealed class FslConfiguration
{
    public bool IsCacheEnabled { get; set; }
}


#Injeção de Dependência

Segundo passo é criar uma classe e um método para serializar/retornar essa configuração do arquivo JSON.

public interface IConfigService
{
    Models.FslConfiguration GetConfig();
}

public sealed class NetCoreConfigService :
    IConfigService
{
    private readonly IOptions<FslConfiguration> _config;

    public NetCoreConfigService(
        IOptions<FslConfiguration> config)
    {
        _config = config;
    }

    public FslConfiguration GetConfig()
    {
        return _config?.Value;
    }
}

Eu criei uma classe e uma interface já pensando na injeção de dependência. Repare que no construtor da classe NetCoreConfigService é injetado uma interface IOptions tipada com a classe FslConfiguration.

Então, se eu precisar acessar alguma propriedade em qualquer lugar na aplicação, basta eu usar a interface IConfigService em qualquer constructor, exemplo:

public sealed class BusinessRuleService
{
    private readonly IConfigService _configService;

    public BusinessRuleService(
        IConfigService configService)
    {
        _configService = configService;

        var isEnabled = _configService.GetConfig().IsCacheEnabled;
    }
}

Por fim, para isso tudo funcionar, é necessário registrar as classes e interface para a injeção de dependência. Essa parametrização é feita no arquivo Startup.cs.

OptionsConfigurationServiceCollectionExtensions.Configure<FslConfiguration>(
    services, 
    Configuration.GetSection("FslConfiguration"));

services.AddSingleton<IConfigService, NetCoreConfigService>();

A injeção de dependência no .NET Core á nativa, não precisando mais instalar outras bibliotecas como Ninject ou Simple Injector.


#Considerações finais

Utilizando os conceitos de uma aplicação web comum, usando a lógica de serialização de JSON em classe C# e injeção de dependência nativa do .NET Core, como desenvolvedor .NET, não tive dificuldade em fazer toda essa comparação com o .NET Framework.

O próximo passo agora é ir mais a fundo e converter uma aplicação MVC .NET Framework existente, mas isso fica para um próximo artigo.

Faltou alguma coisa? Encontrou erro?
Comente, critique, compartilhe!

Obrigado e até a próxima!

30 Pessoas que Influenciaram minha Carreira Profissional

Faça download completo do código fonte no github.
Sobre o Autor:
Trabalha como arquiteto de soluções e desenvolvedor, tem mais de 18 anos de experiência em desenvolvimento de software em diversas plataformas sendo mais de 16 anos somente para o mercado de seguros.
Revisado por:
Apaixonado por Tecnologia, a mais de 10 anos trabalhando com tecnologias web, pai do Gustavo. Sempre querendo aprender novas tecnologias para poder passar adiante, adoro video game e futebol.


Apaixonado por tecnologia, atualmente trabalho com aplicações web e estou aprofundando meu conhecimento em mobile. Meu objetivo é contribuir com a comunidade ajudando os desenvolvedores que estão iniciando.