Project: Wcf.Testing



void Main()
{
	var serviceConfiguration =
		new ServiceConfiguration(
			new NetTcpBinding(SecurityMode.None), 
			"localhost", 
			8900, 
			int.MaxValue, 
			int.MaxValue, 
			true);
			
	using (var host = new WcfTestHost<ICustomerService>(new CustomerService(), serviceConfiguration))
	{
		host
			.CreateProxy()
			.GetAll().Dump();
	}
}

public class CustomerService : ICustomerService
{
	public IQueryable<Customer> GetAll()
	{
		return
			new List<Customer> { new Customer { Name = "Bill" } }.AsQueryable();
	}
}

[ServiceContract]
public interface ICustomerService
{
	[OperationContract]
	IQueryable<Customer> GetAll();
}

public class Customer { public string Name { get; set; } }

public class ServiceConfiguration
{
	public ServiceConfiguration(Binding binding, string hostName, int port, long maxReceivedMessageSize, int maxBufferSize, bool prepareForLongOperation)
	{
		Binding = binding;
		HostName = hostName;
		Port = port;
		MaxReceivedMessageSize = maxReceivedMessageSize;
		MaxBufferSize = maxBufferSize;
		PrepareForLongOperation = prepareForLongOperation;

		Url =
			string
				.Format(
					"{0}://{1}:{2}//{3}",
					binding.Scheme,
					hostName,
					port,
					Guid.NewGuid());
	}

	public Binding Binding { get; private set; }

	public string HostName { get; private set; } 

	public int Port { get; private set; }

	public long MaxReceivedMessageSize { get; private set; }
	
	public int MaxBufferSize { get; private set; }

	public bool PrepareForLongOperation { get; private set; }

	public string Url { get; private set; }
}

public class UnhandledErrorFault
{
	public UnhandledErrorFault(Exception ex, string message, string stackTrace)
	{
		if (ex != null)
		{
			ExceptionType = ex.GetType().FullName;
		}

		Message = message;
		StackTrace = stackTrace;
	}

	public string ExceptionType
	{
		get; 
		private set;
	}

	public string Message
	{
		get; 
		private set;
	}

	public string StackTrace
	{
		get; 
		private set;
	}
}
	
internal class ErrorHandlerBehavior : IErrorHandler, IServiceBehavior
{
	private Type ServiceType
	{
		get;
		set;
	}

	void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase host)
	{
	}

	void IServiceBehavior.AddBindingParameters(
		ServiceDescription description,
		ServiceHostBase host,
		Collection<ServiceEndpoint> endpoints,
		BindingParameterCollection parameters)
	{   
	}

	void IServiceBehavior.ApplyDispatchBehavior(
		ServiceDescription description,
		ServiceHostBase host)
	{
		ServiceType = description.ServiceType;

		foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers)
		{
			dispatcher.ErrorHandlers.Add(this);
		}
	}

	bool IErrorHandler.HandleError(Exception error)
	{
		return false;
	}

	void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
	{
		var faultException = error as FaultException;

		if (faultException == null)
		{
			var data = new UnhandledErrorFault(error, error.Message, error.StackTrace);
			faultException = new FaultException<UnhandledErrorFault>(data);
		}

		var messageFault = faultException.CreateMessageFault();
		fault = Message.CreateMessage(version, messageFault, faultException.Action);
	}
}

public class InstanceProvider 
	: IInstanceProvider
{
	private readonly object serviceInstance;

	public InstanceProvider(object serviceInstance)
	{
		this.serviceInstance = serviceInstance;
	}

	public object GetInstance(InstanceContext instanceContext)
	{
		return GetInstance(instanceContext, null);
	}

	public object GetInstance(InstanceContext instanceContext, Message message)
	{
		return serviceInstance;
	}

	public void ReleaseInstance(InstanceContext instanceContext, object instance)
	{
	}
}

public class DependencyServiceBehavior 
	: IServiceBehavior
{
	private readonly object serviceInstance;

	public DependencyServiceBehavior(object serviceInstance)
	{
		this.serviceInstance = serviceInstance;
	}

	public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
	{
		foreach (var endpoint in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>().SelectMany(cd => cd.Endpoints))
		{
			endpoint.DispatchRuntime.InstanceProvider =
				new InstanceProvider(serviceInstance);
		}
	}

	public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
	{
	}

	public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
	{
	}
}

public class WcfServiceFactory<TServiceContract>
{
	private TimeSpan timeSpan = new TimeSpan(0, 0, 20);

	public ICommunicationObject Create(TServiceContract service, ServiceConfiguration serviceConfiguration)
	{
		if (serviceConfiguration.PrepareForLongOperation)
		{
			timeSpan = new TimeSpan(0, 0, 50, 0);

			var readerQuotas = 
				new XmlDictionaryReaderQuotas
					{
						MaxArrayLength = 100 * 1024 ////Set max array size to 100kb
						////MaxStringContentLength = _sanebutusablelimit_,
						////MaxBytesPerRead = _sanebutusablelimit_,
						////MaxDepth = _sanebutusablelimit_,
						////MaxNameTableCharCount = _sanebutusablelimit_
					};

			serviceConfiguration
				.Binding
				.GetType()
				.GetProperty("ReaderQuotas")
				.SetValue(serviceConfiguration.Binding, readerQuotas, null);

			var dynamicBinding = (dynamic)serviceConfiguration.Binding;
			dynamicBinding.MaxBufferPoolSize = int.MaxValue;
			dynamicBinding.MaxBufferSize = serviceConfiguration.MaxBufferSize;
			dynamicBinding.MaxReceivedMessageSize = serviceConfiguration.MaxReceivedMessageSize;
		}

		serviceConfiguration.Binding.OpenTimeout = timeSpan;
		serviceConfiguration.Binding.CloseTimeout = timeSpan;
		serviceConfiguration.Binding.SendTimeout = timeSpan;
		serviceConfiguration.Binding.ReceiveTimeout = timeSpan;

		var host =
			new ServiceHost(service.GetType()) 
				{
					CloseTimeout = timeSpan,
					OpenTimeout = timeSpan
				};

		var serviceContractType = typeof(TServiceContract);

		host.AddServiceEndpoint(serviceContractType, serviceConfiguration.Binding, serviceConfiguration.Url);

		var serviceDebugBehavior = (ServiceDebugBehavior)host.Description.Behaviors[typeof(ServiceDebugBehavior)];

		if (host.Description.Behaviors.Find<ErrorHandlerBehavior>() == null)
		{
			host.Description.Behaviors.Add(new ErrorHandlerBehavior());
		}

		host.Description.Behaviors.Add(new DependencyServiceBehavior(service));

		serviceDebugBehavior.IncludeExceptionDetailInFaults = true;

		try
		{
			host.Open();
		}
		catch (TimeoutException timeoutException)
		{
			Debug.WriteLine("Failed to close the service host - Exception: " + timeoutException.Message);
			throw;
		}
		catch (CommunicationException communicationException)
		{
			if (communicationException.Message.Contains("10013"))
			{
				PortAlreadyUsed(serviceConfiguration, communicationException);
			}

			Debug.WriteLine("Failed to close the service host - Exception: " + communicationException.Message);
			throw;
		}

		return host;
	}

	private void PortAlreadyUsed(ServiceConfiguration serviceConfiguration, CommunicationException communicationException)
	{
		var message =
			string.Format("The port {0} used for the test could be in use by another application.", serviceConfiguration.Port);

		throw new CommunicationException(message, communicationException);
	}
}
	
public class WcfTestHost<TServiceContract>
	: IDisposable
{
	private readonly ServiceConfiguration serviceConfiguration;

	private readonly TServiceContract serviceInstance;

	private ICommunicationObject host;
	private ChannelFactory<TServiceContract> factory;
	private TServiceContract proxy;

	public WcfTestHost(TServiceContract serviceInstance, ServiceConfiguration serviceConfiguration)
	{
		this.serviceConfiguration = serviceConfiguration;
		this.serviceInstance = serviceInstance;
	}

	public TServiceContract CreateProxy()
	{
		host =
			new WcfServiceFactory<TServiceContract>()
				.Create(serviceInstance, serviceConfiguration);

		factory = new ChannelFactory<TServiceContract>(serviceConfiguration.Binding);
		proxy = factory.CreateChannel(new EndpointAddress(serviceConfiguration.Url));

		return proxy;
	}

	public void Dispose()
	{
		if (factory != null)
		{
			if (factory.State == CommunicationState.Opened)
			{
				factory.Close();
			}

			factory = null;
		}

		TearDown();
	}


	private void TearDown()
	{
		if (host == null)
		{
			return;
		}

		try
		{
			if (host.State == CommunicationState.Opened || host.State == CommunicationState.Opening)
			{
				host.Close(new TimeSpan(0, 0, 0, 1));
			}
		}
		catch (TimeoutException timeoutEx)
		{
			Debug.WriteLine("Failed to close the service host - Exception: " + timeoutEx.Message);
		}
		catch (CommunicationException communicationEx)
		{
			Debug.WriteLine("Failed to close the service host - Exception: " + communicationEx.Message);
		}
		catch (Exception ex)
		{
			Debug.WriteLine("Exception: " + ex.Message);
			throw;
		}
		finally
		{
			host = null;
		}
	}
}

Last edited Mar 29, 2012 at 3:43 PM by teoarch, version 1

Comments

No comments yet.