C# 具有两个依赖服务的循环依赖关系
我对C#和依赖注入非常陌生。目前我正在做一个新项目,希望在技术上向前迈进一步 在这个项目中,我有三种情况导致循环依赖 我已经读了很多关于这方面的书,并找到了类似于C# 具有两个依赖服务的循环依赖关系,c#,.net,rest,dependency-injection,webassembly,C#,.net,Rest,Dependency Injection,Webassembly,我对C#和依赖注入非常陌生。目前我正在做一个新项目,希望在技术上向前迈进一步 在这个项目中,我有三种情况导致循环依赖 我已经读了很多关于这方面的书,并找到了类似于Lazy和IServiceProvider的解决方案,但我想学习一个干净的解决方案来解决这个问题,并想遵循最常见的建议来重构代码 在本例中,我们有四项服务: AccountService->登录、注销等 HttpService->做API工作 LogService->做一些日志记录 LogRepository->EF的日志表/包装器的C
Lazy
和IServiceProvider
的解决方案,但我想学习一个干净的解决方案来解决这个问题,并想遵循最常见的建议来重构代码
在本例中,我们有四项服务:
AccountService
->登录、注销等
HttpService
->做API工作
LogService
->做一些日志记录
LogRepository
->EF的日志表/包装器的CRUD
AccountService
使用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);
}
}
公共接口服务
{
标识{get;}
任务登录(凭证);
任务注销();
}
公共类AccountService:IAccountService
{
公共标识{get;private set;}
专用只读IHttpService_httpService;
专用只读ILogService(日志服务);;
公共会计服务(
IHttpService HttpService、ILogService LogService)
{
_httpService=httpService;
_logService=logService;
}
公共异步任务登录(凭据)
{
Identity=wait\u httpService.Post(
“api/rest/v1/user/authenticate”,凭证);
}
}
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);
}
}
公共接口IHttpService
{
任务获取(字符串uri);
任务Post(字符串uri、对象值);
任务Post(字符串uri、对象值);
}
公共类HttpService:IHttpService
{
私有只读HttpClientu HttpClient;
私有只读IAccountService\u accountService;
专用只读ILogService(日志服务);;
公共HTTPS服务(
HttpClient HttpClient,
IAccountService AccountService,
ILogService(ILogService)
{
_httpClient=httpClient;
_accountService=accountService;
_logService=logService;
}
专用异步任务AddAuthentication(HttpRequestMessage请求)
{
Request.Headers.Authorization=新建AuthenticationHeaderValue(
“持票人”,_accountService.Identity.SystemToken);
}
}
如何解决或正确重新设计此问题的最佳实践
我有更多的循环依赖性,例如在LogRepository
中使用LogService
,或者在HttpService
中使用LogService
(因为HttpService
将日志条目发送到服务器)
非常感谢你的帮助 尽管对象图是循环的(AccountService
->HttpService
->AccountService
),但调用图不是循环的。可能的调用如下所示:
AccountService.Login
-> HttpService.Post
-> HttpService.AddAuthentication
-> AccountService.Identity
具有非循环调用图的循环对象图通常发生在违反。类获得的功能(方法)越多,其对象图循环的可能性就越大。将类拆分为更小、更集中的部分,不仅可以解决循环依赖性问题,而且通常还可以改进应用程序的设计
我认为你的情况实际上与我在中讨论的例子非常相似。该部分专门讨论修复循环依赖项
长话短说,我认为您最好的选择是将AccountService
拆分为(至少)两种服务:
- 一个服务负责登录和注销
- 负责获取用户身份的第二个服务
IAccountService
相比,这些新接口的宽度现在更小了。这将提高您遵守规则的机会
下面是一个这样的例子:
让我们从新的接口定义开始:
//包含旧IAccountService的登录和注销方法
公共接口IAAuthenticationService
{
任务登录(凭证);
任务注销();
}
//包含旧IAccountService的标识属性
公共接口IIdentialProvider
{
//为了简单起见,我在接口中添加了一个setter,因为这样可以保持
//示例很简单,但如果
//必需的。
标识{get;set;}
}
//此接口保持不变。
公共接口IHttpService
{
任务获取(字符串uri);
任务Post(字符串uri、对象值);
任务Post(字符串uri、对象值);
}
下面让我们看一下实现,从IAuthenticationService
实现开始:
//旧的AccountService,现在取决于IIdentialProvider
公共类AuthenticationService:IAAuthenticationService
{
专用只读IHttpService_httpService;
专用只读ILogService(日志服务);;
专用只读IIdentialProvider _identityProvider;
公共会计服务(
IHTTP服务HttpService,
ILogService日志服务,
IIdentityProvider IdentityProvider)
{
_httpService=httpService;
_logService=logService;
_identityProvider=identityProvider;
}
公共异步任务登录(凭据)
{
_identityProvider.Identity=wait_httpService.Post(
“api/rest/v1/user/authenticate”,凭证);
}
}
这个“新的”AuthenticationService
包含了AccountService
的部分代码,而旧的AccountService
逻辑的其余部分隐藏在新的IIdentityProvider
抽象之后,该抽象正在