我们是否应该为C#中的Microsoft.Rest.ServiceClient派生的客户使用Singletons?

时间:2017-04-19 00:55:32

标签: c# .net azure autorest

使用swagger规范生成的Azure .NET SDK(例如与Azure Resource Manager关联的那些)时,生成的库利用Microsoft AutoRest Client Runtime,各种“Clients”都继承自“ServiceClient”。

我们一直在使用DocumentDB Client,并阅读了很多关于在.NET中使用本机HttpClient的问题。尽管使用单例模式存在众所周知的问题,但Microsoft建议对这两个客户端使用单例模式,因为它们在内部工作。在这些情况下,这是必要的。

因此,我们为这些案例制定了使用和管理单例的策略,因此我们想知道是否应该对从ServiceClient派生的Azure REST客户端使用相同的策略。如果它使用HttpClient,那将是有道理的。

注意:这个问题不是寻找关于单身人士或客户的一般开发人员建议的问题,而是基于对其内部工作的了解而与AutoRest客户端运行时相关联的Microsoft开发团队的特定问题。

3 个答案:

答案 0 :(得分:3)

我一直在努力解决同样的问题。我正在使用许多autorest服务客户端,但必须在每次传递用户特定客户端凭据的请求时重新实例化它们。使用Microsoft.Rest.ClientRuntime 2.3.6,您现在可以使用自己的HttpClient实例化ServiceClient。这允许我使用具有单例HttpClient的瞬态ServiceClient。我只是在生成的autorest客户端添加了一个新的构造函数。

public partial class MyClient : ServiceClient<IMyClient>, IMyClient
{

    public MyClient(Uri baseUri, ServiceClientCredentials credentials, HttpClient client) : base(client)
    {
        if (baseUri == null)
        {
            throw new ArgumentNullException("baseUri");
        }
        if (credentials == null)
        {
            throw new ArgumentNullException("credentials");
        }

        this.Initialize();
        this.Credentials = credentials;
        Credentials?.InitializeServiceClient(this);
        this.BaseUri = baseUri;

    }
    [...]
}

然而,这会在第一个请求之后导致ObjectDisposedException。这是因为ServiceClient处理HttpClients,无论您是否传入它。 method

protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        _disposed = true;

        // Dispose the client
        HttpClient.Dispose();
        HttpClient = null;
        FirstMessageHandler = null;
        HttpClientHandler = null;
    }
}

我只是覆盖'MyClient'中的Dispose方法什么也不做,因为唯一被处理的对象是HttpClient。

protected override void Dispose(bool disposing) { }

我没有发现任何后果,因为当ServiceClient为您创建HttpClient时,FirstMessageHandler和HttpClientHandler仅被实例化。这种方法允许我在多个AutoRest生成的ServiceClient上使用单个HttpClient,并在每个请求上使用自定义用户凭据。

我有兴趣看看是否有人看到这种做法有任何后果。

答案 1 :(得分:1)

是和否。 :-)您不需要使用Singleton设计模式,但建议尽可能共享ServiceClient - 派生实例,因为每个实例都封装了HttpClient

对于某些Azure库,并不总是可以共享单个客户端。例如,Azure搜索库中的SearchIndexClient一次只能定位一个索引,因此如果您的应用程序使用多个索引,则需要以某种方式对它们进行池化。 Here is a related question on this topic与其他地方的其他讨论有关联。

答案 2 :(得分:1)

您现在可以在ServiceClient实例之间共享HttpClient实例,因此不再有大量理由使用单例模式