Share Data Through Service in ASP.NET Blazor (Client Side)

南笙酒味 提交于 2019-12-11 11:01:54

问题


I use to have a common service in MVC Application , register it as Transient service and access its value across whole application without any issue .

I tried to implement same mechanism inside my client side blazor app

First created a class AppState

public class AppState
{
    public string BaseUrl { get; set; }
}

registered as a service

services.AddSingleton<AppState, AppState>();

Used in Blazor Component Index Component

public class IndexComponent : ComponentBase
{
    [Inject]
    HttpClient Http { get; set; }

    [Inject]
    public AppState AppState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        AppState = await Http.GetJsonAsync<AppState>(ConfigFiles.GetPath("appsettings.json"));
        await Task.FromResult(0);
    }
}

Tried to print base url in index.razor file

@page "/"
@inherits IndexComponent

<p>@AppState.BaseUrl</p>

Till Here its fine , now as it contain base url so i wanted to access it in another component

public class MiniCartComponent : ComponentBase
{
    [Inject]
    public AppState AppState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await Task.FromResult(0);
    }
}

Here it is empty , i dont know why

I tried to print it in razor file

@inherits MiniCartComponent
<p>@AppState.BaseUrl</p>

Here it is empty , it is registered as a service to share data across components , should not it have value across the app once it is set ??


回答1:


1st you register a singleton instance

services.AddSingleton<AppState, AppState>();

this look a bit weird to me. IMHO, it should be

services.AddSingleton<IAppState, AppState>();

or

services.AddSingleton<AppState>();

But that's not the probleme.

You inject this service in a component whicht is great

[Inject]
public AppState AppState { get; set; }

And you erase this component instance with a new one get from a web api

protected override async Task OnInitializedAsync()
{
    AppState = await Http.GetJsonAsync<AppState>(ConfigFiles.GetPath("appsettings.json"));
    await Task.FromResult(0);
}

Their again the code is weird, it should be

protected override async Task OnInitializedAsync()
{
    AppState = await Http.GetJsonAsync<AppState>(ConfigFiles.GetPath("appsettings.json"));
}

But that doesn't reset the singleton instance you inject in your second component. That just replace the instance in your 1st component.

  • You should register your service with
services.AddSingleton<AppState>(provider =>
{
    var http = provider.GetRequiredService<HttpClient>();
    return http.GetJsonAsync<AppState>(ConfigFiles.GetPath("appsettings.json")).ConfigureAwait(false).GetAwaiter().GetResult();
});

This way you make just one call to appsettings.json during the app life. (IMHO, it's not a good practice to use appsettings.json, you should use another config file, like clientsettings.json for sample).

  • And remove OnInitializedAsync code.

Async

But actually, the best way to achieve that is to register a Task returning your settings

services.AddSingleton(provider =>
{
    var http = provider.GetRequiredService<HttpClient>();
    return http.GetJsonAsync<AppState>("appsettings.json");
});

You can inject it in your components with

[Inject]
public Task<AppState> AppStateAsync { get; set; }

public AppState AppState { get; set; }

protected override async Task OnInitializedAsync()
{
    AppState = await AppStateAsync;
}

And use it with

@page "/"
@inherits IndexComponent

<p>@AppState.BaseUrl</p>


来源:https://stackoverflow.com/questions/58128731/share-data-through-service-in-asp-net-blazor-client-side

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!