问题
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