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