По моему мнению, написать один типизированный клиент для всего доступа к определенному удаленному сервису - правильный путь.Это именно тот шаблон использования, который Microsoft предусматривает для типизированного http-клиента.
В то же время я понимаю вашу озабоченность, но ситуация менее отчаянная, чем вы думаете.
Прежде всего вы получите огромный интерфейс и, следовательно, огромныйреализующий класс, но ответственность за него очевидна: на типизированном клиенте лежит ответственность за определение прокси-сервера для доступа к удаленному веб-сервису (студенческий сервис в вашем примере).
Типизированный клиентский класс не совсемсложный: он может быть огромным, конечно, но он не имеет состояния и просто предоставляет методы для доступа к конечным точкам удаленного веб-сервиса.Каждый метод имеет четкую и четко определенную ответственность: доступ к определенной конечной точке удаленного веб-сервиса;Подобный код редко бывает сложным.
Единственная проблема - использование интерфейса IStudentClient
от контроллера или службы.Интерфейс огромен, поэтому, если вы внедрите его как зависимость в потребительский класс, вы нарушите принцип разделения .Возможное решение этой проблемы - моделирование интерфейсов меньшего размера, разработанных для конкретных потребностей потребительских классов.
Представьте, что одна из конечных точек, предоставляемых вашим удаленным веб-сервисом, позволяет вам получить сведения об одном ученике (это может быть что-то вроде GET / student / {studentId}).Это означает, что одним из методов, предоставляемых IStudentClient
, будет GetStudentById(Guid studentId)
, который оборачивает запрос GET в /students/{studentId}
.
. В этот момент вы можете определить меньший интерфейс с именем IStudentProvider
, имеющий такую форму:
public interface IStudentProvider
{
StudentContract GetstudentById(Guid studentId);
}
Теперь вы можете внедрить меньший интерфейс IStudentProvider
в свои потребительские классы (например, контроллер MVC или класс обслуживания, который вы определяете в своем приложении).
Для реализации интерфейса IStudentProvider
вы можете сделать следующее:
public class HttpStudentProvider : IStudentProvider
{
private readonly IStudentClient client;
public HttpStudentProvider(IStudentClient client)
{
this.client = client;
}
public StudentContract GetstudentById(Guid studentId)
{
return this.client.GetStudentById(studentId);
}
}
ВАЖНЫЙ ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ : для простоты обсуждения я не использовалTask
класс на интерфейсах, но, конечно, все методы должны возвращать Task<T>
и принимать экземпляр CancellationToken
в качестве параметра, потому что вызовы http являются естественными асинхронными операциями, а вы не хотитевыполнить блокировку звонков с вашим http-клиентом.
Как зарегистрировать эти классы в контейнере DI
Контейнер Microsoft DI предложит вам несколько методов расширения для регистрации типизированного клиента.Служба будет зарегистрирована как временная зависимость, поэтому каждая другая служба, зависящая от нее, должна быть также зарегистрирована как временная зависимость (во избежание проблемы неявной зависимости ).
Так вы должны зарегистрировать свои услуги:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<IStudentClient, StudentClient>();
services.AddTransient<IStudentProvider, HttpStudentProvider>();
}