简体   繁体   English

Blazor WebAssembly - appsettings.json 作为注册服务时的依赖项

[英]Blazor WebAssembly - appsettings.json as dependency while registering services

I'm trying to register my custom AppSettings class as a service but it's not working and I'm lost.我正在尝试将我的自定义 AppSettings 类注册为服务,但它不起作用并且我迷路了。 I have the AppSettings class and the corresponding appsettings.json file located at wwwroot.我有位于 wwwroot 的 AppSettings 类和相应的 appsettings.json 文件。 Then I have another class that depends on the AppSettings class, ctor looking like this:然后我有另一个依赖于 AppSettings 类的类,ctor 看起来像这样:

public GeneratorService(AppSettings appSettings)
{
    _appSettings = appSettings;
}

The Main method looks like this: Main 方法如下所示:

public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("app");
    builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
    builder.Services.AddTransient(async sp =>
        {
            var httpClient = sp.GetRequiredService<HttpClient>();
            var response = await httpClient.GetAsync("appsettings.json");
            using var json = await response.Content.ReadAsStreamAsync();
            return await JsonSerializer.DeserializeAsync<AppSettings>(json);
        }
    );
    builder.Services.AddTransient<GeneratorService>();
    await builder.Build().RunAsync();
}

I know for sure that the JsonSerializer creates the correct instance of AppSettings from the file.我确信 JsonSerializer 从文件中创建了正确的 AppSettings 实例。 I'm pretty new to this but from what I understand, it should work like this:我对此很陌生,但据我所知,它应该像这样工作:

  1. I'm injecting GeneratorService to a .razor page so the page asks for GeneratorService instance我将 GeneratorService 注入到 .razor 页面,因此该页面要求 GeneratorService 实例
  2. GeneratorService has AppSettings in it's ctor so it asks for AppSettings instance GeneratorService 在它的 ctor 中有 AppSettings,所以它要求 AppSettings 实例
  3. Service provider knows that to get AppSettings instance it has to call HttpClient, read and deserialize the appsettings.json file服务提供者知道要获取 AppSettings 实例,它必须调用 HttpClient,读取和反序列化 appsettings.json 文件

But when I try to load the mentioned .razor page, I'm getting this error:但是当我尝试加载提到的 .razor 页面时,我收到了这个错误:

Unhandled exception rendering component: Unable to resolve service for type 'BP.AppSettings' while attempting to activate 'BP.Services.GeneratorService'.

How come that the service provider can't create AppSettings and inject it into the GeneratorService?为什么服务提供者无法创建 AppSettings 并将其注入 GeneratorService 中? Thank you for your answers.谢谢您的回答。

example appsettings.json示例 appsettings.json

{
  "ClientConfigurations": {
    "AzureAd": {
      "Authority": "https://login.microsoftonline.com/001f3bfc-XXXX-XXXX-XXX-17c0e6de3b0f",
      "ClientId": "815442365ec-xxxx-xxxx-xxxx-1ce9c3f3429",
      "ValidateAuthority": true
    }
  }
}

Add these classes.添加这些类。 Note matching names.注意匹配的名称。

    public class LocalConfigurations
    {
        public ClientConfigurations ClientConfigurations { get; set; }
    }
    public class ClientConfigurations
    {
        public AzureAdConfigurations AzureAd { get; set; }
    }
    public class AzureAdConfigurations
    {
        public string Authority { get; set; }
        public string ClientId { get; set; }
        public bool ValidateAuthority { get; set; }
    }

In program.cs it is already loaded into builder.Configuration.在 program.cs 中,它已经加载到 builder.Configuration 中。 These two lines should help you access it.这两行应该可以帮助您访问它。

var LocalConfigurations = builder.Configuration.Get<LocalConfigurations>();    
builder.Services.AddSingleton(LocalConfigurations.ClientConfigurations);

then in any component然后在任何组件中

@page "/"
@inject Models.ClientConfigurations config


@config.AzureAd.ClientId

在此处输入图片说明

I'm very pretty new in Blazor, but if you has an appsettings.json in root like,eg我在 Blazor 中非常新,但是如果您在根目录中有一个 appsettings.json,例如

{
  "message": "Hello word"
}

Just inject in your service IConfiguration, so只需注入您的服务 IConfiguration,所以

public WeatherForecastClient(HttpClient client, IConfiguration Configuration)
{
     Console.WriteLine(Configuration["message"]);
     this.client = client;
}

In Dane Vinson's this entry you has another aproach that it's embed the "appsettings.json" as an Embedded resource.Dane Vinson 的这个条目中,您有另一种方法,它将“appsettings.json”作为嵌入式资源嵌入。

1.-Put the file in the root of your Blazor client project 1.-将文件放在 Blazor 客户端项目的根目录中

2.-Edit your project.csproj and add some like 2.-编辑您的 project.csproj 并添加一些类似

  <ItemGroup>
    <EmbeddedResource Include="your-file.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </EmbeddedResource>
  </ItemGroup>

3.-Create a .json and a class SettingsInfo 3.-创建一个 .json 和一个类 SettingsInfo

4.-In program.cs, you add the service 4.-在program.cs中,添加服务

public static async Task Main(string[] args)
{
    //fileName is NameOf your Assembly.your-file.json, e.g.
    string fileName = "Blazor1.Client.appsettings.json";
    var stream = Assembly.GetExecutingAssembly()
                         .GetManifestResourceStream(fileName);

    var config = new ConfigurationBuilder()
            .AddJsonStream(stream)
            .Build();

    builder.Services.AddTransient(_ =>
    {
        return config.GetSection("AppSettings")
                     .Get<SettingsInfo>();
    });

    ....
 }

Now you can Inject SettingsInfo in your razor pages or in your services现在您可以在剃刀页面或服务中注入 SettingsInfo

Thank you both for your answers.谢谢你们的回答。 After reading Orak's answer I decided to register my AppSettings instance as a singleton and now it works.阅读 Orak 的回答后,我决定将我的 AppSettings 实例注册为单例,现在它可以工作了。 So instead of:所以而不是:

builder.Services.AddTransient(async sp =>
    {
        var httpClient = sp.GetRequiredService<HttpClient>();
        var response = await httpClient.GetAsync("appsettings.json");
        using var json = await response.Content.ReadAsStreamAsync();
        return await JsonSerializer.DeserializeAsync<AppSettings>(json);
    }
);

I simply have:我只是:

var response = await client.GetAsync("appsettings.json");
using var json = await response.Content.ReadAsStreamAsync();
var appSettings = await JsonSerializer.DeserializeAsync<AppSettings>(json);
builder.Services.AddSingleton(appSettings);

I guess it even makes more sense to have AppSettings as a singleton instead of a transient.我想将 AppSettings 作为单例而不是瞬态更有意义。 I'm still not sure why my original code didn't work though.我仍然不确定为什么我的原始代码不起作用。

Edit: using Configuration also works:编辑:使用配置也有效:

var appSettings = builder.Configuration.Get<AppSettings>();
builder.Services.AddSingleton(appSettings.NamesLists);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM