首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我可以在WCF Test Client中使用WcfFacility吗?

我可以在WCF Test Client中使用WcfFacility吗?
EN

Stack Overflow用户
提问于 2012-04-08 06:04:48
回答 2查看 991关注 0票数 1

我有一个WCF服务库,其中包含从DefaultServiceHostFactory派生的自定义ServiceHostFactory。我无法让测试客户端使用此工厂。我只是得到了“找不到无参数构造器”的错误。

这是我的托管环境配置:

代码语言:javascript
复制
<serviceHostingEnvironment>
  <serviceActivations>
    <add service="TestService.WcfLibrary.TestService"
         relativeAddress="/TestService.svc"
         factory="TestService.WcfLibrary.TestServiceHostFactory, TestService.WcfLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  </serviceActivations>
</serviceHostingEnvironment>

请注意,我实际上没有.svc文件。我正在尝试使用无文件激活。

下面是我的自定义ServiceHostFactory:

代码语言:javascript
复制
public class TestServiceHostFactory : DefaultServiceHostFactory
{
    public TestServiceHostFactory() : base(CreateKernel()) { }

    private static IKernel CreateKernel()
    {
        WindsorContainer container = new WindsorContainer();

        container.AddFacility<WcfFacility>();

        container.Register(Component.For<TestService>());
        container.Register(Component.For<IServiceManager>().ImplementedBy<ServiceManager>());

        return container.Kernel;
    }
}

看起来这条路径从来没有执行过。如何让WCF测试客户端使用我的自定义实现?

EN

Stack Overflow用户

回答已采纳

发布于 2012-04-13 15:02:35

好吧,这是可能的,但它不是很好……

首先,我们需要一种在加载程序集时挂钩的方法,因为在这种情况下,它们不是“主”或“应用程序启动”或任何东西。在AppDomain上有一个名为AssemblyLoaded的有趣事件,看起来它可能会做到这一点,嗯,但是如何挂钩它,我认为实现这一点的一种方法是定义一个自定义的应用程序域管理器,所以……

创建一个全新的程序集,并在其中定义一个接口,该接口可以由一些客户端和AppDomainManager实现,如下所示:

代码语言:javascript
复制
public interface IAssemblyLoaded
{
    void AssemblyLoaded();
}

public class CustomManager : AppDomainManager
{
    public override void InitializeNewDomain(AppDomainSetup appDomainInfo)
    {
        base.InitializeNewDomain(appDomainInfo);

        // Look for any classes that implement IAssemblyLoaded,
        // constuct them (will only work if they have a default constructor)
        // and call the AssemblyLoaded method
        var loaded = typeof (IAssemblyLoaded);
        AppDomain
            .CurrentDomain
            .AssemblyLoad += (s, a) =>
                                 {
                                     var handlers = a
                                         .LoadedAssembly
                                         .GetTypes()
                                         .Where(loaded.IsAssignableFrom);

                                     foreach (var h in handlers)
                                     {
                                         ((IAssemblyLoaded)
                                          Activator.CreateInstance(h))
                                             .AssemblyLoaded();
                                     }
                                 };
    }
}

确保程序集已签名,然后将其添加到GAC。假设我调用了程序集AssemblyInitCustomDomainManager,我可以像这样添加它(并且我立即获得了关于它的详细信息,因为我将需要它们):

代码语言:javascript
复制
gacutil /i AssemblyInitCustomDomainManager.dll
gacutil /l AssemblyInitCustomDomainManager

现在编辑WcfServiceHost.exe.config (通常位于: C:\Program Files\Microsoft Visual Studio10.0\Common7\IDE或64位系统上的x86版本),并在运行时元素中添加以下内容(有关此设置的信息,请参阅here ):

代码语言:javascript
复制
<appDomainManagerType value="AssemblyInitCustomDomainManager.CustomManager" />
<appDomainManagerAssembly value="AssemblyInitCustomDomainManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c841b3549556e52a, processorArchitecture=MSIL" />

注意:您将需要至少更改其中之一(也可能全部更改,这取决于您在上面调用的内容):类型名称、命名空间、程序集名称、公钥、版本号。我想你应该能弄清楚它们在你的箱子里需要什么。

好了,这很简单,现在我们将在visual studio中创建一个新的"WCF Service Library“项目,它将为我们创建一个app.config和一个服务(这是您想要测试的项目类型,哦,我希望如此!)。

首先,从app.config中删除system.servicemodel部件,因为我们不希望服务主机应用程序读入此部件,然后删除Service1.cs和IService1.cs (稍后我将创建自己的部件)。确保引用之前创建的应用程序域管理器程序集,因为您需要实现该接口。

现在,创建一个新文件并插入以下代码(我们只有一个简单的服务,该服务具有Castle WCF Facility托管的依赖项):

代码语言:javascript
复制
using System;
using System.ServiceModel;

using AssemblyInitCustomDomainManager;

using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Castle.Windsor.Installer;

namespace TestWcfServiceLibrary
{
    public class AssemblyInitializedHandler : IAssemblyLoaded
    {
        // This method is called when the assembly loads so we will create the
        // windsor container and run all the installers we find
        public void AssemblyLoaded()
        {            
            new WindsorContainer().Install(FromAssembly.This());            
        }        
    }

    // This installer will set up the services
    public class ServicesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, 
                            IConfigurationStore store)
        {
            container
                .AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero)
                .Register(Component
                              .For<ITestDependency>()
                              .ImplementedBy<TestDependency>(),
                          Component
                              .For<IService1>()
                              .ImplementedBy<Service1>()
                              .AsWcfService(new DefaultServiceModel(WcfEndpoint
                                                                        .BoundTo(new WSHttpBinding()))
                                                .AddBaseAddresses("http://localhost:9777/TestWcfServiceLibrary/Service1")
                                                .PublishMetadata(m => m.EnableHttpGet())));
        }
    }

    // This is the contract of something we want to make sure is loaded
    // by Windsor
    public interface ITestDependency
    {
        int DoSomething(int value);
    }

    public class TestDependency : ITestDependency
    {
        public int DoSomething(int value)
        {
            return value;
        }
    }

    // Regular WCF service contract
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);
    }

    // Service implementation - notice it does not have a default 
    // constructor
    public class Service1 : IService1
    {
        private readonly ITestDependency _td;

        public Service1(ITestDependency td)
        {
            _td = td;
        }

        public string GetData(int value)
        {
            int v = _td.DoSomething(value);
            return string.Format(
                "According to our dependency you entered: {0}", v);
        }
    }
}

单击run,您将看到一条错误消息,内容为:

WCF服务主机找不到任何服务元数据。这可能会导致客户端应用程序运行不正常。请检查元数据是否启用。是否要退出?

不用担心,只需单击no即可。

测试客户端启动,但遗憾的是它没有您的服务。不用担心,只需右键单击添加服务...并放入服务的URL (它在安装程序中的代码-http://localhost:9777/TestWcfServiceLibrary/Service1中)。

这就是WCF Test Client内部托管的WCF服务。不要相信我-测试它,调用GetData操作,您应该会看到结果。

这就对了。现在,如果你问这是不是一个好主意…我不知道,但它是有效的,我认为这是你所要求的…

票数 3
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10058761

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档