简体   繁体   English

Asp.net Core获取依赖注入实例

[英]Asp.net Core get instance of Dependency Injection

I am adding a global error handler filter in Startup.cs like this: 我在Startup.cs中添加一个全局错误处理程序过滤器,如下所示:

services.AddMvc(o =>
{
    o.Filters.Add(new GlobalExceptionFilter());
});

However, I need to pass in my Email Service which is also being injected. 但是,我需要传递我的电子邮件服务,该服务也正在注入。 How can I retrieve it from these services in the filter? 如何从过滤器中的这些服务中检索它?

public class GlobalExceptionFilter : IExceptionFilter
{
    private readonly IEmailService _emailService;

    public GlobalExceptionFilter()
    {
    }

    public void OnException(ExceptionContext context)
    {

    }
}

I use to be able to use DependencyResolver Class to do that in MVC5. 我曾经能够使用DependencyResolver类在MVC5中做到这一点。 Is there a way to accomplish this in core? 有没有办法做到这一点? Or is there a way for me to force instantiation of the service in the Startup so I can pass it as part of the constructor? 还是我有办法在启动中强制实例化服务,以便可以将其作为构造函数的一部分传递?

I tried looking it up in the services and then looking at ImplementationInstance, but its null at this point so I can't grab it from there it appears. 我尝试在服务中查找它,然后查看ImplementationInstance,但是此时它为null,所以我无法从那里获取它。 Also keep in mind that my EmailService requires a parameter of IOptions<Settings> so that it can get email settings it needs. 另外请记住,我的EmailService需要IOptions<Settings>参数,以便它可以获取所需的电子邮件设置。

You can use constructor injection. 您可以使用构造函数注入。

public class GlobalExceptionFilter : IExceptionFilter
{
    private readonly IEmailService emailService;
    public GlobalExceptionFilter(IEmailService emailService)
    {
        this.emailService = emailService;
    }
    public void OnException(ExceptionContext context)
    {
       //do something with this.emailService
    }
}

But you have to change the way you are registering the global filter in ConfigureServices method. 但是您必须更改在ConfigureServices方法中注册全局过滤器的方式。 You should use the Add overload which takes a Type 您应该使用带有类型的Add重载

services.AddMvc(o =>
{
    o.Filters.Add(typeof(GlobalExceptionFilter));
});

Another option is, explicitly resolving the dependency inside the OnException method by calling the GetService method on HttpContext.RequestServices . 另一个选择是,通过在HttpContext.RequestServices上调用GetService方法来显式解决OnException方法内部的依赖关系。

using Microsoft.Extensions.DependencyInjection;

public void OnException(ExceptionContext context)
{
    var emailService = context.HttpContext.RequestServices.GetService<IEmailService>();
    // use emailService
} 

But you should be fine with the first approach. 但是第一种方法应该没问题。 Let the framework resolve it for you and inject to your constructor instead of you trying to do it. 让框架为您解决它,然后注入到构造函数中,而不用尝试这样做。

I think best practice for a Global Exception Handler is actually to create a custom middleware step for it. 我认为,全局异常处理程序的最佳实践实际上是为其创建自定义中间件步骤。 From the documentation 文档中

Exception filters are good for trapping exceptions that occur within MVC actions, but they're not as flexible as error handling middleware. 异常过滤器非常适合捕获MVC操作中发生的异常,但它们不像错误处理中间件那样灵活。 Prefer middleware for the general case, and use filters only where you need to do error handling differently based on which MVC action was chosen. 一般情况下,最好使用中间件,并且仅在需要根据所选择的MVC操作不同地进行错误处理的地方使用过滤器。

Then you register you classes in the ConfigureServices method: 然后,您在ConfigureServices方法中注册类:

services.AddTransient<IEmailService, EmailService>();

Then in your Configure method, you register your customer global exception handler. 然后在您的Configure方法中,注册您的客户全局异常处理程序。 You will want this to be the first thing you do in the Configure method so you catch any exceptions following it in other middleware. 您将希望这是您在Configure方法中要做的第一件事,这样您就可以在其他中间件中捕获其后的所有异常。

app.UseMiddleware<MyGlobalExceptionHandler>();

And any services you registered will be available for your middleware constructor which might look something like this: 您注册的所有服务都将对您的中间件构造函数可用,如下所示:

public sealed class MyGlobalExceptionHandler
{
    private readonly RequestDelegate _next;
    private readonly IEmailService _emailService;

    public NlogExceptionHandler(
        RequestDelegate next,
        IEmailService emailService)
    {
        _next = next;
        _emailService = emailService;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {

            await _next(context);
        }
        catch (Exception ex)
        {
            try
            {
                _emailService.SendEmail(ex.ToString());
            }
            catch (Exception ex2)
            {
                //Its good practice to have a second catch block for simple logging in case the email fails too
            }

            throw;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM