6

使用从 swagger 规范(例如与 Azure 资源管理器相关联的那些)生成的 Azure .NET SDK 时,生成的库利用 Microsoft AutoRest 客户端运行时和各种“客户端”都继承自“服务客户端”。

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

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

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

4

3 回答 3

3

我一直在尝试解决同样的问题。我正在使用许多 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,无论您是否传入它。方法

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,并在每个请求上使用自定义用户凭据。

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

于 2017-04-21T20:33:05.767 回答
1

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

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

于 2017-04-19T17:43:38.633 回答
1

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

于 2017-04-21T01:59:46.340 回答