Должны ли мы использовать Singletons для клиентов, производных от Microsoft.Rest.ServiceClient в C#?
При работе с Azure .NET SDK, сгенерированными на основе технических характеристик (например, связанных с Azure Resource Manager), полученные библиотеки используют среду выполнения клиента Microsoft AutoRest, а различные "Клиенты" наследуются от "ServiceClient".
Мы работали с клиентом DocumentDB и много читали о проблемах с использованием встроенного HttpClient в.NET. Microsoft предлагает использовать одноэлементные шаблоны для обоих этих клиентов из-за их внутренней работы, несмотря на известные проблемы с использованием одноэлементного шаблона. В этих случаях это необходимо.
В результате мы разработали стратегию использования и управления синглетами для этих случаев, поэтому мы хотим знать, следует ли нам использовать ту же стратегию для клиентов Azure REST, полученных из ServiceClient. Если бы он использовал HttpClient, это имело бы смысл.
Примечание. Этот вопрос - не вопрос общих советов разработчиков по поводу синглетонов или клиентов, а скорее вопрос для групп разработчиков Microsoft, связанных с клиентской средой AutoRest, основанной на знании его внутренней работы.
3 ответа
И да и нет.:-) Вам не нужно использовать шаблон проектирования Singleton, но желательно поделиться ServiceClient
экземпляры, где это возможно, поскольку каждый из них инкапсулирует HttpClient
,
Для некоторых библиотек Azure совместное использование одного клиента не всегда возможно. Например, SearchIndexClient
в библиотеке поиска Azure можно указывать только один индекс за раз, поэтому, если ваше приложение использует несколько индексов, вам нужно как-то их объединить. Вот связанный вопрос на эту тему, который связан с другими обсуждениями в другом месте.
Я пытался решить эту же проблему. Я использую несколько клиентов службы автореста, но мне приходится каждый раз повторять их запросы для передачи пользовательских учетных данных клиента. С Microsoft.Rest.ClientRuntime 2.3.6 теперь вы можете создать экземпляр ServiceClient с вашим собственным HttpClient. Это позволяет мне использовать временный 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;
}
}
Я просто переопределил метод Dispose в "MyClient", чтобы ничего не делать, поскольку единственный объект, который удаляется, - это HttpClient.
protected override void Dispose(bool disposing) { }
Я не заметил каких-либо последствий от этого, поскольку FirstMessageHandler и HttpClientHandler создаются только тогда, когда ServiceClient создает для вас HttpClient. Этот подход позволил мне использовать один HttpClient для нескольких сгенерированных AutoRest ServiceClients с настраиваемыми учетными данными пользователя для каждого запроса.
Мне было бы интересно посмотреть, если кто-нибудь видит какие-либо последствия от этого подхода.
Теперь вы можете совместно использовать экземпляры HttpClient между экземплярами ServiceClient, так что больше нет особой причины для использования одноэлементного шаблона.