[英]How to get current User in base class of service layer in ASP.Net Core?
There are answers how to get User principal in service layer using IHttpContextAccessor
but they are always related to getting the user in service itself, not in its base (abstract class).有如何使用IHttpContextAccessor
在服务层中获取用户主体的答案,但它们始终与让用户进入服务本身有关,而不是在其基础(抽象类)中。
I have following situation:我有以下情况:
There is an UserService
which is injected in controller which needs it like this:在 controller 中注入了一个UserService
,它需要这样:
private IUserService UserService;
public UserController(IUserService userService)
{
UserService = userService;
}
Pretty standard, this is service layer for getting/posting/patching... user.非常标准,这是用于获取/发布/修补...用户的服务层。 Problem is, this UserService
inherits something called ServiceBase
:问题是,这个UserService
继承了一个叫做ServiceBase
的东西:
public class UserService : ServiceBase, IUserService
{
private IDatabaseService DatabaseService;
public UserService(IDatabaseService databaseService, ServiceManager serviceManager) : base(serviceManager)
{
DatabaseService = databaseService;
}
.. rest of code omitted ...
and ServiceBase
looks like this:和ServiceBase
看起来像这样:
public abstract class ServiceBase
{
internal static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
private ServiceManager ServiceManager;
public ServiceBase(ServiceManager serviceManager)
{
ServiceManager = serviceManager;
}
... rest of code omitted...
Now, if I wanted to use IHttpContextAccessor
I would have to inject it in each of services so it can be passed to ServiceBase
, much like ServiceManager
(another singleton service, not related to this question) is passed to it.现在,如果我想使用IHttpContextAccessor
我必须将它注入到每个服务中,以便它可以传递给ServiceBase
,就像传递给它的ServiceManager
(另一个 singleton 服务,与这个问题无关)一样。 Reason why ServiceBase
is needed is for logging and more importantly, providing a way for each of services to post changes made by them (post, patch, delete) to rest of microservices.需要ServiceBase
的原因是用于日志记录,更重要的是,为每个服务提供一种将它们所做的更改(发布、修补、删除)发布到微服务的 rest 的方法。
Startup looks like this:启动看起来像这样:
services.AddSingleton<ServiceManager>();
services.AddHostedService(provider => provider.GetService<ServiceManager>());
services.AddHttpContextAccessor();
services.AddScoped<IDatabaseService, DatabaseService>();
services.AddScoped<ILoginService, LoginService>();
services.AddScoped<IUserService, UserService>();
Is there a way to get IHttpContextAccessor
in this ServiceBase
without passing it around?有没有办法在这个ServiceBase
中获取IHttpContextAccessor
而无需传递它? Same question could be asked for ServiceManager
since that dependancy also has to be passed from implementation to base class?可以对ServiceManager
提出同样的问题,因为依赖关系也必须从实现传递到基础 class? What I want is to know which user did call the controller action (and consequently the service layer) without writing bunch of boilerplate code in each of controllers and/or services.我想知道哪个用户确实调用了 controller 操作(以及服务层),而无需在每个控制器和/或服务中编写一堆样板代码。
Another way of asking would be is it possible to resolve singleton services like IHttpContextAccessor
and ServiceManager
inside service layer without injecting them in each service?另一种询问方式是是否可以在服务层内部解决 singleton 服务(如IHttpContextAccessor
和ServiceManager
)而不在每个服务中注入它们?
Short answer: You can't.简短的回答:你不能。
Bad answer: You shouldn't.错误的答案:你不应该。 But you can with a ServiceLocator . 但是您可以使用 ServiceLocator 。
Alternate answer: we can make the paramter transfer less pain.替代答案:我们可以使参数传输不那么痛苦。
Instead of passing ServiceManager
to the base class, pass a ServiceBaseServiceContext
to it:不要将ServiceManager
传递给基础 class,而是将ServiceBaseServiceContext
传递给它:
public class ServiceBaseServiceContext
{
public ServiceManager ServiceManager {get;}
public IUserService UserService {get;}
public ServiceBaseServiceContext(ServiceManager serviceManager, IUserService userService)
{
ServiceManager = serviceManager;
UserService = userService;
}
}
This way, you have only one Parameter, regardless how many services you need.这样,无论您需要多少服务,您都只有一个参数。
public abstract class ServiceBase
{
private ServiceManager _serviceManager;
private IUserService_userService;
public ServiceBase(ServiceBaseServiceContext serviceContext)
{
_serviceManager = serviceContext.ServiceManager;
_userService = serviceContext.UserService;
}
}
ServiceBaseServiceContext
needs also to be registered in your ServiceCollection to make it work: ServiceBaseServiceContext
还需要在您的 ServiceCollection 中注册以使其工作:
// depending on the services maybe Scoped
services.AddTransient<ServiceBaseServiceContext>();
Instead of making a ServiceBaseServiceContext
you could also pass a IServiceProvider
to ServiceBase
, but this would be the same as a ServiceLocator, which is bad, because it hides the dependencies.除了创建ServiceBaseServiceContext
之外,您还可以将IServiceProvider
传递给ServiceBase
,但这与 ServiceLocator 相同,这很糟糕,因为它隐藏了依赖项。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.