Dav*_*ali 3 dependency-injection asp.net-core
我的目标是根据我将要工作的环境设置用户名字符串,该字符串必须是:
HttpContext.User.Identity.Name生产中。这是因为我必须能够模拟不同类型的用户,并且我通过调用使用此用户名字符串作为参数FindByIdAsync的自定义实现上的方法来实现UserIdentity此目的,如下所示:
public class HomeController : Controller
{
UserManager<AppUser> userManager;
AppUser connectedUser;
public HomeController(UserManager<AppUser> usrMgr, IContextUser ctxUser)
{
connectedUser = usrMgr.FindByNameAsync(ctxUser.ContextUserId).Result;
}
}
Run Code Online (Sandbox Code Playgroud)
appsettings.{environment}.json我开始为三个常用的开发、登台和生产环境创建三个文件;development 和 staging .json 文件都具有以下配置:
...
"Data": {
...
"ConnectedUser" : "__ADMIN"
}
...
Run Code Online (Sandbox Code Playgroud)
而生产环境配置文件中没有这个key。
我创建了一个简单的界面
public interface IContextUser
{
public string ContextUserId { get; }
}
Run Code Online (Sandbox Code Playgroud)
及其实施:
public class ContextUser : IContextUser
{
string contextUser;
IHttpContextAccessor contextAccessor;
public ContextUser(IHttpContextAccessor ctxAccessor, string ctxUser = null)
{
contextUser = ctxUser;
contextAccessor = ctxAccessor;
}
public string ContextUserId => contextUser ?? contextAccessor.HttpContext.User.Identity.Name;
}
Run Code Online (Sandbox Code Playgroud)
现在,我想到简单地配置类ConfigureServices中的方法Startup:
public void ConfigureServices(IServiceCollection services)
{
// --- add other services --- //
string ctxUser = Configuration["Data:ConnectedUser"];
services.AddSingleton(service => new ContextUser( ??? , ctxUser ));
}
Run Code Online (Sandbox Code Playgroud)
但它需要一个IHttpContextAccessor对象,在应用程序的这个阶段似乎不可用。我该如何解决这个问题?
它在幕后HttpContextAccessor使用静态属性,这意味着任何实现都将访问相同的数据。这意味着您可以简单地执行以下操作:AsyncLocal<T>HttpContextAccessor
services.AddSingleton(c => new ContextUser(new HttpContextAccessor(), ctxUser));
// Don't forget to call this; otherwise the HttpContext property will be
// null on production.
services.AddHttpContextAccessor();
Run Code Online (Sandbox Code Playgroud)
HttpContextAccessor如果您发现这太隐含了,或者将来不会破坏实现,您还可以执行以下操作:
var accessor = new HttpContextAccessor();
services.AddSingleton<IHttpContextAccessor>(accessor);
services.AddSingleton(c => new ContextUser(accessor, ctxUser));
Run Code Online (Sandbox Code Playgroud)
或者您可以将注册的实例从类中“拉出” ServiceCollection:
services.AddHttpContextAccessor();
var accessor = (IHttpContextAccessor)services.Last(
s => s.ServiceType == typeof(IHttpContextAccessor)).ImplementationInstance;
services.AddSingleton(c => new ContextUser(accessor, ctxUser));
Run Code Online (Sandbox Code Playgroud)
然而,我发现一个更令人愉快的解决方案,特别是从设计角度来看,是拆分类ContextUser;目前似乎实施了两种不同的解决方案。您可以拆分它们:
public sealed class HttpContextContextUser : IContextUser
{
private readonly IHttpContextAccessor accessor;
public HttpContextContextUser(IHttpContextAccessor accessor) =>
this.accessor = accessor ?? throw new ArgumentNullException("accessor");
public string ContextUserId => this.accessor.HttpContext.User.Identity.Name;
}
public sealed class FixedContextUser : IContextUser
{
public FixedContextUser(string userId) =>
this.ContextUserId = userId ?? throw new ArgumentNullException("userId");
public string ContextUserId { get; }
}
Run Code Online (Sandbox Code Playgroud)
现在,根据您运行的环境,您可以注册其中之一:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
if (this.Configuration.IsProduction())
{
services.AddSingleton<IContextUser, HttpContextContextUser>();
}
else
{
string ctxUser = Configuration["Data:ConnectedUser"];
services.AddSingleton<IContextUser>(new FixedContextUser(ctxUser));
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6898 次 |
| 最近记录: |