配置Simple Injector以支持解析ASP.NET Core中间件依赖项?

时间:2016-08-12 17:28:28

标签: c# asp.net-core simple-injector asp.net-core-middleware

如何配置SimpleInjector来解析LogMiddleware的Invoke方法依赖,比如IMessageService?

据我所知,Asp.net核心使用HttpContext.RequestServices(IServiceProvider)来解析依赖关系,我将SimpleInjector容器设置为HttpContext.RequestServices属性但是没有用。我想动态更改ServiceProvider,因为每个租户都应该有一个容器。

public class LogMiddleware
{
    RequestDelegate next;
    private readonly ILogger log;

    public LogMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        this.next = next;
        this.log = loggerFactory.CreateLogger<LogMiddleware>();
    }

    public async Task Invoke(HttpContext context, IMessageService messageService)
    {
         await context.Response.WriteAsync(
                messageService.Format(context.Request.Host.Value));
    }
}

public interface IMessageService
{
    string Format(string message);
}

public class DefaultMessageService : IMessageService
{
  public string Format(string message)
  {
    return "Path:" + message;
  }
}

2 个答案:

答案 0 :(得分:2)

您可以按照以下方式使用LogMiddleware课程:

applicationBuilder.Use(async (context, next) => {
    var middleware = new LogMiddleware(
        request => next(),
        applicationBuilder.ApplicationServices.GetService<ILoggerFactory>());

    await middleware.Invoke(context, container.GetInstance<IMessageService>());
});

但是我建议你稍微改变你的中间件类。将运行时数据(next()委托)移出构造函数(自components should not require runtime data during construction起),并将IMessageService依赖项移动到构造函数中。并将ILoggerFactory替换为ILogger依赖项,因为注入构造函数应do no more than store its incoming dependencies(或将ILogger替换为your own application-specific logger abstraction instead)。

您的中间件类将如下所示:

public sealed class LogMiddleware
{
    private readonly IMessageService messageService;
    private readonly ILogger log;

    public LogMiddleware(IMessageService messageService, ILogger log) {
        this.messageService = messageService;
        this.log = log;
    }

    public async Task Invoke(HttpContext context, Func<Task> next) {
        await context.Response.WriteAsync(
            messageService.Format(context.Request.Host.Value));

        await next();
    }
}

这允许您按如下方式使用中间件:

var factory = applicationBuilder.ApplicationServices.GetService<ILoggerFactory>();

applicationBuilder.Use(async (context, next) => {
    var middleware = new LogMiddleware(
        container.GetInstance<IMessageService>(),
        factory.CreateLogger<LogMiddleware>());

    await middleware.Invoke(context, next);
});

或者,如果您在Simple Injector中注册了ILogger(或您的自定义日志记录抽象),您可以执行以下操作:

applicationBuilder.Use(async (context, next) => {
    var middleware = container.GetInstance<LogMiddleware>();
    await middleware.Invoke(context, next);
});

答案 1 :(得分:0)

您的代码存在两个问题。

  1. 您的“DefaultMessageService”未实现“IMessageService”接口。 它应该是这样的。
  2.  public class DefaultMessageService : IMessageService
     {
     public string Format(string message)
    {
       return "Path:" + message;
     }
    }
    
    1. 您必须在Startup.cs中的ConfigureService中注册DefaultMessageService。
    2.  public void ConfigureServices(IServiceCollection services)
              {
                  // Add framework services.
                  services.AddMvc();
                  services.AddSingleton<IMessageService>(new DefaultMessageService());
              }