好吧,这是可能的,但它并不漂亮......
首先,我们需要一种在程序集加载时挂接的方法,因为在这种情况下,它们不是“主”或“应用程序启动”或任何东西。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\Microsoft Visual Studio 10.0\Common7\IDE 或 64 位系统上的 x86 版本)并在运行时元素中添加以下内容(有关信息,请参见此处此设置):
<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(因为我将自己制作一点之后)。确保您引用了您之前创建的应用程序域管理器程序集,因为您需要实现该接口。
现在,创建一个新文件并粘贴以下代码(我们只是有一个简单的服务,它具有由 Castle 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 服务主机找不到任何服务元数据。这可能会导致客户端应用程序运行不正常。请检查是否启用了元数据。你想离开吗?
不用担心,只需单击no。
测试客户端启动,但遗憾的是它没有您的服务。不用担心,只需右键单击 add service... 并输入服务的 URL(它位于代码的安装程序中 - http://localhost:9777/TestWcfServiceLibrary/Service1)。
你去 - WCF 服务托管在 WCF 测试客户端内。不信 - 测试一下,调用 GetData 操作,您应该会看到结果。
你去吧。现在,如果您问这是否是个好主意...我不知道,但它有效,我认为这是您所要求的...