使用 SimpleInjector 混合 WebAPI 和 WCF

Mix WebAPI and WCF with SimpleInjector

我创建了一个使用 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 生活方式的注入,我已经尝试 "just add" 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 的生活方式,并且在我尝试调用方法时抛出错误:

The ITransferOrderRequest is registered as 'Web API Request' lifestyle, but the instance is requested outside the context of a Web API Request.

更新

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

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 is registered as WCF operation lifestyle.

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

谢谢!

I have no idea how to detect whether it's currently a WCF or WebApi request...

您可以通过检查是否OperationContext.Current != null.

来检查请求是否为WCF请求
var lifestyle = Lifestyle.CreateHybrid(
    lifestyleSelector: () => OperationContext.Current != null,
    trueLifestyle: new WcfOperationLifestyle(true),
    falseLifestyle: new WebApiRequestLifestyle()
);

I don't know "what I lose by just newing up a controller".

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

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

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