我可以在WCF Test Client中使用WcfFacility吗?
我有一个WCF服务库包含从DefaultServiceHostFactory派生的自定义ServiceHostFactory。我无法让测试客户端使用这个工厂。我只是得到“没有无参数的构造函数被发现”错误。我可以在WCF Test Client中使用WcfFacility吗?
这里是我的托管环境配置:
<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:
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 Test Client使用我的自定义实现?
OK,这是可能的,但它不是很...
我们需要一种方法来钩当组件加载,因为在这种情况下他们是没有“主”或“应用程序启动的第一“或任何东西。在AppDomain上有一个名为AssemblyLoaded的有趣事件,看起来好像它可以做到这一点,嗯,但如何挂钩它,我认为这样做的一种方式是定义一个自定义应用程序域管理器,所以...
创建一个全新的组装和里面定义一个接口,可以通过一些客户端来实现和AppDomainManager像这样:
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我可以添加它像这样(和我回去吧细节直线距离,因为我需要他们):
gacutil /i AssemblyInitCustomDomainManager.dll
gacutil /l AssemblyInitCustomDomainManager
现在编辑WcfServiceHost.exe.config(通常位于:C:\ Program Files文件\微软的Visual Studio 10.0 \ Common7 \ IDE或在64个系统的x86版),并添加运行元素中的以下内容(见here有关此设置的信息):
<appDomainManagerType value="AssemblyInitCustomDomainManager.CustomManager" />
<appDomainManagerAssembly value="AssemblyInitCustomDomainManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c841b3549556e52a, processorArchitecture=MSIL" />
注意:您将需要更改至少一个(可能全部取决于您所称的以上内容):类型名称,名称空间,程序集名称,公钥,版本号。我想你应该能够弄清楚自己需要做什么。
好的,这很容易,现在我们将在Visual Studio中创建一个新的“WCF服务库”项目,它将为我们创建一个app.config和一个服务(这是您想要的项目类型测试的权利,哦,我希望如此!)。
首先,从app.config中删除system.servicemodel一部分,因为我们不希望服务主机应用程序在阅读,然后删除Service1.cs和IService1.cs(因为我要去稍后再做我自己的)。确保您参考之前创建的应用程序域管理器程序集,因为您需要实现该界面。
现在,创建一个新的文件,并坚持在下面的代码(我们只是有与城堡WCF基金托管依赖一个简单的服务):
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);
}
}
}
点击运行,你会得到一个错误消息说:
WCF服务主机找不到任何服务元数据。这可能会导致 客户端应用程序无法正常运行。请检查是否启用了元数据 。你想出去吗?
别担心,只需点击否。
测试客户端启动,但可悲的是它没有你的服务。不用担心,只需右键单击添加服务...并将其放入服务的URL中(它位于代码的安装程序中 - http://localhost:9777/TestWcfServiceLibrary/Service1)。
你去 - WCF服务托管在WCF测试客户端。不要相信我 - 测试一下,调用GetData操作,你应该看到结果。
你走了。现在,如果你问这是否是一个好主意......我不知道但它的工作原理,我认为这是你要求的...
哇。非常感谢,很好的回答。我应该通知你,我可以运行它而不会收到关于元数据的任何错误,服务已经被添加,并且只是运行。 – 2012-04-14 14:24:26
+1为忍者代码skilz :) – 2012-04-15 08:47:22
我记得有人读过这个地方! link
“WcfSvcHost的最大缺点是,你不打开它,或者它的事件模型的编程访问一旦打开前需要对主机实例编程访问它仅适用于简单的方案。不像IIS或托管Windows激活服务(WAS)没有相应的服务主机工厂支持,因此无法动态添加基址,配置端点,调用调用,在主机级别配置自定义行为等等。除了最简单的情况外,最终你需要对主机实例进行编程访问,所以我不认为WcfSvcHost是一个完整的有生产价值的主机,因为我做的是WAS或专用的自主主机。“
这个服务是如何托管的? – 2012-04-12 06:06:40
@PetarVucetin这只是一个WCF服务库,当我调试时我必须使它在WCF测试客户端上运行。我知道我可以在svc文件上设置工厂,如果我在ISS或Windows服务上托管它,但它仍然必须作为库工作。 – 2012-04-12 06:50:13
好的。我只是不确定WCF TC在托管服务时做了什么。 – 2012-04-12 15:15:16