在类库项目的基类中定义HttpClient实例的最佳方法是什么?

时间:2019-07-31 12:29:54

标签: c# .net httpclient

有一个具有3个接口的应用程序,任何想使用此应用程序的人都需要实现这些接口。我创建了一个类库项目,该项目具有这些接口实现,我已从同一基类继承了所有接口实现,以便能够拥有一个HttpClient。到目前为止,这是我所做的:

    public class BaseProxy
    {
        protected static readonly HttpClient Client;

        static BaseProxy()
        {
            Client = new HttpClient();
        }
    }

并且我在所有派生类中都使用了此Client来进行GetAsync和PostAsync请求,如下所示:

    public class XProxyImplementation
    {
        var response = Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/").Result;
        response.EnsureSuccessStatusCode();
    }

顺便说一句,Web API中的所有方法都不是异步的,因此我选择了单例解决方案,因为我不想为每个请求使用using块。我的问题是我应该使用DI解决方案,还是此代码足够用于内部使用的应用程序?欢迎提出所有改进建议。

我已经阅读了许多有关使用DI容器的答案,但这只是具有代理实现的类库。

我的另一个担心是,即使我想使用DI,目前也无法在构造函数类中引入DI,因为使用我的实现的另一个应用程序正在寻找空的构造函数。当我尝试将HttpClient参数传递给构造函数时,出现以下错误:

  

当前类型System.Net.Http.HttpMessageHandler是一个抽象   类,无法构建

使用我的dll的应用程序不允许我将任何参数传递给使用任何抽象类的构造函数。我猜这个应用程序使用Unity进行握手,并以某种方式寻找空的构造函数。尝试进行以下更改后,我得到了错误:

        public BaseProxy() : this(Service.HttpClient)
        {
        }

        public XProxyImplementation(HttpClient client) : base(client)
        {
        } 

这就是为什么我实际上更喜欢单例实例而不是DI实现。

3 个答案:

答案 0 :(得分:0)

我肯定会使用Microsoft.Extensions.DependencyInjection包来提供DI解决方案。 https://dzone.com/articles/dependency-injection-in-net-core-console-applicati

您还应该非常了解如何使用异步方法(如GetAsync)。 使用.Result几乎永远不会给出期望的结果,您最好使方法异步并使用await关键字,如下所示:

var response = await Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/");

https://montemagno.com/c-sharp-developers-stop-calling-dot-result/

是了解此最佳做法的方式和方式的好资源

答案 1 :(得分:0)

DI是答案。如果您不想使用ID,则可以实现一个HttpClientFactory。 你可以在这里阅读更多 https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

答案 2 :(得分:0)

DI?是的

DI将启用代理类的可测试性,而当前的实现不能进行单元测试。它还将改善关注点分离:remove the responsibility控制HttpClient的生存期与代理之间。

通常,您会执行以下操作:

public abstract class BaseProxy
{
    protected readonly HttpClient Client;

    protected BaseProxy(HttpClient client)
    {
        Client = client;
    }

    // ... other members
}

public class XProxyImplementation : BaseProxy
{
    public XProxyImplementation(HttpClient client) : base(client)
    {
    }

    // ... other members

    public Task SendRequest() // for example
    { 
         return Client.GetAsync("....");
    }
}

在测试期间,您将初始化HttpClient的另一个实例,并注入HttpMessageHandler的易于测试的实现:

// you implement TestHttpMessageHandler that aids your tests
var httpClient = new HttpClient(new TestHttpMessageHandler());
var proxyUnderTest = new XProxyImplementation(httpClient);

有关使用HttpClientHttpMessageHandler进行单元测试的说明,请参见this blog post

DI容器?否

现在我们在您的代码中引入了依赖注入,下一个问题是,应该使用哪种注入机制。

在您的特定情况下,我不赞成耦合到任何特定的DI容器,因为您希望您的库被许多不同的应用程序使用,并且您不想膨胀它们的依赖关系(一个应用程序可能已经在使用不同的DI容器)。

此外,由于您发布的代码非常简单,因此,成熟的DI容器可能会显得过分杀伤力。在生产代码中,您只需将单身HttpClient移至“服务定位器”:

public static class SingletonServices
{
    public static readonly HttpClient HttpClient;

    static SingletonServices()
    {
        HttpClient = new HttpClient();
    }
}

因此,当您在生产代码中实例化代理时,请执行以下操作:

var proxy = new XProxyImplementation(SingletonServices.HttpClient);