【问题标题】:Mix WebAPI and WCF with SimpleInjector将 WebAPI 和 WCF 与 SimpleInjector 混合使用
【发布时间】:2016-02-10 14:50:49
【问题描述】:

我创建了一个使用 SimpleInjector 的 WebApi 应用程序。
现在,API 的用户希望 WCF 端点使用它(无论出于何种原因)。

为了让事情变得更简单,我只想从 WCF 服务内部调用 WebApi 控制器:

public class MyService : IMyService
{
    private MyApiController controller;

    public MyService(IMyInjection inject)
    {
        controller = new MyApiController(inject);
    }

    public int GetResult(string data)
    {
        return controller.GetResult(data);
    }
}

为了使其在 WebApi 中工作,我的控制器当前使用WebApiRequestLifeStyle 生活方式的注入,我尝试“添加”SimpleInjector WCF Integration

public static void LoadDependencyInjection()
{
    var container = new Container();
    container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
    container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

    // some more registration

    // configure WCF to use SimpleInjector
    container.RegisterWcfServices(Assembly.GetExecutingAssembly());

    // verify
    container.Verify();

    // configure the global WebApi to use SimpleInjector
    GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

    // configure WCF to use SimpleInjector
    SimpleInjectorServiceHostFactory.SetContainer(container);
}

显然,WCF 服务不喜欢 WebApi 的生活方式,当我尝试调用方法时会抛出错误:

ITransferOrderRequest 注册为“Web API 请求”生活方式,但实例是在 Web API 请求的上下文之外请求的。

更新

我尝试创建第二个具有不同生活方式的容器:

public static void LoadDependencyInjection()
{
    // WebApi container
    var webApiContainer = CreateContainer(new WebApiRequestLifestyle(true));
    webApiContainer.RegisterWebApiControllers(GlobalConfiguration.Configuration);
    webApiContainer.EnableHttpRequestMessageTracking(GlobalConfiguration.Configuration);

    // WCF container
    var wcfContainer = CreateContainer(new WcfOperationLifestyle(true));
    wcfContainer.RegisterWcfServices(Assembly.GetExecutingAssembly());

    // verify
    webApiContainer.Verify();
    wcfContainer.Verify();

    // configure the global WebApi to use SimpleInjector
    GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(webApiContainer);

    // configure WCF to use SimpleInjector
    SimpleInjectorServiceHostFactory.SetContainer(wcfContainer);
}

private static Container CreateContainer(ScopedLifestyle lifestyle)
{
    var container = new Container();

    // set the default lifestyle
    container.Options.DefaultScopedLifestyle = lifestyle;

    // here I register a bunch of interfaces/instances using the Scoped lifestyle

    return container;
}

但是第二次调用container.Options.DefaultScopedLifestyle = lifestyle;(使用WcfOperationLifestyle)也改变了第一个容器的默认生活方式!在这种情况下,当我调用我的 WebApi 服务时,我得到了同样的错误,但反过来:

IMyStuff 注册为 WCF 操作生活方式。

我已经看到有一种 Hybrid 生活方式,但是我不知道如何检测它当前是 WCF 还是 WebApi 请求...

谢谢!

【问题讨论】:

  • 您是否反对让 WCF 通过 HTTP 发送请求(使用类似 WebClient),而不是尝试新建控制器?我认为您的控制器不会通过您提出的解决方案获得 WebAPI 请求管道的所有好处。
  • 为什么不将ScopedLifestyle 实例作为参数传递给LoadDependencyInjection() 方法?这样,每个应用程序都可以拥有自己的范围生活方式(这正是该功能的设计目的)。
  • @danludwig :您希望 WCF 服务通过 HTTP 调用 REST 服务吗?老实说,我不太喜欢这种解决方案。
  • @Steven :我尝试创建 2 个容器并更改 DefaultScopedLifestyle 但似乎(也许这是一个错误?)覆盖一个容器上的默认值会覆盖另一个容器。
  • 据我所知,不存在导致 DefaultScopedLifestyle 实例在容器之间共享的错误。如果您能够通过失败的单元测试来证明这一点,请将其作为问题发布在 Simple Injector 的 Github 项目页面上。

标签: wcf asp.net-web-api simple-injector


【解决方案1】:

我不知道如何检测当前是 WCF 还是 WebApi 请求...

可以通过检查OperationContext.Current != null是否是WCF请求来判断请求是否为WCF请求。

var lifestyle = Lifestyle.CreateHybrid(
    lifestyleSelector: () => OperationContext.Current != null,
    trueLifestyle: new WcfOperationLifestyle(true),
    falseLifestyle: new WebApiRequestLifestyle()
);

我不知道“仅仅更新控制器会失去什么”。

为了澄清我在 cmets 中的建议,我了解您来自哪里。我仍然认为您应该在完全排除之前考虑通过 HTTP 执行此操作。您可以通过使 URL 成为 WCF 项目的 app.config 的一部分来克服“硬线路由”问题。有一些不错的配置转换工具可以用来为不同的环境生成不同的路由。更改配置以修改程序行为是松散耦合且高度内聚的。

效率有点低,但我认为如果 实际 额外延迟足够小,成本可能是合理的。您失去的东西是添加到控制器的所有 WebAPI 请求管道优势,例如内容协商、过滤器等。由于您没有发布任何代码并且对您的决定感到满意,我假设您真的只是在GetResults(string data) 方法体及其作用域依赖项,不需要其他任何东西。

但是请注意,与 HTTP 网络调用相比,您的决定会在 WCF 服务和 WebAPI 控制器之间创建更紧密的耦合。

【讨论】:

  • (关于编辑):啊!我想我明白“我失去了什么”。是的,这是一个基本的“数据”网络服务,供内部使用(由公司的其他部门),所以我除了[Route()]之外没有其他属性...实际上我希望将两者结合起来,这样一个有与其他方法相同。这只是访问同一事物的两种方法。
  • @cosmo0 很公平。正如他们所说,“直到出现问题才成为问题。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 2015-07-07
  • 1970-01-01
相关资源
最近更新 更多