如何使用ASP.NET Core MVC内置依赖注入框架手动解析类型?
设置容器很容易:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
Run Code Online (Sandbox Code Playgroud)
但是如何在ISomeService不进行注射的情况下解决?例如,我想这样做:
ISomeService service = services.Resolve<ISomeService>();
Run Code Online (Sandbox Code Playgroud)
没有这样的方法IServiceCollection.
我正在使用ASP.NET Core,并尝试本地化应用程序.我设法使用新的 asp .net核心资源来本地化控制器和视图,并使用旧资源来本地化错误消息以进行模型验证.但是,当错误消息未链接到模型字段注释(如"必需")并且模型绑定的数据不正确时(如预期数字的文本),我收到如下错误,我是无法本地化:
"值'abc'对ID无效."
当我进入abc了ID房地产View,因为模型绑定无法做到的领域,它显示为近场验证消息,称"值'ABC’是无效的ID." .这是我正在使用的课程:
public class Country : IHasID
{
public int ID { get; set; }
[Required(ErrorMessageResourceType = typeof(L.Val),
ErrorMessageResourceName = "NameR")]
[MaxLength(100, ErrorMessageResourceType = typeof(L.Val),
ErrorMessageResourceName = "Max")]
public string Name { get; set; }
/*Some other properties*/
}
Run Code Online (Sandbox Code Playgroud)
我在互联网上发现的类似问题要么针对较旧的asp .net版本,否则无法解决问题.
我刚刚从另一个项目的最后粘贴了 4 行,它可以工作,但我收到警告..我显然不太了解 DI ......它想让我改变什么?
public void ConfigureServices(IServiceCollection services)
{
if (HostingEnvironment.EnvironmentName == "Local")
{
services.AddHealthChecksUI()
.AddHealthChecks()
.AddCheck<TestWebApiControllerHealthCheck>("HomePageHealthCheck")
.AddCheck<DatabaseHealthCheck>("DatabaseHealthCheck");
}
services.Configure<PwdrsSettings>(Configuration.GetSection("MySettings"));
services.AddDbContext<PwdrsContext>(o => o.UseSqlServer(Configuration.GetConnectionString("PwdrsConnectionRoot")));
services.AddMvc(o =>
{
o.Filters.Add<CustomExceptionFilter>();
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", b => b
.SetIsOriginAllowed((host) => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddSwaggerDocument();
services.AddHttpContextAccessor();
services.AddAutoMapper(typeof(ObjectMapperProfile));
services.AddTransient<IEmailSender, EmailSender>();
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
services.AddScoped(typeof(IAsyncRepository<>), typeof(Repository<>));
services.AddScoped<IRfReportTypeRepository, RfReportTypeRepository>();
services.AddScoped<IRfReportRepository, RfReportRepository>();
services.AddScoped<IRfReportLookupsService, RfReportLookupsService>();
services.AddScoped<IRfReportService, RfReportService>();
services.Configure<RAFLogging>(Configuration.GetSection("RAFLogging"));
ServiceProvider serviceProvider = services.BuildServiceProvider(); //WARNING IS HERE
IOptions<RAFLogging> RAFLogger = serviceProvider.GetRequiredService<IOptions<RAFLogging>>();
RegisterSerilogLogger logger = new RegisterSerilogLogger(RAFLogger);
}
Run Code Online (Sandbox Code Playgroud) 我正在使用IServiceCollection来为我的对象创建所需服务的列表。现在,我想实例化一个对象,并让DI容器解析该对象的依赖关系
例
// In my services config.
services
.AddTransient<IMyService, MyServiceImpl>();
// the object I want to create.
class SomeObject
{
public SomeObject(IMyService service)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
如何获得DI容器以创建类型SomeObject为注入依赖项的对象?(大概这就是对控制器的作用?)
注意:我不想存储SomeObject在服务集合中,我只想能够执行以下操作...
SomeObject obj = startup.ServiceProvider.Resolve<SomeObject>();
Run Code Online (Sandbox Code Playgroud)
...基本原理:我不必将所有控制器都添加到服务容器中,所以我也看不到为什么也必须添加SomeObject它!
我有一个 .Net Core 项目,它注册了许多单例,如下所示:
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddLogging();
services.AddSingleton<IConfiguration>(Configuration);
services.AddSingleton<IDbFactory, DefaultDbFactory>();
services.AddSingleton<IUserRepository, UserRepository>();
services.AddSingleton<IEmailService, EmailService>();
services.AddSingleton<IHostedService, BackgroundService>();
services.AddSingleton<ISettingsRepository, SettingsRepository>();
services.AddSingleton(typeof(TokenManager));
var sp = services.BuildServiceProvider();
var userRepository = sp.GetService<IUserRepository>();
// ...
}
Run Code Online (Sandbox Code Playgroud)
这是注册这些类的唯一地方,在任何地方都没有创建其他实例,但是我注意到构造函数被调用了两次。这是为什么?
c# singleton dependency-injection service-locator asp.net-core-2.0
我不确定我是否正确地处理这个问题。
背景:我有一个控制器操作 GET foo() 作为示例。这个 foo() 需要去调用 bar(),而 bar() 可能需要很长时间。因此,我需要 foo() 在 bar() 完成之前(或无论何时)以“OK”响应。
稍微复杂的是 bar() 需要访问 DBContext 并从 DB 中获取一些数据。在我当前的实现中,当我尝试通过 bar 访问数据库时,我得到了一个“DBContext System.ObjectDisposed”异常。任何想法为什么以及如何解决这个问题?我对线程和任务真的很陌生,所以我可能完全犯了这个错误!
我使用依赖注入在启动时提供数据库上下文
services.AddEntityFrameworkNpgsql()
.AddDbContext<MyDBContext>()
.BuildServiceProvider();
Run Code Online (Sandbox Code Playgroud)
然后我调用 foo() ,它又使用一个新线程调用 bar() (也许我做错了?):
public async Task<string> foo(string msg)
{
Thread x = new Thread(async () =>
{
await bar(msg);
});
x.IsBackground = true;
x.Start();
return "OK.";
}
Run Code Online (Sandbox Code Playgroud)
所以 bar 立即尝试访问 DBContext 以获取一些实体并抛出异常!
未处理的异常:System.ObjectDisposedException:无法访问已处理的对象。此错误的一个常见原因是处理从依赖注入解析的上下文,然后尝试在应用程序的其他地方使用相同的上下文实例。如果您在上下文上调用 Dispose() 或将上下文包装在 using 语句中,则可能会发生这种情况。如果你使用依赖注入,你应该让依赖注入容器来处理上下文实例。对象名称:'MyDBContext'。
如果我从线程中取出 bar() ,那很好,但当然“OK”不会返回,直到 bar 完成其非常长的过程,这是我需要解决的问题。
非常感谢您的指导。
使用正在运行的代码进行编辑,但它仍在等待 Task.Run 在返回“OK”之前完成。(差不多好了?)
public async …Run Code Online (Sandbox Code Playgroud) c# multithreading entity-framework dependency-injection entity-framework-core
我有一个 ASP.NET Core 3 应用程序,并且使用 AzureAD 进行身份验证。我的 Startup.ConfigureSerivces 方法中有以下几行,其目的是在附加 cookie 时执行一些业务规则。
services.Configure<CookiePolicyOptions>(options => {
options.CheckConsentNeeded = ctx => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
options.OnAppendCookie = ctx => {
var svc = ctx.Context.RequestServices.GetRequiredService<IUserInformationService>();
// do something with svc
};
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => {
Configuration.Bind("AzureAd", options);
});
Run Code Online (Sandbox Code Playgroud)
这效果很好,我IUserInformationService按照方法中的预期获得了注入的对象OnAppendCookie,并且 AzureAD 信息取自 appsettings.json。
然而最近,有关 AzureAD 租户的信息不得驻留在 appsettings.json 中,而是我现在必须查阅数据库。我有一项服务已经查询数据库并获取 AD 设置。就像是:
public interface IAzureADConfiguration {
void Configure(AzureADOptions options);
}
Run Code Online (Sandbox Code Playgroud)
但是,我找不到在调用时检索注入的服务的方法AddAzureAD。我想要的是这样的:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => {
var svc = ???
svc.Configure(options); …Run Code Online (Sandbox Code Playgroud) 我正在尝试为IWebHostBuilder执行一些代码的新扩展方法,例如在某处注册。重要的是,它在应用程序关闭时也会注销。
我添加了一些代码来显示我想做什么。这里的问题是,的实例IApplicationLifetime尚不可用。这种新的扩展方法是在构建WebHost的管道中最后添加的。
public static IWebHostBuilder UseHttpGatewayappRegistration(this IWebHostBuilder webHostBuilder)
{
webHostBuilder.ConfigureServices(services =>
{
var sp = services.BuildServiceProvider();
// This instance is not available
IApplicationLifetime applicationLifetime = sp.GetService<IApplicationLifetime>();
// These instances are ok
AppSettings appSettings = sp.GetService<AppSettings>();
ILoggerFactory loggerFactory = sp.GetService<ILoggerFactory>();
var registration = new Registration(loggerFactory.CreateLogger<Registration>());
applicationLifetime.ApplicationStopping.Register(() =>
{
registration.Unregister();
});
});
return webHostBuilder;
}
Run Code Online (Sandbox Code Playgroud)
IApplicationLifetime即使在构建WebHost管道的管道中最后添加了此扩展方法,实例为何也为null?这将是巨大的,如果有人向我提供有关的所有“ConfigureServices”方法的执行顺序和如何或者如果它是在所有可能使用一些信息IApplicationLifetime的ConfigureServices方法。
我知道无需使用即可完成所有操作WebHostBuilder,但在我看来这样做很合乎逻辑,而且我也认为必须有一种方法。
不幸的是,我在网上找不到太多信息...
谢谢。
编辑:我找到了一种在ConfigureServices方法中使用DI的方法。我相应地编辑了问题。这对我有帮助:如何在ASP.NET Core中的ConfigureServices中解析实例
我在 ASP.NET Core 应用程序中使用 ML.NET,并且在 中使用以下代码Startup:
var builder = services.AddPredictionEnginePool<Foo, Bar>();
if (File.Exists("model.zip"))
{
builder.FromFile(String.Empty, "model.zip", true);
}
Run Code Online (Sandbox Code Playgroud)
如果model.zip不存在,我稍后会在中间件中创建它。如何将其添加到PredictionEnginePool注入的内容中?
没有通过 加载模型的选项PredictionEnginePool,并且实例化或注入 aPredictionEnginePoolBuilder不是它所需要的选项IServiceCollection(因此必须在 期间配置Startup.ConfigureServices)。
目前我能看到的唯一选择是,如果启动时文件不存在,则设置一个标志,然后在稍后在中间件中创建model.zipIApplicationLifetime.StopApplication后重新启动服务(使用),但我真的不这样做像这样作为一个选项。
我已经实现了一个自定义的InputFormatter(MyInputFormatter):
public class MyInputFormatter : SystemTextJsonInputFormatter
{
private readonly IMyDepenency _mydependency;
public CustomInputFormatter(
JsonOptions options,
ILogger<SystemTextJsonInputFormatter> logger,
IMyDependency myDependency
) : base(options, logger)
{
_mydependency = myDependency ?? throw new ArgumentNullException(nameof(myDependency));
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
现在,根据文档我需要按如下方式使用它:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new MyInputFormatter(...));
});
}
Run Code Online (Sandbox Code Playgroud)
但是,正如您所看到的,我CustomInputFormatter需要一些构造函数参数并且需要一些服务,但我不清楚如何使用 DI 来解析这些服务。我已经阅读了很多像这样的答案/博客/页面,但是输入格式化程序没有任何构造函数参数(因此不需要 DI,只需内联新建一个新实例)或者建议以下内容:
public void ConfigureServices(IServiceCollection services)
{
var sp = services.BuildServiceProvider();
services.AddControllers(options =>
{ …Run Code Online (Sandbox Code Playgroud)