Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrieve IToastService trough IServiceProvider #2691

Open
nullreferencez opened this issue Sep 20, 2024 · 13 comments
Open

Retrieve IToastService trough IServiceProvider #2691

nullreferencez opened this issue Sep 20, 2024 · 13 comments
Labels
vNext For the next major version

Comments

@nullreferencez
Copy link

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}");
      }
   }
@microsoft-github-policy-service microsoft-github-policy-service bot added the triage New issue. Needs to be looked at label Sep 20, 2024
@vnbaaij vnbaaij added needs: repro code or repository The provided description or code is insufficient to repro the issue and removed triage New issue. Needs to be looked at labels Sep 20, 2024
@vnbaaij
Copy link
Collaborator

vnbaaij commented Sep 20, 2024

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
Copy link

Hwiet commented Sep 20, 2024

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
Copy link
Collaborator

vnbaaij commented Sep 21, 2024

Good catch @Hwiet!

Closing this as it is an unsupported scenario.

@vnbaaij vnbaaij closed this as not planned Won't fix, can't repro, duplicate, stale Sep 21, 2024
@nullreferencez
Copy link
Author

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 vnbaaij added vNext For the next major version and removed needs: repro code or repository The provided description or code is insufficient to repro the issue labels Sep 23, 2024
@vnbaaij
Copy link
Collaborator

vnbaaij commented Sep 23, 2024

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 vnbaaij reopened this Sep 23, 2024
@vnbaaij
Copy link
Collaborator

vnbaaij commented Sep 23, 2024

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
Copy link
Author

nullreferencez commented Sep 24, 2024

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();
            };
        });
    }

@mmaderic
Copy link

I've also encountered a similar issue. I have a scenario where I have to use a dedicated service scope.

Example:
var service = (_scope ??= serviceScopeFactory.CreateAsyncScope()).ServiceProvider.GetRequiredService<TService>();

If the resolved service has IToastService as a dependency, it won't show any messages.

@vnbaaij
Copy link
Collaborator

vnbaaij commented Sep 30, 2024

I've also encountered a similar issue. I have a scenario where I have to use a dedicated service scope.

Example: var service = (_scope ??= serviceScopeFactory.CreateAsyncScope()).ServiceProvider.GetRequiredService<TService>();

If the resolved service has IToastService as a dependency, it won't show any messages.

You can't just have IToastService alone. You als need to have the implementation. As can be seen in AddFluentUIComponents, we add services.AddScoped<IToastService, ToastService>();

@mmaderic
Copy link

mmaderic commented Oct 1, 2024

I understand, but messages won't be shown if the consuming service has IToastService as a dependency and that consuming service is being resolved from a dedicated scope created somewhere in the code.

I assume this is a limitation because the component responsible for rendering the messages will have a different instance of IToastService than the one created here from the dedicated scope or at least subscribe to its events.

We cannot have IToastService as a singleton, and it seems designed to work within the rendered UI context scope.
It will be best to rethink my approach and stop having direct UI dependencies in my data processing services, which I create in a dedicated scope.

I've taken this approach because of the server-side simultaneous data processing between the components and EF's limitations regarding that. Still, I was looking to use the toast for error messages, but I will have to change it, and it completely makes sense to me now.

@dominicusmento
Copy link

Same problem here.. I need to access IDialogService from singleton (wasm) and if used with using (var scope = serviceProvider.CreateScope()), and as expected it throws: System.ArgumentNullException: needs to be added to the main layout of your application/site.. We need at least additional AddFluentUIComponents methods for singleton, or bool parameter in currentMethod to include as singleton..

@mmaderic
Copy link

That is true, @dominicusmento. A useful use case for a singleton is Wasm applications. My context is server-rendered, so it must be scoped there.

@svrooij
Copy link
Contributor

svrooij commented Nov 25, 2024

May I suggest a AddFluentUIComponents(Lifetime serviceLifeTime = Lifetime.Scoped)? This way the developer can pick which ever lifetime that suits their needs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
vNext For the next major version
Projects
None yet
Development

No branches or pull requests

6 participants