Injecting dependencies into an IErrorHandler implementation - wcf

I am implementing IErrorHandler in order to centralize all of the error handling for my WCF service in one place. This works fairly well:
public class ServiceErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
// ..Log..
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// ..Provide fault..
}
}
Now, we're using Ninject to inject dependencies in the rest of the service, and I'd like to do the same here. Since WCF is constructing the objects based on my configuration, and I don't think I have any hooks into this process, I need to use property injection:
[Inject]
public ILoggingService Logger { get; set; }
However, this never seems to get injected. I tried using Ninject's MVC extensions to set ServiceErrorHandler to allow injection like a filter, but that didn't seem to do the trick. Is there a way to make this happen?

Late answer, but you can inject dependencies into IErrorHandler by creating your custom ServiceHost, let's say TestServiceHost.
In your TestServiceHost you need to do:
Implement constructor with IErrorHandler parameter.
Inside, create a private nested class named ErrorHandlerBehaviour*, which needs to implement both IServiceBehavior and IErrorHandler. It also must have constructor with IErrorHandler parameter.
Override OnStarting() method, where you will add ErrorHandlerBehaviour to service behaviours. All behaviours must be added before base.OnStarting().
*the idea came from Juval Lowy's example in book - "Programming WCF Services". More information about Faults and Error extensions you can find there.
Here is the working host console application. I don't use IoC there, just Pure DI, but you can easily resolve logger with any IoC you want:
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace ConsoleHost
{
class Program
{
static void Main(string[] args)
{
var logger = new DummyLogger();
var errorHandler = new TestErrorHandler(logger);
ServiceHost host = new TestServiceHost(errorHandler, typeof(TestService), new Uri("net.tcp://localhost:8002"));
host.Open();
Console.WriteLine("Press enter to exit");
Console.ReadKey();
}
}
[ServiceContract]
public interface ITestService
{
[OperationContract]
string Test(int input);
}
public class TestService : ITestService
{
public string Test(int input)
{
throw new Exception("Test exception!");
}
}
public class TestErrorHandler : IErrorHandler
{
private ILogger Logger { get; }
public TestErrorHandler(ILogger logger)
{
Logger = logger;
}
public bool HandleError(Exception error)
{
Logger.Log(error.Message);
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException fe = new FaultException();
MessageFault message = fe.CreateMessageFault();
fault = Message.CreateMessage(version, message, null);
}
}
public class TestServiceHost : ServiceHost
{
private readonly IErrorHandler errorHandler;
public TestServiceHost(IErrorHandler errorHandler, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
this.errorHandler = errorHandler;
}
protected override void OnOpening()
{
Description.Behaviors.Add(new ErrorHandlerBehaviour(errorHandler));
base.OnOpening();
}
class ErrorHandlerBehaviour : IServiceBehavior, IErrorHandler
{
private readonly IErrorHandler errorHandler;
public ErrorHandlerBehaviour(IErrorHandler errorHandler)
{
this.errorHandler = errorHandler;
}
bool IErrorHandler.HandleError(Exception error)
{
return errorHandler.HandleError(error);
}
void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
errorHandler.ProvideFault(error, version, ref fault);
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
channelDispatcher.ErrorHandlers.Add(this);
}
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}
// Dummy logger
public interface ILogger
{
void Log(string input);
}
public class DummyLogger : ILogger
{
public void Log(string input) => Console.WriteLine(input);
}
}
And configuration:
<system.serviceModel>
<services>
<service name="ConsoleHost.TestService">
<endpoint address="net.tcp://localhost:8002/TestService"
binding="netTcpBinding"
contract="ConsoleHost.ITestService" />
</service>
</services>
</system.serviceModel>
Btw. Make sure you added System.Runtime.Serialization to your references

Related

WCF One method to execute before every service method's call

I am looking for a way to execute specific method, at the server side, on every request method's call.
This is for security validations but not only.
This is NOT duplicated with this question since we mean to completely different things and. I addition, all the relevant answers there have unavailable links so it's impossible to get to the right answer.
(Sorry I haven't attached any code here, there is no code to specify in this issue).
The best solution is to create WCF custom behavior.
Here is how you do this by several simple steps:
Client Side:
public class FillHeaderDataBehaviourExtension : BehaviorExtensionElement, IEndpointBehavior
{
#region BehaviorExtensionElement Implementation
public override Type BehaviorType
{
get
{
return typeof(FillHeaderDataBehaviourExtension);
}
}
protected override object CreateBehavior()
{
return this;
}
#endregion
#region IServiceBehaviour Implementation
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new MessageInspector());
}
#endregion
}
public class MessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
MessageHeader header = MessageHeader.CreateHeader("HeaderData", String.Empty, HeaderDataVM.GetInstance().GetBaseInstance());
request.Headers.Add(header); // There is no need for checking if exist before adding. Every request has it's own headers.
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
}
Server Side:
public class ExtractHeadersBehaviourExtension : BehaviorExtensionElement, IServiceBehavior
{
#region BehaviorExtensionElement Implementation
public override Type BehaviorType
{
get
{
return typeof(ExtractHeadersBehaviourExtension);
}
}
protected override object CreateBehavior()
{
return this;
}
#endregion
#region IServiceBehavior Implementation
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
{
ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
if (channelDispatcher != null)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
MessageInspector inspector = new MessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
#endregion
}
public class MessageInspector : IDispatchMessageInspector
{
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
HeaderData headerData = request.Headers.GetHeader<HeaderData>("HeaderData", String.Empty);
if(headerData != null)
{
OperationContext.Current.IncomingMessageProperties.Add("HeaderData", headerData);
}
return null;
}
}
And finally, don't forget to configure it in the app.config files (client & server side) as follows:
<behaviors>
<endpointBehaviors>
<behavior name="NewBehavior">
<fillHeaderDataBehaviourExtension/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
You can also add these lines via the WCF config editor. To do so, look at this answer.
EDIT: You might get an error in the app config after adding these lines of configuration code:
Don't worry about this, your application will run fine. It causes because the GAC (Global Assembly Cache) folder doesn't contain this behavior (since it is a custom behavior). You can fix it by adding this behavior manually to your GAC folder on your computer.
However, this error might prevent you from updating service reference. If you try to, you'll get this error message:
So just comment out this line (<extractHeadersBehaviourExtension/>) (in client & server side) when you update your service reference.
Sources: How to add behavior on a specific endpoint? &
Adding Custom Message Headers to a WCF Service

Singleton DBContext for a Per-Call WCF Service using castle

I am trying find a proper way of injecting an EF6 DbContext into my WCF service but I kind of struggle to find a proper working example. Does anyone know of a good demonstration of a per-call WCF service and Entity framework? I use Castle for the injection however any other IOC container is welcomed. If you are against using Singleton dbcontext [Massive DB] please show me a working example with the least performance hit.
This worked for me:
Create a concrete context interface:
public class CustomersContext :DbContext, ICustomerContext
Then register in the container as singleton
container.Register(Component.For<ICustomerContext>().ImplementedBy<CustomersContext>());
Then you should register it as a WCF service and provide your own Instance Provider
like this:
First add some attributes to your interface:
[InstanceProviderBehavior(typeof (ICustomerContext))]
[DataContract]
public class CustomersContext :DbContext, ICustomerContext
Then, write the InstanceProviderBehavior attribute:
public class InstanceProviderBehaviorAttribute : Attribute, IServiceBehavior
{
private readonly Type _type;
public InstanceProviderBehaviorAttribute(Type type)
{
_type = type;
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
if (!ed.IsSystemEndpoint)
{
ed.DispatchRuntime.InstanceProvider = new WindsorServiceInstanceProvider(_type);
}
}
}
}
}
Note that you tell the WCF to use the WindsorServiceInstanceProvider.
Here it is:
public class WindsorServiceInstanceProvider : IInstanceProvider
{
public static IWindsorContainer Container;
private readonly Type _type;
public WindsorServiceInstanceProvider(Type type)
{
_type = type;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return Container.Resolve(_type);
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
Container.Release(instance);
}
}
Please note the static object named Container, this is pretty ugly, but I didnt find any other way to pass my container instance into the InstanceProvider
Thats it. now, when some client will ask for ICustomerContext from your WCF service, it will resolve it from your container.
More about WCF Instance Provider here

Catching generic FaultException<T> thrown from IErrorHandler?

For a service, there is a group of faults which can be thrown by all operations, so in order to centralize that, I have made a behavior, FaultAdderBehavior, which adds fault contracts to all operations on a service. It seems to work fine as the contracts are added to the WSDL and the client can catch the fault with a line like:
...
catch(FaultException<MyFault> e){ ... }
...
I have also made an IErrorHandler which converts non-fault exceptions to a certain kind of fault. See below.
The problem is, that the fault which is constructed in the error handler cannot be caught on the client. That is, it cannot be caught as a generic FaultException<MyFault>, but only as FaultException.
If I explicitly adds a FaultContract(typeof(MyFault)) to the operation, the client can suddenly catch the generic fault exception just fine.
So that could indicate that something is wrong with my FaultAdderBehavior after all. Or is there something wrong with my error handler?
I have noticed, that the fault.Action given as argument to CreateMessage() is null. This raises my concern.
Below is an example illustrating the problem. It is the method ShouldThrowFault() that causes headaches, while ThrowsDirectly() works exactly as desired.
To summarize, my question is: why can't the client catch the generic FaultException<MyFault> when it comes from the error handler?
[ServiceContract]
public interface IUncatchableFaultService
{
[OperationContract]
// [FaultContract(typeof(MyFault))]
void ShouldThrowFault(string arg1);
[OperationContract]
void ThrowsDirectly();
}
[FaultAdderBehavior(typeof(MyFault), typeof(MyFault2))]
[MyErrorHandlerBehavior]
internal class UncatchableFaultService : IUncatchableFaultService
{
public void ShouldThrowFault(string arg1)
{
throw new Exception();
}
public void ThrowsDirectly()
{
throw new FaultException<MyFault>(new MyFault());
}
}
[DataContract]
public class MyFault
{
}
[DataContract]
public class MyFault2
{
}
public class MyErrorHandlerBehaviorAttribute : Attribute, IServiceBehavior
{
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase dispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = dispatcherBase as ChannelDispatcher;
if (channelDispatcher == null) continue;
channelDispatcher.ErrorHandlers.Add(new MyErrorHandler());
}
}
private class MyErrorHandler : IErrorHandler
{
public void ProvideFault(Exception error, MessageVersion version, ref Message message)
{
if (error is FaultException) return;
var fault = new FaultException<MyFault>(new MyFault(), "I am a fault.");
MessageFault messageFault = fault.CreateMessageFault();
message = Message.CreateMessage(version, messageFault, fault.Action);
}
public bool HandleError(Exception error)
{
return false;
}
}
}
public class FaultAdderBehaviorAttribute : Attribute, IContractBehavior
{
private Type[] faults;
public FaultAdderBehaviorAttribute(params Type[] faults)
{
this.faults = faults;
}
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
foreach (OperationDescription op in contractDescription.Operations)
foreach (Type fault in this.faults)
op.Faults.Add(this.ExposeFault(fault));
}
private FaultDescription ExposeFault(Type fault)
{
string action = fault.Name;
DescriptionAttribute attr = (DescriptionAttribute)Attribute.GetCustomAttribute(fault, typeof(DescriptionAttribute));
if (attr != null) action = attr.Description;
FaultDescription description = new FaultDescription(action);
description.DetailType = fault;
description.Name = fault.Name;
return description;
}
}
There is a problem with FaultAdderBehaviorAttribute and you are right to be worried that fault.Action is null.
For FaultException functionality to work properly you must have non-null actions for each fault.
When you declare the FaultContract on the operation itself you are implicitly using WCF's ability to automatically generate the action string (further details). However, when you use your FaultAdderBehaviorAttribute, any default actions for declared operations have already been generated, and you are failing to provide a valid action.

How To Make WCF routing service log message to SQL server

I'm trying to use Routing Service (http://msdn.microsoft.com/en-us/library/ee517422.aspx) to route the data from clients to other end points. I have multiple clients and the end point which is called from routing service is located at a third party.
I also need to Log every transaction passed through routing service into SQL Database.
The problem is I can't write custom code in routing service as it's working from configuration files. Given that I can't write custom code in these classes, how can I achieve this?
1) create a class library and sign it with strong key.
2)create RoutingServiceBehavior class this class will implement IServiceBehavior, IDispatchMessageInspector interfaces, the code for message interception will be in this class:
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace Services.RoutingServiceBehavior
{
public class RoutingServiceBehavior : IServiceBehavior, IDispatchMessageInspector
{
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
// This is your envelop
string s = request.ToString();
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
}
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
}
3) Create RoutingServiceBehaviorElement class, this class will implement BehaviorExtensionElement interface:
using System;
using System.ServiceModel.Configuration;
namespace Services.RoutingServiceBehavior
{
public class RoutingServiceBehaviorElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(RoutingServiceBehavior); }
}
protected override object CreateBehavior()
{
return new RoutingServiceBehavior();
}
}
}
4)Build your project.
5)Add your assembly to GAC.
6)Open machine.config and add the name of your assembly under <behaviorExtensions> it shall look like that:
<add name="RoutingServiceBehavior" type="Services.RoutingServiceBehavior.RoutingServiceBehaviorElement, Services.RoutingServiceBehavior, Version=1.0.0.0, Culture=neutral" />
7) add the name of your service behavior in your wcf service under <serviceDebug>
<RoutingServiceBehavior/>
8)Make sure that the assembly dlls are included in your WCF service.

Using Unity Dependency Injection with WCF services

I have the following after doing some research on other questions:
MyServiceHost:
public class MyServiceHost : ServiceHost
{
public MyServiceHost(IUnityContainer container, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
foreach (var cd in this.ImplementedContracts.Values)
{
cd.Behaviors.Add(new DependencyInjectionInstanceProvider(container));
}
}
}
DependencyInjectionInstanceProvider:
public class DependencyInjectionInstanceProvider : IInstanceProvider, IContractBehavior
{
private readonly IUnityContainer container;
public DependencyInjectionInstanceProvider(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
#region IInstanceProvider Members
public object GetInstance(InstanceContext instanceContext, Message message)
{
return this.GetInstance(instanceContext);
}
public object GetInstance(InstanceContext instanceContext)
{
var serviceType = instanceContext.Host.Description.ServiceType;
return this.container.Resolve(serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
this.container.Teardown(instance);
}
#endregion
#region IContractBehavior Members
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider = this;
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
#endregion
}
MyServiceHostFactory:
public class MyServiceHostFactory : ServiceHostFactory
{
private readonly IUnityContainer container;
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new MyServiceHost(this.container, serviceType, baseAddresses);
}
}
Email Service with an attempted Constructor Injection:
public class EmailValidator : IEmailValidator
{
private IFakeDAL fakeDAL;
public EmailValidator(IFakeDAL fakeDAL)
{
this.fakeDAL = fakeDAL;
}
public bool ValidateAddress(string emailAddress)
{
Console.WriteLine("Validating: {0}", emailAddress);
string pattern = #"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*#(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$";
return Regex.IsMatch(emailAddress, pattern);
}
}
My Console Host to start the Service:
static void Main(string[] args)
{
Type serviceType = typeof(EmailValidator);
Uri serviceUri = new Uri("http://localhost:8080/");
MyServiceHostFactory shf = new MyServiceHostFactory();
ServiceHost host = shf.CreateServiceHost(serviceType, serviceUri);
//ServiceHost host = new ServiceHost(serviceType, serviceUri);
host.Open();
My problem resides in the console host logic. The CreateServiceHost call has a syntax error due to the first argument expecting a Constructor string and not a Type. Which I don't understand since it does accept a Type parameter. In addition to that I don't understand where I should be mapping IFakeDAL to a concrete class. Can I do that in an app.config file or should I register that somewhere else?
ServiceHostFactory is for hosting in IIS. In self hosting you should use your derived ServiceHost directly. Here you have whole example including Unity configuration.
I´m using the following classes in my windows service to create WCF services and inject dependencies to it using unity.
UnityInstanceProvider:
internal class UnityInstanceProvider : IInstanceProvider {
private readonly IUnityContainer container;
private readonly Type contractType;
public UnityInstanceProvider(IUnityContainer container, Type contractType) {
this.container = container;
this.contractType = contractType;
}
public object GetInstance(InstanceContext instanceContext) {
return GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message) {
return container.Resolve(contractType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance) {
container.Teardown(instance);
}
}
UnityServiceBehavior:
public class UnityServiceBehavior : IServiceBehavior {
private readonly IUnityContainer container;
public UnityServiceBehavior(IUnityContainer container) {
this.container = container;
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) {
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) {
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints) {
if (endpointDispatcher.ContractName != "IMetadataExchange") {
string contractName = endpointDispatcher.ContractName;
ServiceEndpoint serviceEndpoint = serviceDescription.Endpoints.FirstOrDefault(e => e.Contract.Name == contractName);
endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(this.container, serviceEndpoint.Contract.ContractType);
}
}
}
}
}
UnityServiceHost:
public class UnityServiceHost : ServiceHost {
private IUnityContainer unityContainer;
public UnityServiceHost(IUnityContainer unityContainer, Type serviceType)
: base(serviceType) {
this.unityContainer = unityContainer;
}
protected override void OnOpening() {
base.OnOpening();
if (this.Description.Behaviors.Find<UnityServiceBehavior>() == null) {
this.Description.Behaviors.Add(new UnityServiceBehavior(this.unityContainer));
}
}
}
With this classes you can do the following (The configuration of services is done in .config):
UnityContainer container = new UnityContainer();
UnityServiceHost serviceHost = new UnityServiceHost(container, typeof("Type of Service to host"));
serviceHost.Open();
The CreateServiceHost method expects an array of Uri instances, so try this instead:
ServiceHost host = shf.CreateServiceHost(serviceType, new[] { serviceUri });
You can map interfaces to types in either XML or code, but I'd recommend code, since XML has too high a maintenance overhead.
The Main method is an excellent Composition Root, but if you want to configure the container at that level, you'll need to pass it from the Main method to MyServiceHostFactory - which is perfectly fine when you host the service in a console application, but will not work if you want to host it in IIS, where MyServiceHostFactory should be the Composition Root, since IIS requires a default constructor.