/// <summary> /// Register a WCF client proxy for the given service interface with the IOC. The service /// will be contacted at the given URI. /// </summary> /// <remarks> /// <para> /// To register different endpoint behaviours the behaviour must be added to the clientModel (not the endpoint directly like the service registration). /// Adding the endpoint behaviours directly to the endpoint will not invoke the endpoint behaviours. /// </para> /// </remarks> /// <typeparam name="T">service interface</typeparam> /// <param name="k">IoC kernel to register to</param> /// <param name="uri">service URI</param> /// <param name="streamed">true if streaming must be supported</param> /// <param name="maxMsg">maximum message size supported</param> /// <param name="sendTimeout">WCF proxy timeout to send a message</param> /// <param name="receiveTimeout">WCF proxy timeout to receive a message</param> /// <param name="useExternalEndpointBehaviour">Optional: Flag to add external endpoint behaviour (<c>true</c>) or the default endpoint behaviour. Default: false</param> public void RegisterWCFClientProxy <T>(string uri, bool streamed, int maxMsg, TimeSpan sendTimeout, TimeSpan receiveTimeout, bool useExternalEndpointBehaviour) where T : class { var endPoint = GetEndpoint(uri, streamed, maxMsg, sendTimeout, receiveTimeout); try { var clientModel = new DefaultClientModel() { Endpoint = endPoint.At(uri) }; clientModel = clientModel.WithoutAsyncCapability(); var endpointBehaviour = this.CreateEndpointBehaviour(useExternalEndpointBehaviour); clientModel.AddExtensions(endpointBehaviour); Kernel.Register(Component .For <T>() .LifeStyle.Transient .AsWcfClient(clientModel) ); Logger.InfoFormat("WCF CLIENT proxy registered at [{0}]: Endpoint-Behaviour-Count: {1}, Use-External-EndpointBehaviour = '{2}.'", uri, clientModel.Extensions.Count(), useExternalEndpointBehaviour.ToString()); } catch (Exception ex) { var msg = string.Format("Error: WCF client proxy registration failed at address = [{0}], useExternalEndpointBehaviour = '{1}', Ex='{2}'", uri, useExternalEndpointBehaviour.ToString(), ex.ToString()); Logger.Fatal(msg); IoCSetup.ShutdownAndExit(msg, 1); } }
/// <summary> /// If in debug mode, shut the application down before throwing an assertion exception. /// Otherwise just throw an assertion exception. /// </summary> /// <remarks> /// IoCSetup.Shutdown() is asynchronous. That is, control may return from the shutdown /// call which in turn measns control will return from assert. Previously, we just /// allowed a normal return in this situation with the result that code *after* the /// assert would continue to execute for a small time window (i.e. until the async /// shutdown completed). Allowing code to execute after an assert is bad, so now /// we always thrown an exception. /// </remarks> private static void ShutdownIfNeededAndThrow(string msg) { #if DEBUG IoCSetup.ShutdownAndExit("Shutting down - " + msg, 1); Thread.Sleep(1000); #endif throw new AssertException(msg); }
/// <summary> /// Register a WCF service and implementation with the IoC /// </summary> /// <para> /// WCF configuration is finicky. If you want metadata published, you need to use BaseAddresses rather /// than configuring the endpoint with .At() -- which is the interface that most examples use. Also, /// metadata cannot be published over the Net.Tcp transport; it only works over Http. So if you are /// using Net.Tcp and want metadata published then you have to have an Http base address in addition /// to the Net.Tcp address. And in this case, the Http base address and the Net.Tcp address must /// have different port numbers (because you can't have two different transports bound to the /// same port). /// </para> /// <para> /// For self-hosted services, you must *not* use .Hosted() on the service model, as that indicates /// the services lives in IIS/WAS. Also, the service implementation must *not* have a ServiceBehaviour /// attribute, because that will cause .NET to try and create the service host and it demands a /// parameter-less constructor (which we don't have since we're trying to do dependency injection /// via constructor parameters). /// </para> /// <para> /// To register different endpoint behaviours the behaviour must be added to the endpoint instance as an extension (AddExtension). /// Adding the endpoint behaviours to the serviceModel directly fails if the same endpoint behaviour is registered for another service. /// </para> /// <para> /// Every service will be registered with a unique random name because registering 2 services with different (I) interfaces but same implementation (C) /// conflicts with Castle Windsor - it needs a unique name. /// The unique name is never been used to resolve the registered service. It is only needed to generate a unique key for Castle Windsor. /// Resolve the service with the proper interface (I). /// </para> /// </remarks> /// <typeparam name="I">interface for service</typeparam> /// <typeparam name="C">implementation class for service</typeparam> /// <param name="serviceName">service name (used in endpoint URL)</param> /// <param name="http">indicates whether to use the HTTP transport or Net.Tcp</param> /// <param name="streamed">whether the service needs a streamed protocol</param> /// <param name="port">the port number to use for the service</param> /// <param name="mexPort">the port for the mex endpoint (only used if http == false)</param> /// <param name="maxMsg">the max message size configuration parameter for WCF</param> /// <param name="sendTimeout">WCF service timeout to send a message</param> /// <param name="receiveTimeout">WCF service timeout to receive a message</param> /// <param name="useExternalEndpointBehaviour">Optional: Flag to add external endpoint behaviour (<c>true</c>) or the default endpoint behaviour. Default: false</param> public void RegisterWCFServiceImpl <I, C>(string serviceName, bool http, bool streamed, int port, int mexPort, int maxMsg, TimeSpan sendTimeout, TimeSpan receiveTimeout, bool useExternalEndpointBehaviour) where I : class where C : I { Func <int, string, string> GenAddr = GetServiceAddressNetTCP; if (http) { GenAddr = GetServiceAddressHTTP; } var serviceUri = GenAddr(port, serviceName); List <string> baseAddresses = new List <string>(); var endPoint = CreateEndpoint( GetEndpoint(serviceUri, streamed, maxMsg, sendTimeout, receiveTimeout), this.CreateEndpointBehaviour(useExternalEndpointBehaviour), baseAddresses, serviceUri); if (!http) { var mexUri = GetServiceAddressHTTP(mexPort, serviceName); baseAddresses.Add(mexUri); } try { var serviceModel = new DefaultServiceModel() .PublishMetadata(o => o.EnableHttpGet()) .AddBaseAddresses(baseAddresses.ToArray()); serviceModel.AddEndpoints(endPoint); string uniqueRegistrationName = Guid.NewGuid().ToString(); Kernel.Register(Component .For <I>() .ImplementedBy <C>() .AsWcfService(serviceModel) .Named(uniqueRegistrationName)); Logger.InfoFormat("START and REGISTER service '{0}' - listening at [{1}]: Endpoint-Behaviour-Count: {2}, Use-External-EndpointBehaviour = '{3}'.", serviceName, serviceUri, serviceModel.Extensions.Count(), useExternalEndpointBehaviour.ToString()); } catch (Exception ex) { var msg = string.Format("Error: Service registration failed for address = [{0}], Use-External-EndpointBehaviour = '{1}', Ex='{2}'", serviceUri, useExternalEndpointBehaviour.ToString(), ex.ToString()); Logger.Fatal(msg); IoCSetup.ShutdownAndExit(msg, 1); } }