从 IHttpContextAccessor 创建共享 class 以跨 class 库传递它

Create shared class from IHttpContextAccessor to pass it across class libraries

我正在使用 .NET Core 3.1,对于每个请求,我都需要访问一些已记录的用户声明并将其传递给 API 之外的业务服务(另一个 class 库)项目。

我已经尝试创建 UserService:

public class UsersService
    {
       private readonly IHttpContextAccessor _context;

       public UsersService(IHttpContextAccessor context)
       {
         _context = context;
       }

    public UserSession GetUser()
    {
        return new UserSession()
        {
            UserDisplayName = _context.HttpContext.User?.Identity?.Name,

        };
    }
}

并在 Startup.cs

        public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();

其他业务服务或存储库应该 used/injected 像这样:

    public class ExampleBusinessService
{
    private readonly IUnitOfWork _unitOfWork;
    private IUsersService _userService;
    public ExampleBusinessService(IUnitOfWork unitOfWork, IUsersService userService)
    {
        this._unitOfWork = unitOfWork;
        this._userService = userService;
    }


    

但是我似乎无法在 Web 项目之外访问 IHttpContextAccessor。

这能实现吗?

当然我不能在 API 中创建 UserService 然后在其他库中使用它,因为库应该引用 Web 项目。

如果不能,是否可以在控制器中启动 class 从当前用户那里获取所需的信息并将其传递给服务?或者以某种方式在控制器中这样做? 据说我需要自定义 class 以及从业务服务(单独的 class 库)和存储库(单独的 class 库)

中的登录用户获取的信息

这就是我需要访问 BusinessServices 库中记录的用户信息(自定义 UserSession class)的解决方案:

谢谢

IHttpContextAccessor 类型是 ASP.NET 核心框架的一部分,因此仅在您的 Web 项目中可用。如果您的 UsersService 实现在不同的项目中,那么您将无法正确引用上下文访问器。

解决这个问题的一个好方法是将契约与实现分开:在您的库项目中定义一个 IUsersService,并且只为您的业务逻辑引用它。服务的用户不需要知道实现可能依赖于什么;他们只关心他们可以使用此服务的 public 接口。

然后在您的 Web 项目中,创建一个 IUsersService 的实现,它使用 IHttpContextAccessor 来访问用户信息。由于实现存在于 Web 项目中,因此它可以正确访问上下文访问器。

最后,通过将您的服务实现注册为您的 Web 应用程序的一部分来组合接口和实现:

services.AddTransient<IUsersService, UsersService>();

一旦您的服务(在 Web 项目之外)现在需要 IUsersService,他们将获得使用上下文访问器访问用户信息的实现,并且一切都应该工作,而无需添加引用到您(否则不相关)库中的 ASP.NET 核心框架。

如果将完整的 dotnetcore 添加到共享解决方案(外部 class 库项目)。只需添加对 Microsoft.AspNetCore.HTTP 的引用即可访问 IHttpContextAccessor

好的,我理解你的担忧,但你似乎以错误的方式解决了问题。 指出来,我相信这就是你想要的:

  • 您有 ExampleBusinessService,它位于共享的 class 库中
  • 你有UsersService,处理用户会话等服务
  • 您想通过 IHttpContextAccessor
  • 访问会话信息

首先,ExampleBusinessServiceUsersService 都不需要在 API 项目中或与它绑定。您可以随意将它们放入您的 class 图书馆。

您可以通过以下方式解决此问题:

  • 首先,在您的 class 库中添加 Microsoft.AspNetCore.Http 包。
  • 创建静态 class UsersService(在 class 库中)
  • 添加以下代码(到UsersService
public static class UsersService
{
    // extend IHttpContextAccessor 
    public static UserSession GetUserSession( this IHttpContextAccessor accessor)
    {
         return new UserSession
         {
             UserDisplayName = _context.HttpContext.User?.Identity?.Name,
         }
    }
}
  • 现在,在你的 ExampleBusinessService 中注入 IHttpContextAccessor
public class ExampleBusinessService
{
    private readonly IHttpContextAccessor _contextAccessor;

    public ExampleBusinessService(IHttpContextAccessor accessor)
    {
        _contextAccessor = accessor,
    }

    // now do whatever you want with the session info
    public SomeBusinessAboutSessionInfo()
    {
        // retrieve the session
        var userSession = _contextAccessor.GetUserSession();
        //...your logic
    }
}

最后一块(这很重要

  • IHttpContextAccessor 添加到 API 项目中的 IServiceCollection

services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();

现在应该一切正常了!!!