microsoft / fluentui-blazor

Microsoft Fluent UI Blazor components library. For use with ASP.NET Core Blazor applications
https://www.fluentui-blazor.net
MIT License
3.73k stars 358 forks source link

Retrieve IToastService trough IServiceProvider #2691

Open nullreferencez opened 1 week ago

nullreferencez commented 1 week ago

I'm attempting to retrieve the IToastService from a singleton class through IServiceProvider using the code below. However, although I do obtain an instance of IToastService , it does not display the toast.


  private readonly IServiceProvider _serviceProvider;

  public TaskService(IServiceProvider serviceProvider)
  {
          _serviceProvider = serviceProvider;
  }

  private async Task ProcessCompletedTask(PendingTask task)
  {
      //other code above
      using (var scope = _serviceProvider.CreateScope())
      {
          var toastService = scope.ServiceProvider.GetRequiredService<IToastService>();
          toastService?.ShowSuccess($"Uploaded and processed {document.Name}");
      }
   }
vnbaaij commented 1 week ago

HI,

Please supply us with ready-to-run reproduction code in the form of something we can copy/paste, a (zipped) project structure or a GitHub repository.

We do not have capacity to craft or compose a reproduction for every issue that gets raised.

If no code or repository is provided, this issue will be closed in 3 days

Help us to help you. Thanks.

Hwiet commented 1 week ago

IToastService is injected as a scoped service if you look at the implementation of AddFluentUIComponents. As is, not cannot be injected into a singleton service.

In addition, from my experience (with FluentUI and even with MudBlazor), I had to re-inject the ToastService as a singleton class in order for it to be injected into a class that is not a Blazor component, even if the class was scoped or transient.

vnbaaij commented 1 week ago

Good catch @Hwiet!

Closing this as it is an unsupported scenario.

nullreferencez commented 1 week ago

IToastService is injected as a scoped service if you look at the implementation of AddFluentUIComponents. As is, not cannot be injected into a singleton service.

In addition, from my experience (with FluentUI and even with MudBlazor), I had to re-inject the ToastService as a singleton class in order for it to be injected into a class that is not a Blazor component, even if the class was scoped or transient.

You are correct brother.

It appears that AddFluentUIComponents needs to be fixed to become a singleton, making it accessible throughout the Blazor application. I have tested it thoroughly and observed no negative effects from converting it into a singleton.

vnbaaij commented 6 days ago

I'm re-opening this with a vNext label so we can see if it is indeed do-able to change these to singleton

vnbaaij commented 6 days ago

In the meantime, nothing is stopping you from creating your own AddFluentUIComponents-alternative that injects the required/needed services as singleton into the service collection...

nullreferencez commented 5 days ago

In the meantime, nothing is stopping you from creating your own AddFluentUIComponents-alternative that injects the required/needed services as singleton into the service collection...

So I indeed changed it to a AddSingleton however there is a strange behavior. I can create Toasts and remove them from another singleton class however it fails to update a Toast without error message.

Now when I looked into it when updating a Toast instance if you create a new ToastParameters like below it wont update.

            _toastService.UpdateToast($"{task.Id}_processing", new ToastParameters<ProgressToastContent>()
            {
                Id = $"{task.Id}_processing",
                Intent = ToastIntent.Progress,
                Title = "Generating Requirements Matrix",
                Timeout = 0,
                Content = new ProgressToastContent()
                {
                    Details = $"Requirements found: {task.Progress}",
                },
            });

The issue seems to stem from that it must be the same original ToastParameters object.

For now I added a new function to at least get my use case working with adding the function below to FluentToastProvider.cs.

    private void UpdateToastProgressContent(string? toastId, ProgressToastContent Content)
    {
        _ = InvokeAsync(() =>
        {
            ToastInstance? toastInstance = _toastList.SingleOrDefault(x => x.Id == toastId);
            if (toastInstance is not null)
            {
                toastInstance.Content = Content;
                StateHasChanged();
            };
        });
    }