# 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.

**Publicado:** 13/10/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-criar-servico-validacao-cpf-dotnet-injecao-dependencia

---


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.

```csharp
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.

```csharp
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.

```csharp
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.

```csharp
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:

```csharp
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](https://www.gov.br/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.

### Leia também

- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [SLA de API de CPF: níveis de disponibilidade e o que exigir do seu provedor](https://cpfhub.io/blog/sla-api-cpf-niveis-disponibilidade)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [10 erros mais comuns ao integrar uma API de CPF e como evitá-los](https://cpfhub.io/blog/10-erros-mais-comuns-ao-integrar-uma-api-de-cpf)

---

## 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](https://www.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.

