MediatR
Tayra integrates with MediatR through a pipeline behavior that automatically encrypts and decrypts [PersonalData] fields on requests and responses flowing through the mediator. Your handlers work with plaintext values and never need to know about encryption.
Prerequisites
Tayra.MediatR requires MediatR 12.x or later. Earlier versions use a different IPipelineBehavior signature and are not supported.
Install
dotnet add package Tayra.MediatRInstall-Package Tayra.MediatRSetup
Register Tayra core services, a key store, and the MediatR pipeline behavior in your DI container:
services.AddTayra(opts => opts.LicenseKey = licenseKey); // defaults to InMemoryKeyStore; use PostgreSQL, Vault, etc. in production
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblyContaining<Program>();
});
services.AddTayraMediatR(); // Registers the pipeline behaviorAddTayraMediatR() registers a single IPipelineBehavior<TRequest, TResponse> that wraps every MediatR request/response pipeline. You can optionally pass an Action<TayraMediatROptions> to configure behavior:
services.AddTayraMediatR(opts =>
{
opts.EncryptRequests = true; // default
opts.DecryptResponses = true; // default
});Prerequisites
Tayra core services must be registered via services.AddTayra() (optionally chaining a production key store) before AddTayraMediatR() is called. The pipeline behavior resolves ITayra from DI at runtime.
Options
services.AddTayraMediatR(opts =>
{
opts.EncryptRequests = true; // default
opts.DecryptResponses = true; // default
});| Property | Type | Default | Description |
|---|---|---|---|
EncryptRequests | bool | true | Encrypt PII fields on the request object before passing it to the handler |
DecryptResponses | bool | true | Decrypt PII fields on the response object after the handler returns |
Requests and Responses
Annotate your MediatR request and response classes with [DataSubjectId] and [PersonalData]:
public class CreateCustomerCommand : IRequest<CreateCustomerResult>
{
[DataSubjectId]
public string CustomerId { get; set; }
[PersonalData]
public string Name { get; set; }
[PersonalData]
public string Email { get; set; }
public string AccountType { get; set; } // Not encrypted
}
public class CreateCustomerResult
{
[DataSubjectId]
public string CustomerId { get; set; }
[PersonalData]
public string Name { get; set; }
[PersonalData]
public string Email { get; set; }
public DateTime CreatedAt { get; set; }
}How the Pipeline Behavior Works
MediatR processes requests through a chain of IPipelineBehavior<TRequest, TResponse> instances. Tayra registers a single behavior that wraps the entire pipeline:
Before the handler -- The behavior scans the
TRequestfor[PersonalData]fields. IfEncryptRequestsis enabled, it encrypts all annotated fields so that PII is protected before reaching the handler. If your handler needs cleartext (the typical case), setEncryptRequests = falseand rely on the upstream caller to send encrypted data, or leave it enabled when you want the handler to work with encrypted values (e.g., for pass-through persistence).After the handler -- The behavior scans the
TResponsefor[PersonalData]fields. IfDecryptResponsesis enabled, it decrypts all annotated fields so your calling code receives plaintext.
A typical in-process workflow where the handler needs plaintext looks like this:
services.AddTayraMediatR(opts =>
{
opts.EncryptRequests = false; // Handler receives cleartext
opts.DecryptResponses = true; // Caller receives cleartext
});Your handlers work with plaintext values and do not need to know about encryption:
public class CreateCustomerHandler
: IRequestHandler<CreateCustomerCommand, CreateCustomerResult>
{
public async Task<CreateCustomerResult> Handle(
CreateCustomerCommand request,
CancellationToken cancellationToken)
{
// request.Name and request.Email are plaintext
var customer = await SaveCustomer(request);
return new CreateCustomerResult
{
CustomerId = customer.Id,
Name = customer.Name, // Will be decrypted if needed
Email = customer.Email, // Will be decrypted if needed
CreatedAt = customer.CreatedAt,
};
}
}Graceful Error Handling
If encryption or decryption fails (e.g., a key store is temporarily unavailable), the pipeline behavior logs a warning and allows the request to proceed. This prevents transient key store failures from blocking request processing.
Notifications
The pipeline behavior only applies to IRequest<TResponse> pipelines. MediatR notifications (INotification) do not pass through IPipelineBehavior and are not intercepted by Tayra. If you need to protect PII in notification handlers, call ITayra directly:
public class CustomerCreatedNotificationHandler
: INotificationHandler<CustomerCreatedNotification>
{
private readonly ITayra _tayra;
public CustomerCreatedNotificationHandler(ITayra tayra)
{
_encrypter = encrypter;
}
public async Task Handle(
CustomerCreatedNotification notification,
CancellationToken cancellationToken)
{
await _encrypter.DecryptAsync(notification);
// notification.Name and notification.Email are now plaintext
}
}Use with EF Core
MediatR is commonly paired with EF Core in CQRS-style applications. When both Tayra.MediatR and Tayra.EFCore are registered, be careful to avoid double-encryption. A recommended pattern:
// MediatR behavior handles request/response PII
services.AddTayraMediatR(opts =>
{
opts.EncryptRequests = false; // Let EF Core handle persistence encryption
opts.DecryptResponses = true;
});
// EF Core interceptors handle storage-level PII
services.AddDbContext<AppDbContext>((sp, opts) =>
{
opts.UseNpgsql(connectionString)
.UseTayra(sp);
});This way, MediatR handlers work with plaintext, EF Core encrypts on save, and the response is decrypted for the caller.
See Also
- Getting Started -- End-to-end encryption tutorial
- EF Core Integration -- Entity Framework Core integration
- Wolverine Integration -- Wolverine message pipeline encryption
- MassTransit Integration -- MassTransit message pipeline encryption
- Key Stores -- Production key store options
