Closed ghost closed 2 years ago
Likely the problem here is that you are using a single class for both the razor backend and the notification handler. The .AddServices()
extension method registers the handlers as Transient
, which creates a new instance of the class to handle the notification. That means the one that is being used in rendering is not the same instance as the one that is handling the notification. In order to share data between the handlers and the Razor components you will need a shared dependency that both can interact with. I don't know the details of the lifecycle of the Razor components though so you will have to work that out yourself.
@orantwolinkme, if you solved this can you share your solution?
@ryanbuening I have created a library just for this, with it you can subscribe/unsubscribe to and from MediatR notifications through an ICourier interface: https://dev.azure.com/kandras9642/MediatR.Courier EDIT: this would be using it in Component2Base
public class Component2Base : ComponentBase, IDisposable
{
[Inject] ICourier Courier { get;set; }
protected string Data { get; set; }
protected override void OnInitialized()
{
Data = "1234";
Courier.Subscribe<Ping>(Handle);
}
public void Dispose()
{
Courier.UnSubscribe<Ping>(Handle);
}
public Task Handle(Ping notification, CancellationToken cancellationToken)
{
Console.WriteLine($"Got ping with data '{notification.Data}'");
try
{
Console.WriteLine("updating");
Data = notification.Data;
StateHasChanged();
Console.WriteLine("updated");
}
catch (Exception e)
{
Console.WriteLine(e);
}
return Task.CompletedTask;
}
}
@KuraiAndras awesome, thanks for sharing.
@KuraiAndras I have a similar problem only with Blazor Server. Having wired up your package I am not able to capture the event. Could you help please?
Registration:
builder.Services
.AddMediatR(Assembly.GetAssembly(typeof(Program))! ,Assembly.GetAssembly(typeof(SyncService))!)
.AddCourier(Assembly.GetAssembly(typeof(Program))!, Assembly.GetAssembly(typeof(SyncService))!);
Blazor page summary:
@using MediatR.Courier
@inject ICourier _courier
protected override void OnInitialized()
{
_courier.Subscribe<DataSyncResult<SalesOrder>>(Handle);
}
public Task Handle(DataSyncResult<SalesOrder> notification, CancellationToken cancellationToken)
{
_messages.Add(notification.ToString());
StateHasChanged();
return Task.CompletedTask;
}
Where:
public class DataSyncResult<T> : INotification
{ ...
and down the stack...
await _mediator.Publish(result, cancellationToken);
If I use Mediatr instead (with page implementing INotificationHandler<>), the Handle() method gets called but throws exception "The render handle is not yet assigned" which is why I am trying your suggestion.
@melmullen this should work, altough I did not try it with balzor server. Please open an issue at https://github.com/KuraiAndras/MediatR.Courier let's not discuss this here.
.NET Standard 2.1 .NET Core 3.1.402 MediatR - 8.1.0
Program.cs
register MediatR in DI
Component1.razor
Publish notification when button is clicked
Component1Base.cs
Component2.razor
Handle notification and try to update the value of the input
Component2Base.cs
Ping.cs
Notification class
Index.razor
Use the 2 components