Como criar um serviço de validação de CPF em .NET com injeção de dependência

Crie um serviço de validação de CPF em .NET usando injeção de dependência, interfaces e boas práticas de arquitetura.

Redação CPFHub.io
Redação CPFHub.io
··6 min de leitura
Como criar um serviço de validação de CPF em .NET com injeção de dependência

Para criar um serviço de validação de CPF em .NET com injeção de dependência, defina três interfaces — ICpfValidator, ICpfApiClient e ICpfValidationService — e registre suas implementações no contêiner de DI usando AddSingleton, AddHttpClient e AddScoped. Esse padrão permite trocar implementações em testes unitários sem alterar o código consumidor e mantém cada componente com responsabilidade única. A integração com a API do CPFHub.io é encapsulada no CpfApiClient, que usa HttpClientFactory para gerenciamento eficiente de conexões.

Introdução

A injeção de dependência é um dos pilares do desenvolvimento moderno em .NET. Ela permite criar componentes desacoplados, testáveis e fáceis de manter. Este artigo mostra como estruturar um serviço de validação de CPF seguindo boas práticas de arquitetura em .NET Core para consumir a API do CPFHub.io.


Definindo as interfaces do serviço

O primeiro passo é criar contratos claros através de interfaces. Isso permite trocar implementações sem alterar o código consumidor.

public interface ICpfValidator
{
    bool ValidarFormato(string cpf);
}

public interface ICpfApiClient
{
    Task<CpfResponse?> ConsultarAsync(string cpf);
}

public interface ICpfValidationService
{
    Task<ValidationResult> ValidarCompletoAsync(string cpf);
}

public record ValidationResult(
    bool IsValid,
    bool IsFound,
    string? Name,
    string? BirthDate,
    string Message
);

public record CpfResponse(
    bool Success,
    CpfData Data
);

public record CpfData(
    string Cpf,
    string Name,
    string NameUpper,
    string Gender,
    string BirthDate,
    string Day,
    string Month,
    string Year
);

Implementando o validador local

A implementação do validador de formato verifica os dígitos verificadores do CPF sem necessidade de chamada externa.

public class CpfValidator : ICpfValidator
{
    public bool ValidarFormato(string cpf)
    {
    cpf = new string(cpf.Where(char.IsDigit).ToArray());

    if (cpf.Length != 11 || cpf.Distinct().Count() == 1)
    return false;

    var soma = 0;
    for (int i = 0; i < 9; i++)
    soma += (cpf[i] - '0') * (10 - i);

    var digito1 = soma % 11 < 2 ? 0 : 11 - (soma % 11);

    soma = 0;
    for (int i = 0; i < 10; i++)
    soma += (cpf[i] - '0') * (11 - i);

    var digito2 = soma % 11 < 2 ? 0 : 11 - (soma % 11);

    return cpf[9] - '0' == digito1 && cpf[10] - '0' == digito2;
    }
}

Implementando o cliente da API

O cliente da API encapsula toda a lógica de comunicação HTTP com o CPFHub.io.

public class CpfApiClient : ICpfApiClient
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<CpfApiClient> _logger;

    public CpfApiClient(HttpClient httpClient, ILogger<CpfApiClient> logger)
    {
    _httpClient = httpClient;
    _logger = logger;
    }

    public async Task<CpfResponse?> ConsultarAsync(string cpf)
    {
    try
    {
    _logger.LogInformation("Consultando CPF: {Cpf}", cpf[..3] + "***");
    var response = await _httpClient.GetAsync($"cpf/{cpf}");

    if (!response.IsSuccessStatusCode)
    {
    _logger.LogWarning("API retornou status {Status}", response.StatusCode);
    return null;
    }

    return await response.Content.ReadFromJsonAsync<CpfResponse>();
    }
    catch (Exception ex)
    {
    _logger.LogError(ex, "Erro ao consultar API de CPF");
    return null;
    }
    }
}

Compondo o serviço de validação

O serviço de validação orquestra o validador local e o cliente da API, retornando um resultado unificado.

public class CpfValidationService : ICpfValidationService
{
    private readonly ICpfValidator _validator;
    private readonly ICpfApiClient _apiClient;

    public CpfValidationService(ICpfValidator validator, ICpfApiClient apiClient)
    {
    _validator = validator;
    _apiClient = apiClient;
    }

    public async Task<ValidationResult> ValidarCompletoAsync(string cpf)
    {
    if (!_validator.ValidarFormato(cpf))
    return new ValidationResult(false, false, null, null,
    "CPF com dígitos verificadores inválidos");

    var response = await _apiClient.ConsultarAsync(cpf);

    if (response is not { Success: true })
    return new ValidationResult(true, false, null, null,
    "CPF válido, porém não encontrado na base");

    return new ValidationResult(
    true, true,
    response.Data.Name,
    response.Data.BirthDate,
    "CPF válido e encontrado na base"
    );
    }
}
ComponenteResponsabilidadeLifetime no DI
ICpfValidatorValidação matemática localSingleton
ICpfApiClientComunicação HTTP com a APITransient (via HttpClientFactory)
ICpfValidationServiceOrquestração da validaçãoScoped

Registrando tudo no container de DI

No Program.cs, registre todos os serviços com seus respectivos lifetimes:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<ICpfValidator, CpfValidator>();

builder.Services.AddHttpClient<ICpfApiClient, CpfApiClient>(client =>
{
    client.BaseAddress = new Uri("https://api.cpfhub.io/");
    client.DefaultRequestHeaders.Add("x-api-key",
    builder.Configuration["CpfHub:ApiKey"]);
});

builder.Services.AddScoped<ICpfValidationService, CpfValidationService>();

builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();

Perguntas frequentes

Por que usar três interfaces em vez de uma única classe de validação?

Separar ICpfValidator, ICpfApiClient e ICpfValidationService em interfaces distintas segue o princípio da responsabilidade única e facilita testes unitários. Em testes, você pode mockar apenas ICpfApiClient sem precisar simular toda a lógica de validação local. Além disso, se quiser trocar o provedor de API sem alterar a lógica de negócio, basta criar uma nova implementação de ICpfApiClient e registrá-la no contêiner.

Qual lifetime de DI devo usar para o serviço de validação de CPF?

ICpfValidator deve ser Singleton pois não tem estado mutável. ICpfApiClient deve ser registrado via AddHttpClient (Transient gerenciado pelo HttpClientFactory) para evitar o problema de HttpClient esgotado. ICpfValidationService pode ser Scoped, pois sua vida útil é naturalmente limitada ao ciclo de uma requisição HTTP na maioria dos cenários.

Como garantir conformidade com a LGPD ao usar a API de CPF em .NET?

Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário (não guarde o CPF cru se um token bastar), implemente controle de acesso aos logs de consulta e documente a base legal para o tratamento. A ANPD orienta que dados de identificação devem ser tratados com o princípio da necessidade.

Como testar unitariamente o serviço de validação sem chamar a API real?

Crie um mock de ICpfApiClient usando qualquer framework de mocking (Moq, NSubstitute). Configure o mock para retornar um CpfResponse com Success: true e os dados desejados, depois injete-o no CpfValidationService no teste. Como o serviço depende apenas da interface, ele não faz chamadas HTTP reais durante os testes, tornando o suite rápido e determinístico.


Conclusão

Utilizar injeção de dependência para criar um serviço de validação de CPF resulta em código limpo, testável e extensível. Cada componente tem uma responsabilidade bem definida e pode ser substituído ou mockado em testes unitários.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e integre a consulta de CPF na sua aplicação .NET com arquitetura de injeção de dependência pronta para produção.

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

Sobre a redação

Redação CPFHub.io

Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.

WhatsAppFale conosco via WhatsApp