Back to Examples

C# / .NET

Integrate GuardCrow into your .NET applications using HttpClient.

Basic Example

A simple example using HttpClient:

Program.cscsharp
using System.Text.Json;
using System.Text.Json.Serialization;
var apiKey = Environment.GetEnvironmentVariable("GUARDCROW_API_KEY");
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", apiKey);
var request = new { content = "Hello, this is a test message" };
var response = await client.PostAsJsonAsync(
"https://api.guardcrow.com/v1/analyze",
request
);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<AnalyzeResponse>();
Console.WriteLine($"Passed: {result?.Passed}, Score: {result?.Score}");
public record AnalyzeResponse(
bool Passed,
int Score,
string Sentiment,
string Description,
string[] Categories,
[property: JsonPropertyName("processingTimeMs")] int ProcessingTimeMs
);

Complete Client Class

A production-ready client with error handling and retry logic:

GuardCrowClient.cscsharp
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace GuardCrow;
public class GuardCrowClient : IDisposable
{
private readonly HttpClient _client;
private readonly string _baseUrl;
private readonly int _maxRetries;
private readonly JsonSerializerOptions _jsonOptions;
public GuardCrowClient(string apiKey, string? baseUrl = null, int maxRetries = 3)
{
_baseUrl = baseUrl ?? "https://api.guardcrow.com/v1";
_maxRetries = maxRetries;
_client = new HttpClient
{
Timeout = TimeSpan.FromSeconds(30)
};
_client.DefaultRequestHeaders.Add("X-API-Key", apiKey);
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
}
public async Task<AnalyzeResponse> AnalyzeAsync(
string content,
Dictionary<string, string>? metadata = null,
CancellationToken cancellationToken = default)
{
var request = new AnalyzeRequest
{
Content = content,
Metadata = metadata
};
Exception? lastException = null;
for (int attempt = 0; attempt < _maxRetries; attempt++)
{
try
{
var response = await _client.PostAsJsonAsync(
$"{_baseUrl}/analyze",
request,
_jsonOptions,
cancellationToken
);
if (response.StatusCode == HttpStatusCode.TooManyRequests)
{
var resetHeader = response.Headers
.GetValues("X-RateLimit-Reset")
.FirstOrDefault();
if (resetHeader != null && long.TryParse(resetHeader, out var resetTime))
{
var waitTime = DateTimeOffset.FromUnixTimeSeconds(resetTime) - DateTimeOffset.UtcNow;
if (waitTime > TimeSpan.Zero)
{
await Task.Delay(waitTime, cancellationToken);
continue;
}
}
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)), cancellationToken);
continue;
}
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadFromJsonAsync<ErrorResponse>(
_jsonOptions,
cancellationToken
);
throw new GuardCrowException(
error?.Error?.Code ?? "UNKNOWN",
error?.Error?.Message ?? "Unknown error",
(int)response.StatusCode
);
}
var result = await response.Content.ReadFromJsonAsync<AnalyzeResponse>(
_jsonOptions,
cancellationToken
);
return result ?? throw new GuardCrowException(
"INVALID_RESPONSE",
"Failed to parse response",
200
);
}
catch (GuardCrowException ex) when (
ex.Code == "INVALID_API_KEY" ||
ex.Code == "CONTENT_TOO_LONG")
{
throw;
}
catch (Exception ex) when (ex is not GuardCrowException)
{
lastException = ex;
if (attempt < _maxRetries - 1)
{
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)), cancellationToken);
}
}
}
throw lastException ?? new GuardCrowException(
"MAX_RETRIES",
"Max retries exceeded",
0
);
}
public async Task<bool> HealthCheckAsync(CancellationToken cancellationToken = default)
{
var response = await _client.GetAsync($"{_baseUrl}/health", cancellationToken);
return response.IsSuccessStatusCode;
}
public void Dispose() => _client.Dispose();
}
public class AnalyzeRequest
{
public required string Content { get; set; }
public Dictionary<string, string>? Metadata { get; set; }
}
public class AnalyzeResponse
{
public bool Passed { get; set; }
public int Score { get; set; }
public string Sentiment { get; set; } = "";
public string Description { get; set; } = "";
public string[] Categories { get; set; } = [];
[JsonPropertyName("processingTimeMs")]
public int ProcessingTimeMs { get; set; }
}
public class ErrorResponse
{
public ApiError? Error { get; set; }
}
public class ApiError
{
public string Code { get; set; } = "";
public string Message { get; set; } = "";
public int Status { get; set; }
}
public class GuardCrowException : Exception
{
public string Code { get; }
public int StatusCode { get; }
public GuardCrowException(string code, string message, int statusCode)
: base(message)
{
Code = code;
StatusCode = statusCode;
}
}

Using the Client

Program.cscsharp
using GuardCrow;
var apiKey = Environment.GetEnvironmentVariable("GUARDCROW_API_KEY")
?? throw new InvalidOperationException("API key not set");
using var client = new GuardCrowClient(apiKey);
try
{
// Simple analysis
var result = await client.AnalyzeAsync("Hello, this is a test message");
Console.WriteLine($"Passed: {result.Passed}");
Console.WriteLine($"Score: {result.Score}");
Console.WriteLine($"Sentiment: {result.Sentiment}");
// With metadata
var resultWithMeta = await client.AnalyzeAsync(
"Check this content",
new Dictionary<string, string>
{
["source"] = "user-comments",
["user_id"] = "user_123"
}
);
Console.WriteLine($"Description: {resultWithMeta.Description}");
}
catch (GuardCrowException ex)
{
Console.WriteLine($"API Error: {ex.Code} - {ex.Message}");
}

ASP.NET Core Integration

Register the client with dependency injection:

Program.cscsharp
using GuardCrow;
var builder = WebApplication.CreateBuilder(args);
// Register GuardCrow client
builder.Services.AddSingleton(_ =>
{
var apiKey = builder.Configuration["GuardCrow:ApiKey"]
?? throw new InvalidOperationException("GuardCrow API key not configured");
return new GuardCrowClient(apiKey);
});
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();

Controller with Moderation

CommentsController.cscsharp
using GuardCrow;
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Controllers;
[ApiController]
[Route("api/[controller]")]
public class CommentsController : ControllerBase
{
private readonly GuardCrowClient _contentShield;
private readonly ILogger<CommentsController> _logger;
public CommentsController(
GuardCrowClient contentShield,
ILogger<CommentsController> logger)
{
_contentShield = contentShield;
_logger = logger;
}
[HttpPost]
public async Task<IActionResult> CreateComment([FromBody] CreateCommentRequest request)
{
try
{
var moderation = await _contentShield.AnalyzeAsync(
request.Content,
new Dictionary<string, string>
{
["user_id"] = request.UserId
}
);
if (moderation.Score >= 7)
{
return BadRequest(new
{
Error = "Content blocked by moderation",
Reason = moderation.Description
});
}
// Save comment to database (your logic here)
return Created("", new
{
Status = "created",
ModerationScore = moderation.Score
});
}
catch (GuardCrowException ex)
{
_logger.LogError(ex, "Moderation API error");
// Allow content through on API errors
return Created("", new { Status = "created" });
}
}
}
public record CreateCommentRequest(string Content, string UserId);

Action Filter for Auto-Moderation

Create a reusable action filter for automatic content moderation:

ModerationFilter.cscsharp
using GuardCrow;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace MyApp.Filters;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ModerateContentAttribute : Attribute, IAsyncActionFilter
{
public string ContentProperty { get; set; } = "Content";
public int MaxScore { get; set; } = 6;
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
var contentShield = context.HttpContext.RequestServices
.GetRequiredService<GuardCrowClient>();
// Find content in action arguments
string? content = null;
foreach (var arg in context.ActionArguments.Values)
{
if (arg is null) continue;
var prop = arg.GetType().GetProperty(ContentProperty);
if (prop?.GetValue(arg) is string value)
{
content = value;
break;
}
}
if (string.IsNullOrEmpty(content))
{
await next();
return;
}
try
{
var result = await contentShield.AnalyzeAsync(content);
if (result.Score > MaxScore)
{
context.Result = new BadRequestObjectResult(new
{
Error = "Content blocked by moderation",
Reason = result.Description,
Score = result.Score
});
return;
}
// Store result for use in action
context.HttpContext.Items["ModerationResult"] = result;
}
catch (GuardCrowException)
{
// Allow through on API errors
}
await next();
}
}
// Usage on a controller action
[HttpPost]
[ModerateContent(ContentProperty = "Content", MaxScore = 6)]
public IActionResult CreatePost([FromBody] CreatePostRequest request)
{
var moderation = HttpContext.Items["ModerationResult"] as AnalyzeResponse;
// Your logic here
return Ok();
}

Minimal API Example

Program.cscsharp
using GuardCrow;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(_ => new GuardCrowClient(
builder.Configuration["GuardCrow:ApiKey"]!
));
var app = builder.Build();
app.MapPost("/moderate", async (
GuardCrowClient client,
ModerateRequest request) =>
{
try
{
var result = await client.AnalyzeAsync(request.Content);
return Results.Ok(new
{
result.Passed,
result.Score,
result.Sentiment,
result.Description
});
}
catch (GuardCrowException ex)
{
return Results.Problem(
title: ex.Code,
detail: ex.Message,
statusCode: ex.StatusCode
);
}
});
app.Run();
record ModerateRequest(string Content);

Configuration

Add your API key to appsettings.json or environment variables:

appsettings.jsonjson
{
"GuardCrow": {
"ApiKey": "sk_live_your_api_key_here"
}
}

Or use an environment variable:

Terminalbash
# Windows
set GUARDCROW_API_KEY=sk_live_your_api_key_here
# Linux/macOS
export GUARDCROW_API_KEY=sk_live_your_api_key_here