DEV Community

Cover image for Scripts em C#
Andre Claudinei Barsotti
Andre Claudinei Barsotti

Posted on • Updated on

Scripts em C#

Introdução

Scripts são uma ferramenta bem antiga nos ambientes de TI e ainda hoje são muito utilizados.

Sua natureza interpretada da à eles um dinamismo que supera em muito as facilidades de qualquer linguagem compilada.

JavaScript, com Node Js, e Python são exemplos que demonstram que a utilização de scripts no desenvolvimento de aplicações ainda segue em alta e sua força.

Estudando sobre Azure Functions me deparei com um arquivo a diferente extensão ".csx". Trata-se de um arquivo de scripts em linguagem C#, uma novidade para mim depois de vários anos trabalhando com essa linguagem.

Compartilho aqui com vocês o que aprendi sobre essa ferramenta e minhas conclusões.

Os scripts em C Sharp

Nos idos de 2011, Kirill Osenkov informou a comunidade .NET que a MS estava entregando o primeiro release preview do Roslyn Project. Nesse artigo, ele também informa que foi "introduzido o conceito de um arquivo de script C#" (OSENKOV, 2011). "A ideia principal por trás de escrever scripts em C# foi permitir que o código fosse avaliado dinamicamente pelo _runtime." (WOJ, 2015).

Para escrever um script C# você só precisa criar um arquivo com a extensão ".csx" em qualquer editor de textos. Depois de criar o arquivo você vai precisar de um programa para interpretá-lo. Hoje três opções:

  • Mono/Roslyn CSI (que já vem instalado com o Visual Studio);
  • cs-scripts;
  • dotnet-scripts.

O cs-scripts e dotnet-scripts são multiplataforma, e dotnet-scripts tem a vantagem ser instalado com um dotnet tool e rodar usando o .NET 5.

No restante desse artigo vamos utilizar o dotnet-scripts para nossos exemplos. Para instalá-lo digite o comando abaixo em seu console de preferência:

dotnet tool install -g dotnet-script
Enter fullscreen mode Exit fullscreen mode

Sintaxe

"Um script C# tem requisitos de sintaxe mais flexíveis, então a experiência geral pode ser sem cerimônias. Abaixo estão algumas coisas a serem lembradas:

  • o ponto de entrada para o seu script é a primeira linha do seu arquivo (nenhum método Main obrigatório)
  • qualquer código é permitido a partir da primeira linha (nenhuma classe de nível superior, Program, obrigatória)
  • funções globais são permitidas;
  • sem namespaces;
  • sem um arquivo de projeto ou solução;
  • seu script pode ser totalmente autocontido;
  • instruções using e referências são importados implicitamente pelo aplicativo hospedeiro (responsável por executar o script)" (WOJCIESZYN, 2015)

Eu acrescento à essa lista o desenvolvimento de extensões, que foi algo que identifiquei nos meus testes.

Abaixo um exemplo de arquivo de script C# utilizado para inicializar o processo:

#load "Configs.csx"
#load "src/Data/TodoListRepository.csx"
#load "src/Services/TodoListService.csx"
#load "src/Controller/TodoListController.csx"
using Microsoft.Extensions.Configuration;

await Run(Args.ToArray());

async Task Run(string[] args)
{
    using TodoListRepository repository = new(Configs.Configuration.GetConnectionString("db"));
    TodoListService service = new(repository);
    TodoListController controller = new(service);
    await controller.ExecuteCommand(args);
}
Enter fullscreen mode Exit fullscreen mode

Como pode ser visto a sintaxe da linguagem é a mesma já conhecida, só que sem a estrutura Program.Main. A forma de referenciar outros arquivos ".csx" é utilizando a diretiva #load "<caminho do arquivo>".

Abaixo um exemplo de arquivo para leitura de configurações, que faz referência à pacotes nuget:

#r "nuget: Microsoft.Extensions.Configuration, 5.0.0"
#r "nuget: Microsoft.Extensions.Configuration.Binder, 5.0.0"
#r "nuget: Microsoft.Extensions.Configuration.UserSecrets, 5.0.0"
#r "nuget: Microsoft.Extensions.Configuration.EnvironmentVariables, 5.0.0"

using Microsoft.Extensions.Configuration;

public static class Configs
{
    private static IConfiguration _config;

    public static IConfiguration Configuration 
    {
        get 
        {
            if (_config is null)
                SetConfig();

            return _config;
        }
    }

    private static void SetConfig()
    {
        _config = new ConfigurationBuilder()
                        .SetBasePath(Directory.GetCurrentDirectory())
                        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddUserSecrets("csx-script-app")
                        .AddEnvironmentVariables()
                        .Build();
    }

    public static T GetConfig<T>(string sectionName)
    {
        return Configuration.GetSection(sectionName).Get<T>();
    }
}
Enter fullscreen mode Exit fullscreen mode

Referenciar um pacote é bem simples utilizando #r "nuget: <nome do pacote>, <versão>".

Se for necessário importar um assembly próprio é utilize a direntiva #r "<caminho da dll>". Segue um exemplo:

#r: "./build/MeuAssembly.dll"
Enter fullscreen mode Exit fullscreen mode

Desenvolvi um aplicativo Todo de exemplo e publiquei no meu GitHub onde é possível ver esses scripts em ação. Esse é o link do projeto.

Debug

Se você utiliza o Visual Studio Code como seu editor de texto/IDE debugar um script é algo que seguirá os padrões que você já esta acostumado. Basta configurar seu launch.json conforme abaixo, colocar o breakpoint e clicar em F5.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": ".NET Script Debug - Linux",
      "type": "coreclr",
      "request": "launch",
      "program": "${env:HOME}/.dotnet/tools/dotnet-script",
      "args": [
        "${file}"
      ],
      "cwd": "${workspaceFolder}",
      "stopAtEntry": false,
    },
    {
      "name": ".NET Script Debug - Windows",
      "type": "coreclr",
      "request": "launch",
      "program": "dotnet",
      "args": [
          "${env:USERPROFILE}/.dotnet/tools/.store/dotnet-script/1.2.1/dotnet-script/1.2.1/tools/net5.0/any/dotnet-script.dll",
          "${file}"
      ],
      "cwd": "${workspaceRoot}",
      "stopAtEntry": false
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Compilação com um aplicativo e execução no Linux.

Um ponto interessante que achei utilizando o dotnet-script no Windows foi a possibilidade de criar um aplicativo autocontido. Para fazer isso é muito simples basta publicar o script como no exemplo abaixo:

dotnet script publish Main.csx
Enter fullscreen mode Exit fullscreen mode

Um diretório publish será criado com um executável. Como é um aplicativo autocontido, basta copiá-lo para qualquer computador e, mesmo sem o .NET instalado, executá-lo.

Em um ambiente Linux incluindo como primeira linha a diretiva #!/usr/bin/env dotnet-script é possível executar o script como qualquer outro, lembrando que é preciso dar permissão de execução no arquivo.

Conclusão e aplicações

Observando a tecnologia vemos que essa ferramenta é bem madura e que vem se desenvolvendo junto com a plataforma e que irá continuar nesse caminho no futuro.

Hoje é possível escrever um programa console em C# de forma minimalista sem uma classe Program, um método Main e com funções globais, algo que até pouco tempo atrás era impensável. Com scripts C# você consegue tudo isso e ainda a vantagem de desenvolver sem um ".csproj" e sem o tempo de compilação, apenas escrever o código e já validar seu programa prontamente.

Testes de integração que serão executados sob demanda; programas de carga que serão utilizados apenas uma vez; pequenos testes e estudos de algum pacote Nuget novo; Scripts de configuração de ambiente. Esses são apenas alguns exemplos de utilização de scripts em C#.

No caso de scripts para configuração de ambiente ou inicialização de uma aplicativo, ainda existe a vantagem latente de seguir com a mesma linguagem que o projeto foi desenvolvido. Para a equipe isso é uma vantagem, visto que é preciso um esforço adicional para aprender e escrever o mesmo script com um bash script ou bat tradicional.

Em programas de carga existe ainda a vantagem de conseguir reaproveitar o código e as regras de negócio do próprio projeto, sem duplicidades.

As aplicações são muitas e certamente vale a pena incluir no "arsenal".

Referências

BAHRAMINEZHAD, Ali. Hitchhiker’s Guide to the C# scripting. ITNEXT, 2019. Disponível em: <https://itnext.io/hitchhikers-guide-to-the-c-scripting-13e45f753af9>. Acesso em: 11-09-2021

MICHAELIS, Mark. C# Scripting. Microsotf Docs, 2016. Disponível em: <https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/january/essential-net-csharp-scripting>. Acesso em: 11-09-2021

OSENKOV, Kirill. Introducing the Microsoft “Roslyn” CTP. Microsoft DevBlogs, 2011. Disponível em <https://devblogs.microsoft.com/visualstudio/introducing-the-microsoft-roslyn-ctp/>. Acesso em: 12-09-2021

SALVADEO, André C B. Todo List em C# script (CSX). Github, 2021. Disponível em <https://github.com/andrebarsotti/csx-script-sample>. Acesso em: 12-09-2021

VOGEL, Peter. Making Your Life Easier with C# Scripting. Visual Studio Magazine, 2021. Disponível em: <https://visualstudiomagazine.com/articles/2021/06/14/csharp-scripting.aspx>. Acesso em: 11-09-2021

WOJCIESZYN, Filip. Dotnet script. Github, 2021. Disponível em <https://github.com/filipw/dotnet-script>. Acesso em: 11-09-2021

WOJCIESZYN, Filip. Adding C# scripting to your development arsenal - Part 1. Microsoft Docs - Blog Archive - Canadian Developer Connection, 2015. Disponível em <https://docs.microsoft.com/pt-br/archive/blogs/cdndevs/adding-c-scripting-to-your-development-arsenal-part-1>. Acesso em: 12-09-2021

Top comments (0)