【问题标题】:blazor wasm how to inject from di into custom classblazor wasm 如何从 di 注入自定义类
【发布时间】:2021-04-30 06:29:34
【问题描述】:

有没有办法将 httpClient 注入到我自己的自定义类中?

明确一点 - 我知道如何在 blazor 中使用 DI 注入组件或其他服务。 只是为了测试它的可能性。

我想做一些类似代码的事情

protected override async Task OnInitializedAsync()
{
  GSP gsp = new GSP("db1","table1");
  gsp.get("users", ()=>{ do something with data}); // and this should call api and get users
}

所以我有

public class GSP
{
    [Inject]
    public HttpClient httpClient { get; set; }
 ...
}

但它是null

我还检查了 ctor 选项

    public GSP(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

但是我必须手动传递这个注入到组件中的 httpClient。

我可以的

  private HttpClient httpClient = new HttpClient { BaseAddress }

但是我没有 BaseAdres。听说我们又去了 - 在这个地方得到这个 BaseAddres 的更简单的方法? ;)

有可能吗?或者这只是“糟糕的做法”,这就是我找不到的原因? 非常感谢!

【问题讨论】:

标签: dependency-injection blazor blazor-webassembly


【解决方案1】:

通过 ctor 和 HttpClientFactory,您可以执行以下操作:

public class Program
{
    public static async Task Main(string[] args)
    {
         var builder = WebAssemblyHostBuilder.CreateDefault(args);
         builder.Services
         .AddTransient<GSP>()
         .AddHttpClient().ConfigureHttpClient(httpClient =>
         {
              httpClient.BaseAddress = builder.HostEnvironment.BaseAddress;
         });
         await host.RunAsync();
    }
}

或者没有 HttpClientFactory

public class Program
{
    public static async Task Main(string[] args)
    {
         var builder = WebAssemblyHostBuilder.CreateDefault(args);
         builder.Services
         .AddTransient(p => new GSP(new HttpClient { BaseAddress = builder.HostEnvironment.BaseAddress });

         await host.RunAsync();
    }
}

【讨论】:

    【解决方案2】:

    我觉得this article里的解释还不错:

    复杂的服务可能需要额外的服务。在下面的 例如,DataAccess 需要 HttpClient 默认服务。 @注入 (或 [Inject] 属性)不可用于服务。 必须改用构造函数注入。所需的服务是 通过向服务的构造函数添加参数来添加。

    你在正确的轨道上:

     public GSP(HttpClient httpClient)
        {
            this.httpClient = httpClient;
        }
    

    但这是你误会的地方

    但是我必须手动传递这个注入的 httpClient 以组件为例。

    不要手动传递任何东西。而是将您的 GSP 类注入到您的组件中。

    在您的剃须刀组件基类中:

       [Inject]
        public GSP myGspService { get; set; }
    

    或直接在剃刀文件中:

    @Inject GSP myGspService
    

    如果您每次使用时都想要一个新实例,请注入一个GSPFactory 类。您不能直接使用 DI 注入未注册的参数(例如您的“db1”和“table1”),工厂类必须处理它,或者您必须在每次创建时设置它们..

    在您的剃须刀组件基类中:

       [Inject]
        public GSPFactory myGspService { get; set; }
    

    或直接在剃刀文件中:

    @Inject GSPFactory myGspService
    

    和你的工厂类:

    public class GSPFactory {
       Func<GSP> iocFactory;
       public GSPFactory(Func<GSP> iocFactory) {}
          this.iocFactory = iocFactory;
       }
    
       public GSP Create(string option1, string option2) {
          var gsp = this.iocFactory();
          gsp.Option1 = option1;
          gsp.Option2 = option2;
          return gsp;
       }
    }
    

    设置可能如下所示:

    Services.AddTransient<GSP>()
    .AddTransient<Func<GSP>>(x => () => x.GetService<GSP>())
    .AddSingleton<GSPFactory>() // (... plus httpClient etc)
    

    如果你坚持要注入属性,工厂类变体:

    public class GSPFactory {
       HttpClient httpClient;
       public GSPFactory(HttpClient httpClient) {}
          this.httpClient= httpClient;
       }
    
       public GSP Create(string option1, string option2) {
          var gsp = new GSP(option1, option2);
          gsp.HttpClient= httpClient;
          return gsp;
       }
    }
    

    然后设置可能看起来像这样:

    Services.AddSingleton<GSPFactory>() // (... plus httpClient etc)
    

    在任何情况下,您总是会注入工厂,并像这样获取 GSP 的新实例:

    injectedGspFactory.Create("db1", "table1");
    

    【讨论】:

    • thx 我更新了我的 quastion,因为我稍微简化了它,我现在看到这也很重要 - 如果我想使用自己的 ctor,比如 new GSP("db1","table1"); ?也有可能吗?或者这是限制 - 我可以像你发布的那样 DI 这个 GSP 但不能使用自己的 ctors?
    猜你喜欢
    • 2022-06-22
    • 2021-10-01
    • 2021-05-14
    • 1970-01-01
    • 2021-04-19
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    相关资源
    最近更新 更多