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"
);
}
}
| Componente | Responsabilidade | Lifetime no DI |
|---|---|---|
ICpfValidator | Validação matemática local | Singleton |
ICpfApiClient | Comunicação HTTP com a API | Transient (via HttpClientFactory) |
ICpfValidationService | Orquestração da validação | Scoped |
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.
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.



