使用swagger规范生成的Azure .NET SDK(例如与Azure Resource Manager关联的那些)时,生成的库利用Microsoft AutoRest Client Runtime,各种“Clients”都继承自“ServiceClient”。
我们一直在使用DocumentDB Client,并阅读了很多关于在.NET中使用本机HttpClient的问题。尽管使用单例模式存在众所周知的问题,但Microsoft建议对这两个客户端使用单例模式,因为它们在内部工作。在这些情况下,这是必要的。
因此,我们为这些案例制定了使用和管理单例的策略,因此我们想知道是否应该对从ServiceClient派生的Azure REST客户端使用相同的策略。如果它使用HttpClient,那将是有道理的。
注意:这个问题不是寻找关于单身人士或客户的一般开发人员建议的问题,而是基于对其内部工作的了解而与AutoRest客户端运行时相关联的Microsoft开发团队的特定问题。
答案 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实例,因此不再有大量理由使用单例模式