在.NET Core 2中注册基于范围的HttpClient

问题描述 投票:1回答:2

我有NET Core 2 Web API应用程序。在此过程中,我必须调用客户端A的API来获取一些数据。所以我使用HttpClient来调用它。客户端A还要求我在标头中传递用户标识和密码。

所以,而不是直接注入HttpClient我有HttpClient包装如下所示

public class ClientA : IClientA
{
    private readonly HttpClient _httpClient;

    public ClientA(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<string> GetData()
    {
        return await _httpClient.HttpGetAsync("someurl");
    }
 }

然后在服务中使用ClientA

  public class MyService :IMyService
  {
      private readonly IClientA _clientA

      public MyService(IClientA clientA)
      {
           _clientA= clientA
      }

      public void DoSomethig()
      {
          _clientA.GetData();
      }           
  }

然后我在Startup.cs中注册所有内容

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IMyService, MyService>();           

        services.AddScoped(factory =>
        {
            Func<Task<IClientA>> provider = async () =>
            {
                using (var dbContext = factory.GetService<MyDBContext>())
                {
                    // get userid and password from database here

                    var httpClient = new HttpClient();
                    httpClient.DefaultRequestHeaders.Add("UserId",userid);
                    httpClient.DefaultRequestHeaders.Add("Password",password);
                    return new ClientA(httpClient);
                }
            };

            return provider;
        });
    }

但是我收到了错误

System.InvalidOperationException:尝试激活“XXXXXXXXX.ClientA”时,无法解析类型“System.Net.Http.HttpClient”的服务。在Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(类型serviceType,类型implementationType,ISet1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet1 callSiteChain)

为简洁而删除了剩余的例外

请注意,在注册期间,我是HttpClient的新实例并将其传递给ClientA类,因为我必须设置用户ID和密码。

为了消除上述错误,我可以使用DI框架向用户ID和密码注册HttpClient,我猜这样可行。

但是,在这种情况下,如果有另一个客户端ClientB,它接受HttpClient,那么DI框架将注入具有用户ID和密码的相同httpclient。这会产生安全问题,因为ClientB会在请求标头中看到ClientA的凭据。

   public class ClientB(HttpClient client)
   {
        private readonly _httpClient;
        public class ClientB(HttpClient client)
        {
           _httpClient = client;
        }

        public string CallClientB(string url)
        {
            // here ClientB will receive ClientA's credentials
            return await _httpClient.HttpGetAsync(url);
        }
   }
asp.net-core .net-core asp.net-core-2.0 asp.net-core-webapi coreclr
2个回答
3
投票

您不希望在作用域上下文中实例化httpclient,即为每个请求创建一个httpclient实例,这不是该类的推荐使用模式。 (不会很好地扩展)。 https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

为每个客户创建一个单独的接口(假设客户数量很少) - 可能在其实现中具有代码访问安全性需求,具体取决于您的设置(启用身份模拟?)

这将a)规模很好b)每个应用程序实例/启动每个客户只运行一次,c)强制执行访问检查。

此外,这个答案是连接的,并与您的标题要求相关 - HttpClient single instance with different authentication headers


-1
投票

解决了我的问题

   services.AddScoped<IClientA>(factory =>
    {            
            var dbContext = factory.GetService<MyDBContext>();                
                // get userid and password from database here

                var httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("UserId",userid);
                httpClient.DefaultRequestHeaders.Add("Password",password);
                return new ClientA(httpClient);
    });
© www.soinside.com 2019 - 2024. All rights reserved.