Skip to main content
BuildingBlocks.Hangfire.MediatR.Extensions, MediatR komut/event’lerini Hangfire arka plan job’u olarak çalıştırmayı sağlar. Hangfire payload’ı Type’ı bilmeden serialize edemediği için paket iki şeyi çözer: (1) Hangfire serializer’ını TypeNameHandling ile yapılandırma, (2) MediatR mesajını MediatorSerializedObject’e paketleyip job içinde tekrar deserialize edip _mediator.Send(...) ile dispatch etme.
Çalışan Hangfire altyapısı (PostgreSQL storage hangfire şeması, dashboard /jobs, server kuyrukları, DLX) için bkz. Hangfire servisi. Bu sayfa MediatR köprüsüne odaklanır.

UseMediatR — Hangfire serializer kurulumu

Hangfire’ın global JSON ayarlarını, polimorfik tip bilgisini koruyacak şekilde yapılandırır. TypeNameHandling.All sayesinde serialize edilen MediatR komutu, worker tarafında doğru concrete tipe geri çözülebilir.
public static IGlobalConfiguration UseMediatR(this IGlobalConfiguration configuration, IServiceCollection services)
{
    var jsonSettings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All
    };
    configuration.UseSerializerSettings(jsonSettings);
    return configuration;
}
// Program.cs — Hangfire kurulumu içinde
GlobalConfiguration.Configuration
    .UsePostgreSqlStorage(/* ... */)
    .UseMediatR(builder.Services);

Köprü bileşenleri

MediatR mesajı doğrudan değil, MediatorSerializedObject zarfıyla taşınır. Bu zarf job storage’da güvenle saklanır ve worker’da yeniden kurulur.
TipRol
IBusMessageİşaretleyici (marker) — taşınabilir mesaj
IBusCommand : IRequest, IBusMessageJob olarak çalıştırılacak MediatR komutu
ICommandBusKomut enqueue/schedule API’si
IEventBusEvent publish API’si
ICommandExecuter / IEventDispatcherWorker tarafı — deserialize edip _mediator.Send çağırır
MediatorSerializedObjectFullTypeName, AssemblyName, Data (JSON), AdditionalDescription

ICommandBus

MetotAmaç
string Send<T>(T request, string description = null, ...)Komutu hemen kuyruğa alır; job id döner
string Send<T>(T request, string parentJobId, JobContinuationOptions, ...)Başka bir job’ın devamı olarak zincirler
void Schedule<T>(T request, DateTimeOffset scheduleAt, ...)Belirli zamanda çalıştır
void Schedule<T>(T request, TimeSpan delay, ...)Gecikmeli çalıştır
void ScheduleRecurring<T>(T request, string name, string cron, RecurringJobOptions, ...)Cron tabanlı tekrarlı job
IEventBus: void Publish<T>(...) ve Task PublishAsync<T>(...) — event’i IEventDispatcher üzerinden enqueue eder.

Serialize → enqueue → execute

CommandBus, mesajı MediatorSerializedObject’e paketleyip BackgroundJob.Enqueue<ICommandExecuter>(...) ile kuyruğa alır:
// CommandBus (kütüphane içi)
public string Send<T>(T request, string description = null, ...) where T : IBusMessage
{
    var serialized = SerializeObject(request, description);   // FullTypeName + AssemblyName + JSON
    return BackgroundJob.Enqueue<ICommandExecuter>(x => x.ExecuteCommand(serialized));
}
Worker tarafında CommandExecuter zarfı çözer, tipi assembly’den bulur, JSON’u o tipe deserialize eder ve MediatR’a verir:
// CommandExecuter (kütüphane içi) — "command-queue" kuyruğunda çalışır
public async Task ExecuteCommand(MediatorSerializedObject obj)
{
    var assembly = AppDomain.CurrentDomain.GetAssemblyByName(obj.AssemblyName);
    var type = assembly?.GetType(obj.FullTypeName);
    if (type is null) return;

    dynamic req = JsonConvert.DeserializeObject(obj.Data, type);
    await _mediator.Send(req as IRequest);   // pipeline behavior'lar dahil normal akış
}
ICommandExecuter.ExecuteCommand [Queue("command-queue")] ile işaretlidir; bu işler Hangfire’da ayrı bir kuyrukta çalışır. Job dashboard’da MediatorSerializedObject.ToString() çıktısıyla (komut adı + açıklama) görünür.

Kullanım

// 1) Job olarak çalışacak komut
public sealed record SendMonthlyReportCommand(Guid OrganizationId) : IBusCommand;

// 2) Hemen enqueue
public class ReportController(ICommandBus bus)
{
    [HttpPost("api/admin/reports/monthly/{orgId:guid}")]
    public IActionResult Trigger(Guid orgId)
    {
        string jobId = bus.Send(new SendMonthlyReportCommand(orgId), description: $"org:{orgId}");
        return Accepted(new { jobId });
    }
}

// 3) Gecikmeli
bus.Schedule(new SendMonthlyReportCommand(orgId), TimeSpan.FromMinutes(30));

// 4) Cron tabanlı tekrarlı (her ayın 1'i 03:00)
bus.ScheduleRecurring(
    new SendMonthlyReportCommand(orgId),
    name: "monthly-report",
    cronExpression: "0 3 1 * *",
    recurringJobOption: new RecurringJobOptions());
Komut, normal MediatR pipeline’ından geçer — yani SendMonthlyReportCommandHandler ve tüm pipeline behavior’lar (validation, exception, authorization) arka planda da uygulanır.
Komut payload’ını küçük ve serileştirilebilir tutun (id’ler, primitive’ler). Job storage’a entity grafiği yazmayın; handler içinde repository’den taze veriyi çekin. Polimorfik tip bilgisi (TypeNameHandling.All) güvenilmeyen kaynaktan gelen veri için risklidir — yalnızca uygulamanın kendi ürettiği job’lar enqueue edilmelidir.

İlgili

Hangfire servisi

PostgreSQL storage, dashboard ve server kuyrukları.

Application (CQRS)

Command/handler ve pipeline behavior’lar.

Event-Driven akış

Domain/integration event’lerle karşılaştırma.

Email servisi

SendBackground ile arka plan gönderim deseni.