Using a Windows service in your .NET project part 3: the application service layer

Introduction

In the previous post we built the Domain and Repository layers of the demo app. We’ll now build the application service layer that connects the two with the consumer layer which we’ll build in the next post.

Normally the consumer layer, such as a Web UI should not directly contact the repository for its data. The application service is responsible for joining all necessary repositories and other services to provide the data that the consumer layer needs to show.

We’ll build upon the demo app we’ve been working on so far in this series so have it ready in Visual Studio.

Short return to Infrastructure

Before we begin we’ll need two new elements in the Infrastructure layer. You’ll recall from the previous post that the abstract MongoDbRepository class will need an IDatabaseConnectionSettingsService interface to read the connection string and database name. We’ll store those in the app.config file which we’ll create in the next post. However, these settings could potentially be stored in various different places: a database, a web service, etc.

We saw in this post how reading settings can be hidden behind an interface. We’ll take a similar approach here.

Add a new folder called ConfigurationService to the Infrastructure layer. Insert the following interface into it:

public interface IConfigurationRepository
{
	T GetConfigurationValue<T>(string key);
	T GetConfigurationValue<T>(string key, T defaultValue);
	string GetConnectionString(string connectionStringName);
}

Normally settings come in name-value pairs so we pass some key value and expect the corresponding setting value back.

For the implementation we’ll take the ConfigurationManager class located in the System.Configuration namespace. You’ll need to add this dll to the references list of the Infrastructure layer. Here’s the implementing class:

public class ConfigFileConfigurationRepository : IConfigurationRepository
{
	public T GetConfigurationValue<T>(string key)
	{
		string value = ConfigurationManager.AppSettings[key];
		if (value == null)
		{
			throw new KeyNotFoundException("Key " + key + " not found.");
		}
		try
		{
			if (typeof(Enum).IsAssignableFrom(typeof(T)))
				return (T)Enum.Parse(typeof(T), value);
			return (T)Convert.ChangeType(value, typeof(T));
		}
		catch (Exception ex)
		{
			throw ex;
		}
	}

	public T GetConfigurationValue<T>(string key, T defaultValue)
	{
		string value = ConfigurationManager.AppSettings[key];
		if (value == null)
		{
			return defaultValue;
		}
		try
		{
			if (typeof(Enum).IsAssignableFrom(typeof(T)))
				return (T)Enum.Parse(typeof(T), value);
			return (T)Convert.ChangeType(value, typeof(T));
		}
		catch (Exception ex)
		{
			return defaultValue;
		}
	}

	public string GetConnectionString(string connectionStringName)
	{
		return ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
	}
}

We’ll see shortly how this abstraction is used.

The service layer

Add a new C# library called Demo.ApplicationService to the solution. Add a project reference to the Domain and Infrastructure layers. Insert 3 folders:

  • Messaging
  • JobServices
  • DatabaseConnectionService

Let’s get the database connection service out of the way first. The implementation will need a dependency of type IConfigurationRepository to read the connection string and database name values. Insert the following class into the DatabaseConnectionService folder:

public class HttpJobDatabaseConnectionService : IDatabaseConnectionSettingsService
{
	private readonly IConfigurationRepository _configurationRepository;

	public HttpJobDatabaseConnectionService(IConfigurationRepository configurationRepository)
	{
		if (configurationRepository == null) throw new ArgumentNullException("IConfigurationRepository");
		_configurationRepository = configurationRepository;
	}

	public string GetDatabaseConnectionString()
	{
		return _configurationRepository.GetConnectionString(Constants.HttpJobsConnectionStringKeyName);
	}

	public string GetDatabaseName()
	{
		return _configurationRepository.GetConfigurationValue<string>(Constants.HttpJobsDatabaseNameSettingKeyName);
	}
}

This class reads the setting key names from another class called Constants:

public static class Constants
{
	public static string HttpJobsConnectionStringKeyName = "HttpJobsConnectionString";
	public static string HttpJobsDatabaseNameSettingKeyName = "HttpJobsDatabaseName";
}

So we’ll store the connection string with the key “HttpJobsConnectionString” and the database name with the key “HttpJobsDatabaseName”. Remember, these settings could be stored anywhere hence the need to inject the service which actually reads the settings. We’ll fill in the app settings file shortly.

Service abstractions

OK, let’s create the abstractions for the Job related services. An IHttpJobService should be able to retrieve a specific job, retrieve all new jobs, insert a new job and update an existing job. Add the following interface to the JobServices folder:

public interface IHttpJobService
{
	InsertHttpJobResponse InsertHttpJob(InsertHttpJobRequest request);
	GetHttpJobResponse GetHttpJob(GetHttpJobRequest request);
	UpdateHttpJobResponse UpdateHttpJob(UpdateHttpJobRequest request);
	GetHttpJobsResponse GetNewHttpJobs();
}

We have several new but simple RequestResponse objects here. They are used to relay all necessary inputs to the Service instead of creating many overloaded variants of the same methods. Insert the following classes to the Messaging folder:

public abstract class BaseResponse
{
	public Exception OperationException { get; set; }
}
public class InsertHttpJobResponse : BaseResponse
{
	public Guid JobCorrelationId { get; set; }
}
public class InsertHttpJobRequest
{
	private List<Uri> _urisToRun;

	public InsertHttpJobRequest(List<Uri> urisToRun)
	{
		if (urisToRun == null || !urisToRun.Any())
		{
			throw new ArgumentException("The URI list cannot be empty.");				
		}
		_urisToRun = urisToRun;
	}

	public List<Uri> UrisToRun
	{
		get
		{
			return _urisToRun;
		}
	}
}
public class GetHttpJobResponse : BaseResponse
{
	public HttpJob Job { get; set; }
}
public class GetHttpJobRequest
{
	public Guid CorrelationId { get; set; }
}
public class UpdateHttpJobResponse : BaseResponse
{}
public class UpdateHttpJobRequest
{
	private HttpJob _updatedJob;
	public UpdateHttpJobRequest(HttpJob updatedJob)
	{
		_updatedJob = updatedJob;
	}

	public HttpJob UpdatedHttpJob
	{
		get
		{
			return _updatedJob;
		}
	}
}
public class GetHttpJobsResponse : BaseResponse
{
	public IEnumerable<HttpJob> HttpJobs { get; set; }
}

Those were the elements needed for the HttpJob service. We’ll need a separate service to carry out a single JobUrl within a HttpJob object. Add the following interface to the JobServices folder:

public interface IHttpJobUrlService
{
	Task<JobUrlProcessResponse> CarryOutSingleJobUrl(Uri uri);
}

Carrying out a HTTP call can take some time so we’ll go for an asynchronous model using the Task library. JobUrlProcessResponse is similar to the above Response objects. Insert the following class to the Messaging folder:

public class JobUrlProcessResponse : BaseResponse
{
	public int HttpResponseCode { get; set; }
	public string HttpContent { get; set; }
	public TimeSpan TotalResponseTime { get; set; }
}

You’ll recognise the properties from the JobUrl domain object: we’ll need to read the HTTP response code, the HTML content and the response time from a single URL call.

We need one final abstraction: an interface which co-ordinates the functions of IHttpJobService and IHttpJobUrlService. In other words we need a service that carries out a complete job. Insert the following interface into the JobServices folder:

public interface IHttpJobExecutionService
{
	Task Execute(HttpJob httpJob);
}

Again, it takes time to carry out a job so we’ll go for asynchronous calls here as well.

If you don’t understand why these methods are meant to be asynchronous and why they return Task objects then start here.

Concrete service classes

OK, enough of abstractions, let’s look at the implementations now. HttpJobService which implements IHttpJobService will work with the IJobRepository interface to carry out the repository-related actions such as insertions and updates. Insert the following class to the JobServices folder:

public class HttpJobService : IHttpJobService
{
	private readonly IJobRepository _jobRepository;

	public HttpJobService(IJobRepository jobRepository)
	{
		if (jobRepository == null) throw new ArgumentNullException("Job repository!!");
		_jobRepository = jobRepository;
	}

	public InsertHttpJobResponse InsertHttpJob(InsertHttpJobRequest request)
	{
		InsertHttpJobResponse response = new InsertHttpJobResponse();
		HttpJob job = new HttpJob();
		job.StatusMessage = "Inserted";
		List<JobUrl> jobUrls = new List<JobUrl>();
		foreach (Uri uri in request.UrisToRun)
		{
			jobUrls.Add(new JobUrl() { Uri = uri });
		}
		job.UrlsToRun = jobUrls;
		try
		{
			Guid correlationId = _jobRepository.InsertNewHttpJob(job);
			response.JobCorrelationId = correlationId;
		}
		catch (Exception ex)
		{
			response.OperationException = ex;
		}
		return response;
	}

	public GetHttpJobResponse GetHttpJob(GetHttpJobRequest request)
	{
		GetHttpJobResponse response = new GetHttpJobResponse();

		try
		{
			response.Job = _jobRepository.FindBy(request.CorrelationId);
		}
		catch (Exception ex)
		{
			response.OperationException = ex;
		}

		return response;
	}

	public UpdateHttpJobResponse UpdateHttpJob(UpdateHttpJobRequest request)
	{
		UpdateHttpJobResponse response = new UpdateHttpJobResponse();			
		try
		{
			_jobRepository.Update(request.UpdatedHttpJob);
		}
		catch (Exception ex)
		{
			response.OperationException = ex;
		}
		return response;
	}

	public GetHttpJobsResponse GetNewHttpJobs()
	{
		GetHttpJobsResponse response = new GetHttpJobsResponse();
		try
		{
			response.HttpJobs = _jobRepository.GetUnhandledJobs();
		}
		catch (Exception ex)
		{
			response.OperationException = ex;
		}
		return response;
	}
}

I think the code is really simple and straightforward, there’s nothing magic in it.

HttpJobUrlService which implements IHttpJobUrlService will need an IHttpService interface to carry out the HTTP calls. We saw the IHttpService interface in the first post of this series. Insert the following class into the JobServices folder:

public class HttpJobUrlService : IHttpJobUrlService
{
	private readonly IHttpService _httpService;

	public HttpJobUrlService(IHttpService httpService)
	{
		if (httpService == null) throw new ArgumentNullException("HttpService");
		_httpService = httpService;
	}

	public async Task<JobUrlProcessResponse> CarryOutSingleJobUrl(Uri uri)
	{
		JobUrlProcessResponse response = new JobUrlProcessResponse();
		
		try
		{				
			MakeHttpCallRequest httpCallRequest = new MakeHttpCallRequest();
			httpCallRequest.HttpMethod = HttpMethodType.Get;
			httpCallRequest.Uri = uri;
			DateTime start = DateTime.UtcNow;
			MakeHttpCallResponse httpCallResponse = await httpService.MakeHttpCallAsync(httpCallRequest);
         		DateTime stop = DateTime.UtcNow;
			TimeSpan diff = stop - start;
			response.TotalResponseTime = diff;
			if (!string.IsNullOrEmpty(httpCallResponse.ExceptionMessage))
			{
				response.HttpContent = httpCallResponse.ExceptionMessage;
				response.HttpResponseCode = -1;
			}
			else
			{					
				response.HttpContent = httpCallResponse.HttpResponse;
				response.HttpResponseCode = httpCallResponse.HttpResponseCode;
			}				
		}
		catch (Exception ex)
		{
			response.OperationException = ex;
		}
			
		return response;
	}
}

We initiate a HTTP request through the injected IHttpService service and note the time between the start and end of the call. This might not be the most precise way to measure the response time of a URL but it’s good enough for the demo. Then we populate the HttpContent and HttpResponseCode properties of the JobUrlProcessResponse object based on the result stored in MakeHttpCallResponse.

Finally, we have an implementation of the IHttpJobExecutionService interface. This implementation will use IHttpJobService and IHttpJobUrlService to carry out its work. Insert the following class into the JobServices folder:

public class HttpJobExecutionService : IHttpJobExecutionService
{
	private readonly IHttpJobService _httpJobService;
	private readonly IHttpJobUrlService _httpJobUrlService;

	public HttpJobExecutionService(IHttpJobService httpJobService, IHttpJobUrlService httpJobUrlService)
	{
		if (httpJobService == null) throw new ArgumentNullException("HttpJobService");
		if (httpJobUrlService == null) throw new ArgumentNullException("HttpJobUrlService");
		_httpJobService = httpJobService;
		_httpJobUrlService = httpJobUrlService;
	}

	public async Task Execute(HttpJob httpJob)
	{
		httpJob.Started = true;
		httpJob.StatusMessage = string.Format("Starting job {0}.", httpJob.CorrelationId);
		_httpJobService.UpdateHttpJob(new UpdateHttpJobRequest(httpJob));
		TimeSpan totalTime = new TimeSpan(0, 0, 0);
		foreach (JobUrl jobUrl in httpJob.UrlsToRun)
		{
			jobUrl.Started = true;
			httpJob.StatusMessage = string.Concat("Starting url ", jobUrl.Uri);
			_httpJobService.UpdateHttpJob(new UpdateHttpJobRequest(httpJob));
			JobUrlProcessResponse jobUrlProcessResponse = await _httpJobUrlService.CarryOutSingleJobUrl(jobUrl.Uri);				
			jobUrl.Finished = true;
			jobUrl.HttpContent = jobUrlProcessResponse.HttpContent.Length > 30 ? jobUrlProcessResponse.HttpContent.Substring(0, 30) : jobUrlProcessResponse.HttpContent;
			jobUrl.HttpResponseCode = jobUrlProcessResponse.HttpResponseCode;
			jobUrl.TotalResponseTime = jobUrlProcessResponse.TotalResponseTime;
			httpJob.StatusMessage = string.Concat("Finished url ", jobUrl.Uri);
			_httpJobService.UpdateHttpJob(new UpdateHttpJobRequest(httpJob));
			totalTime += jobUrlProcessResponse.TotalResponseTime;
		}
		httpJob.Finished = true;
		httpJob.TotalJobDuration = totalTime;
		httpJob.StatusMessage = string.Format("Job {0} finished.", httpJob.CorrelationId);
		_httpJobService.UpdateHttpJob(new UpdateHttpJobRequest(httpJob));
	}		
}

In the Execute method we first update the job status to Started. Then we go through each URL in the UrlsToRun list of the HttpJob object. In the for-each loop we update the status of the URL to started and then save the HTTP response code and content. We also add the response time of the URL to the total response time of the job. Finally we update the job status to Finished and assign the total response time to the appropriate property.

That’s it, we have the service layer ready to go.

In the next post we’ll build the consumer layer which will be a simple Console app.

View the list of posts on Architecture and Patterns here.

Using a Windows service in your .NET project part 2: the domain and repository

Introduction

In the previous post we went through the goals of this series and also started building a demo app. At present we have an Infrastructure layer in the solution to abstract away the service that makes the HTTP calls. As we said the demo project will carry out HTTP calls and measure the response times.

In this post we’ll build the domain and repository layers. We’ll build upon the demo project so have it ready in Visual Studio.

The domain

The domain will be quite small with only two domain objects and one abstract repository. Add a C# library to the solution called Demo.Domain. Add the following object to it:

public class JobUrl
{
	public Uri Uri { get; set; }
	public int HttpResponseCode { get; set; }
	public string HttpContent { get; set; }
	public bool Started { get; set; }
	public bool Finished { get; set; }
	public TimeSpan TotalResponseTime { get; set; }
}

JobUrl has the following properties:

  • Uri: the Uri to call
  • HttpResponseCode: the HTTP response from the call such as 200, 403 etc.
  • HttpContent: the pure HTML content of the URI
  • Started: whether the HTTP call to the URI has been initiated
  • Finished: whether the HTTP call has been processed
  • TotalResponseTime: the response time of the URL

We want to be able to carry out multiple HTTP calls within a single job so we’ll need the following “wrapper” object:

public class HttpJob
{
	public List<JobUrl> UrlsToRun { get; set; }
	public string StatusMessage { get; set; }
	public bool Started { get; set; }
	public bool Finished { get; set; }
	public TimeSpan TotalJobDuration { get; set; }
	public Guid CorrelationId { get; set; }

	public override string ToString()
	{
		string NL = Environment.NewLine;
		StringBuilder sb = new StringBuilder();
		sb.Append("Status report of job with correlation id: ").Append(CorrelationId).Append(NL);
		sb.Append("------------------------------------------").Append(NL);
		sb.Append("Started: ").Append(Started).Append(NL);
		sb.Append("Finished: ").Append(Finished).Append(NL);
		sb.Append("Status: ").Append(StatusMessage).Append(NL).Append(NL);

		foreach (JobUrl jobUrl in UrlsToRun)
		{
			sb.Append(NL);
			sb.Append("Url: ").Append(jobUrl.Uri).Append(NL);
			sb.Append("Started: ").Append(jobUrl.Started).Append(NL);
			sb.Append("Finished: ").Append(jobUrl.Finished).Append(NL);
			if (jobUrl.Finished)
			{
				sb.Append("Http response code: ").Append(jobUrl.HttpResponseCode).Append(NL);
				sb.Append("Partial content: ").Append(jobUrl.HttpContent).Append(NL);
				sb.Append("Response time: ").Append(Convert.ToInt32(jobUrl.TotalResponseTime.TotalMilliseconds)).Append(" ms").Append(NL);					
			}
		}

		if (Finished)
		{
			sb.Append("Total job duration: ").Append(Convert.ToInt32(TotalJobDuration.TotalMilliseconds)).Append(" ms. ").Append(NL);
		}
		sb.Append("------------------------------------------").Append(NL).Append(NL);

		return sb.ToString();
	}
}

HttpJob has the following properties:

  • UrlsToRun: the URIs to be visited in the job
  • StatusMessage: a status message such as “starting” or “in progress”
  • Started: whether the job has been started
  • Finished: whether the job has been finished
  • TotalJobDuration: the sum of the response times of the individual URLs
  • CorrelationId: in essence the job ID which can be used to retrieve the job from the data store

Then we have an overridden ToString method which builds a long string to show the current status of the job. We’ll see it in action towards the end of the series.

We’ll also need an abstract repository where we declare the capabilities of the job repository. This abstraction must be then implemented by a concrete repository such as Entity Framework or NHibernate. Add the following interface to the Domain layer:

public interface IJobRepository
{
	Guid InsertNewHttpJob(HttpJob httpJob);
	HttpJob FindBy(Guid correlationId);
	void Update(HttpJob httpJob);
	IEnumerable<HttpJob> GetUnhandledJobs();
}

So in this interface we declare that any concrete repository implementation should be able to do the following:

  • Insert a new HttpJob and return a correlation ID
  • Find a job based on the correlation ID
  • Update a job
  • Find all “unhandled” jobs i.e. the ones that have not been started yet

This concludes the Domain layer.

The repository layer

As mentioned in the previous post we’ll use the file-based MongoDb as the data storage mechanism. Don’t worry if you’ve never used it, it’s very easy to get going and you’ll learn something new. We won’t see much of MongoDb in action here anyway. I have a series devoted to MongoDb that you can go through if you wish, the list of posts is available here.

In order to move on though you’ll need to install MongoDb. If you want to keep it short then go through the section called “Setup on Windows” in part two of the MongoDb series. In case you want to read the foundations then here’s part one for you.

At the end of the setup process you should have MongoDb up and running as a Windows service:

MongoDb as Windows Service

Add a new C# library called Demo.Repository.MongoDb to the solution. Add a project reference to the Domain and Infrastructure layers. We’ll also need to work with MongoDb in a programmatic way so add the following Nuget package:

MongoDb C# driver

Add a new folder called DatabaseObjects and insert a class called DbHttpJobs into that folder:

public class DbHttpJob : HttpJob
{
	public ObjectId Id { get; set; }
}

Let’s stop for a second

What on Earth is this??? We can save just about any object in MongoDb on one condition: the object must have a property called Id which will be used as the primary key for the object. The most straightforward implementation for the Id is the MongoDb ObjectId type which is similar to a GUID. We won’t work with it at all but it’s a must for MongoDb so we simply add it to the DbHttpJob object which inherits everything else from HttpJob.

Why not use the correlation ID as the ID in the DB??? We could certainly do that by decorating the CorrelationId property of the HttpJob object with the BsonId attribute. However, that would require us to add a reference to the MongoDb C# driver in the Domain layer and add that MongoDb-specific attribute to our POCO model(s).

And so what??? If you’ve gone through the series on Domain Driven Design then you’ll understand the concept of POCO classes that are oblivious of the underlying storage mechanism. This is called persistence ignorance. A POCO should be as POCO as possible. As soon as we add data storage specific elements to a POCO then it’s not really POCO any more I think. There will be traces of the concrete repository in the POCO, so at best it can be called a contaminated POCO. The domain layer will have a tight coupling to the underlying concrete repository which could be avoided. In case you’d like to share the class with someone else who also needs to work with the domain then that person will also inherit MongoDb from you whereas they might work with an entirely different data storage mechanism.

If we go down that path and introduce MongoDb at the domain level then it can be difficult to change the storage mechanism later. Say that you want to store the HttpJob objects in Sql Server with Entity Framework or in Amazon S3 later on. Then you’ll first have to decouple the Domain layer from MongoDb and replace it with another technology, right? Well, hopefully you won’t make the same mistake again and keep the technology-specific code in the technology-specific layer.

OK, let’s move on

After some theory we’ll move on with the practical discussion. A MongoDb repository will need two things in order to find the database: the connection string and the database name. These elements will most likely be stored in a settings file like app.config or web.config but they could come from any other store: a database, a web service etc. This sounds like we’ll need to abstract away the service that finds the connection-related elements.

Let’s return briefly to the Infrastructure layer. Add a new folder called DatabaseConnectionSettingsService and insert the following interface:

public interface IDatabaseConnectionSettingsService
{
	string GetDatabaseConnectionString();
	string GetDatabaseName();
}

Back in the repository layer we can build the abstract base class for all repositories. Insert the following class to the project:

public abstract class MongoDbRepository
{
	private readonly IDatabaseConnectionSettingsService _databaseConnectionSettingsService;
	private MongoClient _mongoClient;
	private MongoServer _mongoServer;
	private MongoDatabase _mongoDatabase;

	public MongoDbRepository(IDatabaseConnectionSettingsService databaseConnectionSettingsService)
	{
		if (databaseConnectionSettingsService == null) throw new ArgumentNullException();
		_databaseConnectionSettingsService = databaseConnectionSettingsService;
		_mongoClient = new MongoClient(_databaseConnectionSettingsService.GetDatabaseConnectionString());
		_mongoServer = _mongoClient.GetServer();
		_mongoDatabase = _mongoServer.GetDatabase(_databaseConnectionSettingsService.GetDatabaseName());
	}

	public MongoDatabase HttpJobsDatabase
	{
		get
		{
			return _mongoDatabase;
		}
	}

	public MongoCollection<DbHttpJob> HttpJobs
	{
		get
		{
			return HttpJobsDatabase.GetCollection<DbHttpJob>("httpjobs");
		}
	}
}

You’ll recognise the IDatabaseConnectionSettingsService interface which is injected to the MongoDbRepository constructor. I won’t go into the MongoDb-specific details here, just keep in mind the following:

  • A “collection” in MongoDb is similar to a “table” in MS SQL
  • The collection name “httpjobs” could be anything, like “mickeymouse”, it doesn’t matter really – the type variable declares the type of objects stored in the collection
  • There’s no need to check for the presence of a database or a collection – they will be created by MongoDb upon the first data entry
  • The HttpJobs property is similar to DbContext.Cars in EntityFramework i.e. it gets a reference to the collection of DbHttpJobs in the database

We’re now ready to implement the IJobRepository interface. Add the following class to the project:

public class JobRepository : MongoDbRepository, IJobRepository
{
	public JobRepository(IDatabaseConnectionSettingsService databaseConnectionSettingsService)
		: base(databaseConnectionSettingsService)
	{}

	public Guid InsertNewHttpJob(HttpJob httpJob)
	{
		Guid correlationId = Guid.NewGuid();
		httpJob.CorrelationId = correlationId;
		DbHttpJob dbHttpJob = httpJob.ConvertToInsertDbObject();
		HttpJobs.Insert(dbHttpJob);
		return correlationId;
	}

	public HttpJob FindBy(Guid correlationId)
	{
		return FindInDb(correlationId);
	}

	public void Update(HttpJob httpJob)
	{
		DbHttpJob existing = FindInDb(httpJob.CorrelationId);
		existing.Finished = httpJob.Finished;
		existing.Started = httpJob.Started;
		existing.StatusMessage = httpJob.StatusMessage;
		existing.TotalJobDuration = httpJob.TotalJobDuration;
		existing.UrlsToRun = httpJob.UrlsToRun;
		HttpJobs.Save(existing);
	}

	public IEnumerable<HttpJob> GetUnhandledJobs()
	{
		IMongoQuery query = Query<DbHttpJob>.EQ(j => j.Started, false);
		return HttpJobs.Find(query);
	}

	private DbHttpJob FindInDb(Guid correlationId)
	{
		IMongoQuery query = Query<DbHttpJob>.EQ(j => j.CorrelationId, correlationId);
		DbHttpJob firstJob = HttpJobs.FindOne(query);
		return firstJob;
	}		
}

Again, I won’t go into the MongoDb specific code. It is quite easy to follow anyway as it’s only about retrieving, inserting and updating a HttpJob object.

There’s one extension method called ConvertToInsertDbObject() which looks as follows:

namespace Demo.Repository.MongoDb
{
	public static class ModelExtensions
	{
		public static DbHttpJob ConvertToInsertDbObject(this HttpJob domain)
		{
			return new DbHttpJob()
			{
				CorrelationId = domain.CorrelationId
				, Finished = domain.Finished
				, Started = domain.Started
				, StatusMessage = domain.StatusMessage
				, TotalJobDuration = domain.TotalJobDuration
				, UrlsToRun = domain.UrlsToRun
				, Id = ObjectId.GenerateNewId()
			};
		}		
	}
}

You can put this anywhere in the MongoDb layer. The method simply constructs a new DbHttpJob object with a new ObjectId ready for insertion. The generation of the Id is not really necessary as MongoDb will create one for us in case it’s null but I prefer to be specific.

We’re done with the repository layer. In the next post we’ll look at the Service layer.

View the list of posts on Architecture and Patterns here.

Using a Windows service in your .NET project part 1: foundations

Introduction

As the title suggests we’ll discuss Windows services in this new series and how they can be used in your .NET project. We’ll take up the following topics:

  • What is a Windows service?
  • How can it be (un)installed using scripts?
  • What’s the use of a Windows Service?
  • How can it be taken advantage of in a .NET project?
  • Simplified layered architecture with OOP principles: we’ll see a lot of abstractions and dependency injection

We’ll also build a small demo application with the following components:

  • A Windows service
  • A Console-based consumer with a simplified layered architecture
  • A MongoDb database

If you’re not familiar with MongoDb, don’t worry. You can read about it on this blog starting here. Just make sure you read at least the first 2 posts so that you know how to install MongoDb as a Windows service on your PC. Otherwise we won’t see much MongoDb related code in the demo project.

A warning: it’s not possible to create Windows services in the Express edition of Visual Studio. I’ll be building the project in VS 2013 Professional.

Windows services

Windows services are executable assemblies that run in the background without the user’s ability to interact with them directly. They are often used for long running or periodically recurring activities such as polling, monitoring, listening to network connections and the like. Windows services have no user interface and have their own user session. It’s possible to start a Windows service without the user logging on to the computer.

An average Windows PC has a large number of pre-installed Windows services, like:

…and many more. You can view the services by opening the Services window:

Windows services window

We’ll go through the different categories like “Name” and “Status” when we create the Windows service project.

There are some special considerations about Windows services:

  • A Windows service project cannot be started directly in Visual Studio and step through its code with F11
  • Instead the service must be installed and started in order to see it in action
  • An installer must be attached to the Windows service so that it can registered with the Windows registry
  • Windows services cannot communicate directly with the logged-on user. E.g. it cannot write to a Console that the user can read. Instead it must write messages to another source: a log file, the Windows event log, a web service, email etc.
  • A Windows service runs under a user context different from that of the logged-on user. It’s possible to give a different role to the Windows service than the role of the user. Normally you’ll run the service with roles limited to the tasks of the service

Demo project description

In the demo project we’ll simulate a service that analyses web sites for us: makes a HTTP call, takes note of the response time and also registers the contents of the web site. This operation could take a long time especially of the user is allowed to enter a range of URIs that should be carried out in succession. Think of a recorded session in Selenium where each step is carried out sequentially, like…

  • Go to login page
  • Log in
  • Search for a product
  • Reserve a product
  • Pay
  • Log out

It is not too wise to make these URL calls directly from a web page and present the results at the end. The HTTP communication may take far too much time to get the final status and the end user won’t see any intermediate results, such as “initialising”, “starting step 1”, “step 2 complete” etc. Websites are simply not designed to carry out long-running processes and wait for the response.

Instead it’s better to just create a “job” in some data storage that a continuous process, like a Windows service, is monitoring. This service can then carry out the job and update the data storage with information. The web site receives a correlation ID for the job which it can use to query the data store periodically. The most basic solution for the web page is to have a timer which automatically refreshes the window and runs the code that retrieves the latest status of the job using the correlation ID. An alternative here is web sockets.

You could even hide the data store and the Windows service setup behind a web service so that the web site only communicates with this web service using the correlation ID.

To keep this series short and concise I’ll skip the web page. I’m not exactly a client-side wizard and it would only create unnecessary noise to build a web side with all the elements to enter the URLs and show the job updates. Instead, we’ll replace it with a Console based consumer.

At the end we’ll have a console app where you can enter a series of URLs which are then entered in the MongoDb data store as a job. The Console will receive a job correlation ID. The Windows Service will monitor this data store and act upon every new job. It will call the URLs in succession and take note of the response time and string content of each URL. It will also update the status message of the job. The console will in turn monitor the job status and print the messages so that the user can track the status. We’ll also put in place a simple file-based logging system to see what the Windows service is actually doing.

Start: infrastructure

Open Visual Studio 2012/2013 Pro and create a blank solution called WindowsServiceDemo. Make sure to select .NET4.5 as the framework for all layers we create within this solution.

We’ll start from the very end of the project and create an abstraction for the planned HTTP calls. We’ve discussed a lot on this blog why it’s important to factor out dependencies such as file system operations, emailing, service calls etc. If you’re not sure why this is a good idea then go through the series on SOLID starting here, where especially Dependency Injection is most relevant.

We’ve also gone through a range of examples of cross cutting concerns in this series where we factored out the common concerns into an Infrastructure project. We’ll do it here as well and describe the HTTP communication service in an interface first.

Insert a new C# class library called Demo.Infrastructure into the blank solution. Add a folder called HttpCommunication to it. Making a HTTP call can require a large amount of inputs: the URI, the HTTP verb, a HTTP body, the headers etc. Instead of creating a long range of overloaded methods we’ll gather them in an object which will be used as the single input parameter. Let’s keep this simple and insert the following interface into the folder:

public interface IHttpService
{
    Task<MakeHttpCallResponse> MakeHttpCallAsync(MakeHttpCallRequest request);
}

The HTTP calls will be carried out asynchronously. If you’re not familiar with asynchronous method calls in .NET4.5 then start here. MakeHttpCallResponse and MakeHttpCallRequest have the following form:

public class MakeHttpCallResponse
{
        public int HttpResponseCode { get; set; }
        public string HttpResponse { get; set; }
        public bool Success { get; set; }
        public string ExceptionMessage { get; set; }
}
  • HttpResponseCode: the HTTP response code from the server, such as 200, 302, 400 etc.
  • HttpResponse: the string contents of the URL
  • Success: whether the HTTP call was successful
  • ExceptionMessage: any exception message in case Success was false
public class MakeHttpCallRequest
{
	public Uri Uri { get; set; }
	public HttpMethodType HttpMethod { get; set; }
	public string PostPutPayload { get; set; }
}
  • Uri: the URI to be called
  • HttpMethodType: the HTTP verb
  • PostPutPayload: the string HTTP body for POST and PUT operations

HttpMethodType is an enumeration which you can also insert into HttpCommunication:

public enum HttpMethodType
{
	Get
	, Post
	, Put
	, Delete
	, Head
	, Options
	, Trace
}

That should be straightforward.

Both MakeHttpCallRequest and MakeHttpCallResponse are admittedly oversimplified in their current forms but they suffice for the demo.

For the implementation we’ll use the HttpClient class in the System.Net library. Add the following .NET libraries to the Infrastructure layer:

  • System.Net version 4.0.0.0
  • System.Net.Http version 4.0.0.0

Insert a class called HttpClientService to the HttpCommunication folder, which will implement IHttpService as follows:

public class HttpClientService : IHttpService
{
	public async Task<MakeHttpCallResponse> MakeHttpCallAsync(MakeHttpCallRequest request)
	{
		MakeHttpCallResponse response = new MakeHttpCallResponse();
		using (HttpClient httpClient = new HttpClient())
		{
			httpClient.DefaultRequestHeaders.ExpectContinue = false;
			HttpRequestMessage requestMessage = new HttpRequestMessage(Translate(request.HttpMethod), request.Uri);
			if (!string.IsNullOrEmpty(request.PostPutPayload))
			{
				requestMessage.Content = new StringContent(request.PostPutPayload);
			}
			try
			{
				HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
				HttpStatusCode statusCode = responseMessage.StatusCode;
				response.HttpResponseCode = (int)statusCode;
				response.HttpResponse = await responseMessage.Content.ReadAsStringAsync();
				response.Success = true;
			}
			catch (Exception ex)
			{
				Exception inner = ex.InnerException;
				if (inner != null)
				{
					response.ExceptionMessage = inner.Message;
				}
				else
				{
					response.ExceptionMessage = ex.Message;
				}
			}
		}
		return response;
	}

	public HttpMethod Translate(HttpMethodType httpMethodType)
	{
		switch (httpMethodType)
		{
			case HttpMethodType.Delete:
				return HttpMethod.Delete;
			case HttpMethodType.Get:
				return HttpMethod.Get;
			case HttpMethodType.Head:
				return HttpMethod.Head;
			case HttpMethodType.Options:
				return HttpMethod.Options;
			case HttpMethodType.Post:
				return HttpMethod.Post;
			case HttpMethodType.Put:
				return HttpMethod.Put;
			case HttpMethodType.Trace:
				return HttpMethod.Trace;
		}
		return HttpMethod.Get;
	}
}

So we simply call the URI using the HttpClient and HttpRequestMessage objects. We get the HttpResponseMessage by awaiting the asynchronous SendAsync method of HttpClient. We save the Http status code as an integer and the string content of the URI in the MakeHttpCallResponse object. We also store any exception message in this response object to indicate that the HTTP call failed.

In the next part of the series we’ll build the domain and repository layer.

View the list of posts on Architecture and Patterns here.

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

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: