使用 Ninject 的 WCF 服务问题(从 Windsor 迁移)(InvalidOperationException)

发布于 2024-09-29 15:41:55 字数 3143 浏览 9 评论 0 原文

家里有 Ninject 专家吗? :) 我最近一直在尝试将 WCF 服务应用程序和 Windows 窗体客户端应用程序从 Castle Windsor 依赖注入转换为 Ninject。

Win Forms 方面一切顺利,但我在 WCF 方面遇到了问题。到目前为止,我已经了解到,我相信我需要可用于 Ninject 的 WCF 扩展,以便将 DI 与 WCF 结合使用,我已经完成并引用了该功能,但我认为在尝试解决我的服务时仍然遇到问题:

System.InvalidOperationException :找不到类型“WcfMemberService”,作为 ServiceHost 指令中的 Service 属性值提供,或者在配置元素 system.serviceModel/serviceHostingEnvironment/serviceActivations 中提供。

我所拥有的代码就是我想要的例如,访问我的 WcfMemberService 是正确的,如下所示:

ServiceModule.cs:

public class ServiceModule : NinjectModule
{
    private IKernel _parentContainer;
    public ServiceModule(IKernel container)
    {
    this._parentContainer = container;
    }

    public override void Load()
    {
    Bind<IDataContextProvider>().To<DataContextProvider>()
        .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString);
    Bind(typeof(IRepository<>)).To(typeof(Repository<>));
    Bind<IServiceLocator>().ToConstant(new NinjectServiceLocator(_parentContainer));
    Bind<IUserService>().To<UserService>();

    // ** WCF Services **
    Bind<Business.Common.Wcf.Services.Contracts.IMemberServiceContract>().To<Business.Common.Wcf.Services.MemberService>().InSingletonScope().Named("WcfMemberService");
    }
}

我所做的假设是,当从我的工作 Castle Windsor 配置进行转换时,Named()应与 WCF .svc 文件声明中的条目相同。因此,我的做法如下:

<%@ ServiceHost Language="C#" Service="WcfMemberService" Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>

非常简单,我从 Ninject Wcf Extensions GitHub 页面 这里

任何人都可以看到我在这里做错了什么以及为什么“WcfMemberService”无法解决?它在内核中必然是“WcfMemberService”,并在 @ServiceHost 声明中引用。我看不出还有什么问题。这与我在温莎城堡中声明它的方式完全相同,除了语法大致不同之外,但两者都使用 Named() 并且都在 .svc< 的 Service 部分中引用该名称/代码> 文件。

*更新*我发现如果我不使用Named()方法,而只是在@ ServiceHost<中设置我的服务/code> 声明为 Business.Common.Wcf.Services.MemberService, Business.Common.Wcf.Services 它有效。但我仍然困惑为什么我不能使用命名服务。谢谢。

顺便说一句,我的 Ninject 模块是通过 Global.asax.cs 以这种方式加载的:

public class Global : NinjectWcfApplication
{
    #region Overrides of NinjectWcfApplication

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    protected override IKernel CreateKernel()
    {
        // config to reside in executing directory
        log4net.Config.XmlConfigurator.Configure(new FileInfo("log4net.config"));
        var _container = new StandardKernel();
        _container.Load(new ServiceModule(_container));
        //_container.Load(new Log4netModule());
        ServiceLocator.SetLocatorProvider(() => _container.Get<IServiceLocator>());

        return _container;
    }

    #endregion
}

Any Ninject experts in the house? :)
I've recently been trying to convert my WCF Service Application and Windows Forms Client Application from Castle Windsor dependency injection to Ninject.

All has gone fine on the Win Forms side, but I am encountering issues on the WCF side of things. I have learned so far I believe I need to WCF extensions available for Ninject in order to use DI with WCF which I have done and referenced but still experiencing an issue I believe when my service is attempted to be resolved:

System.InvalidOperationException: The type 'WcfMemberService', provided as the Service attribute value in the ServiceHost directive, or provided in the configuration element system.serviceModel/serviceHostingEnvironment/serviceActivations could not be found.

The code I have which is what I thought to be correct to access just for instance my WcfMemberService is as follows:

ServiceModule.cs:

public class ServiceModule : NinjectModule
{
    private IKernel _parentContainer;
    public ServiceModule(IKernel container)
    {
    this._parentContainer = container;
    }

    public override void Load()
    {
    Bind<IDataContextProvider>().To<DataContextProvider>()
        .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString);
    Bind(typeof(IRepository<>)).To(typeof(Repository<>));
    Bind<IServiceLocator>().ToConstant(new NinjectServiceLocator(_parentContainer));
    Bind<IUserService>().To<UserService>();

    // ** WCF Services **
    Bind<Business.Common.Wcf.Services.Contracts.IMemberServiceContract>().To<Business.Common.Wcf.Services.MemberService>().InSingletonScope().Named("WcfMemberService");
    }
}

The assumption I made is when converting over from my working Castle Windsor configuration is that Named() should be the same entry which is featured in the declaration of your WCF .svc file. So I have done that as follows:

<%@ ServiceHost Language="C#" Service="WcfMemberService" Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>

Pretty simple, I have taken this approach from the TimeService example solution featured on the Ninject Wcf Extensions GitHub page here by the way.

Can anyone see what I have done wrong here and why "WcfMemberService" would not be resolving? It is bound to be "WcfMemberService" in the Kernel and referenced in the @ServiceHost declaration. I can't see what else could be wrong. This is exactly the same as how I declare it in Castle Windsor, except for roughly different syntax, but both use Named() and both ref that name in the Service part of the .svc file.

*Update* I have discovered if I do not use the Named() approach, and simply set my service in @ ServiceHost declaration as Business.Common.Wcf.Services.MemberService, Business.Common.Wcf.Services it works. But I am still stumped as to why I can't use Named services. Thanks.

By the way, my Ninject module is loaded via Global.asax.cs in this fashion:

public class Global : NinjectWcfApplication
{
    #region Overrides of NinjectWcfApplication

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    protected override IKernel CreateKernel()
    {
        // config to reside in executing directory
        log4net.Config.XmlConfigurator.Configure(new FileInfo("log4net.config"));
        var _container = new StandardKernel();
        _container.Load(new ServiceModule(_container));
        //_container.Load(new Log4netModule());
        ServiceLocator.SetLocatorProvider(() => _container.Get<IServiceLocator>());

        return _container;
    }

    #endregion
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南巷近海 2024-10-06 15:41:55

.Named(string) 语法用于条件绑定。例如,如果您有

Bind<IService1>().To<MyService>().Named("MyServiceImpl");
Bind<IService1>().To<DefaultService();

那么 DefaultService 将作为默认值注入,除非您有类似以下内容:

class MyForm([Named("MyServiceImpl")] IService1 service){...}

kernel.Get<IService1>(metadata => metadata.Name == "MyServiceImpl");

kernel.Get<IService1>("MyServiceImpl");

如果您没有该类型的默认绑定,并且只有条件命名绑定,那么您将得到一个当您尝试创建实例时出现激活异常。

-伊恩

The .Named(string) syntax is used in conditional binding. For example, if you have

Bind<IService1>().To<MyService>().Named("MyServiceImpl");
Bind<IService1>().To<DefaultService();

Then DefaultService will be injected as the default unless you have something like the following:

class MyForm([Named("MyServiceImpl")] IService1 service){...}

or

kernel.Get<IService1>(metadata => metadata.Name == "MyServiceImpl");

or

kernel.Get<IService1>("MyServiceImpl");

If you do not have a default binding for the type, and you only have the conditional named binding, then you will get an activation exception when you try to create an instance.

-Ian

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文