将运行时数据传递给通过依赖注入注入的服务

琼·特劳斯提·阿拉森(JónTrausti Arason)

我的ASP.NET MVC应用程序使用依赖注入将服务注入到控制器。

我需要找到一种将运行时数据传递给服务的方法,因为据我所知,使用DI将运行时数据发送给构造函数是一种反模式。

就我而言,我有四个不同的服务,它们都依赖于访问令牌,可以在这些服务之间重用它们。但是,该访问令牌可能会过期,因此在过期时需要采取一些措施来发行新的访问令牌。

服务(独立的NuGet包)是各种服务的所有客户端,每个请求都需要访问令牌。一个示例是IUserServiceBusiness中的AddUserAsync方法,它基本上使用JSON数据发布到端点,并使用承载访问令牌添加Authorization标头。

我当前的解决方案是接受访问令牌作为服务中所有方法的参数,这意味着Web应用程序会处理访问令牌并在需要时传递它们。但是这种解决方案有味道,必须有一种更好的方法来做到这一点。

这是有关当前操作方式的示例。

注册所有实现的RegisterContainer方法。

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));
}

IUserBusiness和IAccessTokenBusiness的实现被注入到AccountController中。

    private readonly IUserBusiness _userBusiness;
    private readonly IAccessTokenBusiness _accessTokenBusiness;

    public AccountController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness)
    {
        _userBusiness = userBusiness;
        _accessTokenBusiness = accessTokenBusiness;
    }

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);
    }

这是我想到的一些想法:

  1. 在控制器的构造函数中,使用设置器将访问令牌传递给服务。例如:

    public HomeController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness) 
    {
        _userBusiness = userBusiness;
        _accessTokenBusiness = accessTokenBusiness;
        string accessToken = _accessTokenBusiness.GetAccessToken();
        _userBusiness.setAccessToken(accessToken);
    }
    

    我不喜欢这个主意,因为那样的话我将不得不在每个控制器中复制此代码。

  2. 将访问令牌与服务上的每种方法一起传递(当前正在执行此操作)例如:

    public ActionResult UpdateUser(int newAge)
    {
        string accessToken = _accessTokenBusiness.GetAccessToken();
        _userBusiness.UpdateAge(newAge, accessToken);
    }
    

    可行,但我不喜欢它。

  3. 将IAccessTokenBusiness的实现传递给服务的构造函数。例如:

    IAccessTokenBusiness accessTokenBusiness = new AccessTokenBusiness();
    
    container.Register<IUserBusiness>(() => new IUserBusiness(accessTokenBusiness));
    

    但是我不确定如何处理访问令牌的缓存。也许我可以让AccessTokenBusiness的构造函数接受一些通用的ICache实现,这样我就不必再局限于一个缓存框架了。

我很想听听如何以一种干净,聪明的方式解决这个问题。

谢谢!

史蒂文

正如我所看到的,拥有与外部服务通信的访问令牌的要求是该类的实现细节,该类实际上负责调用该服务。在当前解决方案中,您正在泄漏这些实现细节,因为IUserBusiness抽象公开了该令牌。这违反了依赖反转原则原则规定:

抽象不应依赖细节。

万一您将此IUserBusiness实现更改为不需要访问令牌的实现,则意味着您将不得不在代码库中进行全面更改,这基本上意味着您破坏了Open / close Principle

解决方案是让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
}

但是我不确定如何处理访问令牌的缓存。

这既不是控制器的问题,也不是业务逻辑的问题。这是AccessTokenBusiness实现的关注点,还是周围的装饰器IAccessTokenBusiness具有装饰器是最明显的解决方案,因为它使您可以独立于访问令牌的生成来更改缓存。

请注意,您可以通过使用容器的自动装配功能来稍微简化配置。您可以让容器分析类型的构造函数并自行确定要注入的内容,而不是使用委托注册类。此类注册如下所示:

container.Register<IUserBusiness, UserServiceBusiness>();
container.Register<IAccessTokenBusiness, AccessTokenBusiness>();

ICacheManager<object> cacheManager = 
    CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());

container.RegisterSingleton<ICacheManager<object>>(cacheManager);

此外,IAccessTokenBusiness可以添加的装饰器,如下所示:

container.RegisterDecorator<IAccessTokenBusiness, CachingAccessTokenBusinessDecorator>();

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

MVC5将运行时数据注入到布局视图中

来自分类Dev

如何在运行时使用简单的注入器将值传递给实例集合的构造函数?

来自分类Dev

ASP.NET Core依赖项注入:服务在运行时使用Func委托解析

来自分类Dev

在CDI中将运行时(Meta)数据传递给生产者方法

来自分类Dev

在CDI中将运行时(Meta)数据传递给生产者方法

来自分类Dev

将运行时依赖项注入到nix包中

来自分类Dev

将运行时依赖项注入到nix包中

来自分类Dev

构造函数的Symfony依赖注入运行时参数

来自分类Dev

使用Google Guice在运行时注入依赖项

来自分类Dev

使用依赖项注入在运行时确定实现

来自分类Dev

使用Google Guice在运行时注入依赖项

来自分类Dev

将数据传递给服务-Android?

来自分类Dev

将依赖注入容器传递给静态方法

来自分类Dev

组件无法识别我通过依赖注入(Angular)传递的服务

来自分类Dev

我们可以将$ http注入Angular Service并将该数据传递给控制器吗?

来自分类Dev

通过cygwin从Shell脚本运行时,如何将参数传递给Powershell脚本?

来自分类Dev

如何通过shell脚本将运行时参数传递给c中的函数

来自分类Dev

通过依赖注入将数据上下文对象传递给控制器是一个好主意吗?

来自分类Dev

ServiceStack:是否可以通过RequestFilterAttribute将数据传递给调用服务

来自分类Dev

当依赖项需要运行时值时,如何注入依赖项?

来自分类Dev

在运行时注入值

来自分类Dev

在运行时更改注入的对象

来自分类Dev

在运行时将变量传递给方法

来自分类Dev

将Burrsuite的JAR传递给Java运行时

来自分类Dev

从 npm 运行时将选项传递给 mocha

来自分类Dev

MVC-如何将数据传递给服务

来自分类Dev

Angular服务将数据传递给组件

来自分类Dev

MVC-如何将数据传递给服务

来自分类Dev

将动态数据传递给可调用服务的构造

Related 相关文章

  1. 1

    MVC5将运行时数据注入到布局视图中

  2. 2

    如何在运行时使用简单的注入器将值传递给实例集合的构造函数?

  3. 3

    ASP.NET Core依赖项注入:服务在运行时使用Func委托解析

  4. 4

    在CDI中将运行时(Meta)数据传递给生产者方法

  5. 5

    在CDI中将运行时(Meta)数据传递给生产者方法

  6. 6

    将运行时依赖项注入到nix包中

  7. 7

    将运行时依赖项注入到nix包中

  8. 8

    构造函数的Symfony依赖注入运行时参数

  9. 9

    使用Google Guice在运行时注入依赖项

  10. 10

    使用依赖项注入在运行时确定实现

  11. 11

    使用Google Guice在运行时注入依赖项

  12. 12

    将数据传递给服务-Android?

  13. 13

    将依赖注入容器传递给静态方法

  14. 14

    组件无法识别我通过依赖注入(Angular)传递的服务

  15. 15

    我们可以将$ http注入Angular Service并将该数据传递给控制器吗?

  16. 16

    通过cygwin从Shell脚本运行时,如何将参数传递给Powershell脚本?

  17. 17

    如何通过shell脚本将运行时参数传递给c中的函数

  18. 18

    通过依赖注入将数据上下文对象传递给控制器是一个好主意吗?

  19. 19

    ServiceStack:是否可以通过RequestFilterAttribute将数据传递给调用服务

  20. 20

    当依赖项需要运行时值时,如何注入依赖项?

  21. 21

    在运行时注入值

  22. 22

    在运行时更改注入的对象

  23. 23

    在运行时将变量传递给方法

  24. 24

    将Burrsuite的JAR传递给Java运行时

  25. 25

    从 npm 运行时将选项传递给 mocha

  26. 26

    MVC-如何将数据传递给服务

  27. 27

    Angular服务将数据传递给组件

  28. 28

    MVC-如何将数据传递给服务

  29. 29

    将动态数据传递给可调用服务的构造

热门标签

归档