Asp.net mvc 将运行时数据传递给使用依赖项注入注入的服务
我的ASP.NET MVC应用程序使用依赖项注入将服务注入控制器 我需要找到某种方法将运行时数据传递给服务,因为据我所知,使用DI将运行时数据发送给构造函数是反模式的 在我的例子中,有四种不同的服务都依赖于访问令牌,这些令牌可以在服务之间重复使用。但是,该访问令牌可能会过期,因此需要注意在其过期时发出新的访问令牌 这些服务(独立的NuGet包)都是各种服务的客户端,每个请求都需要访问令牌。一个例子是IUserServiceBusiness中的AddUserAsync方法,它基本上使用JSON数据发布到端点,并使用承载访问令牌添加授权头 我当前的解决方案是接受访问令牌作为服务中所有方法的参数,这意味着web应用程序负责处理访问令牌并在需要时传递它们。 但是这个解决方案有味道,必须有更好的方法 下面是一个关于当前如何完成的示例 注册所有实现的RegisterContainer方法Asp.net mvc 将运行时数据传递给使用依赖项注入注入的服务,asp.net-mvc,dependency-injection,simple-injector,Asp.net Mvc,Dependency Injection,Simple Injector,我的ASP.NET MVC应用程序使用依赖项注入将服务注入控制器 我需要找到某种方法将运行时数据传递给服务,因为据我所知,使用DI将运行时数据发送给构造函数是反模式的 在我的例子中,有四种不同的服务都依赖于访问令牌,这些令牌可以在服务之间重复使用。但是,该访问令牌可能会过期,因此需要注意在其过期时发出新的访问令牌 这些服务(独立的NuGet包)都是各种服务的客户端,每个请求都需要访问令牌。一个例子是IUserServiceBusiness中的AddUserAsync方法,它基本上使用JSON数据
public static void RegisterContainers()
{
// Create a new Simple Injector container
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
SSOSettings ssoSettings = new SSOSettings(
new Uri(ConfigConstants.SSO.FrontendService),
ConfigConstants.SSO.CallbackUrl,
ConfigConstants.SSO.ClientId,
ConfigConstants.SSO.ClientSecret,
ConfigConstants.SSO.ScopesService);
UserSettings userSettings = new UserSettings(
new Uri(ConfigConstants.UserService.Url));
ICacheManager<object> cacheManager = CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());
container.Register<IUserBusiness>(() => new UserServiceBusiness(userSettings));
container.Register<IAccessTokenBusiness>(() => new AccessTokenBusiness(ssoSettings, cacheManager));
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
AccountController中更新用户年龄的端点示例:
public ActionResult UpdateUserAge(int age)
{
// Get accessToken from the Single Sign On service
string accessToken = _accessTokenBusiness.GetSSOAccessToken();
bool ageUpdated = _userBusiness.UpdateAge(age, accessToken);
return View(ageUpdated);
}
以下是我想到的一些想法:
public HomeController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness)
{
_userBusiness = userBusiness;
_accessTokenBusiness = accessTokenBusiness;
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.setAccessToken(accessToken);
}
public ActionResult UpdateUser(int newAge)
{
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.UpdateAge(newAge, accessToken);
}
IAccessTokenBusiness accessTokenBusiness = new AccessTokenBusiness();
container.Register<IUserBusiness>(() => new IUserBusiness(accessTokenBusiness));
我不喜欢这个想法,因为这样我就必须在每个控制器中复制这个代码 private readonly IUserBusiness _userBusiness;
private readonly IAccessTokenBusiness _accessTokenBusiness;
public AccountController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness)
{
_userBusiness = userBusiness;
_accessTokenBusiness = accessTokenBusiness;
}
public HomeController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness)
{
_userBusiness = userBusiness;
_accessTokenBusiness = accessTokenBusiness;
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.setAccessToken(accessToken);
}
public ActionResult UpdateUser(int newAge)
{
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.UpdateAge(newAge, accessToken);
}
IAccessTokenBusiness accessTokenBusiness = new AccessTokenBusiness();
container.Register<IUserBusiness>(() => new IUserBusiness(accessTokenBusiness));
行,但我不喜欢public HomeController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness)
{
_userBusiness = userBusiness;
_accessTokenBusiness = accessTokenBusiness;
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.setAccessToken(accessToken);
}
public ActionResult UpdateUser(int newAge)
{
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.UpdateAge(newAge, accessToken);
}
IAccessTokenBusiness accessTokenBusiness = new AccessTokenBusiness();
container.Register<IUserBusiness>(() => new IUserBusiness(accessTokenBusiness));
IAccessTokenBusiness accessTokenBusiness=new accessTokenBusiness();
容器。注册(()=>新的IU塞尔维亚业务(accessTokenBusiness));
但我不确定如何处理访问令牌的缓存。也许我可以让AccessTokenBusiness的构造函数接受一些通用的ICache实现,这样我就不会被一个缓存框架所束缚谢谢 在我看来,拥有此访问令牌以与外部服务通信的需求是实际负责调用该服务的类的实现细节。在您当前的解决方案中,您正在泄漏这些实现细节,因为
IUserBusiness
抽象公开了该令牌。这违反了以下规定:
抽象不应该依赖于细节
如果您将这个IUserBusiness
实现更改为一个不需要访问令牌的实现,这将意味着您必须对代码库进行彻底的更改,这基本上意味着您已经实现了
解决方案是让IUserBusiness
实现依赖于IAccessTokenBusiness
本身。这意味着您的代码如下所示:
// HomeController:
public HomeController(IUserBusiness userBusiness)
{
_userBusiness = userBusiness;
}
public ActionResult UpdateUser(int newAge)
{
bool ageUpdated = _userBusiness.UpdateAge(newAge);
return View(ageUpdated);
}
// UserBusiness
public UserBusiness(IAccessTokenBusiness accessTokenBusiness)
{
_accessTokenBusiness = accessTokenBusiness;
}
public bool UpdateAge(int age)
{
// Get accessToken from the Single Sign On service
string accessToken = _accessTokenBusiness.GetSSOAccessToken();
// Call external service using the access token
}
container.Register<IUserBusiness, UserServiceBusiness>();
container.Register<IAccessTokenBusiness, AccessTokenBusiness>();
ICacheManager<object> cacheManager =
CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());
container.RegisterSingleton<ICacheManager<object>>(cacheManager);
container.RegisterDecorator<IAccessTokenBusiness, CachingAccessTokenBusinessDecorator>();
但我不确定如何处理访问令牌的缓存
这既不是控制器的问题,也不是业务逻辑的问题。这要么是AccessTokenBusiness
实现关注的问题,要么是IAccessTokenBusiness
的装饰者关注的问题。拥有decorator是最明显的解决方案,因为它允许您独立于访问令牌的生成来更改缓存
请注意,通过利用容器的自动布线功能,您可以稍微简化配置。不必使用委托注册类,您可以让容器分析类型的构造函数并找出要注入的内容。登记情况如下:
// HomeController:
public HomeController(IUserBusiness userBusiness)
{
_userBusiness = userBusiness;
}
public ActionResult UpdateUser(int newAge)
{
bool ageUpdated = _userBusiness.UpdateAge(newAge);
return View(ageUpdated);
}
// UserBusiness
public UserBusiness(IAccessTokenBusiness accessTokenBusiness)
{
_accessTokenBusiness = accessTokenBusiness;
}
public bool UpdateAge(int age)
{
// Get accessToken from the Single Sign On service
string accessToken = _accessTokenBusiness.GetSSOAccessToken();
// Call external service using the access token
}
container.Register<IUserBusiness, UserServiceBusiness>();
container.Register<IAccessTokenBusiness, AccessTokenBusiness>();
ICacheManager<object> cacheManager =
CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());
container.RegisterSingleton<ICacheManager<object>>(cacheManager);
container.RegisterDecorator<IAccessTokenBusiness, CachingAccessTokenBusinessDecorator>();
在我看来,拥有这个访问令牌以便与外部服务通信的需求是实际负责调用该服务的类的一个实现细节。在您当前的解决方案中,您正在泄漏这些实现细节,因为
IUserBusiness
抽象公开了该令牌。这违反了以下规定:
抽象不应该依赖于细节
如果您将这个IUserBusiness
实现更改为一个不需要访问令牌的实现,这将意味着您必须对代码库进行彻底的更改,这基本上意味着您已经实现了
解决方案是让IUserBusiness
实现依赖于IAccessTokenBusiness
本身。这意味着您的代码如下所示:
// HomeController:
public HomeController(IUserBusiness userBusiness)
{
_userBusiness = userBusiness;
}
public ActionResult UpdateUser(int newAge)
{
bool ageUpdated = _userBusiness.UpdateAge(newAge);
return View(ageUpdated);
}
// UserBusiness
public UserBusiness(IAccessTokenBusiness accessTokenBusiness)
{
_accessTokenBusiness = accessTokenBusiness;
}
public bool UpdateAge(int age)
{
// Get accessToken from the Single Sign On service
string accessToken = _accessTokenBusiness.GetSSOAccessToken();
// Call external service using the access token
}
container.Register<IUserBusiness, UserServiceBusiness>();
container.Register<IAccessTokenBusiness, AccessTokenBusiness>();
ICacheManager<object> cacheManager =
CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());
container.RegisterSingleton<ICacheManager<object>>(cacheManager);
container.RegisterDecorator<IAccessTokenBusiness, CachingAccessTokenBusinessDecorator>();
但我不确定如何处理访问令牌的缓存
这既不是控制器的问题,也不是业务逻辑的问题。这要么是AccessTokenBusiness
实现关注的问题,要么是IAccessTokenBusiness
的装饰者关注的问题。拥有decorator是最明显的解决方案,因为它允许您独立于访问令牌的生成来更改缓存
请注意,通过利用容器的自动布线功能,您可以稍微简化配置。不必使用委托注册类,您可以让容器分析类型的构造函数并找出要注入的内容。登记情况如下:
// HomeController:
public HomeController(IUserBusiness userBusiness)
{
_userBusiness = userBusiness;
}
public ActionResult UpdateUser(int newAge)
{
bool ageUpdated = _userBusiness.UpdateAge(newAge);
return View(ageUpdated);
}
// UserBusiness
public UserBusiness(IAccessTokenBusiness accessTokenBusiness)
{
_accessTokenBusiness = accessTokenBusiness;
}
public bool UpdateAge(int age)
{
// Get accessToken from the Single Sign On service
string accessToken = _accessTokenBusiness.GetSSOAccessToken();
// Call external service using the access token
}
container.Register<IUserBusiness, UserServiceBusiness>();
container.Register<IAccessTokenBusiness, AccessTokenBusiness>();
ICacheManager<object> cacheManager =
CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());
container.RegisterSingleton<ICacheManager<object>>(cacheManager);
container.RegisterDecorator<IAccessTokenBusiness, CachingAccessTokenBusinessDecorator>();
您能展示一些实际使用这些访问令牌的逻辑吗?服务(独立的NuGet包)都是各种服务的客户端,每个请求都需要访问令牌。一个例子是IUserServiceBusiness中的AddUserAsync,它基本上使用JSON数据发布到端点,并使用承载访问令牌添加身份验证头。请显示一些代码。您想查看AddUserAsync背后的代码吗,或者