{"id":283,"date":"2026-06-04T17:39:43","date_gmt":"2026-06-04T17:39:43","guid":{"rendered":"https:\/\/codefornoobs.pt\/?p=283"},"modified":"2026-06-04T17:39:43","modified_gmt":"2026-06-04T17:39:43","slug":"masstransit-descomplicado-o-framework-que-torna-event-driven-realmente-facil","status":"publish","type":"post","link":"https:\/\/codefornoobs.pt\/?p=283","title":{"rendered":"MassTransit Descomplicado: O Framework que Torna Event\u2011Driven Realmente F\u00e1cil"},"content":{"rendered":"\n<p>Quando come\u00e7as a trabalhar com sistemas distribu\u00eddos, uma das primeiras necessidades que surge \u00e9 a capacidade de comunicar entre servi\u00e7os de forma ass\u00edncrona e desacoplada. \u00c9 aqui que entram o <strong>RabbitMQ<\/strong> como message broker e o <strong>MassTransit<\/strong> como framework que simplifica toda a integra\u00e7\u00e3o no ecossistema .NET. Num outro post introduzimos o <a href=\"https:\/\/codefornoobs.pt\/?p=291\" target=\"_blank\" rel=\"noopener\" title=\"\">RabbitMQ<\/a> e fizemos a sua instala\u00e7\u00e3o. Neste, vamos ver como configurar o masstransit e um primeiro exemplo de como tudo funciona. Vamos montar o cen\u00e1rio mais b\u00e1sico \u2014 mas totalmente funcional \u2014 para perceberes como tudo encaixa: configurar o bus, publicar uma mensagem e consumi\u2011la num consumer.<\/p>\n\n\n\n<p>O fluxo b\u00e1sico de trabalho com MassTransit \u00e9 sempre o mesmo:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Definimos o <strong>contrato da mensagem<\/strong> (o evento).<\/li>\n\n\n\n<li>Criamos um <strong>consumer<\/strong> que sabe lidar com esse evento.<\/li>\n\n\n\n<li>Configuramos o <strong>bus<\/strong> do MassTransit para usar RabbitMQ.<\/li>\n\n\n\n<li>Publicamos uma mensagem e deixamos o consumer trat\u00e1\u2011la.<\/li>\n<\/ol>\n\n\n\n<p>A primeira coisa \u00e9 criar um projeto .NET (uma Web API serve perfeitamente) e o RabbitMQ a correr localmente. Para verificar se o RabbitMQ est\u00e1 a correr, basta aceder a <a href=\"http:\/\/localhost:15672\">http:\/\/localhost:15672<\/a> (se seguiste os passos de instala\u00e7\u00e3o que partilhei). Depois instalas os pacotes <code>MassTransit<\/code> e <code>MassTransit.RabbitMQ<\/code>, que s\u00e3o o n\u00facleo da integra\u00e7\u00e3o. A partir daqui, o fluxo \u00e9 sempre o mesmo: defines o contrato da mensagem, crias um consumer que sabe lidar com ela e configuras o MassTransit para ligar tudo ao RabbitMQ.<\/p>\n\n\n\n<p>Come\u00e7amos pelo contrato. Uma mensagem nada mais \u00e9 do que um record simples, imut\u00e1vel, que representa o evento que queres comunicar. Por exemplo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public record OrderSubmitted\n(\n    Guid OrderId,\n    string CustomerName,\n    decimal Total\n);<\/code><\/pre>\n\n\n\n<p>Este objeto \u00e9 o que vai viajar pela queue. N\u00e3o tem l\u00f3gica, n\u00e3o tem comportamento \u2014 apenas dados. Isto mant\u00e9m o sistema previs\u00edvel e f\u00e1cil de evoluir.<\/p>\n\n\n\n<p>Depois criamos o consumer, que \u00e9 a pe\u00e7a respons\u00e1vel por reagir quando uma mensagem deste tipo chega ao RabbitMQ. O MassTransit trata de toda a parte chata: deserializa\u00e7\u00e3o, binding, gest\u00e3o de conex\u00f5es. Por norma damos o nome da a\u00e7\u00e3o com Consumer no sufixo, mas pode ser qualquer coisa, na verdade. Esta classe \u00e9 composta por IConsumer&lt;T&gt;  em que T \u00e9 o evento a consumir. E basta implementar o m\u00e9todo Consume. Como argumento, temos um ConsumeContext&lt;OrderSubmitted&gt; context:. \u00c9 neste contexto que vamos conseguir aceder ao nosso objecto para processar a informa\u00e7\u00e3o. O nosso evento est\u00e1 em context.Message. \u00e9 no Consume que vamos fazer todo o processamento necess\u00e1rio. Por exemplo: Envio de email de confirma\u00e7\u00e3o, ou gravar a informa\u00e7\u00e3o na base de dados, ou chamar um outro servi\u00e7o para enviar a encomenda para o armaz\u00e9m, por exemplo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class OrderSubmittedConsumer : IConsumer&lt;OrderSubmitted&gt;\n{\n    private readonly ILogger&lt;OrderSubmittedConsumer&gt; _logger;\n\n    public OrderSubmittedConsumer(ILogger&lt;OrderSubmittedConsumer&gt; logger)\n    {\n        _logger = logger;\n    }\n\n    public Task Consume(ConsumeContext&lt;OrderSubmitted&gt; context)\n    {\n        var message = context.Message;\n\n        _logger.LogInformation(\n            \"Order received. Id: {OrderId}, Customer: {Customer}, Total: {Total}\",\n            message.OrderId,\n            message.CustomerName,\n            message.Total\n        );\n\n        return Task.CompletedTask;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Com o consumer criado, falta ligar tudo no <code>Program.cs<\/code>. \u00c9 aqui que o MassTransit \u00e9 registado no DI e onde configuramos o RabbitMQ como transporte. A configura\u00e7\u00e3o \u00e9 bastante declarativa: defines o host, as credenciais e a queue onde o consumer vai escutar. Algo assim:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>builder.Services.AddMassTransit(x =&gt;\n{\n    x.AddConsumer&lt;OrderSubmittedConsumer&gt;();\n\n    x.UsingRabbitMq((context, cfg) =&gt;\n    {\n        cfg.Host(\"localhost\", \"\/\", h =&gt;\n        {\n            h.Username(\"guest\");\n            h.Password(\"guest\");\n        });\n\n        cfg.ReceiveEndpoint(\"order-submitted-queue\", e =&gt;\n        {\n            e.ConfigureConsumer&lt;OrderSubmittedConsumer&gt;(context);\n        });\n    });\n});<\/code><\/pre>\n\n\n\n<p>O MassTransit faz o resto: cria a exchange, cria a queue, faz o binding e garante que o consumer est\u00e1 registado e pronto a receber mensagens. N\u00e3o precisas de criar nada manualmente no RabbitMQ.<\/p>\n\n\n\n<p>Para completar o ciclo, criamos um endpoint HTTP que publica uma mensagem. O MassTransit exp\u00f5e o <code>IPublishEndpoint<\/code>, que \u00e9 injetado automaticamente e sabe exatamente para onde enviar a mensagem:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app.MapPost(\"\/orders\", async (IPublishEndpoint publish, OrderRequest request) =&gt;\n{\n    var message = new OrderSubmitted(\n        Guid.NewGuid(),\n        request.CustomerName,\n        request.Total\n    );\n\n    await publish.Publish(message);\n\n    return Results.Accepted($\"\/orders\/{message.OrderId}\", new { message.OrderId });\n});<\/code><\/pre>\n\n\n\n<p>Quando fazes um POST para <code>\/orders<\/code> a API publica o evento, o RabbitMQ recebe\u2011o e o consumer processa\u2011o. O ciclo fica completo e tens o teu primeiro fluxo ass\u00edncrono a funcionar. No RabbitMq, no separador queues e streams vais encontrar a nova queue que foi criada com o nome <em>order-submitted-queue<\/em>. Neste caso, em que coloquei um breakpoint no consumer, podes ver que tem um total de 1 pedido e 1 pedido que est\u00e1 Unacked, o que significa que o pedido est\u00e1 a ser processado, mas ainda n\u00e3o terminou. Quando est\u00e1 ready na queue, significa que o pedido foi recebido, mas ainda n\u00e3o foi processado. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"321\" src=\"https:\/\/codefornoobs.pt\/wp-content\/uploads\/2026\/05\/image-1-1024x321.png\" alt=\"\" class=\"wp-image-287\" srcset=\"https:\/\/codefornoobs.pt\/wp-content\/uploads\/2026\/05\/image-1-1024x321.png 1024w, https:\/\/codefornoobs.pt\/wp-content\/uploads\/2026\/05\/image-1-300x94.png 300w, https:\/\/codefornoobs.pt\/wp-content\/uploads\/2026\/05\/image-1-768x241.png 768w, https:\/\/codefornoobs.pt\/wp-content\/uploads\/2026\/05\/image-1-1536x482.png 1536w, https:\/\/codefornoobs.pt\/wp-content\/uploads\/2026\/05\/image-1-850x267.png 850w, https:\/\/codefornoobs.pt\/wp-content\/uploads\/2026\/05\/image-1.png 1932w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>O mais interessante \u00e9 que, apesar de simples, este padr\u00e3o \u00e9 exatamente o que se usa em sistemas reais: contratos bem definidos, consumidores isolados, filas dedicadas e um bus que abstrai toda a complexidade. A partir daqui podes evoluir para retries, dead\u2011letter queues, sagas, routing avan\u00e7ado e muito mais \u2014 mas a base \u00e9 sempre esta.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quando come\u00e7as a trabalhar com sistemas distribu\u00eddos, uma das primeiras necessidades que surge \u00e9 a capacidade de comunicar entre servi\u00e7os de forma ass\u00edncrona e desacoplada. \u00c9 aqui que entram o RabbitMQ como message broker e o MassTransit como framework que simplifica toda a integra\u00e7\u00e3o no ecossistema .NET. Num outro post introduzimos o RabbitMQ e fizemos&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-283","post","type-post","status-publish","format-standard","hentry","category-sem-categoria"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=\/wp\/v2\/posts\/283","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=283"}],"version-history":[{"count":4,"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=\/wp\/v2\/posts\/283\/revisions"}],"predecessor-version":[{"id":293,"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=\/wp\/v2\/posts\/283\/revisions\/293"}],"wp:attachment":[{"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=283"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=283"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codefornoobs.pt\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=283"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}