Ferramentas gratuitas para desenvolvedores. Nenhum dado real de pessoas é consultado ou armazenado.Como funciona o algoritmo do CPF →
C#

Validar, gerar e formatar CNPJ em C#

Classe estática em C# (.NET 8) para validar, gerar e formatar CNPJ numérico e alfanumérico, testes com xUnit [Theory] e chamada à API com HttpClient.

Roberto GuerraPublicado em 05 de outubro de 2026Editar no GitHub

Em aplicações .NET, o CNPJ costuma aparecer como long em entidades antigas, como string com máscara em DTOs e, às vezes, como os dois no mesmo sistema. O CNPJ alfanumérico obriga a padronizar: o identificador passa a ter letras nos 12 primeiros caracteres e só pode ser texto. A classe abaixo trata os dois formatos com a mesma conta, em que cada caractere vale o código ASCII menos 48 (dígitos de 0 a 9, letras de 17 a 42), e compila em .NET 8 com nullable habilitado e os usings implícitos do SDK. Os demais impactos estão no guia CNPJ alfanumérico: o que muda no seu sistema.

Validar CNPJ em C# (numérico e alfanumérico)

Cnpj.cs
using System.Security.Cryptography;
using System.Text.RegularExpressions;

namespace CpfDev;

public static class Cnpj
{
  private static readonly int[] Pesos1 = { 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
  private static readonly int[] Pesos2 = { 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
  private static readonly Regex Separadores = new(@"[./\-\s]", RegexOptions.Compiled);
  private static readonly Regex Formato = new(@"^[A-Z0-9]{12}[0-9]{2}\z", RegexOptions.Compiled);

  private static int CalcularDigito(string doze, int[] pesos)
  {
      var soma = 0;
      for (var i = 0; i < doze.Length; i++)
      {
          soma += (doze[i] - 48) * pesos[i];
      }
      var resto = soma % 11;
      return resto < 2 ? 0 : 11 - resto;
  }

  public static bool Validar(string? valor)
  {
      if (valor is null) return false;
      var cnpj = Separadores.Replace(valor.ToUpperInvariant(), "");
      if (!Formato.IsMatch(cnpj)) return false;
      var doze = cnpj[..12];
      if (doze.All(c => c == doze[0])) return false;
      var dv1 = CalcularDigito(doze, Pesos1);
      var dv2 = CalcularDigito(doze + dv1, Pesos2);
      return cnpj[12..] == $"{dv1}{dv2}";
  }

Detalhes da implementação:

  • ToUpperInvariant não depende da cultura da thread, o que evita surpresas em servidores configurados em outro idioma.
  • [0-9] em vez de \d. No .NET, \d casa dígitos Unicode de outros alfabetos, que passariam pela regex e estragariam a conta.
  • \z ancora no fim real da string; $ aceitaria uma quebra de linha final.
  • doze.All(c => c == doze[0]) recusa bases repetidas como 00.000.000/0000-00, que fecham a conta, mas não são CNPJs válidos.
  • doze[i] - 48 converte o char pelo código: '0' vira 0 e 'A' vira 17. char.GetNumericValue não serve, porque devolve -1 para letras.

Com 11.222.333/0001-81, a primeira soma é 102 (resto 3, dígito 8) e a segunda é 120 (resto 10, dígito 1). Com 12.ABC.345/01DE-35, as somas são 459 e 424, os restos 8 e 6, e os dígitos 3 e 5. No FluentValidation, a regra fica RuleFor(x => x.Cnpj).Must(Cnpj.Validar).WithMessage("CNPJ inválido").

Gerar CNPJ válido em C#

Os métodos a seguir ficam dentro da mesma classe. RandomNumberGenerator.GetString (.NET 8) sorteia cada caractere com o gerador criptográfico do sistema.

Cnpj.cs
    private const string Digitos = "0123456789";
  private const string Alfanumericos = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  public static string Gerar(bool alfanumerico = false, bool formatado = false)
  {
      var alfabeto = alfanumerico ? Alfanumericos : Digitos;
      string doze;
      do
      {
          doze = RandomNumberGenerator.GetString(alfabeto, 12);
      } while (doze.All(c => c == doze[0]));
      var dv1 = CalcularDigito(doze, Pesos1);
      var dv2 = CalcularDigito(doze + dv1, Pesos2);
      var cnpj = $"{doze}{dv1}{dv2}";
      return formatado ? Formatar(cnpj) : cnpj;
  }

O CNPJ gerado passa na validação, mas pode coincidir com um CNPJ real por acaso; use-o em seeds e testes, nunca como dado de uma empresa. Para simular matriz e filiais, mantenha a raiz e varie a ordem (0001 é a matriz), como explica o guia da estrutura do CNPJ.

Formatar e limpar CNPJ em C#

Cnpj.cs
    public static string Limpar(string? valor) =>
      Regex.Replace((valor ?? "").ToUpperInvariant(), "[^A-Z0-9]", "");

  public static string Formatar(string? valor)
  {
      var c = Limpar(valor);
      if (c.Length != 14)
          throw new ArgumentException("CNPJ precisa de 14 caracteres", nameof(valor));
      return $"{c[..2]}.{c[2..5]}.{c[5..8]}/{c[8..12]}-{c[12..]}";
  }
}

Cnpj.Formatar("12abc34501de35") devolve "12.ABC.345/01DE-35", e aplicar o método de novo no resultado não muda nada. No Entity Framework, mapeie a propriedade como string com HasMaxLength(14) e grave a versão limpa; uma coluna bigint não comporta letras. Para validar a máscara com uma única expressão, veja o guia de regex de CNPJ.

Testes

No xUnit, [Theory] com um [InlineData] por caso gera um teste para cada linha.

CnpjTests.cs
using CpfDev;
using Xunit;

public class CnpjTests
{
  [Theory]
  [InlineData("11.222.333/0001-81", true)]
  [InlineData("12.ABC.345/01DE-35", true)]
  [InlineData("11.222.333/0001-82", false)]
  [InlineData("00.000.000/0000-00", false)]
  public void Validar_DevolveOResultadoEsperado(string cnpj, bool esperado)
  {
      Assert.Equal(esperado, Cnpj.Validar(cnpj));
  }

  [Theory]
  [InlineData(false)]
  [InlineData(true)]
  public void Gerar_ProduzCnpjsValidos(bool alfanumerico)
  {
      for (var i = 0; i < 1000; i++)
          Assert.True(Cnpj.Validar(Cnpj.Gerar(alfanumerico)));
  }

  [Fact]
  public void Formatar_EhIdempotente() =>
      Assert.Equal("12.ABC.345/01DE-35", Cnpj.Formatar(Cnpj.Formatar("12abc34501de35")));
}

Rode com dotnet test. Mais combinações estão nos exemplos de CNPJ alfanumérico para teste.

Usar a API em vez de reimplementar

A API do cpf.dev.br valida e gera CNPJs por HTTP, sem chave, com limite de 60 requisições por minuto por IP. Envie o CNPJ sem máscara, ou passe-o por Uri.EscapeDataString, que troca a barra por %2F. GetFromJsonAsync desserializa a resposta direto para um record.

Program.cs
using System.Net.Http.Json;

using var http = new HttpClient { BaseAddress = new Uri("https://www.cpf.dev.br/") };

var r = await http.GetFromJsonAsync<RespostaCnpj>("api/v1/cnpj/validar/12ABC34501DE35");
Console.WriteLine(r);
// RespostaCnpj { Valido = True, Cnpj = 12ABC34501DE35, Formatado = 12.ABC.345/01DE-35,
//   Formato = alfanumerico, Raiz = 12ABC345, Ordem = 01DE, Matriz = False }

var lote = await http.GetFromJsonAsync<RespostaLote>(
  "api/v1/cnpj/gerar?quantidade=5&formato=alfanumerico&formatado=true");
Console.WriteLine(string.Join(", ", lote!.Cnpjs));

public record RespostaCnpj(bool Valido, string Cnpj, string Formatado, string Formato, string Raiz, string Ordem, bool Matriz);
public record RespostaLote(string[] Cnpjs);

O exemplo cria um HttpClient direto para ficar curto; em ASP.NET Core, registre-o com IHttpClientFactory. Para formulários, a classe local continua sendo a melhor opção. Para conferir um número à mão, use o validador de CNPJ.

Leia também