Table Of Contents
This article is a strange one, in that it is a bit contrived, but numerous
people have asked me to create a LOB (line of business) app that showed how I
would typically structure my layers between a front end and a database (this was
mainly asked for by users of my
Cinch MVVM framework).
Now although this article uses a simple console application as its front end,
my intention is to make this a 2 part article, which I will revisit and expand
apon when I have some more time, which may be a while as I am working on
something rather large outside of this article.
That said this article showcases quite a few things which I tend to use, and
I thought it might make a 1/2 decent article so I thought why not just write up
what I can right now and let the rest follow when it's ready.
So what does this demo app actually do? Put simply it is a simple console app
that retrieves and add some data from a single database table. It uses Linq to
Entities, and Domain Driven Design (DDD), as such it makes use of the Repository
Pattern, and it also has some added extras like how to use some typical
enterpise level things like
- Inversion of control (I am using the new
MEF drop)
- Log4Net
- Unit Of Work working with repositories
- Restful WCF using the new
WCF WebApis
NOTE : I have specifically made this demo code pretty dumb so people can pick
up the concepts, there is nothing worse than wading through tonnes of code when
you are trying to learn something small. So please keep that in mind as you read
the rest of the article.
There are quite a few prerequisites, however most of them are included as
part of the attached demo code. The table below shows them all and tells you
whether they are included in the attached demo code, or whether you really MUST
have them in order to run the code
| Item |
Included |
| SQL Server |
NO
You MUST have this already |
| Entity Framework 4.1 POCO |
YES
See Lib\Entity Framework
4.1\EntityFramework41.exe |
| Log4Net |
YES
See
Lib\Log4Net\1.2.10.0\log4net.dll |
| Lib\MEF 2 |
YES
See Lib\MEF
2\System.ComponentModel.Composition.CodePlex.dll See Lib\MEF
2\System.ComponentModel.Composition.Registration.CodePlex.dll See
Lib\MEF 2\System.ComponentModel.Composition.Web.Mvc.CodePlex.dll See
Lib\MEF 2\System.Reflection.Context.CodePlex.dll |
| Lib\WCF Web API Preview 4 |
YES
See Lib\WCF Web API Preview 4
But to be honest you would be better getting this stuff from the
Nuget package |
Now some of you may note that there are probably later versions of some of
these, and whilst that is true. This articles code was kind of extracted as part
of a bigger thing I am working on and I know this versions work together, so
those are the versions I opted for.
The basic design is pretty easy is works like this
We have a simple 2 table database (which you can setup use the attached demo
codes scripts), which we want to allow the user to be able to add to and query.
We want to be able to do this using a WCF service and we also want to be able to
do this using modern techniques such as IOC/Logging, and provide proper
seperation of concerns, and also maintain the ability to alter/test any part of
the system either by replacing the implementation for another one or by using
mocks.
This diagram illustrates the core layers of the attached demo project. As I
previously stated the attached demo project is very simple, which I did on
purpose, but even with only 2 tables and no real business logic we are able to
forfill all of the requirements above.

Getting Started
To get started you will need to do the following
- Create a new SQL server database called "TESTEntites" which you may do
using the 2 scripts in the "getting started" solution folder.
- Change the Web.Config in the Restful.WCFService to point to your newly
created database and SQL installation
The
WCF WebApi
that Glenn Block and his team have to hard creating is a pretty cool thing, it
kinds of brings stuff that we know and love from WCF land and allows it to be
easily exposed over the web via JSON or XML serialization.
Back in .NET 3.5 SP1 we were able to do this using a limited number of
attributes such as WebGet/WebInvoke on ou standard WCF
service which could then be hosted in a specialised web service host, namely the
WebServiceHost. This was pretty cool at the time and I wrote about this at
the following links should you want to look at that
- http://sachabarber.net/?p=460
- http://sachabarber.net/?p=475
-
http://www.codeproject.com/KB/smart/GeoPlaces.aspx
But that was then and this is now. Now what is available is the new
WCF WebApi
Glenns team have put together.
So what is so cool about this new offering, well here are what I consider to
be the plus points
- It is just a WCF service really
- It doesn't really need a specialized host as such
- It truly is RESTful
- Can be called using simply web client side code, such as jQuery
- Supports oData (allows simply queries using a url)
These are all pretty good reasons to consider it I feel.
So what does one of these services look like. Well for the demo codes service
the complete code is as follows (note this makes use of MEF / Unit Of Work
pattern / Respository pattern / oData / EF 4.1, all of which we will talk about
shortly):
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Net;
using System.Net.Http;
using Microsoft.ApplicationServer.Http.Dispatcher;
using Restful.Models;
using Restful.Models.Dtos;
using System.ComponentModel.Composition;
using Restful.Entities;
using Restful.WCFService.Services.Contracts;
using Models.Utils;
namespace Restful.WCFService.WebApi
{
[ServiceContract]
[Export]
public class EFResource
{
IUnitOfWork unitOfWork;
IRepository<Author> authorsRep;
IRepository<Book> booksRep;
ILoggerService loggerService;
[ImportingConstructor]
public EFResource(
IUnitOfWork unitOfWork,
IRepository<Author> authorsRep,
IRepository<Book> booksRep,
ILoggerService loggerService)
{
this.unitOfWork = unitOfWork;
this.authorsRep = authorsRep;
this.booksRep = booksRep;
this.loggerService = loggerService;
}
[WebGet(UriTemplate = "Authors")]
public IQueryable<DtoAuthor> GetAuthors()
{
loggerService.Info("Calling IQueryable<DtoAuthor> GetAuthors()");
using (unitOfWork)
{
authorsRep.EnrolInUnitOfWork(unitOfWork);
List<Author> authors =
authorsRep.FindAll("Books").ToList();
IQueryable<DtoAuthor> dtosAuthors = authors
.Select(a => DtoTranslator.TranslateToDtoAuthor(a))
.ToList().AsQueryable<DtoAuthor>();
return dtosAuthors;
}
}
[WebGet(UriTemplate = "Books")]
public IQueryable<DtoBook> GetBooks()
{
loggerService.Info("Calling IQueryable<DtoBook> GetBooks()");
using (unitOfWork)
{
booksRep.EnrolInUnitOfWork(unitOfWork);
List<Book> books =
booksRep.FindAll().ToList();
IQueryable<DtoBook> dtosBooks = books
.Select(b => DtoTranslator.TranslateToDtoBook(b))
.ToList().AsQueryable<DtoBook>();
return dtosBooks;
}
}
[WebInvoke(UriTemplate = "AddAuthor", Method = "POST")]
public Restful.Models.Dtos.DtoAuthor AddAuthor(DtoAuthor dtoAuthor)
{
loggerService.Info("Restful.Models.Author AddAuthor(DtoAuthor dtoAuthor)");
if (dtoAuthor == null)
{
loggerService.Error("author parameter is null");
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
using (unitOfWork)
{
authorsRep.EnrolInUnitOfWork(unitOfWork);
Author author = EfTranslator.TranslateToEfAuthor(dtoAuthor);
authorsRep.Add(author);
unitOfWork.Commit();
dtoAuthor.Id = author.Id;
}
return dtoAuthor;
}
[WebInvoke(UriTemplate = "AddBook", Method = "POST")]
public Restful.Models.Dtos.DtoBook AddBook(DtoBook dtoBook)
{
loggerService.Info("Restful.Models.Book AddBook(DtoBook dtoBook)");
if (dtoBook == null)
{
loggerService.Error("book parameter is null");
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
using (unitOfWork)
{
booksRep.EnrolInUnitOfWork(unitOfWork);
Book book = EfTranslator.TranslateToEfBook(dtoBook);
booksRep.Add(book);
unitOfWork.Commit();
dtoBook.Id = book.Id;
}
return dtoBook;
}
}
}
It can be seen that if we took the actual code in the methods away we would
simply be left with a couple of methods that could be invoked by calling a url.
For example to add a new EF 4.1 Book I could simply do this
http:
Where the POST request would contain a new Book object
And how about a GET request that returns all Book objects, that
is just this sort of GET request
http:
Here is screen shot from a browser where I have simply navigated to that Url.
See how it shows all the books I have in my database installation (you will have
to set your own database up)

You may notice that this is in a XML format. That can easily be changed by
changing the RequestFormat and ResponseFormat and
BodyFormat of the
WebGet and
WebInvoke attributes used on the service.
So what about oData. support. In fact if
you do not know what oData is, here is what
www.oData.org say about it
There is a vast amount of data available today and data is now being
collected and stored at a rate never seen before. Much, if not most, of this
data however is locked into specific applications or formats and difficult to
access or to integrate into new uses.
The Open Data Protocol (OData) is
a Web protocol for querying and updating data that provides a way to unlock your
data and free it from silos that exist in applications today. OData does this by
applying and building upon Web technologies such as HTTP, Atom Publishing
Protocol (AtomPub) and JSON to provide access to information from a variety of
applications, services, and stores. The protocol emerged from experiences
implementing AtomPub clients and servers in a variety of products over the past
several years. OData is being used to expose and access information from a
variety of sources including, but not limited to, relational databases, file
systems, content management systems and traditional Web sites.
OData is
consistent with the way the Web works - it makes a deep commitment to URIs for
resource identification and commits to an HTTP-based, uniform interface for
interacting with those resources (just like the Web). This commitment to core
Web principles allows OData to enable a new level of data integration and
interoperability across a broad range of clients, servers, services, and tools.
Well that too is built in, all we need to do is supply some extra parts to
our our. For example here is how I would get the top 1 book
http:
Which yeilds these results

As far as hosting one of these types of service there is very little to it.
There is this bit of Web.Config code
="1.0" ="utf-8"
<configuration>
<system.serviceModel>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true" />
</system.serviceModel>
</configuration>
And this bit of Global.asax.cs (if you use c#), and that's it
using Microsoft.ApplicationServer.Http.Activation;
using System;
using System.ServiceModel.Activation;
using System.Web.Routing;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Registration;
using System.ComponentModel.Composition;
using Restful.Entities;
using Restful.WCFService.Services.Implementation;
using Restful.WCFService.Services.Contracts;
using log4net.Config;
using Restful.WCFService.Mef;
using Restful.WCFService.WebApi;
namespace Restful.WCFService
{
public class Global : System.Web.HttpApplication
{
private void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapServiceRoute<EFResource>("ef");
}
}
}
The other point of interest is that we never actually serialize and send the
raw Entity Framework POCO classes, what we do instead is to use "Data Transfer
Objects" DTOS, which we translate to and from Entity Framework POCO classes. The
general rule of thumb being
- Entity Framework POCO class : Used for server side persistance
- DTO class : Sent from/to the
WCF WebApi
service
One of the readers of this article actually noted that I had nothing mentioned about security, which is a valid point I did not mention that at all. The main reason being that for my OSS project we are not actual using the
WCF WebApis but use ASP MVC, where I hook into the standard ASP authorization methods.
That said, the same reader (RAbbit12 thank you) also gave a nice link to an article which discusses how to use attributes (similar to what ASP MVC actually does) to apply Authorization to a
WCF WebApi service. Here is a link to that article:
http://haacked.com/archive/2011/10/19/implementing-an-authorization-attribute-for-wcf-web-api.aspx
When designing our systems at work we typically choose to asbtract away any
system boundaries, such that these can easily be replaced or mocked if a system
is down, or we wish to use a test version of something. We would typically
expect to be able to do this at the highest level and have all our dependenices
resolved from an IOC container. Which for us means that we would expect our
entire WCF service to be part of the IOC container, which would take
dependencies on other services/repositories or helpers.
We find that abstracting these services/repositories/helpers behind
interfaces, great increases our ability to swap out and part of the system, and
also to create Mocked versions of them.
MEF is my IOC container of choice these
days, as I like the metadata, so that it what this article focuses on.
The following sections talk about the new
MEF APIs that we will one day get within .NET.
When using MEF one of the 1st thing that needs to be done is to define what
Import/Exports we wish to use. Now
MEF V2 has changed
a bit from V1, in that we no longer need to supply ImportAttribute
and ExportAttribute markets to our classes, this should all be
handled by the new and improved registration process, but I
still prefer to use them, as it shows me clearly where things are coming from
and where I can expect to fault find if they are not working.
So here is the demo
WCF WebApi
with all its expected Imports, you may also note that the entire
WCF WebApi
service is also being Exported. This allows the entire graphs
dependency to be satisfied when you obtain an instance of this service. Believe
me that is what you want, manually obtained service location objects can be a
bugger to find if you miss one in a test.
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Net;
using System.Net.Http;
using Microsoft.ApplicationServer.Http.Dispatcher;
using Restful.Models;
using Restful.Models.Dtos;
using System.ComponentModel.Composition;
using Restful.Entities;
using Restful.WCFService.Services.Contracts;
using Models.Utils;
namespace Restful.WCFService.WebApi
{
[ServiceContract]
[Export]
public class EFResource
{
IUnitOfWork unitOfWork;
IRepository<Author> authorsRep;
IRepository<Book> booksRep;
ILoggerService loggerService;
[ImportingConstructor]
public EFResource(
IUnitOfWork unitOfWork,
IRepository<Author> authorsRep,
IRepository<Book> booksRep,
ILoggerService loggerService)
{
this.unitOfWork = unitOfWork;
this.authorsRep = authorsRep;
this.booksRep = booksRep;
this.loggerService = loggerService;
}
[WebGet(UriTemplate = "Authors")]
public IQueryable<DtoAuthor> GetAuthors()
{
loggerService.Info("Calling IQueryable<DtoAuthor> GetAuthors()");
using (unitOfWork)
{
authorsRep.EnrolInUnitOfWork(unitOfWork);
List<Author> authors =
authorsRep.FindAll("Books").ToList();
IQueryable<DtoAuthor> dtosAuthors = authors
.Select(a => DtoTranslator.TranslateToDtoAuthor(a))
.ToList().AsQueryable<DtoAuthor>();
return dtosAuthors;
}
}
[WebGet(UriTemplate = "Books")]
public IQueryable<DtoBook> GetBooks()
{
loggerService.Info("Calling IQueryable<DtoBook> GetBooks()");
using (unitOfWork)
{
booksRep.EnrolInUnitOfWork(unitOfWork);
List<Book> books =
booksRep.FindAll().ToList();
IQueryable<DtoBook> dtosBooks = books
.Select(b => DtoTranslator.TranslateToDtoBook(b))
.ToList().AsQueryable<DtoBook>();
return dtosBooks;
}
}
[WebInvoke(UriTemplate = "AddAuthor", Method = "POST")]
public Restful.Models.Dtos.DtoAuthor AddAuthor(DtoAuthor dtoAuthor)
{
loggerService.Info("Restful.Models.Author AddAuthor(DtoAuthor dtoAuthor)");
if (dtoAuthor == null)
{
loggerService.Error("author parameter is null");
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
using (unitOfWork)
{
authorsRep.EnrolInUnitOfWork(unitOfWork);
Author author = EfTranslator.TranslateToEfAuthor(dtoAuthor);
authorsRep.Add(author);
unitOfWork.Commit();
dtoAuthor.Id = author.Id;
}
return dtoAuthor;
}
[WebInvoke(UriTemplate = "AddBook", Method = "POST")]
public Restful.Models.Dtos.DtoBook AddBook(DtoBook dtoBook)
{
loggerService.Info("Restful.Models.Book AddBook(DtoBook dtoBook)");
if (dtoBook == null)
{
loggerService.Error("book parameter is null");
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
using (unitOfWork)
{
booksRep.EnrolInUnitOfWork(unitOfWork);
Book book = EfTranslator.TranslateToEfBook(dtoBook);
booksRep.Add(book);
unitOfWork.Commit();
dtoBook.Id = book.Id;
}
return dtoBook;
}
}
}
As far satisfying the object graph and hosting of this service goes, that is
pretty easy thanks to the new
WCF WebApi
all we need to do is have this one line in the Global.asax.cs (if you are using
C# that is).
RouteTable.Routes.MapServiceRoute<EFResource>("ef");
Which simply exposes the
WCF WebApi
service a ASP MVC route.
So that is pretty much all we need to expose/host the
WCF WebApi
service and make it callable. But what about satifying that dependency tree from
the top down. Well that is done by using the following
WCF WebApi
code in the Global.asax.cs
var config = new MefConfiguration(container);
config.EnableTestClient = true;
RouteTable.Routes.SetDefaultHttpConfiguration(config);
Note the use of the MefConfiguration class there. Well that is
what we use to ensure that MEF will satisy the Import/Export
requirements of not only the
WCF WebApi
service, but all required MEF parts.
So let's have a look at this class shall we. Here it is in its entirety
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.ApplicationServer.Http;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Primitives;
namespace Restful.WCFService.Mef
{
public class MefConfiguration : WebApiConfiguration
{
public MefConfiguration(CompositionContainer container)
{
CreateInstance = (t, i, m) =>
{
var contract = AttributedModelServices.GetContractName(t);
var identity = AttributedModelServices.GetTypeIdentity(t);
var definition = new ContractBasedImportDefinition(contract,
identity, null, ImportCardinality.ExactlyOne, false, false,
CreationPolicy.NonShared);
return container.GetExports(definition).First().Value;
};
}
}
}
It can be seen that this code is responsible for creating MEF ContractBasedImportDefinition and their actual Exported values
Now MEF used to auto wire up all its Import/Exports using whatever attributes
the developer chose to use. These attributes are still available but the
registration process has changed a lot, it is now more akin to other popular IOC
providers such as Castle/AutoFac etc etc
Here is how we provide what components the
MEF container will actually use
when resolving types from the container.
Lets examine the demo codes
WCF WebApi
service again, where we have this
[ServiceContract]
[Export]
public class EFResource
{
IUnitOfWork unitOfWork;
IRepository<Author> authorsRep;
IRepository<Book> booksRep;
ILoggerService loggerService;
[ImportingConstructor]
public EFResource(
IUnitOfWork unitOfWork,
IRepository<Author> authorsRep,
IRepository<Book> booksRep,
ILoggerService loggerService)
{
this.unitOfWork = unitOfWork;
this.authorsRep = authorsRep;
this.booksRep = booksRep;
this.loggerService = loggerService;
}
....
....
....
....
}
How do we ensure MEF 2 can satify all that. It's pretty simple we just need register the stuff we want in the
MEF container, as follows:
private void Application_Start(object sender, EventArgs e)
{
RegistrationBuilder context = new RegistrationBuilder();
XmlConfigurator.Configure();
context.ForType(typeof(Log4NetLoggerService)).
Export(builder => builder.AsContractType(typeof(ILoggerService)))
.SetCreationPolicy(CreationPolicy.Shared);
context.ForType(typeof(Repository<>))
.Export(builder => builder.AsContractType(typeof(IRepository<>)))
.SetCreationPolicy(CreationPolicy.NonShared);
context.ForType(typeof(TESTEntities))
.Export(builder => builder.AsContractType(typeof(IUnitOfWork)))
.SetCreationPolicy(CreationPolicy.NonShared);
AggregateCatalog catalog = new AggregateCatalog(
new AssemblyCatalog(typeof(Global).Assembly, context),
new AssemblyCatalog(typeof(Repository<>).Assembly, context));
var container = new CompositionContainer(catalog,
CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);
var config = new MefConfiguration(container);
config.EnableTestClient = true;
RouteTable.Routes.SetDefaultHttpConfiguration(config);
}
Note the use of the new registration syntax, also note that we are able to deal open generics support for the IRepository type where
the generic type is actually specifed when we use the
MEF 2 container registered IRepository type. This feature alone is worth moving to
MEF 2 for in my opinion.
It is very handy, as you can see when you look at the demo codes
WCF WebApi
service, where it has 2 different IRepository types each uses a
different generic type. Neato.
We now have all the peices of the puzzle such that when we run our
WCF WebApi
service, we see it fully loaded with all its wants and needs.

Linq to Entities has been around quite a while, and has gone through many
different flavours (at least I think so). Truth is none of it has really
appealed to me until this new Linq to EF 4.1 POCO version came out. What this
allowed us to do was
- Use a very simple data context based object, which simply held sets of
data object
- Do not use any form of code generation (where everything under the sun
is chucked onto the generated objects)
- Use simple hand rolled code classes which has NO database concerns in
them
Using this POCO code first approach we are able to create a simple data
context class such as this one (which we will read more about in a minute)
Lets start by examing the actual Linq to Entities 4.1 POCO context object.
That for us starts life as a class that extends
DbContext
Here is the demo one
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
namespace Restful.Entities
{
public abstract class EfDataContextBase : DbContext, IUnitOfWork
{
public EfDataContextBase(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
public IQueryable<T> Get<T>() where T : class
{
return Set<T>();
}
public bool Remove<T>(T item) where T : class
{
try
{
Set<T>().Remove(item);
}
catch (Exception)
{
return false;
}
return true;
}
public void Commit()
{
base.SaveChanges();
}
public void Attach<T>(T obj) where T : class
{
Set<T>().Attach(obj);
}
public void Add<T>(T obj) where T : class
{
Set<T>().Add(obj);
}
}
}
This provides a basic Entity Framework base class. But we need to extend that further to make a specific implementation
for our EF 4.1 POCO objects. So we then end up with this
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.ComponentModel.Composition;
using Restful.Models;
namespace Restful.Entities
{
public class ApplicationSettings
{
[Export("EFConnectionString")]
public string ConnectionString
{
get { return "name=TESTEntities"; }
}
}
public partial class TESTEntities : EfDataContextBase, IUnitOfWork
{
[ImportingConstructor()]
public TESTEntities(
[Import("EFConnectionString")]
string connectionString)
: base(connectionString)
{
this.Configuration.ProxyCreationEnabled = false;
this.Configuration.LazyLoadingEnabled = true;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Author> Authors { get; set; }
public DbSet<Book> Books { get; set; }
}
}
If we then examin the actual EDMX file we can see that code generation is
turned off

What that means is that we MUST develop our own classes that may be used with
this Linq To Entities EDMX model file. It can be seen that this model consists
of 2 classes
Author and Book, these are both shown below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
namespace Restful.Models
{
public partial class Author
{
public Author()
{
this.Books = new List<Book>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Book> Books { get; set; }
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture,
"Author Name: {0}, Author Id: {1}", Name, Id);
}
}
}
And this is the Book
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Restful.Models
{
public partial class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int AuthorId { get; set; }
public Author Author { get; set; }
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture,
"Title: {0}, Book Id: {1}", Title, Id);
}
}
}
This pattern keeps track of everything that happens during a business
transaction that affects the database. At the conclusion of the transaction, it
determines how to update the database to conform to the changes.
Martin Fowler has an excellent article on this :
http://www.martinfowler.com/eaaCatalog/unitOfWork.html
Now since we are using Linq to Entities 4.1 POCO, we already have some of the
neseccary bits to go about creating a nice Unit Of Work pattern implementation.
As before we start by examing the actual Linq to Entities 4.1 POCO context object.
That for us starts life as a class that extends
DbContext
Here is the demo one
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
namespace Restful.Entities
{
public abstract class EfDataContextBase : DbContext, IUnitOfWork
{
public EfDataContextBase(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
public IQueryable<T> Get<T>() where T : class
{
return Set<T>();
}
public bool Remove<T>(T item) where T : class
{
try
{
Set<T>().Remove(item);
}
catch (Exception)
{
return false;
}
return true;
}
public void Commit()
{
base.SaveChanges();
}
public void Attach<T>(T obj) where T : class
{
Set<T>().Attach(obj);
}
public void Add<T>(T obj) where T : class
{
Set<T>().Add(obj);
}
}
}
Which as you now know provides a basic Entity Framework unit of work base class. But we need to extend that further to make a specific implementation
for our EF 4.1 POCO objects. So we then end up with this
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.ComponentModel.Composition;
using Restful.Models;
namespace Restful.Entities
{
public class ApplicationSettings
{
[Export("EFConnectionString")]
public string ConnectionString
{
get { return "name=TESTEntities"; }
}
}
public partial class TESTEntities : EfDataContextBase, IUnitOfWork
{
[ImportingConstructor()]
public TESTEntities(
[Import("EFConnectionString")]
string connectionString)
: base(connectionString)
{
this.Configuration.ProxyCreationEnabled = false;
this.Configuration.LazyLoadingEnabled = true;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Author> Authors { get; set; }
public DbSet<Book> Books { get; set; }
}
}
The basic idea is that simply exposes DbSet properties and also
methods to Add/Remove and Save changes. The interaction with these methods will
be done by enroling repositories with the unit of work, which we shall see in
just a minute.
The
Repository pattern has been around a very long time, and comes from
Domain Driven Design. MSDN has this to say about the objectives of the
Repository pattern
Use the Repository pattern to achieve one or more of the following
objectives:
You want to maximize the amount of code that can be tested with
automation and to isolate the data layer to support unit testing.
- You access the data source from many locations and want to apply
centrally managed, consistent access rules and logic.
- You want to implement and centralize a caching strategy for the data
source.
- You want to improve the code's maintainability and readability by
separating business logic from data or service access logic.
- You want to use business entities that are strongly typed so that
you can identify problems at compile time instead of at run time.
- You want to associate a behavior with the related data. For example,
you want to calculate fields or enforce complex relationships or business
rules between the data elements within an entity.
- You want to apply a domain model to simplify complex business logic.
Sounds cool doesn't it but how does that translate into code. Well here is my
take on it (again I abstract this behind interfaces to allow alternative
implementations, or mocking)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.Linq.Expressions;
using System.ComponentModel.Composition;
namespace Restful.Entities
{
public class Repository<T> : IRepository<T> where T : class
{
protected IUnitOfWork context;
public void EnrolInUnitOfWork(IUnitOfWork unitOfWork)
{
this.context = unitOfWork;
}
public int Count
{
get { return context.Get<T>().Count(); }
}
public void Add(T item)
{
context.Add(item);
}
public bool Contains(T item)
{
return context.Get<T>().FirstOrDefault(t => t == item) != null;
}
public void Remove(T item)
{
context.Remove(item);
}
public IQueryable<T> FindAll()
{
return context.Get<T>();
}
public IQueryable<T> FindAll(Func<DbSet<T>, IQueryable<T>> lazySetupAction)
{
DbSet<T> set = ((DbSet<T>)context.Get<T>());
return lazySetupAction(set);
}
public IQueryable<T> FindAll(string lazyIncludeStrings)
{
DbSet<T> set = ((DbSet<T>)context.Get<T>());
return set.Include(lazyIncludeStrings).AsQueryable<T>();
}
public IQueryable<T> FindBy(Func<T, bool> predicate)
{
return context.Get<T>().Where(predicate).AsQueryable<T>();
}
public IQueryable<T> FindByExp(Expression<Func<T, bool>> predicate)
{
return context.Get<T>().Where(predicate).AsQueryable<T>();
}
public IQueryable<T> FindBy(Func<T, bool> predicate, string lazyIncludeString)
{
DbSet<T> set = (DbSet<T>)context.Get<T>();
return set.Include(lazyIncludeString).Where(predicate).AsQueryable<T>();
}
public IQueryable<T> FindByExp(Expression<Func<T, bool>> predicate, string lazyIncludeString)
{
return context.Get<T>().Where(predicate).AsQueryable<T>();
}
}
}
At 1st glance this may seem confusing, but all the respitory does is abstract
away dealing with the raw data from the database. It can also been above that my
implementation relies on a IUnitOfWork object. In my case that is
the actual LINQ to Entities 4.1 DbContext class that we use to talk
to the database.
So my allowing your repositories to interact with the IUnitOfWork
(LINQ to Entities 4.1 DbContext) code we can get the
repositories to enrol in a simple transactional peice of work (unit of work
basically).
Shown below is an example of how you might use my UnitOfWork /
Repository implementations together.
[WebGet(UriTemplate = "Books")]
public IQueryable<DtoBook> GetBooks()
{
loggerService.Info("Calling IQueryable<DtoBook> GetBooks()");
using (unitOfWork)
{
booksRep.EnrolInUnitOfWork(unitOfWork);
List<Book> books =
booksRep.FindAll().ToList();
IQueryable<DtoBook> dtosBooks = books
.Select(b => DtoTranslator.TranslateToDtoBook(b))
.ToList().AsQueryable<DtoBook>();
return dtosBooks;
}
}
Obviously this is a very simple example, but I hope you get the idea.
Logging is of upmost importance in any app, and we should all do it. Luckily
we do not have to do all the hard work ourselves there are some truly excellent
logging frameworks out there.
Log4Net being the pick of the crop in my opinion.
Thankfully integrating
Log4Net is very simple. It is just a matter of
- Referencing the
Log4Net Dll
- Adding some config settings for
Log4Net
- Add a logger object
- Get
Log4Net to configure based on you config settings
Assuming you have added
Log4Net reference, what I normally do is start by abstracting (you know so we can substitute
for a different logging library or mock this one) the logging behind a logging
service like so:
using System;
using log4net;
using Restful.WCFService.Services.Contracts;
namespace Restful.WCFService.Services.Implementation
{
public class Log4NetLoggerService : ILoggerService
{
private ILog logger;
private bool isConfigured = false;
public Log4NetLoggerService()
{
if (!isConfigured)
{
logger = LogManager.GetLogger(typeof(Log4NetLoggerService));
log4net.Config.XmlConfigurator.Configure();
}
}
public void Info(string message)
{
logger.Info(message);
}
public void Warn(string message)
{
logger.Warn(message);
}
public void Debug(string message)
{
logger.Debug(message);
}
public void Error(string message)
{
logger.Error(message);
}
public void Error(Exception ex)
{
logger.Error(ex.Message, ex);
}
public void Fatal(string message)
{
logger.Fatal(message);
}
public void Fatal(Exception ex)
{
logger.Fatal(ex.Message, ex);
}
}
}
Then with that in place I take a dependency on the loggingService (this can be seen in the MEF section we discussed earlier)
Next I add the following
Log4Net configuration (you may want to change this or add new appenders (one
of the best
Log4Net features is the ability to add new appenders, and
Log4Net have many many appenders, and make the process of creating new ones
very straight forward)).
In my case this is in the Restful.WCFService Web.Config.
="1.0" ="utf-8"
<configuration>
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
-->
<log4net>
<root>
<priority value="Info"/>
<appender-ref ref="RollingFileAppender"/>
</root>
<appender name="RollingFileAppender"
type="log4net.Appender.RollingFileAppender">
<file value="C:\Temp\Restful.WCFService.log" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<maxSizeRollBackups value="14" />
<maximumFileSize value="15000KB" />
<datePattern value="yyyyMMdd" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern
value="{%level}%date{dd/MM/yyyy HH:mm:ss} - %message%newline"/>
</layout>
</appender>
</log4net>
</configuration>
The next thing is to ensure that you make sure that is that
Log4Net picks up these settings, which you do by running the following line
of code
XmlConfigurator.Configure();
Then all that remains is to use the logging service (the code below shows
this, where the loggingService was provided by MEF)
[WebGet(UriTemplate = "Books")]
public IQueryable<DtoBook> GetBooks()
{
loggerService.Info("Calling IQueryable<DtoBook> GetBooks()");
...
...
...
}
As I say for this demo solution the client side code is pretty simple, it is
just a simple Console app, at some stage further down the line when I do part II
of this (which may never happen), I will make a nice WPF UI over the top of it
all, however for now its a simple console app, which basically does the
following
- Gets a HttpClient which can be used with the demo
WCF WebApi
service
- POSTs a new Author
- Gets all Author objects
- Does an oData query against Author
- POSTs a new Book
Here is the complete client code, pretty simple I think. The best part is
there is no App.Config specific stuff for the
WCF WebApi
service at all, we simply make a request and deal with the results.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Xml.Serialization;
using Microsoft.ApplicationServer.Http;
using Restful.Models;
using System.Net.Http.Formatting;
using Restful.Models.Dtos;
namespace Restful.Client
{
class Program
{
private enum MimeFormat { JSON, Xml };
string[] randomAuthors = new string[] {
"Jonnie Random",
"Philip Morose",
"Damien Olive",
"Santana Miles",
"Mike Hunt",
"Missy Elliot"
};
string[] randomBooks = new string[] {
"Title1",
"Title2",
"Title3",
"Title4",
"Title5",
"Title6"
};
private Random rand = new Random();
public Program()
{
}
public void SimpleSimulation()
{
string baseUrl = "http://localhost:8300/ef";
HttpClient client = GetClient(MimeFormat.Xml);
string uri = "";
DtoAuthor newAuthor = new DtoAuthor { Name = randomAuthors[rand.Next(randomAuthors.Length)] };
uri = string.Format("{0}/AddAuthor", baseUrl);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, new Uri(uri));
request.Content = new ObjectContent<DtoAuthor>(newAuthor, "application/xml");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
HttpResponseMessage response = client.Send(request);
DtoAuthor receivedAuthor = response.Content.ReadAs<DtoAuthor>();
LogAuthor(uri, receivedAuthor);
client = GetClient(MimeFormat.Xml);
uri = string.Format("{0}/Authors", baseUrl);
response = client.Get(uri);
foreach (DtoAuthor author in response.Content.ReadAs<List<DtoAuthor>>())
{
LogAuthor(uri, author);
}
client = GetClient(MimeFormat.Xml);
uri = string.Format("{0}/Authors?$top=1", baseUrl);
response = client.Get(uri);
DtoAuthor authorToUse = response.Content.ReadAs<List<DtoAuthor>>().FirstOrDefault();
if (authorToUse != null)
{
LogAuthor(uri, authorToUse);
DtoBook newBook = new DtoBook
{
Title = randomBooks[rand.Next(randomBooks.Length)],
AuthorId = authorToUse.Id
};
client = GetClient(MimeFormat.Xml);
uri = string.Format("{0}/AddBook", baseUrl);
request = new HttpRequestMessage(HttpMethod.Post, new Uri(uri));
request.Content = new ObjectContent<DtoBook>(newBook, "application/xml");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
response = client.Send(request);
DtoBook receivedBook = response.Content.ReadAs<DtoBook>();
LogBook(uri, receivedBook);
client = GetClient(MimeFormat.Xml);
uri = string.Format("{0}/Books?$top=1", baseUrl);
response = client.Get(uri);
receivedBook = response.Content.ReadAs<List<DtoBook>>().FirstOrDefault();
LogBook(uri, receivedBook);
}
Console.ReadLine();
}
private void LogAuthor(string action, DtoAuthor author)
{
Console.WriteLine(string.Format("{0}:{1}", action, author));
}
private void LogBook(string action, DtoBook book)
{
Console.WriteLine(string.Format("{0}:{1}", action, book));
}
[STAThread]
static void Main(string[] args)
{
Program p = new Program();
p.SimpleSimulation();
}
private static HttpClient GetClient(MimeFormat format)
{
var client = new HttpClient();
switch (format)
{
case MimeFormat.Xml:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/xml"));
break;
case MimeFormat.JSON:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
break;
}
return client;
}
}
}
Anyway that is all I really wanted to say this time, I am now going to get
back to the final 5% of this OSS project that Pete O'Hanlon and I are working
on. Thing is that final 5% is the hardest part, but we are both into it, so
expect to see it appearing here some time soon. Its been a while coming but we
both like it, and feel it will be of use. So until then.....Dum dum dum.
However if you liked this article, and can be bothered to give a comment/vote
they are always appreciated. Thanks for reading. Cheerio