Bru*_*man 18 c# asp.net-mvc dependency-injection asp.net-core-mvc asp.net-core
我正在MVC 6中构建一次性应用程序,并尝试使用不同的依赖架构.
我面临的问题是如何创建MyAppContext特定于应用程序的自定义对象.这将需要HttpContext来自数据库的一些信息和来自数据库的一些信息,并且将是针对特定于应用程序的属性的请求范围的存储库.我想将实例传递HttpContext给' MyAppContext' 的构造函数.
我已成功使用DI 创建了一个DataService带有IDataService接口的对象,这可以正常工作.与'MyAppContext'类的不同之处在于它在构造函数中有两个参数 - DataService'和' Microsoft.AspNet.Http.HttpContext.这是MyAppContext类:
public class MyAppContext : IMyAppContext
{
public MyAppContext(IDataService dataService, HttpContext httpContext)
{
//do stuff here with the httpContext
}
}
Run Code Online (Sandbox Code Playgroud)
在启动代码中,我注册了DataService实例和MyAppContext实例:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
//adds a singleton instance of the DataService using DI
services.AddSingleton<IDataService, DataService>();
services.AddScoped<IMyAppContext, MyAppContext>();
}
public void Configure(IApplicationBuilder app)
{
app.UseErrorPage();
app.UseRequestServices();
app.UseMvc(routes => /* routes stuff */);
}
Run Code Online (Sandbox Code Playgroud)
我希望HttpContext构造函数中的参数能够被DI解析.运行代码时,这是我返回的异常:
InvalidOperationException:尝试激活"MyAppContext"时无法解析类型"Microsoft.AspNet.Http.HttpContext"的服务
我认为这是因为没有特定的实例HttpContext发生此错误,但我不知道如何HttpContext在DI中注册实例.我添加了一行' app.UseRequestServices();',但这没有任何区别.我也试过了一个变种:
services.AddScoped<HttpContext, HttpContext>();
Run Code Online (Sandbox Code Playgroud)
但这失败了,因为第二个HttpContext应该是一个实例 - 我知道它不正确但是无法弄清楚是什么.
总而言之 - 如何将HttpContext对象传递给MyAppContext的构造函数?
Ste*_*ven 16
通过向HttpContext组件中注入一个违反SOLID原则的方法.更具体地说,你违反了:
这两种违规都会使测试代码变得更加困难.虽然您可以反而注入IHttpContextAccessor@victor建议,但这仍然违反了DIP和ISP,因为这是框架提供的抽象,您仍然依赖于HttpContext.根据DIP,客户应该定义抽象.这会导致您的代码不必要地耦合到框架.
相反,你应该努力指定狭窄的角色接口; 为您执行特定于您的应用程序需求的特定事物的接口.注入一个包含字符串值的大字典(就像什么HttpContext,从来都不是非常具体).从你的问题来看,我们不清楚你需要什么样的数据MyAppContext,但我希望有类似当前登录用户的信息.为此,您可以定义特定的IUserContext抽象,例如:
public interface IUserContext {
IPrincipal CurrentUser { get; }
}
Run Code Online (Sandbox Code Playgroud)
可以轻松地为此抽象创建将应用程序连接到ASP.NET框架的适配器:
sealed class AspNetUserContextAdapter : IUserContext {
private readonly IHttpContextAccessor accessor;
public AspNetUserContextAdapter(IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public IPrincipal CurrentUser => accessor.HttpContext.User;
}
Run Code Online (Sandbox Code Playgroud)
这个适配器确实依赖IHttpContextAccessor,但这没关系,因为适配器是位于Composition Root中的基础结构组件.注册这个类有几种方法,例如:
services.AddSingleton<IUserContext, AspNetUserContext>();
Run Code Online (Sandbox Code Playgroud)