Examples
Exemplos C#
Exemplos completos de integração com C#, ASP.NET Core, Entity Framework e mais
Exemplos C#
Exemplos práticos e completos de como integrar o RenderHub em aplicações C# e .NET.
Instalação
dotnet add package Newtonsoft.Json
dotnet add package System.Net.Http
Configuração Básica
Variáveis de Ambiente
Adicione ao appsettings.json:
{
"RenderHub": {
"ApiKey": "rh_live_sua_chave_aqui",
"BaseUrl": "https://renderhub.com/api/v1"
}
}
Ou use variáveis de ambiente:
export RENDERHUB_API_KEY=rh_live_sua_chave_aqui
Cliente RenderHub
// Services/RenderHubClient.cs
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MyApp.Services
{
public class RenderHubClient
{
private readonly HttpClient _httpClient;
private readonly string _apiKey;
private readonly string _baseUrl;
public RenderHubClient(string apiKey = null, string baseUrl = null)
{
_apiKey = apiKey ?? Environment.GetEnvironmentVariable("RENDERHUB_API_KEY");
_baseUrl = baseUrl ?? "https://renderhub.com/api/v1";
if (string.IsNullOrEmpty(_apiKey))
{
throw new Exception("RENDERHUB_API_KEY não configurada");
}
_httpClient = new HttpClient
{
BaseAddress = new Uri(_baseUrl),
Timeout = TimeSpan.FromSeconds(30)
};
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
}
public async Task<RenderResponse> RenderAsync(RenderRequest request)
{
try
{
var json = JsonConvert.SerializeObject(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("/render", content);
if (!response.IsSuccessStatusCode)
{
var errorBody = await response.Content.ReadAsStringAsync();
throw new RenderHubException(
(int)response.StatusCode,
$"Erro ao renderizar: {errorBody}"
);
}
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<RenderResponse>(responseBody);
}
catch (HttpRequestException ex)
{
throw new Exception($"Erro de rede: {ex.Message}", ex);
}
}
public async Task<TemplateResponse> CreateTemplateAsync(TemplateRequest template)
{
var json = JsonConvert.SerializeObject(template);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("/templates", content);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TemplateResponse>(responseBody);
}
public async Task<TemplateResponse> GetTemplateAsync(string templateId)
{
var response = await _httpClient.GetAsync($"/templates/{templateId}");
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TemplateResponse>(responseBody);
}
public void SavePdf(string pdfBase64, string filePath)
{
var pdfBytes = Convert.FromBase64String(pdfBase64);
File.WriteAllBytes(filePath, pdfBytes);
}
}
// Models
public class RenderRequest
{
[JsonProperty("mode")]
public string Mode { get; set; }
[JsonProperty("template_id")]
public string TemplateId { get; set; }
[JsonProperty("input_type")]
public string InputType { get; set; }
[JsonProperty("data")]
public object Data { get; set; }
[JsonProperty("page_size")]
public string PageSize { get; set; }
[JsonProperty("orientation")]
public string Orientation { get; set; }
}
public class RenderResponse
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("pdf_base64")]
public string PdfBase64 { get; set; }
[JsonProperty("pages")]
public int Pages { get; set; }
[JsonProperty("file_size_kb")]
public int FileSizeKb { get; set; }
[JsonProperty("duration_ms")]
public int DurationMs { get; set; }
}
public class TemplateRequest
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("content")]
public string Content { get; set; }
[JsonProperty("category")]
public string Category { get; set; }
}
public class TemplateResponse
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
}
public class RenderHubException : Exception
{
public int StatusCode { get; }
public RenderHubException(int statusCode, string message)
: base(message)
{
StatusCode = statusCode;
}
}
}
Exemplo 1: Converter HTML para PDF
// Program.cs
using System;
using System.Threading.Tasks;
using MyApp.Services;
class Program
{
static async Task Main(string[] args)
{
var client = new RenderHubClient();
var html = @"
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<style>
body {
font-family: Arial, sans-serif;
padding: 40px;
max-width: 800px;
margin: 0 auto;
}
h1 {
color: #2563eb;
border-bottom: 3px solid #2563eb;
padding-bottom: 10px;
}
.highlight {
background: #fef3c7;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
</style>
</head>
<body>
<h1>Relatório de Vendas - Janeiro 2024</h1>
<div class='highlight'>
<h2>Resumo</h2>
<p>Total de vendas: R$ 150.000,00</p>
<p>Novos clientes: 42</p>
<p>Taxa de conversão: 15.8%</p>
</div>
<h2>Detalhes</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
</body>
</html>";
var request = new RenderRequest
{
Mode = "CONVERT",
InputType = "html",
Data = html,
PageSize = "A4",
Orientation = "portrait"
};
var result = await client.RenderAsync(request);
// Salvar PDF
client.SavePdf(result.PdfBase64, "relatorio.pdf");
Console.WriteLine("✅ PDF gerado com sucesso!");
Console.WriteLine($"Páginas: {result.Pages}");
Console.WriteLine($"Tamanho: {result.FileSizeKb} KB");
Console.WriteLine($"Duração: {result.DurationMs}ms");
}
}
Exemplo 2: Fatura com Template
// Models/Invoice.cs
using System.Collections.Generic;
public class InvoiceData
{
public string CompanyName { get; set; }
public string CompanyCnpj { get; set; }
public string InvoiceNumber { get; set; }
public string InvoiceDate { get; set; }
public string CustomerName { get; set; }
public string CustomerEmail { get; set; }
public string CustomerAddress { get; set; }
public List<InvoiceItem> Items { get; set; }
public string Subtotal { get; set; }
public string Tax { get; set; }
public string Total { get; set; }
}
public class InvoiceItem
{
public string Description { get; set; }
public int Quantity { get; set; }
public string UnitPrice { get; set; }
public string Total { get; set; }
}
// Services/InvoiceService.cs
using System;
using System.Linq;
using System.Threading.Tasks;
using MyApp.Services;
public class InvoiceService
{
private readonly RenderHubClient _renderHub;
private readonly string _templateId;
public InvoiceService(RenderHubClient renderHub, string templateId)
{
_renderHub = renderHub;
_templateId = templateId;
}
public async Task<string> GenerateInvoiceAsync(int customerId)
{
// Buscar dados (simulado)
var customer = GetCustomer(customerId);
var orders = GetOrders(customerId);
// Mapear dados para o template
var items = orders.Select(order => new InvoiceItem
{
Description = order.Product,
Quantity = order.Quantity,
UnitPrice = order.Price.ToString("F2"),
Total = (order.Quantity * order.Price).ToString("F2")
}).ToList();
var subtotal = orders.Sum(o => o.Quantity * o.Price);
var tax = subtotal * 0.15m;
var total = subtotal + tax;
var invoiceData = new InvoiceData
{
CompanyName = "Minha Empresa LTDA",
CompanyCnpj = "12.345.678/0001-99",
InvoiceNumber = $"2024-{customerId:D5}",
InvoiceDate = DateTime.Now.ToString("dd/MM/yyyy"),
CustomerName = customer.Name,
CustomerEmail = customer.Email,
CustomerAddress = $"{customer.Address}, {customer.City} - {customer.State}",
Items = items,
Subtotal = subtotal.ToString("F2"),
Tax = tax.ToString("F2"),
Total = total.ToString("F2")
};
// Renderizar PDF
var request = new RenderRequest
{
Mode = "RENDER",
TemplateId = _templateId,
Data = invoiceData
};
var result = await _renderHub.RenderAsync(request);
// Salvar PDF
var filename = $"invoice-{invoiceData.InvoiceNumber}.pdf";
_renderHub.SavePdf(result.PdfBase64, filename);
Console.WriteLine($"✅ Fatura {invoiceData.InvoiceNumber} gerada!");
return filename;
}
// Métodos auxiliares (simulados)
private Customer GetCustomer(int id)
{
return new Customer
{
Id = id,
Name = "João Silva Comércio LTDA",
Email = "joao@example.com",
Address = "Rua das Flores, 123",
City = "São Paulo",
State = "SP"
};
}
private List<Order> GetOrders(int customerId)
{
return new List<Order>
{
new Order { Product = "Notebook Dell", Quantity = 2, Price = 3500.00m },
new Order { Product = "Mouse Logitech", Quantity = 5, Price = 150.00m },
new Order { Product = "Teclado Mecânico", Quantity = 3, Price = 450.00m }
};
}
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
}
public class Order
{
public string Product { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
Exemplo 3: Integração com ASP.NET Core
// Startup.cs / Program.cs
using Microsoft.Extensions.DependencyInjection;
using MyApp.Services;
// ConfigureServices (ou builder.Services em .NET 6+)
services.AddSingleton<RenderHubClient>(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
var apiKey = config["RenderHub:ApiKey"];
return new RenderHubClient(apiKey);
});
// Controllers/PdfController.cs
using Microsoft.AspNetCore.Mvc;
using MyApp.Services;
using System.Threading.Tasks;
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
private readonly RenderHubClient _renderHub;
public PdfController(RenderHubClient renderHub)
{
_renderHub = renderHub;
}
[HttpPost("generate")]
public async Task<IActionResult> GeneratePdf([FromBody] PdfRequest request)
{
try
{
var renderRequest = new RenderRequest
{
Mode = "RENDER",
TemplateId = request.TemplateId,
Data = request.Data
};
var result = await _renderHub.RenderAsync(renderRequest);
return Ok(new
{
success = true,
pdf_base64 = result.PdfBase64,
pages = result.Pages,
file_size_kb = result.FileSizeKb
});
}
catch (RenderHubException ex)
{
return StatusCode(ex.StatusCode, new
{
error = "Erro ao gerar PDF",
message = ex.Message
});
}
}
[HttpPost("download")]
public async Task<IActionResult> DownloadPdf([FromBody] PdfRequest request)
{
try
{
var renderRequest = new RenderRequest
{
Mode = "RENDER",
TemplateId = request.TemplateId,
Data = request.Data
};
var result = await _renderHub.RenderAsync(renderRequest);
var pdfBytes = Convert.FromBase64String(result.PdfBase64);
return File(pdfBytes, "application/pdf", "document.pdf");
}
catch (RenderHubException ex)
{
return StatusCode(ex.StatusCode, new { error = ex.Message });
}
}
}
public class PdfRequest
{
public string TemplateId { get; set; }
public object Data { get; set; }
}
Exemplo 4: Webhooks
// Controllers/WebhookController.cs
using Microsoft.AspNetCore.Mvc;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
[ApiController]
[Route("api/[controller]")]
public class WebhookController : ControllerBase
{
private readonly string _webhookSecret;
public WebhookController(IConfiguration config)
{
_webhookSecret = config["RenderHub:WebhookSecret"];
}
[HttpPost]
public async Task<IActionResult> HandleWebhook()
{
// Ler payload
using var reader = new StreamReader(Request.Body);
var payload = await reader.ReadToEndAsync();
// Validar assinatura HMAC
var signature = Request.Headers["X-RenderHub-Signature"].ToString();
if (!ValidateSignature(payload, signature))
{
return Unauthorized(new { error = "Invalid signature" });
}
// Processar webhook
var data = JsonConvert.DeserializeObject<WebhookPayload>(payload);
if (data.Status == "DONE")
{
Console.WriteLine($"✅ PDF {data.Id} pronto!");
// Baixar PDF da URL temporária
using var httpClient = new HttpClient();
var pdfBytes = await httpClient.GetByteArrayAsync(data.PdfUrl);
// Salvar em storage
await File.WriteAllBytesAsync($"pdfs/{data.Id}.pdf", pdfBytes);
// Atualizar banco de dados
// await _db.Jobs.UpdateAsync(data.JobId, new { Status = "COMPLETED" });
// Notificar usuário
// await _notificationService.NotifyAsync(data.JobId);
}
else if (data.Status == "FAILED")
{
Console.WriteLine($"❌ Erro ao gerar PDF: {data.Error}");
// Atualizar banco de dados
// await _db.Jobs.UpdateAsync(data.JobId, new { Status = "FAILED" });
}
// IMPORTANTE: Retornar 200 OK rapidamente
return Ok(new { received = true });
}
private bool ValidateSignature(string payload, string signature)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(_webhookSecret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
var expectedSignature = BitConverter.ToString(hash).Replace("-", "").ToLower();
return signature == expectedSignature;
}
}
public class WebhookPayload
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("job_id")]
public string JobId { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("pdf_url")]
public string PdfUrl { get; set; }
[JsonProperty("error")]
public string Error { get; set; }
}
Exemplo 5: Processamento em Lote
// Services/BatchInvoiceService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class BatchInvoiceService
{
private readonly RenderHubClient _renderHub;
private readonly string _templateId;
public BatchInvoiceService(RenderHubClient renderHub, string templateId)
{
_renderHub = renderHub;
_templateId = templateId;
}
public async Task GenerateInvoicesAsync(List<int> customerIds)
{
foreach (var customerId in customerIds)
{
try
{
Console.WriteLine($"Processando fatura para cliente {customerId}...");
var invoiceData = await FetchCustomerDataAsync(customerId);
var request = new RenderRequest
{
Mode = "RENDER",
TemplateId = _templateId,
Data = invoiceData
};
var result = await _renderHub.RenderAsync(request);
var filename = $"invoices/invoice-{customerId}.pdf";
_renderHub.SavePdf(result.PdfBase64, filename);
Console.WriteLine($"✅ Fatura gerada: {filename}");
}
catch (Exception ex)
{
Console.WriteLine($"❌ Erro para cliente {customerId}: {ex.Message}");
}
// Aguardar para não exceder rate limit
await Task.Delay(200); // 200ms = 5 req/s (bem abaixo do limite)
}
Console.WriteLine("\nProcessamento concluído!");
}
private async Task<InvoiceData> FetchCustomerDataAsync(int customerId)
{
// Simular busca no banco
await Task.Delay(10);
return new InvoiceData
{
CustomerName = $"Cliente {customerId}",
InvoiceNumber = $"2024-{customerId}",
Total = "1500.00"
};
}
}
// Uso
var customerIds = new List<int> { 1001, 1002, 1003, 1004, 1005 };
var batchService = new BatchInvoiceService(client, "tpl_invoice_v1");
await batchService.GenerateInvoicesAsync(customerIds);
Exemplo 6: Retry com Exponential Backoff
// Services/RetryHelper.cs
using System;
using System.Threading.Tasks;
using Polly;
using Polly.Retry;
public static class RetryHelper
{
public static async Task<RenderResponse> RenderWithRetryAsync(
RenderHubClient client,
RenderRequest request,
int maxRetries = 3)
{
var retryPolicy = Policy
.Handle<RenderHubException>(ex => ex.StatusCode == 429) // Rate limit
.WaitAndRetryAsync(
maxRetries,
retryAttempt => TimeSpan.FromSeconds(Math.Min(Math.Pow(2, retryAttempt), 30)),
onRetry: (exception, timeSpan, retryCount, context) =>
{
Console.WriteLine($"Rate limited. Tentativa {retryCount}/{maxRetries}. Aguardando {timeSpan.TotalSeconds}s...");
}
);
return await retryPolicy.ExecuteAsync(async () =>
{
return await client.RenderAsync(request);
});
}
}
// Uso
var result = await RetryHelper.RenderWithRetryAsync(client, request);
Ou sem Polly:
public static async Task<RenderResponse> RenderWithRetryAsync(
RenderHubClient client,
RenderRequest request,
int maxRetries = 3)
{
for (int attempt = 0; attempt < maxRetries; attempt++)
{
try
{
return await client.RenderAsync(request);
}
catch (RenderHubException ex) when (ex.StatusCode == 429)
{
if (attempt == maxRetries - 1)
{
throw;
}
var delay = Math.Min(Math.Pow(2, attempt), 30);
Console.WriteLine($"Rate limited. Aguardando {delay}s...");
await Task.Delay(TimeSpan.FromSeconds(delay));
}
}
throw new Exception("Não deveria chegar aqui");
}
Exemplo 7: Background Jobs com Hangfire
dotnet add package Hangfire
dotnet add package Hangfire.SqlServer
// Startup.cs
using Hangfire;
using Hangfire.SqlServer;
services.AddHangfire(config => config
.UseSqlServerStorage(Configuration.GetConnectionString("HangfireConnection")));
services.AddHangfireServer();
app.UseHangfireDashboard();
// Jobs/GenerateInvoiceJob.cs
using Hangfire;
using System.Threading.Tasks;
public class GenerateInvoiceJob
{
private readonly RenderHubClient _renderHub;
private readonly string _templateId;
public GenerateInvoiceJob(RenderHubClient renderHub, string templateId)
{
_renderHub = renderHub;
_templateId = templateId;
}
[AutomaticRetry(Attempts = 3, DelaysInSeconds = new[] { 2, 10, 30 })]
public async Task ExecuteAsync(int customerId)
{
Console.WriteLine($"Processando fatura para cliente {customerId}");
var invoiceData = await FetchCustomerDataAsync(customerId);
var request = new RenderRequest
{
Mode = "RENDER",
TemplateId = _templateId,
Data = invoiceData
};
var result = await _renderHub.RenderAsync(request);
var filename = $"invoices/invoice-{customerId}.pdf";
_renderHub.SavePdf(result.PdfBase64, filename);
Console.WriteLine($"Fatura gerada: {filename}");
}
private async Task<InvoiceData> FetchCustomerDataAsync(int customerId)
{
// Buscar do banco de dados
await Task.Delay(10);
return new InvoiceData
{
CustomerName = $"Cliente {customerId}",
InvoiceNumber = $"2024-{customerId}",
Total = "1500.00"
};
}
}
// Disparar jobs
var customerIds = new List<int> { 1001, 1002, 1003, 1004, 1005 };
foreach (var customerId in customerIds)
{
BackgroundJob.Enqueue<GenerateInvoiceJob>(job => job.ExecuteAsync(customerId));
}
Console.WriteLine($"{customerIds.Count} jobs adicionados à fila");
Exemplo 8: Entity Framework + Múltiplos Clientes
// Services/InvoiceGeneratorService.cs
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
public class InvoiceGeneratorService
{
private readonly AppDbContext _db;
private readonly RenderHubClient _renderHub;
private readonly string _templateId;
public InvoiceGeneratorService(
AppDbContext db,
RenderHubClient renderHub,
string templateId)
{
_db = db;
_renderHub = renderHub;
_templateId = templateId;
}
public async Task GenerateAllInvoicesAsync()
{
// Buscar clientes ativos com seus pedidos
var customers = await _db.Customers
.Where(c => c.Active)
.Include(c => c.Orders)
.ThenInclude(o => o.Product)
.ToListAsync();
foreach (var customer in customers)
{
if (!customer.Orders.Any())
{
continue;
}
// Mapear dados
var invoiceData = new InvoiceData
{
CustomerName = customer.Name,
CustomerEmail = customer.Email,
InvoiceNumber = $"{DateTime.Now.Year}-{customer.Id}",
Items = customer.Orders.Select(order => new InvoiceItem
{
Description = order.Product.Name,
Quantity = order.Quantity,
UnitPrice = order.Product.Price.ToString("F2"),
Total = (order.Quantity * order.Product.Price).ToString("F2")
}).ToList(),
Total = customer.Orders
.Sum(o => o.Quantity * o.Product.Price)
.ToString("F2")
};
// Gerar PDF
try
{
var request = new RenderRequest
{
Mode = "RENDER",
TemplateId = _templateId,
Data = invoiceData
};
var result = await _renderHub.RenderAsync(request);
var filename = $"invoices/{customer.Id}-{invoiceData.InvoiceNumber}.pdf";
_renderHub.SavePdf(result.PdfBase64, filename);
Console.WriteLine($"✅ Fatura gerada para {customer.Name}: {filename}");
}
catch (Exception ex)
{
Console.WriteLine($"❌ Erro para {customer.Name}: {ex.Message}");
}
}
}
}
// DbContext
public class AppDbContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Product> Product { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}
Próximos Passos
- Exemplos Node.js - Integração com Node.js/Express
- Exemplos Python - Integração com Python/Flask/Django
- Exemplos PHP - Integração com PHP/Laravel
- API Reference - Documentação completa da API
- Guia de Templates - Templates e variáveis