我是C#和依赖注入的新手。目前我正在做一个新的项目,想做一个技术进步。
在这个项目中,我有三种情况导致循环依赖。
我已经读了很多关于这个问题的文章,并找到了像Lazy<T>
和IServiceProvider
这样的解决方案,但我想学习一个干净的解决方案来解决这个问题,并希望遵循最常见的建议来重构代码。
在这个例子中,我们有四个服务:AccountService
-〉登录、注销等HttpService
-〉执行API操作LogService
-〉执行一些日志记录LogRepository
-〉EF的日志表/ Package 器的CRUDAccountService
通过使用HttpService
的API进行身份验证。稍后,我想使用HttpService
通过API获取更多数据。HttpService
现在需要AccountService
来获取令牌以验证请求。这会导致循环依赖性错误。
账户服务
public interface IAccountService
{
Identity Identity { get; }
Task Login(Credentials Credentials);
Task Logout();
}
public class AccountService : IAccountService
{
public Identity Identity { get; private set; }
private readonly IHttpService _httpService;
private readonly ILogService _logService;
public AccountService(
IHttpService HttpService, ILogService LogService)
{
_httpService = HttpService;
_logService = LogService;
}
public async Task Login(Credentials Credentials)
{
Identity = await _httpService.Post<Identity>(
"api/rest/v1/user/authenticate", Credentials);
}
}
HttpService
public interface IHttpService
{
Task<T> Get<T>(string uri);
Task Post(string uri, object value);
Task<T> Post<T>(string uri, object value);
}
public class HttpService : IHttpService
{
private readonly HttpClient _httpClient;
private readonly IAccountService _accountService;
private readonly ILogService _logService;
public HttpService(
HttpClient HttpClient,
IAccountService AccountService,
ILogService ILogService)
{
_httpClient = HttpClient;
_accountService = AccountService;
_logService = LogService;
}
private async Task AddAuthentication(HttpRequestMessage Request)
{
Request.Headers.Authorization = new AuthenticationHeaderValue(
"bearer", _accountService.Identity.SystemToken);
}
}
如何解决或适当重新设计这一问题的最佳实践?
我有更多的循环依赖,e。例如,在LogRepository
中使用LogService
或在HttpService
中使用LogService
(因为HttpService
向服务器发送日志条目)。
非常感谢您的帮助!
1条答案
按热度按时间jdzmm42g1#
虽然你的 * 对象图 * 是循环的(
AccountService
-〉HttpService
-〉AccountService
),但你的 * 调用图 * 不是。调用可能如下所示:循环 * 对象图 * 和非循环 * 调用图 * 经常发生在违反Single Responsibly Principle的组件上。类获得的功能越多(方法越多),它们的对象图变得循环的可能性就越大。将类拆分成更小、更集中的部分,不仅解决了循环依赖问题,而且通常还提高了应用程序的可维护性。
我认为您的情况实际上与我在section 6.3 of DIPP&P中讨论的示例非常相似。该部分专门讨论了如何修复循环依赖关系。
长话短说,我认为最好的办法是将
AccountService
拆分为(至少)两个服务:这两个服务都有自己的接口,与
IAccountService
相比,这些新接口的宽度更小。这提高了您遵守Interface Segregation Principle的机会。下面是一个例子,它看起来是这样的:
让我们从新的接口定义开始:
接下来让我们看看实现,从
IAuthenticationService
实现开始:这个“新的”
AuthenticationService
包含了AccountService
的部分代码,而旧的AccountService
逻辑的其余部分隐藏在新的IIdentityProvider
抽象之后,该抽象被注入到AuthenticationService
中。这种重构与Facade Service refactoring非常相似(有关Facade Service重构的详细讨论,请参阅DIPP&P的section 6.1)。IdentityProvider
实现新的IIdentityProvider
接口,并包含来自AccountService
的旧逻辑:最后,
HttpService
现在依赖于IIdentityProvider
而不是IAccountService
:使用这种新设计,对象图不再是循环的,并且可以如下构造: