我们应该为从 C# 中的 Microsoft.Rest.ServiceClient 派生的客户端使用单例吗?

Should we use Singletons for clients derived from Microsoft.Rest.ServiceClient in C#?

使用从 swagger 规范生成的 Azure .NET SDK(例如与 Azure 资源管理器关联的规范)时,生成的库利用 Microsoft AutoRest 客户端运行时和各种 "Clients" 全部继承自 "ServiceClient".

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

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

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

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

对于某些 Azure 库,共享单个客户端并不总是可行的。例如,Azure 搜索库中的 SearchIndexClient 一次只能定位一个索引,因此如果您的应用程序使用多个索引,则需要以某种方式将它们集中在一起。 链接到其他地方的其他讨论。

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

我一直在努力解决同样的问题。我正在使用许多 autorest 服务客户端,但必须在每次请求时重新实例化它们以传递特定于用户的客户端凭据。使用 Microsoft.Rest.ClientRuntime 2.3.6,您现在可以使用自己的 HttpClient 实例化 ServiceClient。这允许我将瞬态 ServiceClient 与单例 HttpClient 一起使用。我只是在生成的 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) { }

我没有注意到这有任何影响,因为 FirstMessageHandler 和 HttpClientHandler 仅在 ServiceClient 为您创建 HttpClient 时实例化。这种方法允许我在多个 AutoRest 生成的 ServiceClients 中使用单个 HttpClient,每个请求都有自定义用户凭据。

我很想知道是否有人看到这种方法的任何后果。