MarceloCastelo.IO.OutputEnvelop 2.1.0

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package MarceloCastelo.IO.OutputEnvelop --version 2.1.0
                    
NuGet\Install-Package MarceloCastelo.IO.OutputEnvelop -Version 2.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MarceloCastelo.IO.OutputEnvelop" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MarceloCastelo.IO.OutputEnvelop" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="MarceloCastelo.IO.OutputEnvelop" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MarceloCastelo.IO.OutputEnvelop --version 2.1.0
                    
#r "nuget: MarceloCastelo.IO.OutputEnvelop, 2.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MarceloCastelo.IO.OutputEnvelop@2.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MarceloCastelo.IO.OutputEnvelop&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=MarceloCastelo.IO.OutputEnvelop&version=2.1.0
                    
Install as a Cake Tool

MCIO.OutputEnvelop

Um envelope de resposta que seja leve, de alto desempenho e que forneça uma API de alto nível para ser usado em aplicações LOB (line of business).

📖 Documentos

Status Nome PT-BR
:green_circle: Finalizado Benchmarks BENCHMARKS-PT.md
⚫ Em construção Decisões de design DESIGN-DECISIONS-PT.md

📦 Pacotes

Nome Versão Link Repository
MarceloCastelo.IO.OutputEnvelop Nuget Nuget.org Esse aqui 😃
MarceloCastelo.IO.OutputEnvelop.FluentValidation Nuget Nuget.org Link

🏷️ Labels

Categoria Descrição Labels (todos os ícones são clicáveis e levam as ferramentas externas)
Licença MIT MIT License
Segurança Vulnerabilidades CodeQL Vulnerabilities Security Rating
Qualidade Visão geral Quality Gate Status
Qualidade Cobertura de testes Coverage
Qualidade Teste de mutação Mutation Test
Qualidade Manutenabilidade Maintainability Rating
Qualidade Confiabilidade Reliability Rating
Qualidade Bugs Bugs
Qualidade Dívidas técnicas Technical Debt
Qualidade Linhas duplicadas (%) Duplicated Lines (%)
Qualidade Melhorias de código Code Smells
Pipeline Compilação e testes Build and Test
Pipeline Publicação Publish

📄 Introdução

Esse projeto nasceu de uma necessidade pessoal. Quando estamos desenvolvendo um sistema temos que tomar diversas decisões com relação ao design do código e manter o equilíbrio entre legibilidade, manutenabilidade e performance é sempre um desafio pois, no fim das contas, nós escrevemos código para outra pessoa entender e não para o computador.

Como assim? Existem diferentes tipos de sistemas, mas o mais comum são os que chamamos de sistemas LOB (line of business) que são aplicações que tem como o objetivo automatizar processos de negócios em corporações como processos de venda, compras, pedidos, chamados, suportes, processos financeiros etc. Esses sistemas possuem algumas características que costumam se repetir:

  • Autenticar o usuário que está tentando realizar a operação.
  • Autorizar o usuário autenticado para a operação que está querendo realizar.
  • Receber inputs dos usuários.
  • Validar os inputs dos usuários.
  • Validar os estados dos objetos de negócio.
  • Realizar algum processo de negócio que modifique o estado dos objetos de negócio.
  • Persistir essas informações.
  • Retornar o resultado da solicitação para o usuário.
  • Exibir diversos relatórios a partir das informações armazenadas.

Além disso, nesse tipo de sistema, os retornos dos métodos vão além de um único objeto e é comum querermos saber mais informações do que somente se deu erro ou não, por exemplo:

  • Queremos saber as notificações que ocorreram durante a execução dos métodos.
  • Essas notificações são mais do que simples mensagens de erro, podem ser mensagens de warning (por exemplo: quando um pedido de compra ultrapassa determinado valor), podem ser mensagens informativas (por exemplo: informar a integração com os parceiros foi realizada com sucesso durante o processamento da requisição) etc.
  • O processamento nem sempre se resume a sucesso ou falha. Em processamento em lote por exemplo, o resultado da operação pode ser parcial onde parte dos itens do lote são processados e outra parte não.

📖 Conteúdo

📦 Dependências

voltar ao topo

💻 Tecnologias

voltar ao topo

Esse projeto utiliza as seguintes tecnologias:

  • C# como linguagem de programação.
  • .NET Standard 2.0 para o pacote nuget.
  • .NET 8 para os projetos de teste de unidade, benchmark e exemplos.
  • xUnit como framework de testes de unidade.
  • FluentAssertions para escrita dos Asserts dos testes de unidade de forma fluída,
  • SonarQube para ferramenta de análise estática de código (SAST - Static Application Security Testing),
  • Stryker.NET como framework para testes de mutação.
  • BenchmarkDotNet como framework para realização dos benchmarks.
  • Github Actions para as pipelines.
  • Github CodeQL para análise de vulnerabilidades de segurança.
  • Nuget.org como repositório de pacotes.

⭐ Funcionalidades-chave

voltar ao topo

Esse projeto tem como objetivo fornecer um envelope de resposta que segue os seguintes princípios de design:

  • ✅ Seja otimizado para alocação na stack ao invés da heap para evitar pressão no garbage collector.
  • ✅ Tenha a característica da imutabilidade para ter a garantia que uma vez criado, não será modificado e que, alterações implicarão na criação de um novo objeto.
  • ✅ Ter uma API de alto nível para que seja flexível para ser utilizado em diversos cenários com pouca necessidade de customização do código.
  • ✅ Seja otimizado para não realizar box e unboxing e evitar criação de closures nos encapsulamentos para não gerar alocações na heap.
  • ✅ Evitar o uso desnecessário e lançamento de exceções ocasionando problemas de desempenho.
  • ✅ Ser Thread-safe.

⭐ Roadmap

voltar ao topo

  • :green_circle: Versão 1.0.0
    • :green_circle: Suporte para mensagens de saída dos tipos information, success, warning e error.
    • :green_circle: Notificações imutáveis.
    • :green_circle: Envelope de resposta com encapsulamento de mensagens de saída, exceções e suporte a processamento parcial.
    • :green_circle: Envelope de resposta encapsulando a execução para captura automática de exceções.
    • :green_circle: Envelopes de resposta imutáveis.
  • :green_circle: Versão 1.1.0
    • :green_circle: Suporte para tipagem da propriedade Code do objeto OutputMessage a partir de generics.
    • :green_circle: Remoção da obrigatoriedade do campo Code no objeto OutputMessage.
  • :green_circle: Versão 2.0.0
    • :green_circle: Correção do termo ProcessResult para OutputEnvelop.
  • :green_circle: Criação do pacote MarceloCastelo.IO.OutputEnvelop.FluentValidation para integração com o pacote FluentValidation.

🚀 Executando localmente

voltar ao topo

Por se tratar de um pacote nuget, não existe uma execução. Porém, existe o script build-local-script que pode ser executado via PowerShell que realizará as seguintes ações:

  1. Instalará a CLI do ReportGenerator localmente para visualização do relatório de cobertura no formato opencover.
  2. Instalará a CLI do Stryker localmente para execução e visualização do relatório do teste de mutação.
  3. Restore do projeto.
  4. Build do projeto em modo release.
  5. Execução dos testes de unidade.
  6. Execução do teste de mutação.
  7. Abertura do relatório de cobertura no navegador web padrão.
  8. Abertura do relatório de teste mutante no navegador web padrão.

A partir do diretóio raiz do repositório, no PowerShell, execute o comando .\build-local-script.ps1.

Caso queira limpar todos os arquivos gerados, a partir do diretóio raiz do repositório, no PowerShell, execute o comando .\clear-local-script.ps1.

📚 Utilização básica

voltar ao topo

O trecho do código abaixo foi extraído da classe Customer] do projeto de exemplo na pasta samples/SampleApi.

O trecho de código abaixo possui o envelope de resposta no retorno dos métodos e como unir envelopes de resposta em um único envelope de resposta que agrega todos os demais.


// Public Methods
public static OutputEnvelop<Customer?> RegisterNew(string name, string email, DateOnly? birthDate)
{
    // Process
    var customer = new Customer();

    var processOutputEnvelop = OutputEnvelop.Create(
        customer.GenerateNewId(),
        customer.SetName(name),
        customer.SetEmail(email),
        customer.SetBirthDate(birthDate)
    );

    // Return
    return OutputEnvelop<Customer?>.Create(
        output: processOutputEnvelop.IsSuccess ? customer : null,
        processOutputEnvelop
    );
}

// Private Methods
private OutputEnvelop SetId(Guid id)
{
    // Validate
    if (id == Guid.Empty)
        return OutputEnvelop.CreateError(IdShouldRequiredMessageCode, IdShouldRequiredMessageDescription);

    // Process
    Id = id;

    // Return
    return OutputEnvelop.CreateSuccess();
}
private OutputEnvelop GenerateNewId()
{
    return SetId(Guid.NewGuid());
}

private OutputEnvelop SetName(string name)
{
    // Validate
    if (string.IsNullOrWhiteSpace(name))
        return OutputEnvelop.CreateError(NameShouldRequiredMessageCode, NameShouldRequiredMessageDescription);
    else if(name.Length > NameMaxLength)
        return OutputEnvelop.CreateError(NameShouldLessThanMaxLengthMessageCode, NameShouldLessThanMaxLengthMessageDescription);

    // Process
    Name = name;

    // Return
    return OutputEnvelop.CreateSuccess();
}

private OutputEnvelop SetEmail(string email)
{
    // Validate
    if (string.IsNullOrWhiteSpace(email))
        return OutputEnvelop.CreateError(EmailShouldRequiredMessageCode, EmailShouldRequiredMessageDescription);
    else if (email.Length > EmailMaxLength)
        return OutputEnvelop.CreateError(EmailShouldLessThanMaxLengthMessageCode, EmailShouldLessThanMaxLengthMessageDescription);

    // Process
    Email = email;

    // Return
    return OutputEnvelop.CreateSuccess();
}

private OutputEnvelop SetBirthDate(DateOnly? birthDate)
{
    // Validate
    if (birthDate is not null)
    {
        var age = DateTime.Now.Date.Year - birthDate.Value.Year;

        if (DateTime.Now.Month < birthDate.Value.Month)
            age--;
        else if (DateTime.Now.Month == birthDate.Value.Month && DateTime.Now.Day < birthDate.Value.Day)
            age--;

        if (age > BirthDateMaxAge)
            return OutputEnvelop.CreateError(BirthDateShouldLessThanMaxAgeMessageCode, BirthDateShouldLessThanMaxAgeMessageDescription);
    }

    // Process
    BirthDate = birthDate;

    // Return
    return OutputEnvelop.CreateSuccess();
}

📚 Exemplos

voltar ao topo

Para que possa ver, na prática, a utilização do envelope de resposta nos diferentes cenários para o qual ele foi projetado, criei uma API de exemplo localizando dentro do diretório samples/SampleApi.

🧑‍🤝‍🧑 Contribuindo

voltar ao topo

Você está mais que convidado para constribuir. Caso tenha interesse e queira participar do projeto, não deixe de ver nosso manual de contribuição.

🧑‍🤝‍🧑 Autores

voltar ao topo

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated