.NET Developers’ user guide for troubleshooting networking problems Part 1

Introduction

As a programmer I normally don’t need to deal with hard-core networking issues in my job. The company I work at has a group of well-trained network engineers that fix network related problems for developers. However, I sometimes have the need to check some more basic things within networking to debug my code. Also, it can be beneficial to be able to follow along when network engineers discuss subnets, DNS records, ports and the like.

This is exactly the goal of this series: to help developers get to grips with the most basic concepts within networking. You certainly won’t become a professional networking engineer but you may not need that either.

Note: I did all demos on a Windows 7 machine. Other versions of Windows may output the values in a different format.

A network request

What happens when you enter a URL in your browser and press enter?

Networking diagram

The client wants to view http://www.bbc.co.uk to read the news so she enters that URL in the browser. The URL must then be converted into an IP address by the client computer therefore it needs to find out the IP address of http://www.bbc.co.uk. It performs this task by a service called DNS or Domain Naming System.

So it consults its configured DNS servers for the IP address of bbc.co.uk. The DNS server looks up the IP address and sends it back to the client. The client can now go out to the Internet through its switch and router and reach the data centre where the server is located. It will then pass through a firewall and switches to finally arrive at the web server. In the web server it enters the networking stack of the operating system, usually followed by a host based firewall and at last it reaches the process that’s the actual web server.

The data is then sent back to the client in the form of HTML, JSON, XML or whatever the format of the web application and it is rendered on the client machine.

The IP address

Each node in the network has an IP address, which is analogous to the unique address of your home. The postman needs to find you somehow so he will read the address on the letter and deliver it to your letterbox.

An IPv4 address is made up of 4 octets separated by a period similar to the following: 83.183.46.130.

Then we have the subnet mask which defines which part of the IP address is the subnet and which part is the specific node on that network. A subnet mask may look as follows: 255.255.255.0. We’ll look at subnets in a future post but for the time being it’s enough to know that if you try to reach an IP address which is not part of your subnet then it has to go through the default gateway. The default gateway can have an address such as 192.168.0.254.

Then we have the DNS servers that the client computer will use to turn names into IP addresses. Their IP typically looks like 75.75.75.75 or 75.75.75.76.

It’s easy to check your own IP configuration. Open a command prompt and run the ‘ipconfig’ command. The no-args version of the command will show your basic network configuration:

ip config no args

You will see the IPv4 address, the subnet mask and the default gateway. If you run the command ‘ipconfig -all’ then you’ll get a lot more information. You’ll see your host name at the top of the output. You’ll also find the DNS server somewhere in the middle. Your computer is configured to point to that DNS server to translate http://www.bbc.co.uk into numbers. Also, you’ll see something called the DHCP server. The DHCP server, which stands for Dynamic Host Configuration Protocol, is where your computer obtains the IP configuration.

So when a machine comes online and needs an IP configuration then it sends out a message asking for one. The DHCP server will catch that message and will respond with an IP address, a subnet mask, a default gateway and one or more DNS servers. The client machine will then take that information to configure itself and respond to the DHCP server saying that it will use that address. The DHCP server will then know that this IP is in use and will not hand it out to any other online machine for a specified period of time:

ObtainingAnAddressFromDHCP

Starting with Windows 2000 if the client is unable to get hold of an IP address then eventually it will give itself an address in the 169.254 address range which is a range owned by Microsoft. The client will eventually send out a message saying “I’m using 169.254.x.x”. This scenario occurs extremely rarely but if you see that your computer is struggling to get an IP and gets an IP in this range then it’s telling you that something is wrong and you’re not getting a response from the DHCP server.

What’s IPv6?

The current IP version is use is version 4, or IPv4. With the format mentioned above, i.e. 4 octets we get 2^32 – 2 raised to the power of 32 – different addresses. That’s quite a large number but is definitely finite and we’re soon reaching its upper limit.

IPv6 has been developed to extend the number of possible variations to 2^128 which is so large that we’ll enough left for all visiting extraterrestrials in the year of 10000.

Now IPv4 and IPv6 are running parallel. That’s why the ipconfig command gave you both and IPv4 and an IPv6 address. The ultimate goal is to only go forward with IPv6 sometime in the future.

You’ll see that the format of IPv6 is very different from IPv4. Example: 2001:0:5ef5:79fd:20df:3736:3f57:ffbe. As a developer you need to be aware of the differences if you need to log or validate an IP address or your app needs to show the new format on the screen.

DNS

So how is the name resolved that you enter in the URL text box of your web browser? As we mentioned above the client is configured to point to an initial DNS server. Say that it’s configured to contact nameserverA.isp.com. Therefore the client is going to ask this DNS server to resolve a URL and get the IP address belonging to that URL. The first DNS server probably won’t have this record so it sends a request to the root name servers: do you know where I can find this URL? The root name servers only contain the name server locations for the top level domains: .info, .com, .uk etc. and it’s the only thing it knows. So the root NS responds the first name server, like “no, I only know about top level domains but you can ask the .com name server because I know it has more information.” So nameserverA.isp.com asks the .com name server. The .com name server will have information about where to find the IP addresses of all .com URLs so it tells nameserverA.isp.com to go and ask the cnn.com name server. The cnn.com name server will have all the information about the cnn.com namespace and responds with the IP address.

DNS name resolution

The image is a bit messy so make sure you follow all the arrows based on the description. As you see the configured name server nameserverA.isp.com has a central role in the quest for finding the IP address. It takes a couple of stops before the final answer has been found.

NsLookup

You can use the command line tool called NsLookup to perform DNS queries. Let’s try to look up the IP address of cnn.com:

NsLookup cnn.com

Alternatively you can just type ‘nslookup’, press enter and then you can perform multiple queries:

NsLookup multiple queries

You’ll see that cnn.com returned more than one IP address. It means that we can reach cnn.com using several different IP addresses. Try http://www.microsoft.com and you’ll see that it’s been aliased to akadns.net, which are Akamai addresses. Akamai is a Content Delivery Network solution for faster downloads: Akamai homepage.

When you’re done using nslookup in the multiple query mode you can just type exit to come back to the ‘normal’ command prompt mode. In case you want to change the DNS server for your lookup query then enter the multiple query mode again by typing ‘nslookup’ and run the command ‘server [ip of the dns server you want to ask]’, e.g. server 123.456.678.43 and then ask for http://www.microsoft.com to see if you get the same IP address as in the case of the default DNS server.

The DNS records are cached for a certain period of time in the name servers to speed up the queries. Even your local machine caches this information. In your command window type ping the following 3 URLs using the ping command:

ping http://www.cnn.com
ping http://www.bbc.co.uk
ping http://www.microsoft.com

Then enter the following command: ipconfig /displaydns. This will bring up a list of all records cached on your local machine including the ones you have just pinged:

Ip config display DNS

Check out the Time to Live value. The record microsoft.com is cached for about 3500 seconds on my local machine. Wait a little bit and enter the ipconfig /displaydns command again. You should see that the Time to Live value should decrease. It will eventually reach 0 when the record is cleared from the cache.

Be aware of this caching feature as if you change a DNS record it will take some time to propagate it around the internet. Initially the old record will be returned from the DNS server as it is still in the cache.

Caching also means that if you ask for microsoft.com in your browser multiple times then there’s no need to go through the same name server lookup process over and over again. The immediate name server configured for your computer will have it in its cache and will be able to respond immediately with the correct IP address.

Override DNS in the local host file

It’s possible to override the DNS values on your local machine. This is done in the host file. On Windows machines it is usually located in the C:\Windows\System32\drivers\etc folder. The file is called hosts and you can open and edit it like a normal text file. You can add your ip-name pairs to the file using the following format:

Host file

So the format is: the ip address followed by a tab and then the name. You can even enter localhost IPs where localhost is always 127.0.0.1. You can add multiple names for the same IP as follows:

Host file with multiple names

You can enter the same made up values that I have and save the file. Go back to the command window and type ipconfig /displaydns again. Saving the hosts file will automatically clear the local cache which will be populated with the values in the host file. You should see the values you have just entered in the host file in the command window output. Run a ping command against one of the custom values in the host file, such as ping mysite.com and you’ll see that it will try to reach the IP that you specified. As that IP probably doesn’t exist it will just show a couple of Request timed out values.

Why would you modify the host file? If you migrate a website from one IP address to another, then you probably want to test the new environment in your browser, right? As the URL of the website doesn’t change then it will lead to the old IP address that exists in the name servers. You can then deploy the website to the new environment, override the host file and enter the URL again. You will then be directed to the IP you have specified in the host file. This is a very convenient solution for testing purposes: your clients will not see your beta site as they will still be directed to the old IP. Then when you’re done testing you can propagate the new IP value across the Internet.

Record types

When you type nslookup microsoft.com in the command prompt then it will provide you with one or more records of type A: an A record. An A record turns a name into an IP address. It is the default type of record that nslookup returns. There are other types of records and you can let nslookup return them as well. Run the nslookup command without specifying the name to enter the multiple query mode.

To query name server records you can set the type as follows:

NsLookup name server record

Here you see the name servers that are responsible for the microsoft.com namespace. Here we see 5 name servers. In the name resolution process your computer will pick one of those at random.

You can query mail exchange records (MX) but setting the type as follows:

set type=MX

Then query microsoft.com will give you something like this:

NsLookup mail exchange

If you send an email to Microsoft then you’ll send it to the microsoft-com.mail.protection.outlook.com mail server. That’s who will accept mail for the microsoft.com namespace. It’s possible that there are multiple mail servers in which case the preference parameter tells me in which order I should try to send the email.

Another record type is CNAME which stands for ‘canonical name’, it’s sort of an alias:

set type=CNAME

Then test microsoft.com. You’ll see no CNAME for that:

NSLookup no CNAME

The reason is that we cannot have a CNAME for the root of the domain. However, try http://www.microsoft.com, you’ll get a CNAME:

NsLookup with cname

http://www.microsoft.com is aliased to an Akamai address. This means that when you type http://www.microsoft.com in your web browser and get the IP address for it from the name server lookup then you will be directed to a server owned by the Akamai network.

The last record type to look at is the quad A, or AAAA record type. This is an IPv6 version of an A record so this turns the name into an IPv6 address. If you set the type to CNAME in the command prompt and query a name then you’ll get the AAAA records as well:

AAAA records

This is the case on with Windows 7. If you don’t see this output then test setting the type to AAAA first:

set type=AAAA

and then query a name.

These are the most common record types out there.

Using HashSet in .NET to allow unique values only

Hashsets allow you to add unique values into a collection. So if you have a rule that no two identical objects are added to a collection then a Set is a good choice.

Initialisation:

HashSet<int> integerSet = new HashSet<int>();

Add new items:

integerSet.Add(2);
integerSet.Add(3);

There’s no direct access available with an index parameter, like [2]. There’s no particular order to the items inserted to a Set. You’ll never know where the items end up and which one is the first in the list.

You can simply iterate through the values like this:

foreach (int value in integerSet)
{
}

If you try to add an integer that already exists then it will ignored. The Add method has a boolean return value. It will return false if the item you’re trying to add already exists in the collection and true otherwise.

You can easily build the intersection of two sets:

HashSet<int> integerSet1 = new HashSet<int>(){1, 2, 3};
HashSet<int> integerSet2 = new HashSet<int>(){2, 3, 4};

integerSet1.IntersectWith(integerSet2);

This operation will only keep those items in integerSet1 that were available in both sets, i.e. the intersection of the two sets: 2 and 3.

Building a union is equally easy:

integerSet1.UnionWith(integerSet2);

…resulting in integerSet1 = 1,2,3,4.

SymmetricExceptWith returns those items that are found in set 1 and set 2 but not both:

integerSet1.SymmetricExceptWith(integerSet2);

Result: 1,4.

If you want to store objects, such as Customer, Product, etc. then you need to take some extra care. Sets have no idea when two object are considered equal. By default the following operation will add both objects:

HashSet<Product> productSet = new HashSet<Product>();
productSet.Add(new Product() { Name = "A" });
productSet.Add(new Product() { Name = "A" });

These are two different objects, they point to two different locations in the memory heap.

One way to solve this is that object will implement the IEquatable interface and override the GetHashCode method:

public class Product : IEquatable<Product>
{
	public string Name { get; set; }

	public override int GetHashCode()
	{
		return Name.GetHashCode();
	}

	public bool Equals(Product other)
	{
		return this.Name.Equals(other.Name);
	}
}

This will prevent adding two equal objects to be added to the Set – provided that they should be considered equal of course.

LIFO data collection in .NET: Stack of T

If you need a data collection in .NET where you are forced to handle the objects in a last-in-first-out manner then you can use the Stack of T object: the last object added will be the first to come out. A typical scenario is a deck of cards: you pick the first card from the top, i.e. the one that was added last.

To initialise:

Stack&lt;Card&gt; stackOfCards = new Stack&lt;Card&gt;();

To add items:

stackOfCards.Push(new Card(ace));
stackOfCards.Push(new Card(ten));

To get the most recently added object from the stack:

Card next = stackOfCards.Pop();

The Pop() method will also remove the item from the collection. So the next time you call Pop() you’ll get the item added before the most recently added one.

Just like with a Queue of T you cannot directly reference an object in the stack collection by some index, e.g. [3].

The Peek() method will let you view the next item on the stack but it won’t be removed from the collection:

Card next = stackOfCards.Peek();

You can test for the absence of an item with Contains:

bool contains = stackOfCards.Contains(ace);

If you absolutely need to access the items directly then convert the stack into an array:

Card[] cardArray = stackOfCards.AsArray();

This will copy the items in the stack but leave the stack itself intact.

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

Introduction

In the previous post we finished building a thin but functional SOA web service. Now it’s time to test it. We could build just any type of consumer that’s capable of issuing HTTP requests to a service but we’ll stick to a simple Console app. The goal is to test the SOA service and not to win the next CSS contest.

The tester

Open the SOA application we’ve been working on. Set the WebProxy layer as the start up project and then press F5. Without setting the start up URL in Properties/Web you’ll most likely get a funny looking error page from IIS that says you are not authorised to view the contents of the directory. That’s fine. Extend the URI in the browser as follows:

http://localhost:xxxx/reservation

Refresh the browser and you should get a JSON message saying that there is no GET method for that resource. That’s also fine as we only implemented a POST method. The same is true for the purchase controller:

http://localhost:xxxx/purchase

Open another Visual Studio instance and create a new Console application called SoaTester. Import the Json.NET package through NuGet. Add assembly references to System.Net and System.Net.Http. Add the following private variables to Program.cs:

private static Uri _productReservationServiceUri = new Uri("http://localhost:49679/reservation");
private static Uri _productPurchaseServiceUri = new Uri("http://localhost:49679/purchase");

Recall that the Post methods require Request objects to function correctly. The easiest way to ensure that we don’t need to deal with JSON formatting and serialisation issues we can just copy the Request objects we already have the SoaIntroNet.Service layer. Insert the following two objects into the console app:

public class ReserveProductRequest
{
	public string ProductId { get; set; }
	public int ProductQuantity { get; set; }
}
public class PurchaseProductRequest
{
	public string ReservationId { get; set; }
	public string ProductId { get; set; }
}

Note that we dropped the correlation ID property from the purchase request. It’s irrelevant for the actual user and is set within the Purchase.Post() action anyway before the purchase request is passed to the Service layer.

We’ll need to read the JSON responses as well so insert the following three objects in the console app. They will all look familiar:

public abstract class ServiceResponseBase
{
	public ServiceResponseBase()
	{
		this.Exception = null;
	}

	public Exception Exception { get; set; }
}
public class PurchaseProductResponse : ServiceResponseBase
{
	public string PurchaseId { get; set; }
	public string ProductName { get; set; }
	public string ProductId { get; set; }
	public int ProductQuantity { get; set; }
}
public class ProductReservationResponse : ServiceResponseBase
{
	public string ReservationId { get; set; }
	public DateTime Expiration { get; set; }
	public string ProductId { get; set; }
	public string ProductName { get; set; }
	public int ProductQuantity { get; set; }
}

We’ll first call the Reservation operation. The below method calls the product reservation URI and returns a product reservation response:

private static ProductReservationResponse ReserveProduct(ReserveProductRequest request)
{
	ProductReservationResponse response = new ProductReservationResponse();
	try
	{
		HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, _productReservationServiceUri);
		requestMessage.Headers.ExpectContinue = false;
		String jsonArguments = JsonConvert.SerializeObject(request);
		requestMessage.Content = new StringContent(jsonArguments, Encoding.UTF8, "application/json");
		HttpClient httpClient = new HttpClient();
		httpClient.Timeout = new TimeSpan(0, 10, 0);
		Task<HttpResponseMessage> httpRequest = httpClient.SendAsync(requestMessage,
			HttpCompletionOption.ResponseContentRead, CancellationToken.None);
		HttpResponseMessage httpResponse = httpRequest.Result;
		HttpStatusCode statusCode = httpResponse.StatusCode;
        	HttpContent responseContent = httpResponse.Content;
		Task<String> stringContentsTask = responseContent.ReadAsStringAsync();
		String stringContents = stringContentsTask.Result;
		if (statusCode == HttpStatusCode.OK && responseContent != null)
		{					
			response = JsonConvert.DeserializeObject<ProductReservationResponse>(stringContents);
		}
		else
		{
			response.Exception = new Exception(stringContents);
		}
	}
	catch (Exception ex)
	{
		response.Exception = ex;
	}
	return response;
}

We send a HTTP request to the service and read off the response. We use Json.NET to serialise and deserialise the objects. We set the HttpClient timeout to 10 minutes to make sure we don’t get any timeout exceptions as we are testing the SOA application.

The below bit of code calls this method from Main:

ReserveProductRequest reservationRequest = new ReserveProductRequest();
reservationRequest.ProductId = "13a35876-ccf1-468a-88b1-0acc04422243";
reservationRequest.ProductQuantity = 10;
ProductReservationResponse reservationResponse = ReserveProduct(reservationRequest);

Console.WriteLine("Reservation response received.");
Console.WriteLine(string.Concat("Reservation success: ", (reservationResponse.Exception == null)));
if (reservationResponse.Exception == null)
{
	Console.WriteLine("Reservation id: " + reservationResponse.ReservationId);
}
else
{
	Console.WriteLine(reservationResponse.Exception.Message);
}

Console.ReadKey();

Recall that we inserted a product with that ID in the in-memory database in the post discussing the repository layer.

Set two breakpoints in the SOA app: one within the ReservationController constructor and another within the ReservationController.Post method. Start the console application. You should see that the code execution stops within the controller constructor. Check the status of the incoming productService parameter. It is not null so StructureMap correctly resolved this dependency. The next stop is at the second breakpoint. Check the status of the reserveProductRequest parameter. It is not null and has been correctly populated by Web API and the Json serialiser. From this point on I encourage you to step through the execution by pressing F11 to see how each method is called. At the end the product should be reserved and a product reservation message will be sent back to the client. Back in the client the ProductReservationResponse object is populated by Json.NET based on the string contents from the web service. The results are then printed on the console window.

You can test the service response in the following way:

  • Send a non-existing product id
  • Send a malformatted GUID as the product id
  • Send a quantity higher than the original allocation, e.g. 10000

You’ll get the correct error messages in all three cases.

It’s now time to purchase the product. The below method will send the purchase request to the web service:

private static PurchaseProductResponse PurchaseProduct(PurchaseProductRequest request)
{
	PurchaseProductResponse response = new PurchaseProductResponse();
	try
	{
		HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, _productPurchaseServiceUri);
		requestMessage.Headers.ExpectContinue = false;
		String jsonArguments = JsonConvert.SerializeObject(request);
		requestMessage.Content = new StringContent(jsonArguments, Encoding.UTF8, "application/json");
		HttpClient httpClient = new HttpClient();
		httpClient.Timeout = new TimeSpan(0, 10, 0);
		Task<HttpResponseMessage> httpRequest = httpClient.SendAsync(requestMessage,
			HttpCompletionOption.ResponseContentRead, CancellationToken.None);
		HttpResponseMessage httpResponse = httpRequest.Result;
		HttpStatusCode statusCode = httpResponse.StatusCode;
		HttpContent responseContent = httpResponse.Content;
		Task<String> stringContentsTask = responseContent.ReadAsStringAsync();
		String stringContents = stringContentsTask.Result;
		if (statusCode == HttpStatusCode.OK && responseContent != null)
		{
			response = JsonConvert.DeserializeObject<PurchaseProductResponse>(stringContents);
		}
		else
		{
			response.Exception = new Exception(stringContents);
		}
	}
	catch (Exception ex)
	{
		response.Exception = ex;
	}
	return response;
}

I realise that this is almost identical to PurchaseProduct and a single method probably would have sufficed – you can do this improvement as homework.

Below the code line…

Console.WriteLine("Reservation id: " + reservationResponse.ReservationId);

…add the following bit to complete the loop:

PurchaseProductRequest purchaseRequest = new PurchaseProductRequest();
purchaseRequest.ProductId = reservationResponse.ProductId;
purchaseRequest.ReservationId = reservationResponse.ReservationId;
PurchaseProductResponse purchaseResponse = PurchaseProduct(purchaseRequest);
if (purchaseResponse.Exception == null)
{
	Console.WriteLine("Purchase confirmation id: " + purchaseResponse.PurchaseId);
}
else
{
	Console.WriteLine(purchaseResponse.Exception.Message);
}

So we purchase the reserved product immediately after receiving the reservation response. Run the tester object without any break points. You should see the purchase ID in the console window.

You can test the SOA app in the following way:

  • Set a breakpoint in the Purchase controller and step through the code slowly with F11 – make sure that the purchase expiry time of 1 minute is reached
  • Alternatively use Thread.Sleep() in the tester app before the call to the Purchase controller
  • Modify the reservation id to some non-existent GUID
  • Set the reservation id to a malformed GUID

You will get the correct exception messages in all cases from the SOA app.

That’s all folks about SOA basics in this series. I hope you have learned a lot of new concepts.

View the list of posts on Architecture and Patterns here.

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.

7 ways to start a Task in .NET C#

New threads can be started using the Task Programming Library in .NET in – at last – 5 different ways.

You’ll first need to add the following using statement:

using System.Threading.Tasks;

The most direct way

Task.Factory.StartNew(() => {Console.WriteLine("Hello Task library!"); });

Using Action

Task task = new Task(new Action(PrintMessage));
task.Start();

…where PrintMessage is a method:

private void PrintMessage()
{
    Console.WriteLine("Hello Task library!");
}

Using a delegate

Task task = new Task(delegate { PrintMessage(); });
task.Start();

Lambda and named method

Task task = new Task( () => PrintMessage() );
task.Start();

Lambda and anonymous method

Task task = new Task( () => { PrintMessage(); } );
task.Start();

Using Task.Run in .NET4.5

public async Task DoWork()
{
	await Task.Run(() => PrintMessage());
}

Using Task.FromResult in .NET4.5 to return a result from a Task

public async Task DoWork()
{
	int res = await Task.FromResult<int>(GetSum(4, 5));	
}

private int GetSum(int a, int b)
{
	return a + b;
}

You cannot start a task that has already completed. If you need to run the same task you’ll need to initialise it again.

View the list of posts on the Task Parallel Library here.

A model SOA application in .NET Part 5: the service layer continued

Introduction

In the previous post we started implementing the IProductService interface. We got as far as declaring a couple of private fields and a constructor. Here we’ll implement the ReserveProduct and PurchaseProduct methods.

The concrete service continued

Open the project we’ve been working on in this series and locate ProductService.cs. The implemented ReserveProduct method looks as follows:

public ProductReservationResponse ReserveProduct(ReserveProductRequest productReservationRequest)
{
	ProductReservationResponse reserveProductResponse = new ProductReservationResponse();
	try
	{
		Product product = _productRepository.FindBy(Guid.Parse(productReservationRequest.ProductId));
		if (product != null)
		{
			ProductReservation productReservation = null;
			if (product.CanReserveProduct(productReservationRequest.ProductQuantity))
			{
				productReservation = product.Reserve(productReservationRequest.ProductQuantity);
				_productRepository.Save(product);
				reserveProductResponse.ProductId = productReservation.Product.ID.ToString();
				reserveProductResponse.Expiration = productReservation.Expiry;
				reserveProductResponse.ProductName = productReservation.Product.Name;
				reserveProductResponse.ProductQuantity = productReservation.Quantity;
				reserveProductResponse.ReservationId = productReservation.Id.ToString();
			}
			else
			{
				int availableAllocation = product.Available();
				reserveProductResponse.Exception = new LimitedAvailabilityException(string.Concat(&quot;There are only &quot;, availableAllocation, &quot; pieces of this product left.&quot;));
			}
		}
		else
		{
			throw new ResourceNotFoundException(string.Concat(&quot;No product with id &quot;, productReservationRequest.ProductId, &quot;, was found.&quot;));
		}
	}
	catch (Exception ex)
	{
		reserveProductResponse.Exception = ex;
	}
	return reserveProductResponse;
}

First we let the product repository locate the requested product for us. If it doesn’t exist then we throw an exception with an appropriate message. We check using the CanReserveProduct method whether there are enough products left. If not then we let the client know in an exception message. Otherwise we reserve the product, save the current reservation status and populate the reservation response using the product reservation returned by the Save method. We wrap the entire code in a try-catch block to make sure that we catch any exception thrown during the process.

Here’s the implemented PurchaseProduct method:

public PurchaseProductResponse PurchaseProduct(PurchaseProductRequest productPurchaseRequest)
{
	PurchaseProductResponse purchaseProductResponse = new PurchaseProductResponse();
	try
	{
		if (_messageRepository.IsUniqueRequest(productPurchaseRequest.CorrelationId))
		{					
			Product product = _productRepository.FindBy(Guid.Parse(productPurchaseRequest.ProductId));
			if (product != null)
			{
				ProductPurchase productPurchase = null;
				if (product.ReservationIdValid(Guid.Parse(productPurchaseRequest.ReservationId)))
				{
					productPurchase = product.ConfirmPurchaseWith(Guid.Parse(productPurchaseRequest.ReservationId));
					_productRepository.Save(product);
					purchaseProductResponse.ProductId = productPurchase.Product.ID.ToString();
					purchaseProductResponse.PurchaseId = productPurchase.Id.ToString();
					purchaseProductResponse.ProductQuantity = productPurchase.ProductQuantity;
					purchaseProductResponse.ProductName = productPurchase.Product.Name;
				}
				else
				{
					throw new ResourceNotFoundException(string.Concat(&quot;Invalid or expired reservation id: &quot;, productPurchaseRequest.ReservationId));
				}
				_messageRepository.SaveResponse&lt;PurchaseProductResponse&gt;(productPurchaseRequest.CorrelationId, purchaseProductResponse);
			}
			else
			{
				throw new ResourceNotFoundException(string.Concat(&quot;No product with id &quot;, productPurchaseRequest.ProductId, &quot;, was found.&quot;));
			}
		}
		else
		{
			purchaseProductResponse = _messageRepository.RetrieveResponseFor&lt;PurchaseProductResponse&gt;(productPurchaseRequest.CorrelationId);
		}
	}
	catch (Exception ex)
	{
		purchaseProductResponse.Exception = ex;
	}
	return purchaseProductResponse;
}

If you recall from the first part of this series we talked about the Idempotent pattern. The IsUniqueRequest is an application of the pattern. We check in the message repository if a message with that correlation ID has been processed before. If yes, then we return the response stored in the repository to avoid making the same purchase again. This is not the only possible solution of the pattern, but only one of the viable ones. Probably the domain layer could have a similar logic as well, but I think this is more robust.

If this is a new request then we locate the product just like in the ReserveProduct method and throw an exception if the product is not found. If the product exists then we need to check if the reservation can be made using the reservation ID of the incoming message. If not, then the reservation either doesn’t exist or has expired and a corresponding exception is thrown. Otherwise we confirm the purchase, save the product and dress up the product purchase response using the product purchase object returned by the ConfirmPurchaseWith method. Just like above, we wrap the code within a try-catch block.

This completes the service layer of the SOA project. We’ll look at the web client in the next post. The web client will be a web service client based on the Web API technology so that we don’t need to waste time and energy on presentation stuff such as HTML and CSS.

View the list of posts on Architecture and Patterns here.

A model SOA application in .NET Part 4: the service layer part 1

Introduction

Now that we’re done with the domain and repository layers it’s time to build the service layer. If you are not familiar with the purposes of the service layer then make sure to read this post. I’ll employ the same Request-Response pattern here.

The service layer

Open the application we’ve been working on and add a new C# class library called SoaIntroNet.Service. Remove Class1.cs and make a reference to both the Domain and the Repository layers. Insert a new folder called Responses and in it a base class for all service responses:

public abstract class ServiceResponseBase
{
	public ServiceResponseBase()
	{
		this.Exception = null;
	}

        public Exception Exception { get; set; }
}

The clients will be able to purchase and reserve products. We put the result of the purchasing and reservation processes into the following two Response objects:

public class PurchaseProductResponse : ServiceResponseBase
{
	public string PurchaseId { get; set; }
	public string ProductName { get; set; }
	public string ProductId { get; set; }
	public int ProductQuantity { get; set; }
}
public class ProductReservationResponse : ServiceResponseBase
{
	public string ReservationId { get; set; }
	public DateTime Expiration { get; set; }
	public string ProductId { get; set; }
	public string ProductName { get; set; }
	public int ProductQuantity { get; set; }
}

Nothing really fancy up to this point I hope. In order to make a purchase or reservation the corresponding Request objects must be provided by the client. Add a new folder called Requests and in it the following two requests:

public class PurchaseProductRequest
{
	public string CorrelationId { get; set; }
	public string ReservationId { get; set; }
	public string ProductId { get; set; }
}
public class ReserveProductRequest
{
	public string ProductId { get; set; }
	public int ProductQuantity { get; set; }
}

The only somewhat unexpected property is the correlation id. Recall its purpose from the opening post in this series: ensure that a state-changing operation is not carried out more than once, e.g. purchasing the same tickets twice.

Add a folder called Exceptions and insert the following two custom exceptions:

public class ResourceNotFoundException : Exception
{
	public ResourceNotFoundException(string message)
		: base(message)
	{ }

	public ResourceNotFoundException()
		: base(&quot;The requested resource was not found.&quot;)
	{ }
}
public class LimitedAvailabilityException : Exception
{
	public LimitedAvailabilityException(string message)
		: base(message)
	{}

	public LimitedAvailabilityException()
		: base(&quot;There are not enough products left to fulfil your request.&quot;)
	{}
}

As the names imply we’ll throw these exception if some requested resource could not be located or that the required amount in the request could not be fulfilled.

Add the following service interface to the Service layer:

public interface IProductService
{
	ProductReservationResponse ReserveProduct(ReserveProductRequest productReservationRequest);
	PurchaseProductResponse PurchaseProduct(PurchaseProductRequest productPurchaseRequest);
}

This represents our service contract. We state that our service will be able to handle product purchases and reservations and they need the necessary Request objects in order to fulfil their functions. The concrete implementation – which we’ll look at in a bit – is an unimportant implementation detail from the client’s point of view.

However, before we do that we’ll need to revisit the repository layer and make room for saving and retrieving the messaging history based on the correlation ID. These messages are not part of our domain so we won’t bother with setting up a separate Message object.

Open SoaIntroNet.Repository and add a new folder called MessagingHistory. Insert the following interface which describes the operations a message repository must be able to handle:

public interface IMessageRepository
{
	bool IsUniqueRequest(string correlationId);
	void SaveResponse&lt;T&gt;(string correlationId, T response);
	T RetrieveResponseFor&lt;T&gt;(string correlationId);
}

The purpose of IsUniqueRequest is to show whether the message with that correlation ID has been saved before. You can probably guess the purpose of the other two methods.

Here comes an implementation of the repository with the same lazy loading static initialiser we saw in the ProductRepository example:

public class MessageRepository : IMessageRepository
{
	private Dictionary&lt;string, object&gt; _responseHistory;

	public MessageRepository()
	{
		_responseHistory = new Dictionary&lt;string, object&gt;();
	}

	public bool IsUniqueRequest(string correlationId)
	{
		return !_responseHistory.ContainsKey(correlationId);
	}

	public void SaveResponse&lt;T&gt;(string correlationId, T response)
	{
		_responseHistory[correlationId] = response;
	}

	public T RetrieveResponseFor&lt;T&gt;(string correlationId)
	{
		if (_responseHistory.ContainsKey(correlationId))
		{
			return (T)_responseHistory[correlationId];
		};
		return default(T);
	}

	public static MessageRepository Instance
	{
		get
		{
			return Nested.instance;
		}
	}

	private class Nested
	{
		static Nested()
		{
		}
		internal static readonly MessageRepository instance = new MessageRepository();
	}
}

We store the responses in a Dictionary. In a real case scenario we can store these in any type of storage mechanism: a database, a web service, cache, you name it. An in-memory solution is the easiest in this case.

A side note: it’s not necessary to go with the lazy singleton pattern for all repositories. However, in this example the pattern will make sure that a single object is created every time one is required and the in-memory objects won’t be re-instantiated. We don’t want to lose the Dictionary object every time somebody sends a new purchase request. In the series on DDD, especially in this post and the one after that, I show how it suffices to lazily instantiate a Unit of Work instead of all implemented repositories.

Just like for the ProductRepository we’ll need the corresponding factory:

public interface IMessageRepositoryFactory
{
	MessageRepository Create();
}
public class LazySingletonMessageRepositoryFactory : IMessageRepositoryFactory
{
	public MessageRepository Create()
	{
		return MessageRepository.Instance;
	}
}

We can now turn our attention to the Service layer again. Add a class called ProductService with the following stub:

public class ProductService : IProductService
{
	public ProductReservationResponse ReserveProduct(ReserveProductRequest productReservationRequest)
	{
		throw new NotImplementedException();
	}

	public PurchaseProductResponse PurchaseProduct(PurchaseProductRequest productPurchaseRequest)
	{
		throw new NotImplementedException();
	}
}

The ProductService will need some help from the Repository layer to complete these tasks. It will need a product repository and a message repository. These objects are created by our lazy singleton factories. We know from the discussion on SOLID and especially the Dependency inversion principle that an object – in this case the ProductService – should not create its own dependencies. Instead, the caller should inject the proper dependencies.

The most obvious technique is constructor injection. Add the following private fields and a constructor to ProductService:

private readonly IMessageRepositoryFactory _messageRepositoryFactory;
private readonly IProductRepositoryFactory _productRepositoryFactory;
private readonly IMessageRepository _messageRepository;
private readonly IProductRepository _productRepository;

public ProductService(IMessageRepositoryFactory messageRepositoryFactory, IProductRepositoryFactory productRepositoryFactory)
{
	if (messageRepositoryFactory == null) throw new ArgumentNullException(&quot;MessageRepositoryFactory&quot;);
	if (productRepositoryFactory == null) throw new ArgumentNullException(&quot;ProductRepositoryFactory&quot;);
	_messageRepositoryFactory = messageRepositoryFactory;
	_productRepositoryFactory = productRepositoryFactory;
	_messageRepository = _messageRepositoryFactory.Create();
	_productRepository = _productRepositoryFactory.Create();
}

We let the factories be injected through the constructor. This follows the good habit of programming against abstractions. We then ask the factories to create the repositories for us – note that they are abstractions as well.

In a real application you wouldn’t rely on the memory to store objects for you. A more “normal” constructor would look like this:

private readonly IMessageRepository _messageRepository;
private readonly IProductRepository _productRepository;

public ProductService(IMessageRepository messageRepository, IProductRepository productRepository)
{
	if (messageRepository == null) throw new ArgumentNullException(&quot;MessageRepository&quot;);
	if (productRepository == null) throw new ArgumentNullException(&quot;ProductRepository&quot;);
	_messageRepository = messageRepository;
	_productRepository = productRepository;
}

However, for the reasons outlined above we go with the factory solution in this demo. If we followed this simplified version then our in-memory data would be re-instantiated after every subsequent request making a demo meaningless.

We’ll see in the next post how the reserve ticket and purchase ticket methods are implemented.

View the list of posts on Architecture and Patterns here.

A model SOA application in .NET Part 3: the repository

In the previous post we built the thin domain layer of the model application. Now it’s time to build the repository.

The abstract repository

Open the SoaIntroNet application we started building previously. Add a new interface in the SoaIntroNet.Domain.ProductDomain folder:

public interface IProductRepository
{
	Product FindBy(Guid productId);
	void Save(Product product);
}

This is a very simplified repository interface but it suffices for our demo purposes. In case you’re wondering what the purpose of this interface is and what it is doing in the domain layer then make sure to at least skim through the series on Domain-Driven-Design here. Alternatively you can go through the solution structure of the series about the cryptography project starting here. This latter project follows a simplified repository pattern that we’ll employ here.

The concrete repository

The repository will be a simple in-memory repository so that we don’t need to spend our time on installing external storage mechanisms.

Let’s build the infrastructure around the concrete repository. Add a new C# library project called SoaIntroNet.Repository to the solution. Add a new folder called ProductRepository. Add the following stub to the class:

public class InMemoryProductRepository : IProductRepository
{
	public Product FindBy(Guid productId)
	{
		throw new NotImplementedException();
	}

	public void Save(Product product)
	{
		throw new NotImplementedException();
	}		
}

We’ll use the thread-safe singleton design pattern to build an instance of this object. Add the following code to the class:

public static InMemoryProductRepository Instance
{
	get
	{
		return Nested.instance;
	}
}

private class Nested
{
	static Nested()
	{
	}
	internal static readonly InMemoryProductRepository instance = new InMemoryProductRepository();
}

If you don’t understand what this means then make sure to check out the post on the singleton pattern. It ensures that we always return the same instance of the concrete repository.

Before we get rid of the NotImplementException bits we’ll take care of the rest of the initialisation elements. Add the following interface to the folder:

public interface IProductRepositoryFactory
{
	InMemoryProductRepository Create();
}

The following class implements the above interface:

public class LazySingletonProductRepositoryFactory : IProductRepositoryFactory
{
	public InMemoryProductRepository Create()
	{
		return InMemoryProductRepository.Instance;
	}
}

We don’t want to start with an empty “database” so add the following fields, properties, a constructor and an initialisation method to the class:

private int standardReservationTimeoutMinutes = 1;
public List&lt;Product&gt; DatabaseProducts { get; set; }
public List&lt;ProductPurchase&gt; DatabaseProductPurchases { get; set; }
public List&lt;ProductReservation&gt; DatabaseProductReservations { get; set; }

public InMemoryProductRepository()
{
	InitialiseDatabase();
}

private void InitialiseDatabase()
{
	DatabaseProducts = new List&lt;Product&gt;();
	Product firstProduct = new Product()
	{
		Allocation = 200,
		Description = &quot;Product A&quot;,
		ID = Guid.Parse(&quot;13a35876-ccf1-468a-88b1-0acc04422243&quot;),
		Name = &quot;A&quot;
	};
	Product secondProduct = new Product()
	{
		Allocation = 500,
		Description = &quot;Product B&quot;,
		ID = Guid.Parse(&quot;f5efdfe0-7933-4efc-a290-03d20014703e&quot;),
		Name = &quot;B&quot;
	};
        DatabaseProducts.Add(firstProduct);
	DatabaseProducts.Add(secondProduct);

	DatabaseProductPurchases = new List&lt;ProductPurchase&gt;();
	DatabaseProductPurchases.Add(new ProductPurchase(firstProduct, 10) { Id = Guid.Parse(&quot;0ede40e0-5a52-48b1-8578-de1891c5a7f0&quot;) });
	DatabaseProductPurchases.Add(new ProductPurchase(firstProduct, 20) { Id = Guid.Parse(&quot;5868144e-e04d-4c1f-81d7-fc671bfc52dd&quot;) });
	DatabaseProductPurchases.Add(new ProductPurchase(secondProduct, 12) { Id = Guid.Parse(&quot;8e6195ac-d448-4e28-9064-b3b1b792895e&quot;) });
	DatabaseProductPurchases.Add(new ProductPurchase(secondProduct, 32) { Id = Guid.Parse(&quot;f66844e5-594b-44b8-a0ef-2a2064ec2f43&quot;) });
	DatabaseProductPurchases.Add(new ProductPurchase(secondProduct, 1) { Id = Guid.Parse(&quot;0e73c8b3-f7fa-455d-ba7f-7d3f1bc2e469&quot;) });
	DatabaseProductPurchases.Add(new ProductPurchase(secondProduct, 4) { Id = Guid.Parse(&quot;e28a3cb5-1d3e-40a1-be7e-e0fa12b0c763&quot;) });

	DatabaseProductReservations = new List&lt;ProductReservation&gt;();
	DatabaseProductReservations.Add(new ProductReservation(firstProduct, standardReservationTimeoutMinutes, 10) { HasBeenConfirmed = true, Id = Guid.Parse(&quot;a2c2a6db-763c-4492-9974-62ab192201fe&quot;) });
	DatabaseProductReservations.Add(new ProductReservation(firstProduct, standardReservationTimeoutMinutes, 5) { HasBeenConfirmed = false, Id = Guid.Parse(&quot;37f2e5ac-bbe0-48b0-a3cd-9c0b47842fa1&quot;) });
	DatabaseProductReservations.Add(new ProductReservation(firstProduct, standardReservationTimeoutMinutes, 13) { HasBeenConfirmed = true, Id = Guid.Parse(&quot;b9393ea4-6257-4dea-a8cb-b78a0c040255&quot;) });
	DatabaseProductReservations.Add(new ProductReservation(firstProduct, standardReservationTimeoutMinutes, 3) { HasBeenConfirmed = false, Id = Guid.Parse(&quot;a70ef898-5da9-4ac1-953c-a6420d37b295&quot;) });
	DatabaseProductReservations.Add(new ProductReservation(secondProduct, standardReservationTimeoutMinutes, 17) { Id = Guid.Parse(&quot;85eaebfa-4be4-407b-87cc-9a9ea46d547b&quot;) });
	DatabaseProductReservations.Add(new ProductReservation(secondProduct, standardReservationTimeoutMinutes, 3) { Id = Guid.Parse(&quot;39d4278e-5643-4c43-841c-214c1c3892b0&quot;) });
	DatabaseProductReservations.Add(new ProductReservation(secondProduct, standardReservationTimeoutMinutes, 9) { Id = Guid.Parse(&quot;86fff675-e5e3-4e0e-bcce-36332c4de165&quot;) });

	firstProduct.PurchasedProducts = (from p in DatabaseProductPurchases where p.Product.ID == firstProduct.ID select p).ToList();
	firstProduct.ReservedProducts = (from p in DatabaseProductReservations where p.Product.ID == firstProduct.ID select p).ToList();

	secondProduct.PurchasedProducts = (from p in DatabaseProductPurchases where p.Product.ID == secondProduct.ID select p).ToList();
	secondProduct.ReservedProducts = (from p in DatabaseProductReservations where p.Product.ID == secondProduct.ID select p).ToList();
}

We have 2 products with a couple of product purchases and reservations in our data store.

The lazy singleton implementation will make sure that the initialisation code only runs once so we’ll have access to the initial set of data every time we need a concrete repository.

The implementation of FindBy is very simple:

public Product FindBy(Guid productId)
{
	return (from p in DatabaseProducts where p.ID == productId select p).FirstOrDefault();
}

The implementation of Save is not much harder either:

public void Save(Product product)
{
	ClearPurchasedAndReservedProducts(product);
	InsertPurchasedProducts(product);
	InsertReservedProducts(product);
}

…which calls the following three private methods:

private void ClearPurchasedAndReservedProducts(Product product)
{
	DatabaseProductPurchases.RemoveAll(p =&gt; p.Id == product.ID);
	DatabaseProductReservations.RemoveAll(p =&gt; p.Id == product.ID);
}

private void InsertReservedProducts(Product product)
{
	DatabaseProductReservations.AddRange(product.ReservedProducts);
}

private void InsertPurchasedProducts(Product product)
{
	DatabaseProductPurchases.AddRange(product.PurchasedProducts);
}

In the Save method we want to concentrate on updating the product reservations and purchases and ignore the changes in the Product domain itself. Updating product reservations and purchases line by line is a cumbersome task. It’s easier to remove all existing purchases and reservations first and insert the old ones along with the new ones. The existing product purchases and reservations are always populated correctly in the InitialiseDatabase() method. Therefore a call to FindBy will product a product with the existing purchases and reservations.

So we now have the Domain and the Repository layer ready – we’ll build the service layer in the next solution.

View the list of posts on Architecture and Patterns here.

A model SOA application in .NET Part 2: the domain

Introduction

The SOA model application will simulate a Product purchase system. The Product must be reserved first and the purchase must be then confirmed. So this is a scenario familiar from e-commerce sites, although in reality the flow may be more complicated. The point here is that the purchase is not a one-step process and the web service must be able to track the registration somehow. So the Product can be anything you can think of: tickets, books, whatever, that’s a detail we don’t care about.

We’ll continue from the previous post which set the theoretical basis for the model we’re about to build.

If you have followed along the series on DDD then you’ll notice that the Domain structure I’m going to present is a lot simpler: there’s no aggregate root and entity base etc., and that’s for a good reason. Those belong to the DDD-specific discussion whereas here we want to concentrate on SOA. Therefore I decided to remove those elements that might distract us from the main path and keep the Domain layer simple. Otherwise if you are not familiar with DDD but still want to learn about SOA you may find the code hard to follow.

Demo

Open Visual Studio and insert a new blank solution called SoaIntroNet. Add a C# class library called SoaIntroNet.Domain to it and remove Class1.cs. Add a folder called ProductDomain and a class called Product in it. Here’s the Product domain code with some explanation to follow. The code will not compile at first as we need to implement some other objects as well in a bit.

public class Product
{
	public Product()
	{
		ReservedProducts = new List<ProductReservation>();
		PurchasedProducts = new List<ProductPurchase>();
	}

	public Guid ID { get; set; }
	public string Name { get; set; }
	public string Description { get; set; }
	public int Allocation { get; set; }
	public List<ProductReservation> ReservedProducts { get; set; }
	public List<ProductPurchase> PurchasedProducts { get; set; }

	public int Available()
	{
		int soldAndReserved = 0;
		PurchasedProducts.ForEach(p => soldAndReserved += p.ProductQuantity);
		ReservedProducts.FindAll(p => p.IsActive()).ForEach(p => soldAndReserved += p.Quantity);

		return Allocation - soldAndReserved;
	}

	public bool ReservationIdValid(Guid reservationId)
	{
		if (HasReservation(reservationId))
		{
			return GetReservationWith(reservationId).IsActive();
		}
		return false;
	}

	public ProductPurchase ConfirmPurchaseWith(Guid reservationId)
	{
		if (!ReservationIdValid(reservationId))
		{
			throw new Exception(string.Format("Cannot confirm the purchase with this Id: {0}", reservationId));
		}

		ProductReservation reservation = GetReservationWith(reservationId);
		ProductPurchase purchase = new ProductPurchase(this, reservation.Quantity);
		reservation.HasBeenConfirmed = true;
		PurchasedProducts.Add(purchase);
		return purchase;
	}

	public ProductReservation GetReservationWith(Guid reservationId)
	{
		if (!HasReservation(reservationId))
		{
			throw new Exception(string.Concat("No reservation found with id {0}", reservationId.ToString()));
		}
		return (from r in ReservedProducts where r.Id == reservationId select r).FirstOrDefault();
	}

	private bool HasReservation(Guid reservationId)
	{
		return ReservedProducts.Exists(p => p.Id == reservationId);
	}

	public bool CanReserveProduct(int quantity)
	{
		return Available() >= quantity;
	}

	public ProductReservation Reserve(int quantity)
	{
		if (!CanReserveProduct(quantity))
		{
			throw new Exception("Can not reserve this many tickets.");
		}

		ProductReservation reservation = new ProductReservation(this, 1, quantity);
		ReservedProducts.Add(reservation);
		return reservation;
	}
}

We maintain a list of purchased and reserved products in the corresponding List objects. The Allocation property means the initial number of products available for sale.

  • In Available() we check what’s left based on Allocation and the reserved and purchased tickets.
  • CanReserveProduct: we check if there are at least as many products available as the ‘quantity’ value
  • Reserve: we reserve a product and add it to the reservation list. We set the expiry date of the reservation to 1 minute. In reality this value should be higher of course but in the demo we don’t want to wait 30 minutes to test for the reservation being too old
  • HasReservation: check if the reservation exists in the reservation list using the reservation id
  • GetReservationWith: we retrieve the reservation based on its GUID
  • ReservationIdValid: check if a product can be purchased with the reservation id
  • ConfirmPurchaseWith: confirm the reservation by adding the constructed product to the purchase list

Here comes the ProductReservation class:

public class ProductReservation
{
	public ProductReservation(Product product, int expiryInMinutes, int quantity)
	{
		if (product == null) throw new ArgumentNullException("Product cannot be null.");
		if (quantity < 1) throw new ArgumentException("The quantity should be at least 1.");
		Product = product;
		Id = Guid.NewGuid();
		Expiry = DateTime.Now.AddMinutes(expiryInMinutes);
                Quantity = quantity;
	}

	public Guid Id { get; set; }
	public Product Product { get; set; }
	public DateTime Expiry { get; set; }
	public int Quantity { get; set; }
	public bool HasBeenConfirmed { get; set; }

	public bool Expired()
	{
		return DateTime.Now > Expiry;
	}

	public bool IsActive()
	{
		return !HasBeenConfirmed && !Expired();
	}
}

Note the expiry date property which fits in well with our discussion in the previous post: the client needs to reserve the product first and then confirm the purchase within the expiry date.

The ProductPurchase class is equally straightforward:

public class ProductPurchase
{
	public ProductPurchase(Product product, int quantity)
	{
		Id = Guid.NewGuid();
		if (product == null) throw new ArgumentNullException("Product cannot be null.");
		if (quantity < 1) throw new ArgumentException("The quantity should be at least 1.");
		Product = product;
		ProductQuantity = quantity;
	}

	public Guid Id { get; set; }
	public Product Product { get; set; }
	public int ProductQuantity { get; set; }
}

That’s all the domain logic we have in the model application. In the next post we’ll implement the repository.

View the list of posts on Architecture and Patterns here.

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

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