A model SOA application in .NET Part 6: the client proxy

Introduction

In the previous post we got as far as creating a service layer. Now it’s time to build a client proxy on that, i.e. a layer that the external clients of the service can send their requests to. We’ll use the the Web API technology to build this layer. If you’ve read through the other software architecture series on this blog you’ll see that Web API is very dear to me as it’s very simple to set up and use.

The client proxy

In this section I’ll refer a lot to this post in the series on the DDD skeleton project. Make sure you get familiar with it as it contains a lot of information that’s relevant to this post. In that post I show you how to add a web API project and transform it so that it only contains the web service relevant parts. We don’t want to deal with views, JS files, images etc. in a web service project. I also go through the basics of how to install and use the IoC called StructureMap in an MVC-based project. It will be responsible for resolving dependencies such as the ones in this constructor:

public ProductService(IMessageRepositoryFactory messageRepositoryFactory, IProductRepositoryFactory              productRepositoryFactory)

Add a new MVC4 web application called SoaIntroNet.WebProxy to the solution. Make sure to select the Web API template in the MVC4 Project Template window. Add a reference to all other layers – this is necessary for the StructureMap IoC container as we’ll see in a bit.

Next get rid of the standard MVC4 web application components. Again, consult the above link to see how it can be done. Install StructureMap from NuGet. You should have the following simplified structure of the web client project:

Web project structure after changes

Add the following section to the Register method of WebApiConfig.cs in the App_Start folder to make sure that we respond with JSON:

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;			
config.Formatters.Remove(config.Formatters.XmlFormatter);

In the same method you’ll see that the API calls are routed to api/controller/id by default. Remove the ‘api’ bit as follows:

config.Routes.MapHttpRoute(
	name: "DefaultApi",
	routeTemplate: "{controller}/{id}",
	defaults: new { id = RouteParameter.Optional }
	);	

Add a folder called Helpers to the web layer. Add the following two classes with extension methods:

public static class ExceptionDictionary
{
	public static HttpStatusCode ConvertToHttpStatusCode(this Exception exception)
	{
		Dictionary<Type, HttpStatusCode> dict = GetExceptionDictionary();
		if (dict.ContainsKey(exception.GetType()))
		{
			return dict[exception.GetType()];
		}
		return dict[typeof(Exception)];
	}

	private static Dictionary<Type, HttpStatusCode> GetExceptionDictionary()
	{
		Dictionary<Type, HttpStatusCode> dict = new Dictionary<Type, HttpStatusCode>();
		dict[typeof(ResourceNotFoundException)] = HttpStatusCode.NotFound;
                dict[typeof(LimitedAvailabilityException)] = HttpStatusCode.InternalServerError;
		dict[typeof(Exception)] = HttpStatusCode.InternalServerError;
		return dict;
	}
}	
public static class HttpResponseBuilder
{	
	public static HttpResponseMessage BuildResponse(this HttpRequestMessage requestMessage, ServiceResponseBase baseResponse)
	{
		HttpStatusCode statusCode = HttpStatusCode.OK;
		if (baseResponse.Exception != null)
		{
			statusCode = baseResponse.Exception.ConvertToHttpStatusCode();
			HttpResponseMessage message = new HttpResponseMessage(statusCode);
			message.Content = new StringContent(baseResponse.Exception.Message);
			throw new HttpResponseException(message);
		}
		return requestMessage.CreateResponse<ServiceResponseBase>(statusCode, baseResponse);
	}
}

Set the namespace of both classes to SoaIntroNet.WebProxy so that they are available from everywhere in the Web project without having to set using statements.

Add a new Web API controller in the Controllers folder. Name it ReservationController and make sure to select the Empty Api controller template in the Add Controller window. You’ll see that the controller derives from ApiController. The controller will need the services of the IProductService interface so add the following private field and controller:

private readonly IProductService _productService;

public ReservationController(IProductService productService)
{
	if (productService == null) throw new ArgumentNullException("IProductService");
	_productService = productService;
}

If you are familiar with the SOLID principles then you’ll understand why it’s important to inject an abstract dependency through the constructor this way. If not, then start here.

The client will need to send a POST request with the parameters needed to build a ReserveProductRequest object. This is as simple as inserting a Post() method in the controller which accepts a ReserveProductRequest object. The implementation is equally simple: we delegate the actual work to the product service:

ServiceResponseBase response = _productService.ReserveProduct(reserveProductRequest);
return Request.BuildResponse(response);

Insert another controller in the Controllers folder called PurchaseController. It too will depend on the product service so insert the following private field and constructor:

private readonly IProductService _productService;

public PurchaseController(IProductService productService)
{
	if (productService == null) throw new ArgumentNullException("IProductService");
	_productService = productService;
}

The product purchase will also be a POST operation:

public HttpResponseMessage Post(PurchaseProductRequest purchaseProductRequest)
{
	purchaseProductRequest.CorrelationId = purchaseProductRequest.ReservationId;
	ServiceResponseBase response = _productService.PurchaseProduct(purchaseProductRequest);
	return Request.BuildResponse(response);
}

The only major difference between the the two Post method structures is that here we set the correlation ID ourselves. It is set to the reservation ID which is unique and it makes sense to use as the message correlation ID to check if we have fulfilled the request. Otherwise the client could provide just any correlation ID so we cannot trust that input.

Finally we need to instruct StructureMap to fetch the correct dependencies. Locate IoC.cs in the DependencyResolution folder. Make sure it looks as follows:

public static IContainer Initialize()
{
	ObjectFactory.Initialize(x =>
				{
					x.Scan(scan =>
							{
								scan.TheCallingAssembly();
								scan.AssemblyContainingType<IProductService>();
								scan.AssemblyContainingType<IMessageRepository>();
								scan.WithDefaultConventions();
							});
					x.For<IMessageRepositoryFactory>().Use<LazySingletonMessageRepositoryFactory>();
					x.For<IProductRepositoryFactory>().Use<LazySingletonProductRepositoryFactory>();
				});
	ObjectFactory.AssertConfigurationIsValid();
	return ObjectFactory.Container;
}

We tell IoC where to look for concrete implementations and which concrete types to take in those cases where the standard ‘I’ naming convention doesn’t apply: (I)Service => Service. For more details consult the post I hinted at in the beginning of this post.

This actually completes the client proxy layer. In the next post we’ll test the proxy by building a console application client.

View the list of posts on Architecture and Patterns here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

2 Responses to A model SOA application in .NET Part 6: the client proxy

  1. Pingback: Architecture and patterns | Michael's Excerpts

  2. Pingback: Architecture and patterns | Michael's Excerpts

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: