Jarvis.Toolkit 1.2.2.7

dotnet add package Jarvis.Toolkit --version 1.2.2.7
                    
NuGet\Install-Package Jarvis.Toolkit -Version 1.2.2.7
                    
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="Jarvis.Toolkit" Version="1.2.2.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Jarvis.Toolkit" Version="1.2.2.7" />
                    
Directory.Packages.props
<PackageReference Include="Jarvis.Toolkit" />
                    
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 Jarvis.Toolkit --version 1.2.2.7
                    
#r "nuget: Jarvis.Toolkit, 1.2.2.7"
                    
#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 Jarvis.Toolkit@1.2.2.7
                    
#: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=Jarvis.Toolkit&version=1.2.2.7
                    
Install as a Cake Addin
#tool nuget:?package=Jarvis.Toolkit&version=1.2.2.7
                    
Install as a Cake Tool

Jarvis.Toolkit

Biblioteca de utilidades para .NET com extensões, validações, serviços HTTP, criptografia, autenticação, e-mail, notificações push e muito mais.

Instalação

dotnet add package Jarvis.Toolkit

Extensões

String

// Extrair conteúdo
"123.456.789-00".GetOnlyNumbers(); // "12345678900"
"-12a3".GetOnlyNumbers(allowSign: true); // "-123" (mantém '-' só na 1ª posição)
"abc123".GetOnlyLetters(); // "abc"
"user@mail.com".GetSubstringBeforeChar('@'); // "user"
"abcdef".Take(3); // "abc"
"abcdef".TakeLast(3); // "def"

// Verificações
"texto".IsNullOrEmpty(); // false
"   ".IsNullOrEmptyOrWhiteSpace(); // true
"".NotNullOrEmpty(); // false
"texto".NotNullOrEmptyOrWhiteSpace(); // true

// Caixa e capitalização
"  ABC ".TrimToLower(); // "abc"
"  abc ".TrimToUpper(); // "ABC"
"hello world".FirstCharToUpper(); // "Hello world"
"hELLO WORLD".OnlyFirstCharToUpper(); // "Hello world"
"hello world".AllFirstCharToUpper(); // "Hello World"

// Máscara
"12345678900".SetMask(MaskType.CPF); // "123.456.789-00"
"12345678000199".SetMask(MaskType.CNPJ); // "12.345.678/0001-99"
"12345678".SetMask(MaskType.CEP); // "12345-678"
"4721102".SetMask(MaskType.CNAE); // "4721-1/02"
"1134567890".SetMask(MaskType.Telephone); // "(11) 3456-7890"
"11987654321".SetMask(MaskType.Cellphone); // "(11) 98765-4321"
"11987654321".SetMask(MaskType.PhoneNumber); // "(11) 98765-4321" (10 dígitos = fixo)
"123456".SetMask(MaskType.Money); // "R$ 1.234,56"
"1250".SetMask(MaskType.Percent); // "12,50%"
"1234".SetMask(MaskType.Numeric); // "1.234"
"1430".SetMask(MaskType.Time); // "14:30"
"143000".SetMask(MaskType.LongTime); // "14:30:00"
"25122024".SetMask(MaskType.Date); // "25/12/2024"
"122026".SetMask(MaskType.CreditCardDate); // "12/2026"
"1234567890".SetMask("(##) ####-####"); // "(12) 3456-7890"

// Remover e substituir (RemoveSpecialCharacters/ReplaceSpecialCharacters também removem espaços)
"a-b.c".Remove("-", "."); // "abc" (remove cada string)
"a-b.c".Remove("-."); // "abc" (remove cada caractere)
"café".RemoveAccentuation(); // "cafe"
"a@b#c".RemoveSpecialCharacters(); // "abc"
"a-b@c".RemoveSpecialCharacters("-"); // "a-bc"
"Olá, mundo!".ReplaceSpecialCharacters("-"); // "Ola-mundo-"
"1,234,56".KeepFirstChar(','); // "1,23456"

// Dividir e alinhar
"abcde".SplitString(); // ["abc", "de"]
"abcdefgh".SplitString(3); // ["abc", "def", "gh"]
"A".LeftRightAlign("B", 5); // "A   B" (padrão: 32)

// Montar texto
"João".Format("Olá, {0}! Idade: {1}", 30); // "Olá, João! Idade: 30"
"123".InsertStart("R$ "); // "R$ 123"
"50".InsertEnd("%"); // "50%"
new[] { "a", "b" }.ArrayToHorizontalString(); // "a, b"
new[] { "a", "b" }.ArrayToVerticalString(); // "- a;\n- b;"

// Truncar, nomes e telefone
"texto longo".Truncate(5); // "texto..."
"João Carlos Silva".GetFirstAndLastName(); // "João Silva"
"(11) 98765-4321".NormalizePhoneBr(); // "5511987654321"

// Valor padrão
string nulo = null;
nulo.IfNullOrEmpty("padrão"); // "padrão"
"  ".IfNullOrEmptyOrWhiteSpace("padrão"); // "padrão"

Data e Hora

var data = new DateTime(2026, 2, 1, 14, 30, 0); // domingo
var utc = new DateTime(2026, 2, 1, 17, 30, 0, DateTimeKind.Utc);

// Validações (formato brasileiro)
"14:30".IsTime(); // true
"14:30:15".IsTime(includeSeconds: true); // true
"25/12/2024".IsDate(); // true
"12/2024".IsDate(includeDays: false); // true
"25/12/2024 14:30".IsDateTime(); // true
"25/12/2024 14:30:15".IsDateTime(includeSeconds: true); // true
"01/01/2024 - 31/12/2024".IsDateRange(); // true
"01/01/2024 08:00 - 01/01/2024 18:00".IsDateTimeRange(); // true

// Intervalos
data.InRange("01/01/2026 - 31/12/2026"); // true
data.InRange("01/01/2026", "31/12/2026"); // true
data.InRange(DateRange.ThisMonth); // DateRange
data.InRange(new DateTimeRange(inicio, fim)); // DateTimeRange (considera hora)
data.DateInNextDays(0, 7); // data entre hoje e daqui a 7 dias
nascimento.BirthdayInNextDays(0, 30); // aniversário nos próximos 30 dias
nascimento.IsBirthday(); // hoje é aniversário (dia e mês)
data.IsWeekend(); // true
DayOfWeek.Monday.IsWeekend(); // false

// Conversões para string
data.ToDate(); // "01/02/2026"
data.ToDate(includeDays: false); // "02/2026"
data.ToDateTime(); // "01/02/2026 14:30"
data.ToDateTime(includeSeconds: true); // "01/02/2026 14:30:00"
data.ToTime(); // "14:30"
new TimeSpan(14, 30, 0).ToTime(includeSeconds: true); // "14:30:00"
data.ToISODate(); // "2026-02-01"
data.ToISODateTime(); // "2026-02-01 14:30:00"

// Conversões de string (null se inválido)
"25/12/2024".ToDate(); // DateTime? 25/12/2024
"12/2024".ToDate(includeDays: false); // DateTime? 01/12/2024
"25/12/2024 14:30".ToDateTime(); // DateTime?
"14:30".ToTime(); // TimeSpan? 14:30:00
"2024-12-25".ToISODate(); // DateTime?
"2024-12-25T14:30:00Z".ToISODateTime(); // DateTime? 25/12/2024 14:30:00

// Fuso horário Brasil (Unspecified é tratado como UTC)
utc.ToDateTimeBr(); // 01/02/2026 14:30 (aceita DateTime?)
utc.Br(); // atalho de ToDateTimeBr
utc.ToDateTimeBrString(); // "01/02/2026 14:30"
utc.ToDateBr(); // 01/02/2026 00:00 (aceita DateTime?)
utc.ToDateBrString(); // "01/02/2026"
utc.ToTimeBr(); // TimeSpan 14:30:00
utc.ToTimeBrString(); // "14:30"
TimeZoneInfo.Local.Br(); // TimeZoneInfo de Brasília
DateTimeBr.Now; // agora em Brasília
DateTimeBr.Today; // hoje (sem hora) em Brasília
DateTimeBr.TimeOfDay; // hora atual em Brasília
horarioBr.ToUtcFromBr(); // inverso de ToDateTimeBr: horário de Brasília -> UTC (aceita DateTime?; se já for UTC, retorna igual)

// Fuso local do sistema
utc.ToDateTimeLocal(); // converte para o fuso local
utc.ToDateTimeLocalString(); // "dd/MM/yyyy HH:mm" no fuso local

// Kind (altera apenas o Kind, sem converter o valor; aceita DateTime?)
dataDoBanco.AsUtc(); // marca como DateTimeKind.Utc
dataDoBanco.AsUnspecified(); // marca como DateTimeKind.Unspecified

// Idade
DateTime.Today.AddYears(-30).Age(); // 30
DateTime.Today.AddYears(-2).AddMonths(-3).AgeWithMonths(); // "2 anos e 3 meses"
DateTime.Today.AddMonths(-1).AgeWithMonths(); // "1 mês" (DateTime? null → "")

// Dia da semana / Mês (pt-BR)
data.ToDay(); // "Domingo"
DayOfWeek.Monday.ToDay(); // "Segunda-feira"
data.ToMonth(); // "Fevereiro"

// Limites
data.DaysInMonth(); // 28
data.EndOfDay(); // 01/02/2026 23:59:59.999
data.FirstDayOfMonth(); // 01/02/2026 00:00
data.LastDayOfMonth(); // 28/02/2026 23:59:59.999
data.FirstDayOfYear(); // 01/01/2026 00:00
data.LastDayOfYear(); // 31/12/2026 23:59:59.999
data.Min(DateTime.Today); // nunca antes de hoje (retorna a maior)
data.Max(DateTime.Today); // nunca depois de hoje (retorna a menor)

Objeto

object obj = null;
obj.IsNull(); // true
obj.NotNull(); // false

// Conversões
"123".ToInt(); // 123
"3.14".ToDouble(); // 3.14
"guid-string".ToGuid(); // Guid
"123".ToIntNullable(); // int?

// Condicionais
valor.If(condicao, novoValor);
condicao.IfElse(valorTrue, valorFalse);
item.IsNullOrNotEnabled(); // verifica propriedade "Ativo"

Número

(-5).IfNegative(0); // 0
(0).IfZero(1); // 1
(-5).IfNegativeOrZero(1); // 1

valor.MinValue(0); // não permite menor que 0
valor.MaxValue(100); // não permite maior que 100
valor.RangeValue(0, 100); // limita entre 0 e 100

Formatação (pt-BR)

1234.56.ToMoney(); // "R$ 1.234,56"
15.75.ToPercent(); // "15,75%" (só formata; não multiplica por 100)
0.1575.ToPercent(); // "0,16%"
1234.56.ToNumber(); // "1.234,56"

// Converter de string formatada para número
"R$ 1.234,56".ToNumber<double>(); // 1234.56
"15,75%".ToNumber<double>(); // 15.75

Validação

// Documentos (aceita com ou sem máscara)
"123.456.789-09".IsCPF(); // true
"12345678900".IsCPF(); // false (dígito inválido)
"00.038.166/0001-05".IsCNPJ(); // true
"01310-100".IsCEP(); // true (8 dígitos)
"4721-1/02".IsCNAE(); // true (7 dígitos, com ou sem máscara)

// Contato
"user@email.com".IsEmail(); // true
"(11) 99988-7766".IsPhoneNumber(); // true (DDD + 8 ou 9 dígitos)
"1133334444".IsPhoneNumber(); // true
"a@b.com; c@d.com".IsEmailList(); // true (separados por ; e ignora ; no final)

// Chave PIX (CPF/CNPJ só números, celular +55, e-mail ou EVP)
"12345678909".IsChavePix(); // true
"123.456.789-09".IsChavePix(); // false (CPF com máscara)
"+5511999887766".IsChavePix(); // true
"11999887766".IsChavePix(); // false (celular exige +55)
"123e4567-e89b-12d3-a456-426614174000".IsChavePix(); // true (EVP)

// Cartão de crédito
"4111 1111 1111 1111".IsCreditCard(); // true (só verifica 16 dígitos)
"12/2030".IsCreditCardDate(); // true (MM/yyyy)
"12/30".IsCreditCardDate(); // false

// Negações
"abc".NotEmail(); // true
"abc".NotCPF(); // true
"abc".NotCNPJ(); // true
"abc".NotCEP(); // true
"abc".NotPhoneNumber(); // true
"abc".NotChavePix(); // true

// Guid?
Guid? id = null;
id.IsNull(); // true
id.NotNull(); // false
id.IsEmpty(); // false (null não é Guid.Empty)
id.NotEmpty(); // true
id.IsNullOrEmpty(); // true
id.NotNullOrEmpty(); // false

Serialização JSON

// Serializar
var json = objeto.Serialize();
var json = objeto.Serialize(writeIndented: true);

// Deserializar
var obj = json.Deserialize<Produto>();
var obj = json.TryDeserialize<Produto>(); // retorna default em caso de erro

Mapeamento de Objetos

// Mapear propriedades por nome
var model = source.MapTo<TargetModel>();

// Com controle
var result = source.MapTo(target);
result.Set(x => x.Nome, s => s.FullName);

// Mapear lista
var result = sources.MapListTo(new TargetModel());

// Ignorar propriedades nulas
var result = source.MapToIgnoreNull(target);

// Atributos de controle
[MapIgnoreSource] // na propriedade do destino: não recebe valor da origem
[MapIgnoreTarget] // na propriedade da origem: não é copiada para o destino

Coleções e Listas

// Paginação
var pagina = lista.Page(pageNumber: 2, pageSize: 10);
var total = lista.TotalPages(pageSize: 10);

// Verificações
lista.IsNullOrEmpty();
lista.IsEmpty();
lista.EmptyIfNull(); // retorna vazio em vez de null

// Operações
lista.ForEach(x => x.Ativo = true);
lista.Randomize();
lista.Split(3); // divide em 3 grupos
lista.Partition(10); // divide em páginas de 10
lista.WithIndex(); // ForeachResult com Index, IsFirstItem, IsLastItem

// Filtros opcionais (ignora se valor é null)
lista.WhereOptional(x => x.Status, statusFiltro);
lista.InRange(x => x.Valor, min, max);

IQueryable

// Paginação (compatível com EF Core)
query.Page(pageNumber, pageSize);
query.TotalPages(pageSize);

// Filtros opcionais (ignora se valor é null)
query.WhereOptional(x => x.Status, statusFiltro);
query.InRange(x => x.Valor, min, max);
query.Contains(x => x.Nome, textoBusca);

Enum

public enum Status
{
    [Display(Name = "Ativo", Description = "Registro ativo")]
    Ativo = 1,
    Inativo = 2,
    [Exclude]
    Removido = 3
}

// Conversão
Status.Ativo.ToInt(); // 1
Status.Ativo.ToIntString(); // "1"
1.ToEnum<Status>(); // Status.Ativo (Status?)
99.ToEnum<Status>(); // null
"ativo".ToEnum<Status>(); // Status.Ativo (case-insensitive)
"xyz".ToEnum<Status>(); // null
"Ativo".TryToEnum<Status>(out var status); // true (também compara pelo Display Name)

// Display attribute (sem atributo, retorna ToString())
Status.Ativo.GetName(); // "Ativo"
Status.Ativo.GetDescription(); // "Registro ativo"
Status.Inativo.GetDescription(); // "Inativo"
Status.Ativo.ToName(); // alias de GetName
Status.Ativo.ToDescription(); // alias de GetDescription
1.ToEnumName<Status>(); // "Ativo"
1.ToEnumDescription<Status>(); // "Registro ativo"

// Listar (atalho Enum<T>)
Enum<Status>.AsEnumerable(); // Ativo, Inativo, Removido
Enum<Status>.AsEnumerable(Status.Inativo); // Ativo, Removido
Enum<Status>.FilterExcluded(); // Ativo, Inativo (ignora [Exclude])
Enum<Status>.ToGenericList(); // GenericList<Status> (valor + GetName)

// Listar (ExtensionEnum, todos aceitam params except)
ExtensionEnum.ToList<Status>(); // [Ativo, Inativo, Removido]
ExtensionEnum.ToListInt<Status>(); // [1, 2, 3]
ExtensionEnum.ToListString<Status>(); // ["Ativo", "Inativo", "Removido"]
ExtensionEnum.ToListIntString<Status>(); // ["1", "2", "3"]
ExtensionEnum.ToListName<Status>(Status.Removido); // ["Ativo", "Inativo"]
ExtensionEnum.ToListDescription<Status>(); // ["Registro ativo", "Inativo", "Removido"]
ExtensionEnum.FilterExcluded(typeof(Status)); // IEnumerable<Enum> sem [Exclude]

Arquivo (Extensões)

// byte[] <-> Stream
var stream = bytes.ToStream(); // Stream
var memory = bytes.ToMemoryStream(); // MemoryStream (ArgumentNullException se null)
var bytes = stream.ToByteArray();
var bytes = await stream.ToByteArrayAsync();

// Base64
bytes.ToBase64String(); // "iVBORw0KGgo..."
stream.ToBase64String(); // "iVBORw0KGgo..."
bytes.ToDataBase64String(); // "data:image/png;base64,iVBORw0KGgo..." (prefixo sempre image/png)
stream.ToDataBase64String(); // "data:image/png;base64,iVBORw0KGgo..."
"iVBORw0KGgo...".FromBase64String(); // byte[]
"data:image/png;base64,iVBORw0KGgo...".FromDataBase64String(); // byte[]
"data:image/png;base64,iVBORw0KGgo...".GetBase64String(); // "iVBORw0KGgo..."

// Extensão
"data:image/png;base64,iVBORw0KGgo...".GetFileExtension(); // ".png"
"iVBORw0KGgo...".GetExtension(); // ".png" (detecta pela assinatura; "" se desconhecida)
"JVBERi0xLjQ...".GetExtension(); // ".pdf"
".png".IsImageFile(); // true (png, jpg, jpeg, bmp, gif, tiff, webp)
".PNG".IsImageFile(); // false (case-sensitive)

// Content type
"relatorio.pdf".GetContentType(); // "application/pdf"
"C:\\fotos\\foto.JPG".GetContentType(); // "image/jpeg"
"planilha.xlsx".GetContentType(); // "application/vnd.ms-excel"
"arquivo.xyz".GetContentType(); // "application/octet-stream"
"semextensao".GetContentType(); // ArgumentNullException

// Bytes -> KB/MB (int, long ou byte[])
2048.ToKilobytes(); // 2
2097152L.ToMegabytes(); // 2
bytes.ToKilobytes(); // bytes.Length / 1024
bytes.ToMegabytes(); // bytes.Length / 1024 / 1024

// KB/MB -> bytes (int, long ou double)
50.Kilobytes(); // 51200
1.5.Kilobytes(); // 1536
50.Megabytes(); // 52428800
1.5.Megabytes(); // 1572864

// Tamanho formatado (int, long ou byte[]; separador conforme cultura)
500.GetFileSize(); // "500,0 B"
2048.GetFileSize(); // "2,0 KB"
1572864L.GetFileSize(); // "1,5 MB"
bytes.GetFileSize(); // "1,5 MB"

Criptografia e Hash

// AES (chave de até 16 caracteres, IV aleatório no início do Base64)
var encrypted = "texto".AESEncrypt("chave16chars!!!");
var decrypted = encrypted.AESDecrypt("chave16chars!!!"); // "texto"

// AES-GCM 256 bits autenticado (.NET 5+; chave de qualquer tamanho, derivada via SHA256)
// Saída: Base64 de nonce (12 bytes) + tag (16 bytes) + texto cifrado. Muda a cada chamada.
var cifrado = "texto".AesGcmEncrypt(chave);
var texto = cifrado.AesGcmDecrypt(chave); // "texto" (null se chave errada, adulterado, nulo ou vazio)

// AES-GCM para bytes (ex: arquivo .pfx de certificado digital), mesmo formato sem o Base64
byte[] pfxCifrado = pfx.AesGcmEncrypt(chave); // nonce + tag + bytes cifrados (null se nulo ou vazio)
byte[] pfxOriginal = pfxCifrado.AesGcmDecrypt(chave); // null se chave errada ou adulterado
// Use chave forte e aleatória (ex.: 32+ caracteres vindos da configuração).
// Para senha de usuário, use hash (JarvisPassword), não criptografia.

// Hash (null se vazio)
"texto".ToSHA1Encode(); // hex maiúsculo (40 chars)
"texto".ToSHA256Encode(); // hex maiúsculo (64 chars)
"texto".ToMD5Encode(); // hex minúsculo (32 chars)
"texto".ToSHA1Encode("ISO-8859-1"); // encoding customizado

// Base64 (iterations opcional)
var base64 = "texto".Base64Encode(); // "dGV4dG8="
var original = base64.Base64Decode(); // "texto"
"texto".Base64Encode(2).Base64Decode(2); // codifica/decodifica 2 vezes

// URL Slug (maxLength padrão 50)
"Meu Título Aqui".ToUrlSlug(); // "meu-titulo-aqui"
123.IdToSlug("Meu Título Aqui"); // "123-meu-titulo-aqui"
"123-meu-titulo-aqui".SlugToId(); // 123 (-1 se inválido)

// Ofuscar ID inteiro (SHA1 de ticks + id embutido)
var token = 42.EncrypId(); // string ofuscada (muda a cada chamada)
token.DecryptId(); // 42 (-1 se inválido; exceção se tamanho <= 40)

// Guid
Guid.NewGuid().ToId(); // "3f2504e04f8911d39a0c0305e82c3301" (formato "N")
"guid-string".ToGuid(); // Guid ou Guid.Empty se inválido

JarvisCertificate (.NET 9+)

Carrega certificado e valida vencimento, início de validade e chave privada RSA. Retorna CertificateResponse (IsSuccess, Message, Certificate, ExpirationDate).

// PEM (.crt + .key)
var result = JarvisCertificate.LoadPem("cert.crt", "cert.key");

// PFX por arquivo ou bytes
var result = JarvisCertificate.LoadPfx("cert.pfx", "senha");
var result = JarvisCertificate.LoadPfx(pfxBytes, "senha");

// Flags opcionais (padrão: MachineKeySet | Exportable)
var result = JarvisCertificate.LoadPfx("cert.pfx", "senha", X509KeyStorageFlags.UserKeySet);

if (result.IsSuccess)
{
    var cert = result.Certificate; // X509Certificate2
}
else
{
    var erro = result.Message; // "Certificado digital vencido em dd/MM/yyyy."
}

JarvisUrlEncryptor

Gera tokens criptografados (AES-256) para URLs contendo qualquer valor (Guid, string, int, long, enum etc.), válidos somente para o dia informado. O token é URL-safe (Base64 com - e _).

var secret = "minha-chave-secreta";

// Gerar token válido somente para hoje
var tokenId = JarvisUrlEncryptor.Encrypt(123, DateTime.Today, secret);
var tokenEmail = JarvisUrlEncryptor.Encrypt("cliente@email.com", DateTime.Today, secret);
var tokenGuid = JarvisUrlEncryptor.Encrypt(meuGuid, DateTime.Today, secret);
// Use na URL: /minha-rota?token=xxxx

// Descriptografar e validar (retorna false se o token for de outro dia ou inválido)
if (JarvisUrlEncryptor.TryDecrypt<int>(tokenId, DateTime.Today, secret, out var id))
{
    // id == 123
}

// Retorna default (null, 0 etc.) se inválido
var email = JarvisUrlEncryptor.Decrypt<string>(tokenEmail, DateTime.Today, secret);
var guid = JarvisUrlEncryptor.Decrypt<Guid>(tokenGuid, DateTime.Today, secret); // Guid.Empty se inválido

HTML

"texto".Bold(); // <b>texto</b>
"texto".Italic(); // <i>texto</i>
"texto".Paragraph(); // <p>texto</p>
"texto".Link("https://..."); // <a href='https://...'>texto</a>

Claims

// Ler claims do ClaimsPrincipal
var id = User.Id();
var name = User.Name();
var roles = User.Roles();
var email = User.Email();
var isAuth = User.IsAuthenticated();

URI e Query String

var query = QueryItem.Object("nome", "João")
    .AddObject("idade", 30)
    .AddDate("data", DateTime.Now);

var url = query.ToUri("https://api.exemplo.com/buscar");
// https://api.exemplo.com/buscar?nome=Jo%c3%a3o&idade=30&data=2026-02-01

Atributos de Validação

// Documentos e contato (null/vazio é válido; combine com [Required])
[CPF(ErrorMessage = "CPF inválido")]
public string CPF { get; set; }

[CNPJ(ErrorMessage = "CNPJ inválido")]
public string CNPJ { get; set; }

[CPF_CNPJ(ErrorMessage = "Documento inválido")]
public string Documento { get; set; }

[CEP(ErrorMessage = "CEP inválido")]
[CNAE(ErrorMessage = "CNAE inválido")]
public string CEP { get; set; }

[PhoneNumber(ErrorMessage = "Telefone inválido")]
[EmailList(ErrorMessage = "Informe e-mails válidos separados por ;")]
public string Telefone { get; set; }

[ChavePix(ErrorMessage = "Chave PIX inválida")]
public string ChavePix { get; set; }

// Valores (ctor aceita int, long, float, double ou decimal; null é inválido)
[MinValue(1, ErrorMessage = "Mínimo 1")]
public int Quantidade { get; set; }

[MaxValue(100, ErrorMessage = "Máximo 100")]
public int Porcentagem { get; set; }

// Guid (null é válido; Guid.Empty é inválido)
[NotEmptyGuid(ErrorMessage = "Selecione um item")]
public Guid ItemId { get; set; }

// Listas
[NotEmptyList(ErrorMessage = "Lista não pode ser vazia")] // null válido, vazia inválida
public List<int> Itens { get; set; }

[RequiredList(ErrorMessage = "Lista obrigatória")] // null ou vazia inválida
public List<int> ItensObrigatorios { get; set; }

// Atributos de mapeamento (MapTo)
[MapIgnoreSource] // na propriedade do destino: não recebe valor da origem
[MapIgnoreTarget] // na propriedade da origem: não é copiada para o destino

// Atributo de enum
[Exclude] // no campo do enum: remove de FilterExcluded

Modelos e Respostas

ModelResponse

// Resposta simples
return ModelResponse.Success("Operação realizada");
return ModelResponse.Error("Falha na operação");

// Resposta tipada
return ModelResponse<Produto>.Success(produto);
return ModelResponse<Produto>.Error("Não encontrado");

JsonResponse

return JsonResponse.Success(item, "Salvo com sucesso");
return JsonResponse.Error("Algo deu errado");
return JsonResponse.NotAuthenticated();
return JsonResponse.NotAuthorized();
return JsonResponse.Blocked();

// Deserializar item
var produto = response.Deserialize<Produto>();

HttpResponse

return HttpResponse<Produto>.Success(produto);
return HttpResponse<Produto>.Error("Falha");
return HttpResponse<Produto, ErroDTO>.Error(erroDto);

PaginationResponse

var paginacao = new PaginationResponse<Produto>
{
    PageNumber = 1,
    PageSize = 10,
    TotalItems = 100,
    Items = produtos
};

paginacao.TotalPages; // 10
paginacao.HasNextPage; // true

TokenResponse

var token = new TokenResponse
{
    Token = "jwt...",
    RefreshToken = "refresh...",
    ExpiresToken = DateTime.UtcNow.AddHours(1)
};

token.IsValid; // true se não expirou

Ranges

// DateRange
var range = new DateRange("01/01/2024", "31/12/2024");
range.TotalDays; // 366
range.Dates; // lista de todos os dias
DateRange.Today;
DateRange.ThisMonth;
DateRange.ThisYear;

// TimeRange
var horario = new TimeRange("08:00", "17:00");
horario.TotalHours; // 9

// DateTimeRange
var periodo = new DateTimeRange("01/01/2024 08:00", "31/12/2024 17:00");

CPF e CNPJ (Classes)

CPF cpf = "12345678900";
cpf.Masked; // "123.456.789-00"
cpf.Unmasked; // "12345678900"
cpf.DV; // "00"
cpf.IsValid; // true/false
var novoCpf = CPF.Generate();

CNPJ cnpj = "00038166000105";
cnpj.Masked; // "00.038.166/0001-05"
cnpj.IsValid; // true/false
var novoCnpj = CNPJ.Generate();

GenericItem e GenericList

var item = new GenericItem<int>(1, "Opção 1");
var lista = new GenericList<int> { item };

var item2 = new GenericItem<int, Produto>(1, "Opção", produto);

CardModel

var card = new CardModel<int>
{
    Id = 1,
    Title = "Título",
    Subtitle = "Subtítulo",
    Description = "Descrição",
    Image = "url"
};

Serviços

HTTP Client

JarvisHttpClient

Wrapper IDisposable sobre HttpClient (propriedade Client).

using var http = new JarvisHttpClient("https://api.exemplo.com");
var httpTimeout = new JarvisHttpClient("https://api.exemplo.com", TimeSpan.FromSeconds(10));
var semBase = new JarvisHttpClient();

// Configuração fluente
http.BaseAddress("https://api.exemplo.com")
    .Timeout(TimeSpan.FromSeconds(30))
    .BearerAuthorization(jwtToken)
    .AddAcceptJson()
    .AddHeader("X-Custom", "valor");

// Autorização / headers
http.BasicAuthorization("usuario", "senha"); // Base64 de "usuario:senha"
http.BasicAuthorization(base64Token);
http.AddAuthorization("ApiKey", "valor");
http.AddToken("token"); // header "X-Auth-Token" (nome opcional)
http.AddHeader("X-Lista", new[] { "a", "b" });
http.AddAccept(new MediaTypeWithQualityHeaderValue("application/xml"));
http.ClearAccepts();
http.ClearHeaders();

// GET (T ou default em erro)
var produto = await http.GetAsync<Produto>("/produtos/1");

// GET / POST / PUT / DELETE com HttpResponse<T> (IsSuccess, Item, Message)
var response = await http.GetJsonAsync<Produto>("/produtos/1");
var response = await http.PostJsonAsync<Produto>("/produtos", novoProduto);
var response = await http.PutJsonAsync<Produto>("/produtos/1", produto);
var response = await http.DeleteJsonAsync<Produto>("/produtos/1");

// Erro tipado: HttpResponse<TSuccess, TError> (Item / ItemError)
var response = await http.PostJsonAsync<Produto, ErroDTO>("/produtos", novoProduto);

// POST / PUT / DELETE retornando T (CancellationToken opcional)
var criado = await http.PostAsync<Produto>("/produtos", novoProduto);
var criado = await http.PostAsync<Produto>("/produtos", novoProduto, "application/xml");
var alterado = await http.PutAsync<Produto>("/produtos/1", produto);
var removido = await http.DeleteAsync<Produto>("/produtos/1");

// Download (null em erro)
var bytes = await http.DownloadAsync("/arquivo.pdf");

// Upload multipart (campo "file")
var result = await http.UploadAsync<FileResult>("/upload", fileBytes, "foto.jpg");
var result = await http.UploadAsync<FileResult>("/upload", stream, "foto.jpg");

// Upload PUT em URL pré-assinada (Content-Type pela extensão; true se OK)
var ok = await http.UploadPreSignedURLAsync(urlAssinada, fileBytes);
var ok = await http.UploadPreSignedURLAsync(urlAssinada, stream);
var ok = await http.UploadPreSignedURLAsync(urlAssinada, @"C:\temp\foto.jpg");

Extensões de HttpClient

Os mesmos métodos acima existem como extensões de HttpClient: BaseAddress, Timeout, BearerAuthorization, BasicAuthorization, AddAuthorization, AddToken, AddHeader, GetAsync<T>, GetJsonAsync, PostAsync<T>, PostJsonAsync, PutAsync<T>, PutJsonAsync, DeleteAsync<T>, DeleteJsonAsync, DownloadAsync, UploadAsync<T> e UploadPreSignedURLAsync.

var client = new HttpClient()
    .BaseAddress("https://api.exemplo.com")
    .BearerAuthorization(jwtToken)
    .AddHeader("X-Custom", "valor");

var produto = await client.GetAsync<Produto>("/produtos/1"); // sem token: valida status e loga erro
var produto = await client.GetAsync<Produto>("/produtos/1", ct); // com token: GetFromJsonAsync

// Conversores de HttpResponseMessage
var message = await client.GetAsync("/produtos/1");
var item = await message.ToResult<Produto>(); // T ou default (consoleLog padrão true)
var json = await message.ToJsonResponse(); // JsonResponse (erro do corpo ou StatusCode)
var resp = await message.ToHttpResponse<Produto>(); // HttpResponse<T>
var resp = await message.ToHttpResponse<Produto, ErroDTO>(consoleLog: false); // HttpResponse<TSuccess, TError>

HttpService

Extensões de HttpClient para serviços que retornam JsonResponse. Lançam HttpRequestException em falha de comunicação, ResponseException em formato inválido e OperationCanceledException ao cancelar.

// JsonResponse (CancellationToken opcional)
var json = await client.ServiceGetAsync("/produtos/1");
var json = await client.ServicePostAsync("/produtos", novoProduto);
var json = await client.ServicePostAsync("/produtos", multipartContent);
var json = await client.ServicePutAsync("/produtos/1", produto);
var json = await client.ServicePutAsync("/produtos/1", multipartContent);
var json = await client.ServiceDeleteAsync("/produtos/1");

// Download (null em erro)
var stream = await client.ServiceGetStreamAsync("/arquivo.pdf");
var bytes = await client.ServiceGetByteArrayAsync("/arquivo.pdf");

// DownloadResponse (Bytes, FileName, ContentType); nome via Content-Disposition, fallback ou URI
var download = await client.ServiceDownloadAsync("/arquivo.pdf", "relatorio.pdf");

// Upload multipart retornando JarvisFileResult
var file = await client.ServiceUploadAsync("/upload", fileBytes, "foto.jpg");
var file = await client.ServiceUploadAsync("/upload", stream, "foto.jpg");

Consulta CEP

var endereco = await ViaCEP.FindAsync("01001000");
var endereco = await OpenCEP.FindAsync("01001000");
var endereco = await AwesomeCEP.FindAsync("01001000");

// Busca por endereço (ViaCEP)
var resultados = await ViaCEP.FindAsync("SP", "São Paulo", "Paulista");

BrasilAPI

Consulta de dados públicos brasileiros via BrasilAPI.

// Consulta CNPJ
var empresa = await BrasilAPI.FindCNPJAsync("00038166000105");

empresa.Cnpj;              // "00038166000105"
empresa.RazaoSocial;       // razão social
empresa.NomeFantasia;      // nome fantasia
empresa.NaturezaJuridica;  // natureza jurídica
empresa.Porte;             // porte da empresa
empresa.Cep;               // CEP
empresa.Logradouro;        // logradouro
empresa.Numero;            // número
empresa.Complemento;       // complemento
empresa.Bairro;            // bairro
empresa.Municipio;         // município
empresa.Uf;                // UF
empresa.CodigoMunicipioIbge; // código IBGE do município
empresa.OpcaoPeloMei;      // optante pelo MEI
empresa.OpcaoPeloSimples;  // optante pelo Simples Nacional
empresa.CnaeFiscal;        // 8599603
empresa.CnaeFiscalDescricao; // descrição do CNAE principal
empresa.Qsa;               // sócios (NomeSocio, FaixaEtaria, CnpjCpfDoSocio, QualificacaoSocio, DataEntradaSociedade)
empresa.CnaesSecundarios;  // CNAEs secundários (Codigo, Descricao)
empresa.RegimeTributario;  // regime por ano (Ano, FormaDeTributacao)

// Lista bancos
var bancos = await BrasilAPI.GetBanksAsync();

bancos[0].Ispb;            // "00000000"
bancos[0].Name;            // "BCO DO BRASIL S.A."
bancos[0].Code;            // 1
bancos[0].FullName;        // "Banco do Brasil S.A."
bancos[0].LogoUrl;         // URL do logo (SVG)

// Consulta banco pelo código
var banco = await BrasilAPI.FindBankAsync(1);

// NCM
var ncms = await BrasilAPI.GetNCMsAsync();               // todos
var busca = await BrasilAPI.SearchNCMAsync("notebook");  // por código ou descrição
var ncm = await BrasilAPI.FindNCMAsync("8471.30.12");    // por código

ncm.Codigo;                // "8471.30.12"
ncm.Descricao;             // descrição
ncm.DataInicio;            // início da vigência
ncm.DataFim;               // fim da vigência
ncm.TipoAto;               // tipo do ato legal
ncm.NumeroAto;             // número do ato
ncm.AnoAto;                // ano do ato

// Feriados nacionais
var feriados = await BrasilAPI.GetHolidaysAsync(2026);

feriados[0].Date;          // 2026-01-01
feriados[0].Name;          // "Confraternização mundial"
feriados[0].Type;          // "national"

E-mail (SMTP)

var mail = new JarvisMailClient("smtp.gmail.com", 587, "user@gmail.com", "senha");

// Enviar e-mail
var result = await mail.SendAsync(
    to: "destino@email.com",
    subject: "Assunto",
    body: "<p>Corpo HTML</p>"
);

// Template com placeholders
var template = new JarvisMailTemplate("<p>Olá {nome}!</p>");
template.Replace("{nome}", "João");

OneSignal (Push Notifications)

var onesignal = new JarvisOneSignalClient("app-id", "api-key");

// Enviar notificação
var body = new JarvisOneSignalBody
{
    Title = "Título",
    Message = "Mensagem",
    Segments = new[] { JarvisOneSignalSegments.All }
};

var response = await onesignal.SendAsync(body);

Arquivo (File)

// Upload/download com progresso
var client = new JarvisFileClient();
client.ProgressChanged += (s, e) => Console.WriteLine($"{e.Percent}%");
client.Completed += (s, e) => Console.WriteLine("Concluído");

// Operações de arquivo
var result = JarvisFile.FromBase64(base64String, "foto.jpg");
var base64 = JarvisFile.ToBase64("caminho/arquivo.pdf");

Local Storage

var config = new JarvisLocalStorageConfiguration
{
    FilePath = "C:/dados",
    EnableEncryption = true,
    EncryptionKey = "minha-chave-16!!"
};

using var storage = new JarvisLocalStorageClient(config);
storage.Store("chave", meuObjeto);
var obj = storage.Get<MeuTipo>("chave");
storage.Exists("chave"); // true
storage.Keys(); // lista de chaves

Autenticação

JarvisAuthenticationUser

var user = new JarvisAuthenticationUser("Cookies")
{
    Id = "1",
    Name = "João",
    Email = "joao@email.com",
    Roles = new List<string> { "Admin" }
};

user.SetItem(meuObjeto); // serializa objeto como claim Item
user.AddOther("custom_claim", "valor");

JarvisClaimTypes

JarvisClaimTypes.Id       // claim de ID
JarvisClaimTypes.Name     // claim de nome
JarvisClaimTypes.Email    // claim de e-mail
JarvisClaimTypes.Role     // claim de role
JarvisClaimTypes.ClientId // claim de client ID
JarvisClaimTypes.JwtName  // "unique_name" (JWT)
JarvisClaimTypes.JwtRole  // "role" (JWT)

JWT Options

var options = new JarvisJwtOptions
{
    Issuer = "minha-app",
    Audience = "minha-api",
    SecretKey = "chave-secreta-32-chars!!!!!!!!!",
    Expiration = TimeSpan.FromHours(1)
};

Utilitários

Gerador

var senha = JarvisGenerator.Password(8, PasswordType.Mixed);
var senhaDiaria = JarvisGenerator.DailyPassword(); // 6 dígitos baseado na data
var cpf = JarvisGenerator.CPF();
var cnpj = JarvisGenerator.CNPJ();
var texto = JarvisGenerator.LoremIpsum(100);

Password (PBKDF2/SHA256)

var hash = JarvisPassword.Hash("minha-senha");
var valido = JarvisPassword.Verify("minha-senha", hash); // true

Haversine (Distância Geográfica)

var km = JarvisHaversine.ToKilometers(lat1, lng1, lat2, lng2);
var metros = JarvisHaversine.ToMeters(coord1, coord2);
var milhas = JarvisHaversine.ToMiles(coord1, coord2);

Timer

var elapsed = JarvisTimer.Elapsed(() => MinhaOperacao());
var ms = JarvisTimer.ElapsedMilliseconds(() => MinhaOperacao());
var ms = await JarvisTimer.ElapsedMilliseconds(async () => await MinhaOperacaoAsync());

Log

JarvisLog.Debug("mensagem");
JarvisLog.Info("mensagem");
JarvisLog.Warn("mensagem");
JarvisLog.Error("mensagem");
JarvisLog.Exception(ex);

Matemática

JarvisMath.Percent(10, 100); // 10.0 (10%)
JarvisMath.CalculatePercentage(200, 15); // 30.0 (15% de 200)
JarvisMath.AddPercentage(100, 10); // 110.0
JarvisMath.SubtractPercentage(100, 10); // 90.0
JarvisMath.CalculatePercentage(2000m, 2.69m); // 53.80m (todos os métodos têm sobrecarga decimal, para valores monetários)

Cor

JarvisColor.Combine("#FF0000", "#0000FF"); // combina cores pela média RGB
JarvisColor.HexToRgb("#FF5500"); // "255, 85, 0"
JarvisColor.HexToRgba("#FF5500", 0.5); // "255, 85, 0, 0.5"

Conversões de Unidade

JarvisConverter.MmToPixels(10, 96); // milímetros para pixels
JarvisConverter.PixelsToMm(100, 96); // pixels para milímetros

Diretórios e Arquivos (Helper)

JarvisDirectoryHelper.CreateIfNotExists("C:/minha-pasta");
JarvisDirectoryHelper.GetOrCreate("dados", "C:/base");
JarvisDirectoryHelper.GetOrCreateHidden("dados-ocultos");

JarvisFileHelper.SetHiddenAttribute("C:/arquivo.txt", true);

Estados e Meses (Brasil)

EstadosBrasil.Lista(); // dicionário "SP" => "São Paulo"
EstadosBrasil.Siglas(); // ["AC", "AL", ..., "TO"]
EstadosBrasil.Nomes(); // ["Acre", "Alagoas", ..., "Tocantins"]

MesesAno.Lista(); // ["Janeiro", ..., "Dezembro"]

Structs

// Meses do ano
var meses = new Months(2024);
meses.January; // 01/01/2024
meses.December; // 01/12/2024

// DateTime Brasil
DateTimeBr.Now; // agora em horário de Brasília
DateTimeBr.Today; // hoje em horário de Brasília

// Enum tipado
var valores = Enum<MeuEnum>.AsEnumerable();

Converters JSON

// Converters para System.Text.Json
var options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringDateConverter());     // "yyyy-MM-dd"
options.Converters.Add(new JsonStringDateTimeConverter()); // "yyyy-MM-dd HH:mm:ss"
options.Converters.Add(new JsonStringDoubleConverter());   // aceita string ou número
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  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 is compatible.  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 is compatible.  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 is compatible.  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 is compatible.  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 netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen 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.

NuGet packages (10)

Showing the top 5 NuGet packages that depend on Jarvis.Toolkit:

Package Downloads
Jarvis.Blazor

Biblioteca de componentes para Blazor.

Jarvis.Components.Web.Mvc.Core

Biblioteca de componentes para WEB MVC Core.

Jarvis.Maui

Biblioteca de componentes para Maui.

Jarvis.WebApi

Biblioteca de componentes para API Web.

Jarvis.Blazor.Mud

Biblioteca de componentes para MudBlazor.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.2.7 47 10/18/2026
1.2.2.6 45 10/18/2026
1.2.2.5 56 10/17/2026
1.2.2.4 59 10/17/2026
1.2.2.3 134 9/30/2026
1.2.2.2 447 7/23/2026
1.2.2.1 128 7/12/2026
1.2.2 130 7/10/2026
1.2.1.9 150 5/28/2026
1.2.1.8 191 5/22/2026
1.2.1.7 201 5/16/2026
1.2.1.6 169 5/13/2026
1.2.1.5 134 5/4/2026
1.2.1.4 262 4/3/2026
1.2.1.3 235 3/25/2026
1.2.1.2 214 3/16/2026
1.2.1.1 174 3/8/2026
1.2.1 189 3/8/2026
1.2.0.9 182 3/4/2026
1.2.0.8 155 3/2/2026
Loading failed