【问题标题】:Castle Windsor Lifestyle for EF DbContext Needed For Logging After Web API RequestEF DbContext 的 Castle Windsor Lifestyle 需要在 Web API 请求后进行日志记录
【发布时间】:2015-03-11 23:12:14
【问题描述】:

我正在使用 Castle Windsor 作为 Web API 2 的 DI 容器,并且我的一些控制器具有 EF DbContext 依赖项,我正在使用以下 CW 安装程序进行注入(这部分工作正常):

public class ApiControllerInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
    }
}

public class MyEntitiesInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<MyEntities>().LifestylePerWebRequest());
    }
}

我还使用以下消息处理程序进行了全局日志记录:

public class LoggingHandler : DelegatingHandler
{
    private readonly IWindsorContainer _container;

    public LoggingHandler(IWindsorContainer container)
    {
        _container = container;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                                 CancellationToken cancellationToken)
    {
        // Logic here to parse the request, send off the request, and then parse the response for logging info

        // Log to database
        using (MyEntities myEntities = _container.Resolve<MyEntities>())
        {
            // Log to database using MyEntities (DbContext)
        }

        return response;
    }
}

... 在 WebApiConfig.cs 中设置如下:

    public static void Register(HttpConfiguration config, IWindsorContainer container)
    {
        // Unrelated code

        config.MessageHandlers.Add(new LoggingHandler(container));
    }

问题是我在尝试访问 MyEntities(扩展 EF DbContext)时在 LoggingHandler 中遇到异常,因为它说它已经被处理掉了。我认为这是因为 MyEntitiesInstaller 将其注册为 LifestylePerWebRequest() 并且此时请求已经完成。我认为全局改变DbContext 的生活方式并不是一个好主意,因为出于 api 控制器的目的,我们确实希望它成为每个 Web 请求的实例。但是如何防止它在日志记录发生之前被处置(或者更好的是,使用单独的实例进行日志记录)?

【问题讨论】:

  • 我没用过Castle Windsor,但它不支持“命名”配置吗?我的直觉是为 DbContext 创建一个备用的命名配置,然后配置您的属性以使用它。
  • 我不确定注册您的MyEntities 是不是一个聪明的主意。它们在查询的生命周期内应该是短暂的,而不是整个 Web 请求。我会保持简单,只需使用 using (var entityContext = new MyEntities()) 代替。不需要"Inject all the things"
  • @emodendroket 谢谢!看起来命名实例是我需要的——我是 DI 容器的新手,不知道这个特性。我会尝试看看使用单独的命名实例是否可行。
  • @YuvalItzchakov 出于我的目的,无论如何我都需要整个 Web 请求的上下文,因此最终结果是相同的。此外,如果没有注入,代码是不可测试的。我不同意注入 DbContext 是一个坏主意,只要它在请求结束时被处理。不过,我认为讨论超出了这个问题的范围。
  • 是的,当然我在控制器内部使用它,否则我根本不需要在那里注入它。 :) 我只是没有发布那部分,因为它正在工作并且与我遇到的问题没有直接关系......如果不清楚,对不起。不过,我不想对两者使用相同的实例。命名实例似乎已经解决了这个问题。控制器使用每个 Web 请求的实例,而日志记录处理程序使用我仅在需要时才解析并在之后立即处理的瞬态实例。

标签: c# entity-framework asp.net-web-api dependency-injection castle-windsor


【解决方案1】:

感谢@emodendroket 的评论为我指明了正确的方向。我能够通过在 Web 请求之外为我需要的 DbContext 使用不同的命名实例,使用短暂的生活方式(并在使用后立即手动处理)来完成这项工作。

安装者:

public class MyEntitiesInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<MyEntities>().LifestylePerWebRequest().IsDefault(),
                           Component.For<MyEntities>().Named("MyEntitiesTransient").LifestyleTransient());
    }
}

日志处理程序的用法:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                             CancellationToken cancellationToken)
{
    // Logic here to parse the request, send off the request, and then parse the response for logging info

    // Log to database
    using (MyEntities myEntities = _container.Resolve<MyEntities>("MyEntitiesTransient"))
    {
        // Log to database using MyEntities (DbContext)

        _container.Release(myEntities);
    }

    return response;
}

控制器继续使用具有 per-web-request 生活方式的未命名/默认实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    相关资源
    最近更新 更多