namespace WcfTesting { using System; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; /// /// /// public static class ServiceTestContext { public static Binding Binding { get; set; } static ServiceTestContext() { Binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); } /// /// Sets up a service test context. /// /// The service implementation /// A to be used as a fluent interface. public static ServiceTestBuilder Test() { return new ServiceTestBuilder(typeof(TService)); } private static void Execute(ServiceTestBuilder builder) { var serviceAddress = new Uri(builder.ServiceAddress + builder.ContractType.Name); // Disambiguate var host = Activator.CreateInstance(builder.ServiceHostType, builder.ServiceType, serviceAddress) as ServiceHost; if (host == null) { throw new InvalidOperationException(string.Format("Could not create an instance of the {0} type.", builder.ContractType.Name)); } if (builder.IncludeExceptionDetails) { var sdb = host.Description.Behaviors.Find(); sdb.IncludeExceptionDetailInFaults = true; } host.AddServiceEndpoint(builder.ContractType, builder.Binding, string.Empty); host.Open(); object client = CreateClientProxy(builder.ContractType, builder.Binding, serviceAddress); OperationContextScope ctx = null; if (builder.EstablishOperationContextScope) { ctx = new OperationContextScope((IContextChannel)client); } builder.ClientAction.DynamicInvoke(client); if (ctx != null) { ctx.Dispose(); } host.Abort(); // Fail-fast (instead of .Close() ) } private static object CreateClientProxy(Type contractType, Binding binding, Uri uri) { var concreteFactoryType = typeof(ChannelFactory<>).MakeGenericType(contractType); return concreteFactoryType.InvokeMember("CreateChannel", BindingFlags.Public | /* public static method invocation */ BindingFlags.Static | BindingFlags.InvokeMethod, null, /* default binder */ null, /* no instance - static method */ new object[] { binding, /* WCF Binding */ new EndpointAddress(uri) /* Service Endpoint */ } ); } public class ServiceTestBuilder { private Binding _binding; private Uri _serviceAddress; public Type ServiceHostType { get; private set; } public Type ServiceType { get; private set; } public Type ContractType { get; private set; } public Delegate ClientAction { get; private set; } public bool EstablishOperationContextScope { get; private set; } public bool IncludeExceptionDetails { get; private set; } public Binding Binding { get { if (_binding == null) { _binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); } return _binding; } set { _binding = value; } } public Uri ServiceAddress { get { if (_serviceAddress == null) { _serviceAddress = new Uri("net.pipe://localhost/test/"); } return _serviceAddress; } set { _serviceAddress = value; } } public ServiceTestBuilder(Type serviceType) { ServiceType = serviceType; EstablishOperationContextScope = true; } public ServiceTestBuilder ExposeAt(string address) { ServiceAddress = new Uri(address); return this; } public ServiceTestBuilder WithBinding(Binding binding) { Binding = binding; return this; } public ServiceTestBuilder HostIn() where TServiceHost : ServiceHost { ServiceHostType = typeof(TServiceHost); return this; } public ServiceTestBuilder DisableOperationContext() { EstablishOperationContextScope = false; return this; } public ServiceTestBuilder FlowExceptionDetails() { IncludeExceptionDetails = true; return this; } public void FromContract(Action clientAction) { ContractType = typeof(TContract); ClientAction = clientAction; ServiceTestContext.Execute(this); } } } }