Wolverine es un framework de .NET que funciona a la vez como mediador dentro del proceso (el papel que cumple MediatR) y como framework completo de mensajería asíncrona, con transportes para RabbitMQ, Azure Service Bus, Amazon SQS y Kafka (el papel que cumple MassTransit).
Los handlers son métodos normales, sin interfaces IRequest<T> ni clases base, porque Wolverine los conecta con código generado en lugar de con reflexión en tiempo de ejecución.
MediatR pasó a tener doble licencia con la versión 13.0.0, en julio de 2025, y ofrece la Reciprocal Public License 1.5 o una licencia comercial, mientras que Wolverine sigue con licencia MIT sin ninguna condición de elegibilidad (preguntas frecuentes sobre licencias de Lucky Penny Software, consultadas el 13 de septiembre de 2026).
¿Qué es Wolverine en .NET?
Wolverine es un framework de código abierto para el manejo de comandos y la mensajería asíncrona en .NET, desarrollado como parte del “Critter Stack” junto con la base de datos documental Marten. Se ocupa de dos tareas que normalmente requieren bibliotecas distintas: la mediación de solicitud/respuesta dentro del proceso, donde sustituye a MediatR, y la comunicación duradera basada en mensajes sobre RabbitMQ, Azure Service Bus, Amazon SQS o Kafka, donde compite con MassTransit y NServiceBus.
En lugar de resolver los handlers mediante reflexión y un pipeline de middleware, Wolverine usa la generación de código de Roslyn para compilar la ruta de despacho, de modo que un handler es simplemente un método Handle() público, en una clase *Handler, cuyo primer parámetro es el tipo de mensaje. Ese modelo de ejecución es lo que distingue a Wolverine. La propia guía Message Handlers de Wolverine es rotunda: “no se produce ninguna reflexión en tiempo de ejecución dentro del pipeline de ejecución de Wolverine”.
Eso nos da menos ceremonia y pruebas unitarias más sencillas (los handlers son métodos normales que podemos llamar directamente). Wolverine también incluye funcionalidades para producción que MediatR nunca tuvo: inbox y outbox transaccionales, sagas, mensajes programados y políticas de reintentos.
Primeros pasos con Wolverine
Vamos a empezar a construir nuestra primera aplicación con la biblioteca Wolverine. Creamos un nuevo proyecto de API con este comando:
dotnet new webapi -n IntroductionToWolverineLibrary
Esto crea un nuevo proyecto de API mínima llamado IntroductionToWolverineLibrary, con compatibilidad integrada con OpenAPI. A continuación, instalamos la biblioteca Wolverine:
dotnet add package WolverineFx
Esto instala en nuestro proyecto la última versión de WolverineFx.
A partir de la rama 6.x, Wolverine distribuye su compilador de Roslyn en tiempo de ejecución como un paquete aparte, así que también lo instalamos. Sin él, Wolverine lanza una excepción al iniciar:
dotnet add package WolverineFx.RuntimeCompilation
Después, en el archivo Program.cs, tenemos que añadir una directiva using Wolverine; y esta llamada:
builder.Host.UseWolverine();
Esta llamada hace que Wolverine esté disponible en todo el proyecto. Ya podemos empezar a construir nuestra aplicación aprovechando la biblioteca Wolverine.
La biblioteca Wolverine como mediador
Para la demostración, construimos el proyecto como un sistema de gestión de pedidos de libros. Primero, vamos a crear un objeto sencillo para un nuevo pedido de libro. Ponemos los records en el espacio de nombres IntroductionToWolverineLibrary.Models y añadimos using IntroductionToWolverineLibrary.Models; a todos los archivos que los usan:
public record Order(Guid OrderId, string CustomerName, int BookId);
Aquí definimos un nuevo record, Order, pensado para modelos de datos inmutables. Contiene tres propiedades. La primera, OrderId, es un Guid (identificador único global, Globally Unique Identifier) que identifica el pedido. La segunda, CustomerName, es una cadena que representa el nombre del cliente. Por último, BookId es un int que identifica el libro pedido.

Ebook gratis
¿Tu Web API está lista para producción?
33 puntos que comprobar antes de desplegarla, con la solución de cada uno. Un PDF gratuito de 76 páginas para .NET 10.
El ebook está en inglés.
Descarga la checklist gratisPDF gratuito. Un solo correo para enviártelo. Puedes darte de baja cuando quieras.
InvokeAsync() para enviar un mensaje
Ahora, vamos a configurar nuestro primer endpoint en el archivo Program.cs. Construiremos cada endpoint con la sintaxis de API mínimas:
app.MapPost("/order", async (Order newOrder, IMessageBus bus) => await bus.InvokeAsync(newOrder))
.WithName("NewBookOrder");
Aquí, definimos un endpoint HTTP POST en la ruta /order. Configuramos el endpoint para que acepte como parámetros un objeto Order y una instancia de IMessageBus. Por último, la expresión lambda proporcionada ejecuta de forma asíncrona el método InvokeAsync() sobre bus y le pasa newOrder como argumento.
La llamada a WithName("NewBookOrder") asigna a este endpoint el nombre NewBookOrder, lo que puede ser útil para el enrutamiento o la documentación.
Ahora, vamos a construir el método que recibe el mensaje:
public class OrderHandler
{
public static void Handle(Order? order) => Console.WriteLine($"New order received: {order}");
}
En una clase nueva, implementamos el método Handle, que recibe un objeto Order como parámetro e imprime un mensaje en la consola para indicar que se ha recibido un nuevo pedido. Como definimos un método llamado Handle que recibe un parámetro Order en una clase cuyo nombre termina en Handler, Wolverine lo reconoce como el handler de los mensajes Order. Cuando se recibe un nuevo mensaje de pedido, Wolverine lo enruta a este método para procesarlo mediante su bus de mensajes local.
Cuando Wolverine se integra en una aplicación .NET Core, registra el servicio IMessageBus en el contenedor IoC subyacente del sistema, lo que permite inyectarlo en clases de controlador o en endpoints de API mínimas, como hemos visto antes. Después, el método IMessageBus.InvokeAsync(message) procesa el mensaje recibido: determina la ruta de ejecución adecuada para el tipo de mensaje y ejecuta el handler o los handlers de Wolverine correspondientes.
No necesitamos usar interfaces para declarar la intención de ciertas clases, como IRequest o IHandler. Wolverine usa Roslyn para generar código en tiempo de ejecución y así reducir al mínimo el código que normalmente hace falta para conectar internamente el handler correcto con el comando adecuado. Por eso, podemos probar los métodos con más facilidad. En lugar de crear un mock de una abstracción, podemos probar directamente el método que contiene la lógica de negocio. Como el método Handle es estático y solo recibe el mensaje, podemos invocarlo y probarlo sin dependencias.
Uso de InvokeAsync<T>() con un objeto devuelto
Si queremos que nuestro handler devuelva un objeto, tenemos que usar el método IMessageBus.InvokeAsync<T>():
app.MapPost("/orderReply", async (Order newOrder, IMessageBus bus) =>
await bus.InvokeAsync<string>(newOrder))
.WithName("NewBookOrderReply");
Con la sobrecarga IMessageBus.InvokeAsync<T>(message), esperamos que el handler devuelva un objeto de tipo T. En nuestro ejemplo, esperamos una simple respuesta string.
Ahora, vamos a actualizar el método Handle para que devuelva una respuesta:
public static string Handle(Order? order) => $"New order received: {order}";
Este método devuelve una cadena que confirma que hemos recibido un nuevo pedido. Cabe mencionar que podemos modificar el método Handle para que devuelva un objeto de una clase o de una estructura, aunque no un tipo primitivo como int.
Uso de colas con la biblioteca Wolverine
La biblioteca Wolverine nos permite usar colas para enviar y recibir mensajes. Así, podemos comunicarnos a través de un canal con distintas entidades, como microservicios o API.
Dentro de la llamada a UseWolverine() que ya tenemos, vamos a preparar la configuración para enviar mensajes a una cola concreta:
builder.Host.UseWolverine( x =>
{
x.PublishAllMessages().ToLocalQueue("local-queue");
});
En el archivo Program.cs, configuramos los mensajes para que se transmitan a través de una cola local llamada local-queue. Así nos aseguramos de que cualquier mensaje que enviemos al IMessageBus de Wolverine se procese según las reglas configuradas en Wolverine.
Del mismo modo, vamos a crear un nuevo objeto BookReview:
public record BookReview(int BookId, string ReviewerName, int Rating);

Ebook gratis
¿Tu Web API está lista para producción?
33 puntos que comprobar antes de desplegarla, con la solución de cada uno. Un PDF gratuito de 76 páginas para .NET 10.
El ebook está en inglés.
Descarga la checklist gratisPDF gratuito. Un solo correo para enviártelo. Puedes darte de baja cuando quieras.
Este record sencillo contiene información sobre una nueva reseña de libro. Ahora, vamos a configurar el nuevo endpoint:
app.MapPost("/bookReview", async (BookReview review, IMessageBus bus) =>
{
await bus.PublishAsync(review);
return Results.Ok("Book review submitted successfully.");
})
.WithName("BookReviewEndpoint");
Cuando hacemos una solicitud POST a este endpoint, la aplicación publica esta reseña de forma asíncrona con el IMessageBus de Wolverine. Después de publicar el mensaje, el endpoint devuelve una respuesta HTTP que indica que la reseña se ha enviado correctamente. Esta configuración permite manejar las reseñas de libros de forma desacoplada y aprovecha las capacidades de Wolverine para la comunicación y el procesamiento basados en mensajes dentro de la arquitectura de la aplicación .NET.
Publicamos este mensaje para todos los suscriptores de la cola. Es una buena práctica habitual cuando queremos emitir mensajes que funcionan como eventos. Resulta especialmente necesario en una arquitectura en la que queremos procesar los mensajes de forma asíncrona e independiente del emisor.
Ahora, vamos a implementar el handler:
public class BookReviewHandler
{
public static void Handle(BookReview? review) => Console.WriteLine($"New book review received: {review}");
}
Este handler se invoca después de la transmisión del mensaje, ya que el método se llama Handle, el nombre de su clase termina en Handler y su argumento es de tipo BookReview. En este método, procesamos BookReview de forma similar: generamos una cadena que confirma la recepción de la reseña.
Wolverine registra en el nivel Debug los mensajes en cola que procesa correctamente, así que vamos a establecer ese nivel para el espacio de nombres IntroductionToWolverineLibrary, con "IntroductionToWolverineLibrary": "Debug" dentro de Logging:LogLevel en appsettings.json, y a revisar los logs en la consola:
Successfully processed message IntroductionToWolverineLibrary.Models.BookReview#01909954-3efa-401e-b0ac-f93465bbadc4 from local://local-queue/
Wolverine genera un log cuando procesa correctamente un mensaje en cola. Como vemos, el log indica que Wolverine ha procesado correctamente un mensaje de tipo BookReview del espacio de nombres IntroductionToWolverineLibrary.Models. El origen del mensaje es local://local-queue/, lo que indica además que se maneja desde una cola local dentro de la aplicación.
Colas externas para manejar mensajes
Wolverine permite usar proveedores de colas externos para gestionar la mensajería. Por ejemplo, podemos integrarlo con sistemas de mensajería populares como RabbitMQ, Apache Kafka, Azure Service Bus y Amazon SQS. Wolverine enruta entonces los mensajes a través de ese bróker, de modo que la comunicación asíncrona y el procesamiento distribuido se ejecutan sobre una infraestructura pensada para ello.
Si usamos Wolverine tanto para publicar como para procesar mensajes a través de una infraestructura externa, podemos manejar patrones de mensajería complejos, garantizar una entrega fiable de los mensajes y escalar nuestra arquitectura de mensajería para responder a la demanda de entornos con mucho tráfico.
¿Cómo se compara Wolverine con MediatR en C#?
Ambas bibliotecas despachan un objeto de mensaje a un handler, pero difieren en el mecanismo y en el alcance. MediatR exige que el mensaje implemente IRequest<TResponse> y el handler IRequestHandler<TRequest, TResponse>, resuelve los handlers mediante el contenedor de inyección de dependencias (DI) en tiempo de ejecución y funciona estrictamente dentro del proceso.
Wolverine prescinde por completo de las interfaces. Los métodos públicos Handle() o Consume() de las clases *Handler se descubren por convención y se conectan con código generado, y el mismo handler puede recibir más adelante mensajes de un bróker externo sin cambios. El middleware también es distinto: los pipelines de MediatR son clases IPipelineBehavior, mientras que Wolverine integra el middleware en el código generado, incluidas políticas convencionales de transacciones y de manejo de errores.
El detonante práctico es la licencia. Desde la versión 13.0.0, de julio de 2025, MediatR tiene doble licencia, y las opciones son aceptar la Reciprocal Public License 1.5 y publicar nuestro propio código fuente, cumplir las cuatro condiciones del nivel Community o comprar una licencia comercial. WolverineFx sigue con la licencia MIT, sin más.
MediatR sigue ganando cuando solo hace falta despacho dentro del proceso: es una dependencia más pequeña y sus interfaces hacen explícito el contrato en el punto de llamada. La migración, cuando vale la pena, es sobre todo mecánica: eliminar las interfaces de marcador, cambiar nombres y volver a conectar el registro.
| Criterio | Wolverine | MediatR | MassTransit |
|---|---|---|---|
| Mediador dentro del proceso | Sí | Sí | Sí |
| Transportes para brókeres de mensajes | RabbitMQ, Azure Service Bus, SQS, Kafka | No | RabbitMQ, Azure Service Bus, SQS, Kafka |
| Estilo de handler | Método normal, generación de código | Interfaz IRequestHandler<T>, reflexión | Interfaz IConsumer<T> |
| Outbox/inbox duradero | Sí, mediante un paquete de almacenamiento (PostgreSQL, SQL Server) | No | Sí, mediante un paquete de almacenamiento |
| Sagas | Sí | No | Sí |
| Licencia | MIT, sin condiciones de elegibilidad (WolverineFx 6.36.0) | Doble licencia desde la v13.0.0 (2 de julio de 2025): RPL-1.5 o comercial (MediatR 14.2.0); nivel Community gratuito solo si se cumplen las cuatro condiciones; la v12.5.0 y anteriores siguen con Apache-2.0 | Comercial y de código fuente disponible (source-available) desde la v9 (9.0.0, 6 de enero de 2026), con clave de licencia obligatoria en tiempo de ejecución; la v8 y anteriores conservan la licencia Apache-2.0 de forma permanente y se siguen publicando (8.5.10), pero el proveedor las considera sin soporte y ha anunciado que el mantenimiento oficial de la v8 no se extenderá más allá de 2026; con ingresos brutos anuales inferiores a 1 millón de dólares se puede optar a un descuento del 100 %, sin soporte comercial |
Para el patrón que Wolverine sustituye en su papel de mediador, consulta nuestra guía sobre CQRS y MediatR en ASP.NET Core. En cuanto a la mensajería, tenemos una comparación de Rebus, NServiceBus y MassTransit y una guía práctica para usar MassTransit con RabbitMQ.
Conclusión
En este artículo, hemos presentado la biblioteca Wolverine para gestionar la mensajería en nuestra aplicación .NET. Hemos mostrado, a través de una API, cómo definir endpoints, configurar colas para la transmisión de mensajes e implementar handlers para el procesamiento asíncrono de mensajes.
Probado con .NET 10.0.10 y WolverineFx 6.36.0.