>我已经创建了三个程序集。一个网站、一个 WCF 服务和一个协定程序集,用于保存服务实现的接口。我想使用温莎城堡在客户端(网站)上为我创建服务,这样我就不必在网站的web.config中为我希望使用的每个服务创建一个端点。
我想查看合约程序集并获取命名空间中的所有服务接口。现在,对于每个服务,在向容器注册组件时,我都有如下所示的内容。
container.Register(Component.For<ChannelFactory<IMyService>>().DependsOn(new { endpointConfigurationName = "MyServiceEndpoint" }).LifeStyle.Singleton);
container.Register(Component.For<IMyService>().UsingFactoryMethod((kernel, creationContext) => kernel.Resolve<ChannelFactory<IMyService>>().CreateChannel()).LifeStyle.PerWebRequest);
在我的 web.config 中,我有设置代码。
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="AuthToken" type="MyNamespace.Infrastructure.AuthTokenBehavior, MyNamespace.Contracts" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior>
<AuthToken />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"></readerQuotas>
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint name="MyServiceEndpoint" address="http://someurl/MyService.svc" binding="wsHttpBinding" contract="MyNamespace.Contracts.IMyService"></endpoint>
</client>
</system.serviceModel>
我最终得到了多个服务端点,它们看起来几乎完全相同,当我们部署到客户端计算机上时,他们必须设置每个端点的地址,即使每个端点的基本 url 都相同。
我想在我的 web.config 中有一个通过代码抓取的基本 URL,然后使用合约程序集上的反射将服务注册到容器中。我确实需要上述配置文件中的专用端点行为。
我从哪里开始? WcfFacility看起来很棒,但doco有点缺乏...
我同意缺少 wcf 设施的文档,这很可悲,因为它是一个非常棒的工具,如果人们因为无法开始而不使用它,那将是一个真正的耻辱,所以让我看看我是否可以帮你一点,如果可以的话......
让我们创建一个具有以下功能的三个项目应用程序:
- 共享协定的类库
- 充当服务器的控制台应用程序
- 充当客户端的控制台应用程序
这个想法是,我们希望能够在注册服务时使用服务名称并共享基本URL(我认为这就是您要问的,如果没有,希望您可以从这里推断)。 所以,首先,共享合约只是包含这个(没什么特别的,正常的WCF票价):
[ServiceContract]
public interface IMyService1
{
[OperationContract]
void DoSomething();
}
[ServiceContract]
public interface IMyService2
{
[OperationContract]
void DoSomethingToo();
}
现在服务器控制台应用程序看起来像这样,我们首先实现服务合约(同样没有什么特别的,只是实现接口的类),然后将它们全部注册为服务(请注意,这里不需要任何配置文件,您可以使用 Windsor 给你的所有选项更改你决定什么是服务等的方式 - 我的方案有点有限,但它给你一个想法):
namespace Services
{
public class MyService1 : IMyService1
{
public void DoSomething()
{
}
}
public class MyService2 : IMyService2
{
public void DoSomethingToo()
{
}
}
}
//... In some other namespace...
class Program
{
// Console application main
static void Main()
{
// Construct the container, add the facility and then register all
// the types in the same namespace as the MyService1 implementation
// as WCF services using the name as the URL (so for example
// MyService1 would be http://localhost/MyServices/MyService1) and
// with the default interface as teh service contract
var container = new WindsorContainer();
container.AddFacility<WcfFacility>(
f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
AllTypes
.FromThisAssembly()
.InSameNamespaceAs<MyService1>()
.WithServiceDefaultInterfaces()
.Configure(c =>
c.Named(c.Implementation.Name)
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(
"http://localhost/MyServices/{0}",
c.Implementation.Name)
)))));
// Now just wait for a Q before shutting down
while (Console.ReadKey().Key != ConsoleKey.Q)
{
}
}
}
这就是服务器,现在如何使用这些服务? 好吧,实际上这很容易,这是一个客户端控制台应用程序(它只引用合约类库):
class Program
{
static void Main()
{
// Create the container, add the facilty and then use all the
// interfaces in the same namespace as IMyService1 in the assembly
// that contains the aforementioned namesapce as WCF client proxies
IWindsorContainer container = new WindsorContainer();
container.AddFacility<WcfFacility>(
f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
Types
.FromAssemblyContaining<IMyService1>()
.InSameNamespaceAs<IMyService1>()
.Configure(
c => c.Named(c.Implementation.Name)
.AsWcfClient(new DefaultClientModel
{
Endpoint = WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(
"http://localhost/MyServices/{0}",
c.Name.Substring(1)))
})));
// Now we just resolve them from the container and call an operation
// to test it - of course, now they are in the container you can get
// hold of them just like any other Castle registered component
var service1 = container.Resolve<IMyService1>();
service1.DoSomething();
var service2 = container.Resolve<IMyService2>();
service2.DoSomethingToo();
}
}
就是这样 - 希望这会让你开始(我发现实验和使用智能感知通常会让我到达我需要去的地方)。 我向您展示了服务和客户端,但如果您愿意,您可以只使用其中一个。
您应该能够看到绑定的配置位置以及我如何构造 URL,因此在您的情况下,您可以轻松地从配置文件中提取基本 URL 或您想要执行的任何操作。
最后要提到的一点是,您可以通过将自定义终结点行为作为扩展添加到终结点来添加自定义终结点行为,因此在客户端示例中,您将拥有如下所示的内容:
Endpoint = WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format("http://localhost/MyServices/{0}", c.Name.Substring(1)))
.AddExtensions(new AuthTokenBehavior())