Using Castle Windsor WcfFacility to Create Client Endpoints

I created three assemblies. A website, a WCF service, and a contract assembly that contains interfaces that implement the services. I would like to use Castle Windsor to create services for me on the client (website), so I do not need to have an endpoint in the web.config of the website for every service I want to use.

I would like to see the contract assembly and get all the service interfaces in the namespace. Right now, for each service, I have something like the following when registering components with a container.

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); 

and in my web.config I have the installation code.

  <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> 

As a result, I get several service endpoints that look almost exactly the same, and when we deploy to client machines, they must set the address of each endpoint, even if the base url is the same for each.

I would like to have a base url in my web.config, which is captured through code, and then services registered in the container, using reflection in the contract assembly. I need the specialized endpoint behavior found in the configuration file above.

Where do I start? WcfFacility looks great, but doco is a bit lacking ...

+6
source share
1 answer

I agree that there are no documents for the wcf object, and this is sad because it is a really great tool, and it would be very disappointing if people did not use it because they could not get started, so let me see, I I can help you a little if I can ...

Create three project applications that have:

  • Class Library for General Contracts
  • Console application acting as a server
  • Console application acting as a client

The idea is that we want to be able to use service names when we register services and share the base URL (I think this is what you asked for, and if not, I hope you can extrapolate here). So, firstly, general contracts just have this in it (nothing special, normal WCF tariff):

 [ServiceContract] public interface IMyService1 { [OperationContract] void DoSomething(); } [ServiceContract] public interface IMyService2 { [OperationContract] void DoSomethingToo(); } 

Now the console console application looks like this: first we execute service contracts (again, nothing special there, just classes that implement interfaces), and then just register them as services (do not pay attention to any configuration file here, and you can change how do you decide which services, etc. use all the options that Windsor gives you - my scheme is a bit limited, but it gives you an idea):

 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) { } } } 

And this is the server, now how to use these services? Well, actually it's pretty simple, here is the client console application (it only refers to the contract class library):

 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(); } } 

This, hopefully, will get you started (I find that experimenting and using intellisense usually leads me where I need to go). I showed you both sides of the service and the customer, but you can just use one or the other if you want.

You should be able to see where the binding is and how I started building the URLs, so in your case, you can just rip out your base URL from the configuration file or whatever you want to do.

It should be mentioned that you can add your custom behavior to the endpoint by adding it as an extension for the endpoint, so in the client example you will have something like this:

 Endpoint = WcfEndpoint .BoundTo(new WSHttpBinding()) .At(string.Format("http://localhost/MyServices/{0}", c.Name.Substring(1))) .AddExtensions(new AuthTokenBehavior()) 
+12
source

Source: https://habr.com/ru/post/912826/


All Articles