<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Kazi Manzur Rashid's Blog : C#</title><link>http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx</link><description>Tags: C#</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Shrinkr - Url Shrinking Service Developed with Entity Framework 4.0, Unity, ASP.NET MVC And jQuery (Part 3)</title><link>http://weblogs.asp.net/rashid/archive/2009/09/15/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx</link><pubDate>Tue, 15 Sep 2009 09:57:54 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7206212</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7206212</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7206212</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/09/15/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx#comments</comments><description>&lt;p&gt;In the &lt;a href="http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx" target="_blank"&gt;previous post&lt;/a&gt;, we have created our initial repositories, in this post I will show how you can use the compiled query of Entity Framework in our repository. To use the compiled query we will put each query of our repositories into its own class and create some common interfaces that we can use in our repositories.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;IQuery&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:31954a0b-f65b-4611-aa91-ec26f8b674fd" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public interface IQuery&amp;lt;TResult&amp;gt;
    {
        TResult Execute(Database database);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;IQueryFactory&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:100fd884-478b-4eb1-b0f5-d7ee5255d3c8" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Collections.Generic;

    public interface IQueryFactory
    {
        bool UseCompiled
        {
            get;
        }

        IQuery&amp;lt;User&amp;gt; CreateUserById(long userId);

        IQuery&amp;lt;User&amp;gt; CreateUserByName(string userName);

        IQuery&amp;lt;User&amp;gt; CreateUserByApiKey(string apiKey);

        IQuery&amp;lt;ShortUrl&amp;gt; CreateShortUrlById(long shortUrlId);

        IQuery&amp;lt;ShortUrl&amp;gt; CreateShortUrlByHash(string urlHash);

        IQuery&amp;lt;ShortUrl&amp;gt; CreateShortUrlByAlias(string alias);

        IQuery&amp;lt;int&amp;gt; CreateShortUrlCountByUserId(long userId);

        IQuery&amp;lt;IEnumerable&amp;lt;ShortUrl&amp;gt;&amp;gt; CreateShortUrlsByUserId(long userId, int start, int max);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we will modify our &lt;code&gt;RepositoryBase&lt;/code&gt;, so that we can pass the &lt;code&gt;IQuaryFactory&lt;/code&gt; in its constructor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RepositoryBase&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:337458c8-e1b9-4827-9c69-9d3f6209d36a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public abstract class RepositoryBase&amp;lt;TEntity&amp;gt; where TEntity : class, IEntity
    {
        protected RepositoryBase(Database database, IQueryFactory queryFactory)
        {
            Check.Argument.IsNotNull(database, "database");
            Check.Argument.IsNotNull(queryFactory, "queryFactory");

            Database = database;
            QueryFactory = queryFactory;
        }

        protected Database Database
        {
            get;
            private set;
        }

        protected IQueryFactory QueryFactory
        {
            get;
            private set;
        }

        public virtual void Add(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().AddObject(entity);
        }

        public virtual void Delete(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().DeleteObject(entity);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can now use the query factory in our repository, for example, in &lt;code&gt;UserRepository&lt;/code&gt; we will be able to use:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ec83a2ed-e0af-4cb7-aba4-bcd5fd8c5897" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public User GetById(long id)
{
    IQuery&amp;lt;User&amp;gt; query = QueryFactory.CreateUserById(id);

    return query.Execute(Database);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, lets check how the query is constructed, first the base class which implements the &lt;code&gt;IQuery&amp;lt;T&amp;gt;&lt;/code&gt; interface:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QueryBase&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d3a7c757-08b1-4f57-917d-7c1e1192d0b8" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public abstract class QueryBase&amp;lt;TResult&amp;gt; : IQuery&amp;lt;TResult&amp;gt;
    {
        protected QueryBase(bool useCompiled)
        {
            UseCompiled = useCompiled;
        }

        protected bool UseCompiled
        {
            get;
            private set;
        }

        public abstract TResult Execute(Database database);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;as mentioned that each query will have its own class, for example, for the above user by id query, we will have the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:dd07f0ea-74d5-471d-9165-4d9be0e87489" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System;
    using System.Data.Objects;
    using System.Linq;
    using System.Linq.Expressions;

    public class UserByIdQuery : QueryBase&amp;lt;User&amp;gt;
    {
        private static readonly Expression&amp;lt;Func&amp;lt;Database, long, User&amp;gt;&amp;gt; expression = (Database database, long id) =&amp;gt; database.Users.SingleOrDefault(user =&amp;gt; user.Id == id);
        private static readonly Func&amp;lt;Database, long, User&amp;gt; plainQuery = expression.Compile();
        private static readonly Func&amp;lt;Database, long, User&amp;gt; compiledQuery = CompiledQuery.Compile(expression);

        private readonly long userId;

        public UserByIdQuery(bool useCompiled, long userId) : base(useCompiled)
        {
            Check.Argument.IsNotNegative(userId, "userId");

            this.userId = userId;
        }

        public override User Execute(Database database)
        {
            Check.Argument.IsNotNull(database, "database");

            return UseCompiled ?
                   compiledQuery(database, userId) :
                   plainQuery(database, userId);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and the implementation of &lt;code&gt;QueryFactory&lt;/code&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:70cfe87e-fc6f-46e1-be94-e50ff58a53e0" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Collections.Generic;

    public class QueryFactory : IQueryFactory
    {
        public QueryFactory(bool useCompiled)
        {
            UseCompiled = useCompiled;
        }

        public bool UseCompiled
        {
            get;
            private set;
        }

        public IQuery&amp;lt;User&amp;gt; CreateUserById(long userId)
        {
            return new UserByIdQuery(UseCompiled, userId);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now, when unit testing the Repositories we will be using the plain queries, for example the &lt;code&gt;UserRepository&lt;/code&gt; will be constructed like the following in unit tests:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d2ebb2d3-e33c-48e9-b224-bc3386166a61" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public UserRepositoryTests()
{
    database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");
    var queryFactory = new QueryFactory(false); // plain query

    repository = new UserRepository(database.Object, queryFactory);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and that’s it. But for the data access layer, I would highly recommend to&amp;#160; have the integration tests as well. The reasons are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It will ensure the underlying Linq Providers does support the Linq queries that we have in your repositories, although the Linq queries we have written here are very simple. &lt;/li&gt;

  &lt;li&gt;By using the SQL Profiler we can ensure the generated SQLs are really optimized. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But to start writing the integration tests, we have one more important thing to do, the &lt;code&gt;UnitOfWork&lt;/code&gt;, which persist the changes in our database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UnitOfWork&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4fcebc1c-2df8-41dc-b0bd-d1ce2816b2b4" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly Database database;

        public UnitOfWork(Database database)
        {
            Check.Argument.IsNotNull(database, "database");

            this.database = database;
        }

        public void Commit()
        {
            database.Commit();
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, lets write our first integration test:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:49d39534-2763-4f3b-806d-e60ab021bfdc" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.IntegrationTests
{
    using System;

    using Xunit;
    using Xunit.Extensions;

    using IoC = global::Microsoft.Practices.ServiceLocation.ServiceLocator;

    public class UserRepositoryTests : TestBase
    {
        private const string Name = "http://kazimanzurrashid.myopenid.com";

        private readonly IUnitOfWork unitOfWork;
        private readonly IUserRepository repository;

        public UserRepositoryTests()
        {
            unitOfWork = IoC.Current.GetInstance&amp;lt;IUnitOfWork&amp;gt;();
            repository = IoC.Current.GetInstance&amp;lt;IUserRepository&amp;gt;();
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_add_user()
        {
            var user = CreateUser();

            Assert.NotEqual(0, user.Id);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_update_user()
        {
            var user = CreateUser();

            user.Email = "kazimanzurrashid@gmail.com";

            unitOfWork.Commit();

            var updatedUser = repository.GetById(user.Id);

            Assert.Equal("kazimanzurrashid@gmail.com", updatedUser.Email);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_delete_user()
        {
            var userId = CreateUser().Id;
            var user = repository.GetById(userId);

            repository.Delete(user);
            unitOfWork.Commit();

            user = repository.GetById(userId);

            Assert.Null(user);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_get_user_by_id()
        {
            var userId = CreateUser().Id;
            var user = repository.GetById(userId);

            Assert.NotNull(user);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_get_user_by_name()
        {
            CreateUser();

            var user = repository.GetByName(Name);

            Assert.NotNull(user);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_get_user_by_api_key()
        {
            var apiKey = CreateUser().ApiSetting.Key;
            var user = repository.GetByApiKey(apiKey);

            Assert.NotNull(user);
        }

        private User CreateUser()
        {
            var user = new User { Name = Name };

            user.ApiSetting.Allowed = true;
            user.ApiSetting.DailyLimit = 1000;
            user.ApiSetting.Key = Guid.NewGuid().ToString().ToUpperInvariant();

            repository.Add(user);
            unitOfWork.Commit();

            return user;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When we run the above test, it will generate the following SQL statements, which I think is pretty much optimized:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GetById&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:5f68e2fd-9843-41a2-8892-0bb147ef0617" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'SELECT 
[Limit1].[Id] AS [Id], 
[Limit1].[Name] AS [Name], 
[Limit1].[Email] AS [Email], 
[Limit1].[IsLockedOut] AS [IsLockedOut], 
[Limit1].[CreatedAt] AS [CreatedAt], 
[Limit1].[Role] AS [Role], 
[Limit1].[LastActivityAt] AS [LastActivityAt], 
[Limit1].[C1] AS [C1], 
[Limit1].[ApiKey] AS [ApiKey], 
[Limit1].[ApiAllowed] AS [ApiAllowed], 
[Limit1].[DailyLimit] AS [DailyLimit]
FROM ( SELECT TOP (2) 
	[Extent1].[Id] AS [Id], 
	[Extent1].[Name] AS [Name], 
	[Extent1].[Email] AS [Email], 
	[Extent1].[IsLockedOut] AS [IsLockedOut], 
	[Extent1].[CreatedAt] AS [CreatedAt], 
	[Extent1].[Role] AS [Role], 
	[Extent1].[ApiKey] AS [ApiKey], 
	[Extent1].[ApiAllowed] AS [ApiAllowed], 
	[Extent1].[DailyLimit] AS [DailyLimit], 
	[Extent1].[LastActivityAt] AS [LastActivityAt], 
	1 AS [C1]
	FROM [dbo].[User] AS [Extent1]
	WHERE [Extent1].[Id] = @p__linq__0
)  AS [Limit1]',N'@p__linq__0 bigint',@p__linq__0=125&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;GetByName&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:88c68121-7560-4144-bc09-e9f6403c6a86" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'SELECT 
[Limit1].[Id] AS [Id], 
[Limit1].[Name] AS [Name], 
[Limit1].[Email] AS [Email], 
[Limit1].[IsLockedOut] AS [IsLockedOut], 
[Limit1].[CreatedAt] AS [CreatedAt], 
[Limit1].[Role] AS [Role], 
[Limit1].[LastActivityAt] AS [LastActivityAt], 
[Limit1].[C1] AS [C1], 
[Limit1].[ApiKey] AS [ApiKey], 
[Limit1].[ApiAllowed] AS [ApiAllowed], 
[Limit1].[DailyLimit] AS [DailyLimit]
FROM ( SELECT TOP (2) 
	[Extent1].[Id] AS [Id], 
	[Extent1].[Name] AS [Name], 
	[Extent1].[Email] AS [Email], 
	[Extent1].[IsLockedOut] AS [IsLockedOut], 
	[Extent1].[CreatedAt] AS [CreatedAt], 
	[Extent1].[Role] AS [Role], 
	[Extent1].[ApiKey] AS [ApiKey], 
	[Extent1].[ApiAllowed] AS [ApiAllowed], 
	[Extent1].[DailyLimit] AS [DailyLimit], 
	[Extent1].[LastActivityAt] AS [LastActivityAt], 
	1 AS [C1]
	FROM [dbo].[User] AS [Extent1]
	WHERE [Extent1].[Name] = @p__linq__0
)  AS [Limit1]',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'http://kazimanzurrashid.myopenid.com/'&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GetByApiKey&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:1bee37b7-31c6-4fb2-b8f5-5e3c0a0868c6" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'SELECT 
[Limit1].[Id] AS [Id], 
[Limit1].[Name] AS [Name], 
[Limit1].[Email] AS [Email], 
[Limit1].[IsLockedOut] AS [IsLockedOut], 
[Limit1].[CreatedAt] AS [CreatedAt], 
[Limit1].[Role] AS [Role], 
[Limit1].[LastActivityAt] AS [LastActivityAt], 
[Limit1].[C1] AS [C1], 
[Limit1].[ApiKey] AS [ApiKey], 
[Limit1].[ApiAllowed] AS [ApiAllowed], 
[Limit1].[DailyLimit] AS [DailyLimit]
FROM ( SELECT TOP (2) 
	[Extent1].[Id] AS [Id], 
	[Extent1].[Name] AS [Name], 
	[Extent1].[Email] AS [Email], 
	[Extent1].[IsLockedOut] AS [IsLockedOut], 
	[Extent1].[CreatedAt] AS [CreatedAt], 
	[Extent1].[Role] AS [Role], 
	[Extent1].[ApiKey] AS [ApiKey], 
	[Extent1].[ApiAllowed] AS [ApiAllowed], 
	[Extent1].[DailyLimit] AS [DailyLimit], 
	[Extent1].[LastActivityAt] AS [LastActivityAt], 
	1 AS [C1]
	FROM [dbo].[User] AS [Extent1]
	WHERE [Extent1].[ApiKey] = @p__linq__0
)  AS [Limit1]',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'9C1A8F98-9CC6-4967-8B48-269CA92833E5'&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Insert&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:025f7703-b94d-48fa-8645-7a3fd29279ab" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'insert [dbo].[User]([Name], [Email], [IsLockedOut], [CreatedAt], [Role], [ApiKey], [ApiAllowed], [DailyLimit], [LastActivityAt])
values (@0, null, @1, @2, @3, @4, @5, @6, @7)
select [Id]
from [dbo].[User]
where @@ROWCOUNT &amp;gt; 0 and [Id] = scope_identity()',N'@0 nvarchar(256),@1 bit,@2 datetime,@3 int,@4 nchar(36),@5 bit,@6 int,@7 datetime',@0=N'http://kazimanzurrashid.myopenid.com',@1=0,@2='2009-08-02 22:04:17:067',@3=0,@4=N'9C1A8F98-9CC6-4967-8B48-269CA92833E5',@5=1,@6=1000,@7='2009-08-02 22:04:17:067'&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7d1ef5fe-f72b-46e7-bd2a-0b316d73f8da" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'update [dbo].[User]
set [Email] = @0
where ([Id] = @1)
',N'@0 nvarchar(256),@1 bigint',@0=N'kazimanzurrashid@gmail.com',@1=142&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Delete&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:058de405-398e-42d7-83ff-5cb7c237e6e5" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'delete [dbo].[User]
where ([Id] = @0)',N'@0 bigint',@0=125&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;You will find other tests in the integration test project.&lt;/p&gt;

&lt;p&gt;That is it for this post, in the next post we will discuss on other infrastructural item such shrinking logic, http content,&amp;#160; IoC etc etc.&lt;/p&gt;

&lt;p&gt;Stay tuned!!!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f09%2f15%2fshrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx&amp;amp;title=Shrinkr+-+Url+Shrinking+Service+Developed+with+Entity+Framework+4.0%2c+Unity%2c+ASP.NET+MVC+And+jQuery+(Part+3)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/09/15/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7206212" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DDD/default.aspx">DDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Common+Service+Locator/default.aspx">Common Service Locator</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unity/default.aspx">Unity</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Mock/default.aspx">Mock</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unit+Test/default.aspx">Unit Test</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Best+Practise/default.aspx">Best Practise</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category></item><item><title>Shrinkr - Url Shrinking Service Developed with Entity Framework 4.0, Unity, ASP.NET MVC And jQuery (Part 2)</title><link>http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx</link><pubDate>Sun, 13 Sep 2009 09:02:36 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7203530</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>11</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7203530</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7203530</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx#comments</comments><description>&lt;p&gt;In the &lt;a href="http://weblogs.asp.net/rashid/archive/2009/09/10/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx" target="_blank"&gt;previous post&lt;/a&gt; we have created our initial domain model, in this post I will show you how the domain model&amp;#160; is mapped to database with Entity Framework 4.0. But before that I would like to discuss how I usually structure the Visual Studio Projects. Most often I prefer to have a one class library and one web project where each has its own unit test project and only one integration test project, for example:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Shrinkr.Core &lt;/li&gt;    &lt;li&gt;Shrinkr.Core.UnitTest &lt;/li&gt;    &lt;li&gt;Shrinkr.Web &lt;/li&gt;    &lt;li&gt;Shrinkr.Web.UnitTest &lt;/li&gt;    &lt;li&gt;Shrinkr.IntegrationTest &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The Core Project is then further divided into following folders:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Shrink.Core      &lt;ul&gt;       &lt;li&gt;Common (Utility, Invariant etc etc) &lt;/li&gt;        &lt;li&gt;EntityObjects (Contains both domain objects and DTOs) &lt;/li&gt;        &lt;li&gt;Extensions (Extension methods) &lt;/li&gt;        &lt;li&gt;Repositories (Contains both interface and implementation) &lt;/li&gt;        &lt;li&gt;Services (Contains both interface and implementation) &lt;/li&gt;        &lt;li&gt;Infrastructure          &lt;ul&gt;           &lt;li&gt;Caching &lt;/li&gt;            &lt;li&gt;Database &lt;/li&gt;            &lt;li&gt;Email &lt;/li&gt;            &lt;li&gt;FileSystem &lt;/li&gt;            &lt;li&gt;Http &lt;/li&gt;            &lt;li&gt;IoC &lt;/li&gt;            &lt;li&gt;Logging &lt;/li&gt;            &lt;li&gt;etc etc etc. &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;But since it is an open source project, I should give privilege to community to replace any part of if with the their preferred technology. for example, replacing Entity Framework with NHibernate or may be Azure Storage, Unity with StructureMap or NInject etc etc. So I decided to structure it based upon the component dependency.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/SoutionExplorer_27C63854.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SoutionExplorer" border="0" alt="SoutionExplorer" src="http://weblogs.asp.net/blogs/rashid/SoutionExplorer_thumb_13504CFC.png" width="434" height="538" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;As you can understand that the Shrinkr.Infrastructure.Microsoft.Practices will contain the Unity and other EntLib related codes and Shrinkr.Infrastructure.EntityFramework for the concrete repositories and other data access codes. Although Entity Framework Team has released few more add-ons (known as Features CTP1), but for the time being we will not use those. The first thing we will do is create a new class which inherits from the &lt;code&gt;ObjectContext&lt;/code&gt;, lets name it as &lt;code&gt;Database&lt;/code&gt;.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:30953c94-8b83-446a-9f3a-91526cf60de5" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Data.Objects;
    using System.Diagnostics;

    public class Database : ObjectContext
    {
        private IObjectSet&amp;lt;User&amp;gt; users;
        private IObjectSet&amp;lt;ShortUrl&amp;gt; shortUrls;
        private IObjectSet&amp;lt;Alias&amp;gt; aliases;
        private IObjectSet&amp;lt;Visit&amp;gt; visits;

        public Database(IConfigurationManager configurationManager, string connectionStringName) : base(GetConnectionString(configurationManager, connectionStringName), "ShrinkrEntities")
        {
            ContextOptions.DeferredLoadingEnabled = true;
        }

        public IObjectSet&amp;lt;User&amp;gt; Users
        {
            [DebuggerStepThrough]
            get
            {
                if (users == null)
                {
                    users = ObjectSet&amp;lt;User&amp;gt;();
                }

                return users;
            }
        }

        public IObjectSet&amp;lt;ShortUrl&amp;gt; ShortUrls
        {
            [DebuggerStepThrough]
            get
            {
                if (shortUrls == null)
                {
                    shortUrls = ObjectSet&amp;lt;ShortUrl&amp;gt;();
                }

                return shortUrls;
            }
        }

        public IObjectSet&amp;lt;Alias&amp;gt; Aliases
        {
            [DebuggerStepThrough]
            get
            {
                if (aliases == null)
                {
                    aliases = ObjectSet&amp;lt;Alias&amp;gt;();
                }

                return aliases;
            }
        }

        public IObjectSet&amp;lt;Visit&amp;gt; Visits
        {
            [DebuggerStepThrough]
            get
            {
                if (visits == null)
                {
                    visits = ObjectSet&amp;lt;Visit&amp;gt;();
                }

                return visits;
            }
        }

        public virtual IObjectSet&amp;lt;TEntity&amp;gt; ObjectSet&amp;lt;TEntity&amp;gt;() where TEntity : class, IEntity
        {
            return CreateObjectSet&amp;lt;TEntity&amp;gt;();
        }

        public virtual void Commit()
        {
            SaveChanges();
        }

        private static string GetConnectionString(IConfigurationManager configurationManager, string connectionStringName)
        {
            Check.Argument.IsNotNull(configurationManager, "configurationManager");
            Check.Argument.IsNotNullOrEmpty(connectionStringName, "connectionStringName");

            string connectionString = configurationManager.ConnectionString(connectionStringName);

            return connectionString;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nothing complex, we are just exposing our Domain Entities as properties like &lt;code&gt;Users&lt;/code&gt;, &lt;code&gt;ShortUrls&lt;/code&gt;, &lt;code&gt;Aliases&lt;/code&gt; etc. One important thing you should check in the above code is that instead of using the &lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;()&lt;/code&gt; in the properties, I have created a &lt;code&gt;virtual&lt;/code&gt; method &lt;code&gt;ObjectSet&amp;lt;T&amp;gt;()&lt;/code&gt; which in turns calls the &lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;. The reasons behind creating this new &lt;code&gt;virtual&lt;/code&gt; method are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;&lt;/code&gt; does not return &lt;code&gt;IObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;, instead it returns the concrete &lt;code&gt;ObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;. &lt;/li&gt;

  &lt;li&gt;&lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;&lt;/code&gt; is not a &lt;code&gt;virtual&lt;/code&gt; method, which means we cannot mock it the unit tests (Although it is debatable whether to write unit tests over any Linq provider, but that is an another story). &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I am not sure why the Entity Framework team decided to return the concrete class instead of the interface also not making the method virtual, if they did, we do not have to write this workarounds and I am pretty sure many people will call it a design smell and finds it frustrating. Next, we will create the base repository which the UserRepository and ShortUrlRepository inherits. Although it is a common practise specially in the NHibernate world to have only one&amp;#160; Repository&amp;lt;T&amp;gt; instead of individual repository for each aggregate root which I will discuss in my next post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RepositoryBase&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:26e01c74-0932-4b54-83b1-385b0b84d455" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public abstract class RepositoryBase&amp;lt;TEntity&amp;gt; where TEntity : class, IEntity
    {
        protected RepositoryBase(Database database)
        {
            Check.Argument.IsNotNull(database, "database");

            Database = database;
        }

        protected Database Database
        {
            get;
            private set;
        }

        public virtual void Add(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().AddObject(entity);
        }

        public virtual void Delete(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().DeleteObject(entity);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check that we have marked both &lt;code&gt;Add&lt;/code&gt; and &lt;code&gt;Delete&lt;/code&gt; method as &lt;code&gt;virtual&lt;/code&gt; so that the concrete repository can &lt;code&gt;override&lt;/code&gt; if it has some extra logic. Now, lets create the Unit Test for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RepositoryBaseTests&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e0829934-e9a0-44a8-9199-870dc690990a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System.Collections.Generic;

    using Moq;
    using Xunit;

    public class RepositoryBaseTests
    {
        private readonly Mock&amp;lt;FakeObjectSet&amp;lt;Dummy&amp;gt;&amp;gt; objectSet;
        private readonly Mock&amp;lt;Database&amp;gt; database;
        private readonly DummyRepository repository;

        public RepositoryBaseTests()
        {
            var objects = new List&amp;lt;Dummy&amp;gt; {
                                            new Dummy { Id = 1},
                                            new Dummy { Id = 2},
                                            new Dummy { Id = 3}
                                          };

            objectSet = new Mock&amp;lt;FakeObjectSet&amp;lt;Dummy&amp;gt;&amp;gt;(objects);

            var configurationManager = new Mock&amp;lt;IConfigurationManager&amp;gt;();
            configurationManager.Setup(mgr =&amp;gt; mgr.ConnectionString(It.IsAny&amp;lt;string&amp;gt;())).Returns("Dummy Connection String");

            database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");
            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;Dummy&amp;gt;()).Returns(objectSet.Object);

            repository = new DummyRepository(database.Object);
        }

        [Fact]
        public void Should_be_able_to_add()
        {
            objectSet.Setup(set =&amp;gt; set.AddObject(It.IsAny&amp;lt;Dummy&amp;gt;())).Verifiable();

            repository.Add(new Dummy());

            objectSet.Verify();
        }

        [Fact]
        public void Should_be_able_to_delete()
        {
            objectSet.Setup(set =&amp;gt; set.DeleteObject(It.IsAny&amp;lt;Dummy&amp;gt;())).Verifiable();

            repository.Delete(new Dummy());

            objectSet.Verify();
        }
   } 

    public class Dummy : IEntity
    {
        public long Id
        {
            get;
            set;
        }
    }

    public class DummyRepository : RepositoryBase&amp;lt;Dummy&amp;gt;
    {
        public DummyRepository(Database database) : base(database)
        {
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To test the &lt;code&gt;RepositoryBase&lt;/code&gt; we have to create few fake classes and in the unit test we are using those. The reason is, if we create mock of &lt;code&gt;RepositoryBase&lt;/code&gt; which methods are virtual the mock framework(Moq) will replace those, so the codes of &lt;code&gt;Add&lt;/code&gt; and &lt;code&gt;Delete&lt;/code&gt; will not be executed. By using the &lt;code&gt;DummyRepository&lt;/code&gt; we are making sure the &lt;code&gt;RepositoryBase&lt;/code&gt; methods are called. Another important thing you might have noticed that when setting up expectations on the &lt;code&gt;database.ObjectSet&lt;/code&gt; (line 28) method we are using another new class &lt;code&gt;FakeObjectSet&lt;/code&gt;. This is the another frustrating part of Entity Framework, you cannot pass/set collection of objects in the &lt;code&gt;ObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;. This is what the &lt;code&gt;FakeObjectSet&lt;/code&gt; does, allowing us to pass the collection of objects so that our unit test can run properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FakeObjectSet&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d5c108dd-d8a8-4fca-8c56-9c25715818a2" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Objects;
    using System.Linq;
    using System.Linq.Expressions;

    public abstract class FakeObjectSet&amp;lt;T&amp;gt; : IObjectSet&amp;lt;T&amp;gt; where T : class
    {
        private readonly IEnumerable&amp;lt;T&amp;gt; objects;

        protected FakeObjectSet(IEnumerable&amp;lt;T&amp;gt; objects)
        {
            this.objects = objects;
        }

        public Expression Expression
        {
            get
            {
                return objects.AsQueryable().Expression;
            }
        }

        public IQueryProvider Provider
        {
            get
            {
                return objects.AsQueryable().Provider;
            }
        }

        public Type ElementType
        {
            get
            {
                return typeof(T);
            }
        }

        public abstract void AddObject(T entity);

        public abstract void Attach(T entity);

        public abstract void DeleteObject(T entity);

        public IEnumerator&amp;lt;T&amp;gt; GetEnumerator()
        {
            return objects.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, creating the concrete repositories are plain and simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UserRepository&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:63dc0a99-33e7-475d-8173-6c2fef7bbcc6" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Linq;

    public class UserRepository : RepositoryBase&amp;lt;User&amp;gt;, IUserRepository
    {
        public UserRepository(Database database) : base(database)
        {
        }

        public User GetById(long id)
        {
            Check.Argument.IsNotZeroOrNegative(id, "id");

            return Database.Users.SingleOrDefault(user =&amp;gt; user.Id == id);
        }

        public User GetByName(string name)
        {
            Check.Argument.IsNotNullOrEmpty(name, "name");

            return Database.Users.SingleOrDefault(user =&amp;gt; user.Name == name);
        }

        public User GetByApiKey(string apiKey)
        {
            Check.Argument.IsNotNullOrEmpty(apiKey, "apiKey");

            return Database.Users.SingleOrDefault(user =&amp;gt; user.ApiSetting.Key == apiKey);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;UserRepositoryTests&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f8856c62-50d1-40cd-867f-196ce7e149cf" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System;
    using System.Collections.Generic;

    using Moq;
    using Xunit;

    public class UserRepositoryTests
    {
        private const long UserId = 1;
        private const string UserName = "http://kazimanzurrashid.myopenid.com";
        private readonly static string ApiKey = Guid.NewGuid().ToString().ToUpperInvariant();

        private readonly Mock&amp;lt;Database&amp;gt; database;
        private readonly UserRepository repository;

        public UserRepositoryTests()
        {
            var users = new List&amp;lt;User&amp;gt; { new User { Id = UserId, Name = UserName } };

            users[0].ApiSetting.Key = ApiKey;

            var userSet = new Mock&amp;lt;FakeObjectSet&amp;lt;User&amp;gt;&amp;gt;(users);

            var configurationManager = new Mock&amp;lt;IConfigurationManager&amp;gt;();
            configurationManager.Setup(mgr =&amp;gt; mgr.ConnectionString(It.IsAny&amp;lt;string&amp;gt;())).Returns("Dummy Connection String");

            database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");

            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;User&amp;gt;()).Returns(userSet.Object);

            repository = new UserRepository(database.Object, queryFactory);
        }

        [Fact]
        public void Should_be_able_to_get_by_id()
        {
            var user = repository.GetById(UserId);

            Assert.Equal(UserName, user.Name);
        }

        [Fact]
        public void Should_be_able_to_get_by_name()
        {
            var user = repository.GetByName(UserName);

            Assert.Equal(UserId, user.Id);
        }

        [Fact]
        public void Should_be_able_to_get_by_api_key()
        {
            var user = repository.GetByApiKey(ApiKey);

            Assert.Equal(UserId, user.Id);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ShortUrlRepository&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:61d8681c-5405-4417-83d6-8182e77ab202" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Collections.Generic;
    using System.Linq;

    public class ShortUrlRepository : RepositoryBase&amp;lt;ShortUrl&amp;gt;, IShortUrlRepository
    {
        public ShortUrlRepository(Database database) : base(database)
        {
        }

        public ShortUrl GetById(long id)
        {
            Check.Argument.IsNotZeroOrNegative(id, "id");

            return Database.ShortUrls.SingleOrDefault(shortUrl =&amp;gt; shortUrl.Id == id);
        }

        public ShortUrl GetByHash(string hash)
        {
            Check.Argument.IsNotNullOrEmpty(hash, "hash");

            return Database.ShortUrls.SingleOrDefault(shortUrl =&amp;gt; shortUrl.Hash == hash);
        }

        public ShortUrl GetByAliasName(string aliasName)
        {
            Check.Argument.IsNotNullOrEmpty(aliasName, "aliasName");

            return Database.ShortUrls.SingleOrDefault(shortUrl =&amp;gt; shortUrl.Aliases.Any(alias =&amp;gt; alias.Name == aliasName));
        }

        public PagedResult&amp;lt;ShortUrl&amp;gt; FindByUserId(long userId, int start, int max)
        {
            Check.Argument.IsNotZeroOrNegative(userId, "userId");
            Check.Argument.IsNotNegative(start, "start");
            Check.Argument.IsNotNegative(max, "max");

            int total = Database.Aliases.Count(alias =&amp;gt; alias.User.Id == userId);

            IQueryable&amp;lt;ShortUrl&amp;gt; result = Database.Aliases.Where(alias =&amp;gt; alias.User.Id == userId)
                                                  .OrderByDescending(alias =&amp;gt; alias.CreatedAt)
                                                  .Select(alias =&amp;gt; alias.ShortUrl)
                                                  .Skip(start)
                                                  .Take(max);

            return new PagedResult&amp;lt;ShortUrl&amp;gt;(result, total);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ShortUrlRepositoryTests&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:19336eeb-d906-48b7-b204-279beed4925c" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System.Collections.Generic;

    using Moq;
    using Xunit;

    public class ShortUrlRepositoryTests
    {
        private readonly Mock&amp;lt;Database&amp;gt; database;
        private readonly ShortUrlRepository repository;

        public ShortUrlRepositoryTests()
        {
            var shortUrls = new List&amp;lt;ShortUrl&amp;gt; {
                                                    new ShortUrl { Id = 1, Title = "Shrinkr.com",Url = "http://shrinkr.com", Hash = "http://shrinkr.com".Hash() },
                                                    new ShortUrl { Id = 2, Title = "DotNetShoutout.com", Url = "http://dotnetshoutout.com", Hash = "http://dotnetshoutout.com".Hash() }
                                               };

            shortUrls[1].Aliases.Add(new Alias { Name = "dtntshtt" });

            var shortUrlSet = new Mock&amp;lt;FakeObjectSet&amp;lt;ShortUrl&amp;gt;&amp;gt;(shortUrls);

            var user = new User { Id = 1 };

            var aliases = new List&amp;lt;Alias&amp;gt;{
                                            new Alias { Id = 1, User = user, ShortUrl = shortUrls[0] },
                                            new Alias { Id = 2, User = user, ShortUrl = shortUrls[1] },
                                         };

            var aliasSet = new Mock&amp;lt;FakeObjectSet&amp;lt;Alias&amp;gt;&amp;gt;(aliases);

            var configurationManager = new Mock&amp;lt;IConfigurationManager&amp;gt;();
            configurationManager.Setup(mgr =&amp;gt; mgr.ConnectionString(It.IsAny&amp;lt;string&amp;gt;())).Returns("Dummy Connection String");

            database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");
            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;ShortUrl&amp;gt;()).Returns(shortUrlSet.Object);
            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;Alias&amp;gt;()).Returns(aliasSet.Object);

            repository = new ShortUrlRepository(database.Object);
        }

        [Fact]
        public void Should_be_able_to_get_by_id()
        {
            var shortUrl = repository.GetById(1);

            Assert.Equal(1, shortUrl.Id);
        }

        [Fact]
        public void Should_be_able_to_get_by_hash()
        {
            var shortUrl = repository.GetByHash("http://shrinkr.com".Hash());

            Assert.Equal(1, shortUrl.Id);
        }

        [Fact]
        public void Should_be_able_to_get_by_alias_name()
        {
            var shortUrl = repository.GetByAliasName("dtntshtt");

            Assert.Equal(2, shortUrl.Id);
        }

        [Fact]
        public void Should_be_able_to_find_by_user_id()
        {
            var shortUrls = repository.FindByUserId(1, 0, 10);

            Assert.Equal(2, shortUrls.Total);
            Assert.Equal(2, shortUrls.Result.Count);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and that’s it, we have completed the initial implementation of our Repositories. What do you think, what it is currently lacking? Yes we are not taking the advantages of Compiled Queries. In the next post, I will show how you can use the both compiled and regular queries in your repositories.&lt;/p&gt;

&lt;p&gt;Stay tuned!!!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f09%2f13%2fshrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx&amp;amp;title=Shrinkr+-+Url+Shrinking+Service+Developed+with+Entity+Framework+4.0%2c+Unity%2c+ASP.NET+MVC+And+jQuery+(Part+2)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7203530" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DDD/default.aspx">DDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/TDD/default.aspx">TDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Common+Service+Locator/default.aspx">Common Service Locator</category><category domain="http://weblogs.asp.net/rashid/archive/tags/IoC_2F00_DI/default.aspx">IoC/DI</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unity/default.aspx">Unity</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Mock/default.aspx">Mock</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unit+Test/default.aspx">Unit Test</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Best+Practise/default.aspx">Best Practise</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Entity+Framework/default.aspx">Entity Framework</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category></item><item><title>Use Event Aggregator to make your application more extensible</title><link>http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx</link><pubDate>Thu, 05 Mar 2009 14:35:28 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6938393</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=6938393</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=6938393</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx#comments</comments><description>&lt;p&gt;Recently, in &lt;a href="http://codeplex.com/Kigg" target="_blank"&gt;KiGG&lt;/a&gt;/&lt;a href="http://dotnetshoutout.com/" target="_blank"&gt;DotNetShoutout&lt;/a&gt; we have integrated &lt;a href="http://twitter.com/dotnetshoutout/" target="_blank"&gt;Twitter&lt;/a&gt;, nothing complex, very basic thing like when a story is submitted or appears in the front page it will broadcast in Twitter and like our feed it will post the short url of the original story (Cant resist to do some shameless marketing for &lt;a href="http://dotnetshoutout.com/" target="_blank"&gt;DotNetShoutout&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;Since it is a new requirement, initially I have modified the &lt;font face="Courier New"&gt;StoryService&lt;/font&gt; constructor to include the twitter client as a new argument and use it after the story is added in the database, the code is something like the following:&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9bfefbac-cf47-4e6c-8c86-22799e0c6b9d" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;//Other codes

//Add it in database
_storyRepository.Add(story);

//Increase User Score
_userScoreService.StorySubmitted(byUser);

// Send Trackback
PingStory(content, story, detailUrl);

//Ping the Feed Servers
PingServers();

//Send Tweet
_twitter.UpdateStatus(story);

result = new StoryCreateResult { NewStory = story, DetailUrl = detailUrl };

return result;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see there are quite a few things that I have do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Increase the User Score. &lt;/li&gt;

  &lt;li&gt;Send Trackback (Thank you for submitting this cool story) &lt;/li&gt;

  &lt;li&gt;Ping Feedburner/Pingomatic/technorati servers. &lt;/li&gt;

  &lt;li&gt;Send Tweet. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So for this new requirement we have to modify it and will again have to do if we add more features in future and we do have a plan to implement the Spy/Log (don’t confuse it with the code logger, it is ajax view which shows what is happening currently in the application) and this obviously not a path we should follow. It violets the OCP completely, tie us to write some transactional script&amp;#160; kind of code. We need to find a way where we can add new features without modifying the &lt;font face="Courier New"&gt;StoryService&lt;/font&gt;. One option would be to pass an array of &lt;font face="Courier New"&gt;IBackgroundService&lt;/font&gt; (As these are noting but some background services)in the &lt;font face="Courier New"&gt;StoryService&lt;/font&gt; constructor which these classes will implement and later on the &lt;font face="Courier New"&gt;StoryService&lt;/font&gt; will call the &lt;font face="Courier New"&gt;Execute&lt;/font&gt; method of each background service. But Story Submit, Story Publish is more like a system event which should be globally available.&lt;/p&gt;

&lt;h3&gt;Enter Event Aggregator&lt;/h3&gt;

&lt;p&gt;As per &lt;a href="http://martinfowler.com/eaaDev/EventAggregator.html" target="_blank"&gt;Martin Fowler&lt;/a&gt; “An Event Aggregator acts as a single source of events for many objects. It registers for all the events of the many objects allowing clients to register with just the aggregator.” &lt;a href="http://codebetter.com/blogs/jeremy.miller/" target="_blank"&gt;Jeremy D Miller&lt;/a&gt; also used this pattern in his excellent &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2008/01/11/build-your-own-cab-extensible-pub-sub-event-aggregator-with-generics.aspx" target="_blank"&gt;Build your own CAB series&lt;/a&gt;. And recently I was browsing through the &lt;a href="http://compositewpf.codeplex.com/" target="_blank"&gt;CompositeWpf/Prism&lt;/a&gt; code and found the &lt;font face="Courier New"&gt;EventAggregator&lt;/font&gt; which seems a perfect candidate for my situation. According to its &lt;a href="http://msdn.microsoft.com/en-us/library/dd458915.aspx" target="_blank"&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;“The EventAggregator service is primarily a container for events that allow decoupling of publishers and subscribers so they can evolve independently.”&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/EventAggregator_62D394A8.png"&gt;&lt;img title="EventAggregator" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="557" alt="EventAggregator" src="http://weblogs.asp.net/blogs/rashid/EventAggregator_thumb_2325E5BE.png" width="800" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;But it has some dependency on .NET WPF which I would like to remove, and after talking with &lt;a href="http://codebetter.com/blogs/glenn.block/" target="_blank"&gt;Glen Block&lt;/a&gt;, he confirmed that since it is licensed under MS-PL, I can copy and modify it according to my need. Also most of the example you will find of Event Aggregator demonstrate the UI events, but it is a very powerful pattern and can be used in non UI events too which we will see next.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;As mentioned in the above that &lt;font face="Courier New"&gt;UserScoreService&lt;/font&gt;, &lt;font face="Courier New"&gt;PingStory&lt;/font&gt;, &lt;font face="Courier New"&gt;PingServer&lt;/font&gt;, &lt;font face="Courier New"&gt;SendTweet&lt;/font&gt; is some kind of background task which can be run independently and it will act as subscriber in the above diagram, so lets create an interface:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:68ebaaa5-d82f-4db2-b61b-cfb33e200c50" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public interface IBackgroundTask
{
    bool IsRunning
    {
        get;
    }

    void Start();

    void Stop();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next we will create an abstract class which will implement this interface to reduce the duplicate codes:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b5fc14c6-f3f6-4ffd-afbc-00e2b15f56bd" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public abstract class BaseBackgroundTask : IBackgroundTask
{
    private readonly IEventAggregator _eventAggregator;

    protected BaseBackgroundTask(IEventAggregator eventAggregator)
    {
        if (eventAggregator == null)
        {
            throw new ArgumentNullException("eventAggregator");
        }

        _eventAggregator = eventAggregator;
    }

    public bool IsRunning
    {
        get;
        private set;
    }

    protected IEventAggregator EventAggregator
    {
        get
        {
            return _eventAggregator;
        }
    }

    public void Start()
    {
        OnStart();
        IsRunning = true;
    }

    public void Stop()
    {
        OnStop();
        IsRunning = false;
    }

    protected abstract void OnStart();

    protected abstract void OnStop();

    protected SubscriptionToken Subscribe&amp;lt;TEvent, TEventArgs&amp;gt;(Action&amp;lt;TEventArgs&amp;gt; action) where TEvent : BaseEvent&amp;lt;TEventArgs&amp;gt; where TEventArgs : class
    {
        return EventAggregator.GetEvent&amp;lt;TEvent&amp;gt;().Subscribe(action, true);
    }

    protected void Unsubscribe&amp;lt;TEvent&amp;gt;(SubscriptionToken token) where TEvent : BaseEvent
    {
        EventAggregator.GetEvent&amp;lt;TEvent&amp;gt;().Unsubscribe(token);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now lets create some concrete implementation of these background tasks.&lt;/p&gt;

&lt;p&gt;First, the Twitter:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f98aa985-6ad1-449b-962e-6b584dc055ac" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public class SendTweet : BaseBackgroundTask
{
    private SubscriptionToken _storySubmitToken;

    public SendTweet(IEventAggregator eventAggregator) : base(eventAggregator)
    {
    }

    protected override void OnStart()
    {
        if (!IsRunning)
        {
            _storySubmitToken = Subscribe&amp;lt;StorySubmitEvent, StorySubmitEventArgs&amp;gt;(StorySubmitted);
        }
    }

    protected override void OnStop()
    {
        if (IsRunning)
        {
            Unsubscribe&amp;lt;StorySubmitEvent&amp;gt;(_storySubmitToken);
        }
    }

    private void StorySubmitted(StorySubmitEventArgs eventArgs)
    {
        UpdateStatus(eventArgs.Story);
    }

    private void UpdateStatus(Story story)
    {
        //Update Twitter status goes here
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next the UserScoreService:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:baa09bd9-2598-4629-bf77-1b7b3cae0e73" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public class UserScoreService : BaseBackgroundTask
{
    private SubscriptionToken _storySubmitToken;

    public UserScoreService(IEventAggregator eventAggregator) : base(eventAggregator)
    {
    }

    protected override void OnStart()
    {
        if (!IsRunning)
        {
            _storySubmitToken = Subscribe&amp;lt;StorySubmitEvent, StorySubmitEventArgs&amp;gt;(StorySubmitted);
        }
    }

    protected override void OnStop()
    {
        if (IsRunning)
        {
            Unsubscribe&amp;lt;StorySubmitEvent&amp;gt;(_storySubmitToken);
        }
    }

    private void StorySubmitted(StorySubmitEventArgs eventArgs)
    {
        IncreaseUserScore(eventArgs.Story.PostedBy);
    }

    private void IncreaseUserScore(User user)
    {
        // Increase user score goes here
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I am skipping the &lt;font face="Courier New"&gt;PingStory&lt;/font&gt; and &lt;font face="Courier New"&gt;PingServer&lt;/font&gt; as they are very much same as above. &lt;/p&gt;

&lt;p&gt;Next the published part, now the &lt;font face="Courier New"&gt;StoryService&lt;/font&gt; will forward the &lt;font face="Courier New"&gt;StorySubmit&lt;/font&gt; event to &lt;font face="Courier New"&gt;EventAggregator&lt;/font&gt; instead of calling these class individually.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:3bb33836-0fb2-40f0-897e-fbb45b1c17fb" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;//Other codes

//Add it in database
_storyRepository.Add(story);

//Publish the event
_eventAggregator.GetEvent&amp;lt;StorySubmitEvent&amp;gt;().Publish(new StorySubmitEventArgs(story, detailUrl));

result = new StoryCreateResult { NewStory = story, DetailUrl = detailUrl };

return result;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;And now we have to ensure that these background services can start listing this event. So lets create a &lt;font face="Courier New"&gt;BootstrapperTask&lt;/font&gt; which I have shown in my &lt;a href="http://weblogs.asp.net/rashid/archive/2009/02/17/use-bootstrapper-in-your-asp-net-mvc-application-and-reduce-code-smell.aspx" target="_blank"&gt;previous post&lt;/a&gt;.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:bcf1556a-42c2-4b4f-9378-0b8419d1e103" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public class StartBackgroundTasks : IBootstrapperTask
{
    private readonly IBackgroundTask[] _tasks;

    public StartBackgroundTasks(IBackgroundTask[] tasks)
    {
        _tasks = tasks;
    }

    public void Execute()
    {
        foreach(IBackgroundTask task in _tasks)
        {
            task.Start();
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;And at last the wiring of Unity container, I am using the fluent version but you can also use the xml configuration if you want.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f0874b46-aebf-47ba-896f-dcff7604baa7" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;IUnityContainer container = new UnityContainer();

container.RegisterType&amp;lt;IBackgroundTask, UserScoreService&amp;gt;("userScore", new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IBackgroundTask, SendTweet&amp;gt;("sendTweet", new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IBackgroundTask, PingStory&amp;gt;("pingStory", new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IBackgroundTask, PingServer&amp;gt;("pingServer", new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IEventAggregator, EventAggregator&amp;gt;(new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IControllerFactory, CommonServiceLocatorControllerFactory&amp;gt;(new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IBootstrapperTask, RegisterRoutes&amp;gt;("route", new ContainerControlledLifetimeManager(), new InjectionConstructor(new [] { RouteTable.Routes}))
         .RegisterType&amp;lt;IBootstrapperTask, RegisterControllerFactory&amp;gt;("controllerFactory", new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IBootstrapperTask, StartBackgroundTasks&amp;gt;("startBackgroundTasks", new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IFormsAuthentication, FormsAuthenticationService&amp;gt;(new ContainerControlledLifetimeManager())
         .RegisterType&amp;lt;IMembershipService, AccountMembershipService&amp;gt;(new InjectionConstructor())
         .RegisterType&amp;lt;AccountController&amp;gt;()
         .RegisterType&amp;lt;HomeController&amp;gt;();

ServiceLocator.SetLocatorProvider(() =&amp;gt; new UnityServiceLocator(container));&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;My initial plan was to refer you the &lt;a href="http://codeplex.com/Kigg" target="_blank"&gt;KiGG&lt;/a&gt;/&lt;a href="http://dotnetshoutout.com/" target="_blank"&gt;DotNetShoutout&lt;/a&gt; source code rather than posting a separate version, but as you know that &lt;a href="http://haacked.com/archive/2009/03/03/aspnetmvc-changes-for-rc2.aspx" target="_blank"&gt;ASP.NET MVC RC2 has released&lt;/a&gt; few days ago I would rather upgrade it to that version.&lt;/p&gt;

&lt;p&gt;Further Reference:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://denisvuyka.wordpress.com/2009/02/21/using-eventaggregator-with-mef/" target="_blank"&gt;Denis Vuyka: Using EventAggregator with MEF&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://codebetter.com/blogs/glenn.block/archive/2009/02/23/event-aggregation-with-mef-with-and-without-eventaggregator.aspx" target="_blank"&gt;Glen Block: Event Aggregation with MEF (with and without EventAggregator)&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comments/Suggestions?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download:&lt;/strong&gt; &lt;a href="http://weblogs.asp.net/blogs/rashid/EventAggregator.zip" target="_blank"&gt;EventAggregator.zip&lt;/a&gt;&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f03%2f05%2fuse-event-aggregator-to-make-your-application-more-extensible.aspx&amp;amp;title=Use+Event+Aggregator+to+make+your+application+more+extensible"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6938393" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DotNetShoutout/default.aspx">DotNetShoutout</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Common+Service+Locator/default.aspx">Common Service Locator</category><category domain="http://weblogs.asp.net/rashid/archive/tags/IoC_2F00_DI/default.aspx">IoC/DI</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unity/default.aspx">Unity</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ocp/default.aspx">ocp</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Closed+Principle/default.aspx">Open Closed Principle</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Design+Patterns/default.aspx">Design Patterns</category><category domain="http://weblogs.asp.net/rashid/archive/tags/EventAggregator/default.aspx">EventAggregator</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Patterns/default.aspx">Patterns</category></item><item><title>Unit Testable Configuration Manager</title><link>http://weblogs.asp.net/rashid/archive/2009/03/03/unit-testable-configuration-manager.aspx</link><pubDate>Mon, 02 Mar 2009 22:45:52 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6935677</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=6935677</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=6935677</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/03/03/unit-testable-configuration-manager.aspx#comments</comments><description>&lt;p&gt;If you are a TDD purist, you should know that accessing file system in Unit Test is violating the rule. But in our application, our infrastructural code often requires to access the configuration values form web.config/app.config. In this post, I will show you how can create a simple wrapper class which you can use in your unit tests without hitting the file system.&lt;/p&gt;  &lt;p&gt;First, create a interface which will allow us to access the common sections of the configuration file:&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b5359247-14d1-4f25-a6ee-46db3e7f5ab6" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public interface IConfigurationManager
{
    NameValueCollection AppSettings
    {
        get;
    }

    string ConnectionStrings(string name);

    T GetSection&amp;lt;T&amp;gt;(string sectionName);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, the implementation:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c238def9-94c4-4615-9a90-eeb48d57cb33" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;using System.Collections.Specialized;
using System.Configuration;

public class ConfigurationManagerWrapper : IConfigurationManager
{
    public NameValueCollection AppSettings
    {
        get
        {
            return ConfigurationManager.AppSettings;
        }
    }

    public string ConnectionStrings(string name)
    {
        return ConfigurationManager.ConnectionStrings[name].ConnectionString;
    }

    public T GetSection&amp;lt;T&amp;gt;(string sectionName)
    {
        return (T) ConfigurationManager.GetSection(sectionName);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a very common pattern which you will find all over in the new ASP.NET 3.5 SP1 &lt;font face="Courier New"&gt;System.Web.Abstraction&lt;/font&gt;. The rule is whatever thing is not unit testable, create an interface with the exact same signature and create a wrapper class which internally calls the corresponding method/property.&lt;/p&gt;

&lt;p&gt;Now lets say, we would like to do some processing with some configuration values like the following (By the way the &lt;font face="Courier New"&gt;Process()&lt;/font&gt; is a poor example):&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:0f05647a-a3d4-4eaa-a590-4720909b8483" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public void Process()
{
    string appVersion = _configuration.AppSettings["version"];
    string connectionString = _configuration.ConnectionStrings("myDatabase");

    OutputCacheSettingsSection settings = _configuration.GetSection&amp;lt;OutputCacheSettingsSection&amp;gt;("system.web/caching/outputCacheSettings");
    int duration = 0;

    if (settings.OutputCacheProfiles.Count &amp;gt; 0)
    {
        OutputCacheProfile profile = settings.OutputCacheProfiles.Get("MyProfile");

        if (profile != null)
        {
            duration = profile.Duration;
        }
    }

    //Now perform operation with these values;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we can write the unit test like the following which does not requires the web.config/app.config file:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9de91d83-f2da-4b40-af56-e27d3052146e" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;[Fact]
public void Test_Process()
{
    _configuration.Expect(c =&amp;gt; c.AppSettings).Returns(new NameValueCollection{ { "version", "1.0" } });
    _configuration.Expect(c =&amp;gt; c.ConnectionStrings(It.IsAny&amp;lt;string&amp;gt;())).Returns(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");

    OutputCacheProfile cacheProfile = new OutputCacheProfile("MyProfile") { Duration = 360 };
    OutputCacheSettingsSection cacheSection = new OutputCacheSettingsSection();
    cacheSection.OutputCacheProfiles.Add(cacheProfile);

    _configuration.Expect(c =&amp;gt; c.GetSection&amp;lt;OutputCacheSettingsSection&amp;gt;(It.IsAny&amp;lt;string&amp;gt;())).Returns(cacheSection);

    _processor.Process();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Enjoy!!!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download&lt;/strong&gt;: &lt;a href="http://weblogs.asp.net/blogs/rashid/UnitTestableConfiguration.zip" target="_blank"&gt;UnitTestableConfiguration.zip&lt;/a&gt;&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f03%2f03%2funit-testable-configuration-manager.aspx&amp;amp;title=Unit+Testable+Configuration+Manager"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/03/03/unit-testable-configuration-manager.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6935677" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/TDD/default.aspx">TDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Mock/default.aspx">Mock</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unit+Test/default.aspx">Unit Test</category></item><item><title>100% Unit Testable Linq To Sql Repository</title><link>http://weblogs.asp.net/rashid/archive/2009/02/19/100-unit-testable-linq-to-sql-repository.aspx</link><pubDate>Thu, 19 Feb 2009 16:32:51 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6916954</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>22</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=6916954</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=6916954</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/02/19/100-unit-testable-linq-to-sql-repository.aspx#comments</comments><description>&lt;p&gt;In this post, I will show you how you can architect your Linq To Sql repository which will have 100% code coverage. I will use our favorite Northwind database along with my ongoing &lt;a href="http://weblogs.asp.net/rashid/archive/2009/02/17/use-bootstrapper-in-your-asp-net-mvc-application-and-reduce-code-smell.aspx" target="_blank"&gt;UnityCommonServiceLocatorMVC&lt;/a&gt; project. First, lets add a Linq To Sql diagram in our project and drag n drop the Category and Product table that will look something like following:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/NorthwindL2S_251B89B4.png"&gt;&lt;img title="Northwind-L2S" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="421" alt="Northwind-L2S" src="http://weblogs.asp.net/blogs/rashid/NorthwindL2S_thumb_03ABBE4B.png" width="645" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;We are skipping the other tables as they are same that we are doing here, next we will create an interface which will abstract the Linq To Sql DataContext from our application.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:52911746-b366-409d-8e43-01f95ea5ae28" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public interface IDatabase : IDisposable
{
    IQueryable&amp;lt;Category&amp;gt; CategoryDataSource
    {
        get;
    }

    IQueryable&amp;lt;Product&amp;gt; ProductDataSource
    {
        get;
    }

    IQueryable&amp;lt;TEntity&amp;gt; GetQueryable&amp;lt;TEntity&amp;gt;() where TEntity : class;

    ITable GetEditable&amp;lt;TEntity&amp;gt;() where TEntity : class;

    void Insert&amp;lt;TEntity&amp;gt;(TEntity instance) where TEntity : class;

    void InsertAll&amp;lt;TEntity&amp;gt;(IEnumerable&amp;lt;TEntity&amp;gt; instances) where TEntity : class;

    void Delete&amp;lt;TEntity&amp;gt;(TEntity instance) where TEntity : class;

    void DeleteAll&amp;lt;TEntity&amp;gt;(IEnumerable&amp;lt;TEntity&amp;gt; instances) where TEntity : class;

    void SubmitChanges();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And now we will create a partial class for the DataContext that implements this interface:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4d9da3cc-dc84-410d-97a9-8a332d473c65" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public partial class Database : IDatabase
{
    public IQueryable&amp;lt;Category&amp;gt; CategoryDataSource
    {
        get
        {
            return GetQueryable&amp;lt;Category&amp;gt;();
        }
    }

    public IQueryable&amp;lt;Product&amp;gt; ProductDataSource
    {
        get
        {
            return GetQueryable&amp;lt;Product&amp;gt;();
        }
    }

    public virtual IQueryable&amp;lt;TEntity&amp;gt; GetQueryable&amp;lt;TEntity&amp;gt;() where TEntity : class
    {
        return GetTable&amp;lt;TEntity&amp;gt;();
    }

    public virtual ITable GetEditable&amp;lt;TEntity&amp;gt;() where TEntity : class
    {
        return GetTable&amp;lt;TEntity&amp;gt;();
    }

    public void Insert&amp;lt;TEntity&amp;gt;(TEntity instance) where TEntity : class
    {
        GetEditable&amp;lt;TEntity&amp;gt;().InsertOnSubmit(instance);
    }

    public void InsertAll&amp;lt;TEntity&amp;gt;(IEnumerable&amp;lt;TEntity&amp;gt; instances) where TEntity : class
    {
        GetEditable&amp;lt;TEntity&amp;gt;().InsertAllOnSubmit(instances);
    }

    public void Delete&amp;lt;TEntity&amp;gt;(TEntity instance) where TEntity : class
    {
        GetEditable&amp;lt;TEntity&amp;gt;().DeleteOnSubmit(instance);
    }

    public void DeleteAll&amp;lt;TEntity&amp;gt;(IEnumerable&amp;lt;TEntity&amp;gt; instances) where TEntity : class
    {
        GetEditable&amp;lt;TEntity&amp;gt;().DeleteAllOnSubmit(instances);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By Default Linq To Sql exposes Sql Server tables as &lt;font face="Courier New"&gt;Table&lt;/font&gt; which is a sealed class, so we can not mock it. But Linq to Sql namespace has an interface &lt;font face="Courier New"&gt;ITable&lt;/font&gt; which the &lt;font face="Courier New"&gt;Table&lt;/font&gt; type implements and that is easy to mock, also this &lt;font face="Courier New"&gt;ITable&lt;/font&gt; exposes &lt;font face="Courier New"&gt;InsertOnSubmit&lt;/font&gt;, &lt;font face="Courier New"&gt;InsertAllOnSubmit&lt;/font&gt;, &lt;font face="Courier New"&gt;DeleteOnSubmit&lt;/font&gt;, &lt;font face="Courier New"&gt;DeleteAllOnSubmit&lt;/font&gt;. So in our interface we exposed the ITable instead of that concrete Table which makes this partial Database class completely unit testable. We will be using &lt;a href="http://code.google.com/p/moq/" target="_blank"&gt;Moq&lt;/a&gt; and &lt;a href="http://www.codeplex.com/xunit" target="_blank"&gt;xUnit.net&lt;/a&gt; for our unit tests but you can also use RhinoMock, NUnit, MBUnit or MSTest.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9fce9dcc-2974-4227-a7aa-5e2e501169c3" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public class DatabaseTest
{
    private readonly Mock&amp;lt;Database&amp;gt; _database;

    public DatabaseTest()
    {
        _database = new Mock&amp;lt;Database&amp;gt;("A dummy connection string");
    }

    [Fact]
    public void CategoryDataSource_Should_Call_GetQueryable()
    {
        _database.Expect(d =&amp;gt; d.GetQueryable&amp;lt;Category&amp;gt;()).Returns(new List&amp;lt;Category&amp;gt;().AsQueryable()).Verifiable();

        Assert.NotNull(_database.Object.CategoryDataSource);

        _database.Verify();
    }

    [Fact]
    public void ProductDataSource_Should_Call_GetQueryable()
    {
        _database.Expect(d =&amp;gt; d.GetQueryable&amp;lt;Product&amp;gt;()).Returns(new List&amp;lt;Product&amp;gt;().AsQueryable()).Verifiable();

        Assert.NotNull(_database.Object.ProductDataSource);

        _database.Verify();
    }

    [Fact]
    public void Insert_Should_Call_GetEditable_And_InsertOnSubmit()
    {
        var editable = new Mock&amp;lt;ITable&amp;gt;();
        var category = new Category();

        _database.Expect(d =&amp;gt; d.GetEditable&amp;lt;Category&amp;gt;()).Returns(editable.Object).Verifiable();
        editable.Expect(e =&amp;gt; e.InsertOnSubmit(category)).Verifiable();

        _database.Object.Insert(category);

        _database.Verify();
        editable.Verify();
    }

    [Fact]
    public void InsertAll_Should_Call_GetEditable_And_InsertAllOnSubmit()
    {
        var editable = new Mock&amp;lt;ITable&amp;gt;();
        var categories = new List&amp;lt;Category&amp;gt;();

        _database.Expect(d =&amp;gt; d.GetEditable&amp;lt;Category&amp;gt;()).Returns(editable.Object).Verifiable();
        editable.Expect(e =&amp;gt; e.InsertAllOnSubmit(categories)).Verifiable();

        _database.Object.InsertAll(categories);

        _database.Verify();
        editable.Verify();
    }

    [Fact]
    public void Delete_Should_Call_GetEditable_And_DeleteOnSubmit()
    {
        var editable = new Mock&amp;lt;ITable&amp;gt;();
        var category = new Category();

        _database.Expect(d =&amp;gt; d.GetEditable&amp;lt;Category&amp;gt;()).Returns(editable.Object).Verifiable();
        editable.Expect(e =&amp;gt; e.DeleteOnSubmit(category)).Verifiable();

        _database.Object.Delete(category);

        _database.Verify();
        editable.Verify();
    }

    [Fact]
    public void DeleteAll_Should_Call_GetEditable_And_DeleteAllOnSubmit()
    {
        var editable = new Mock&amp;lt;ITable&amp;gt;();
        var categories = new List&amp;lt;Category&amp;gt;();

        _database.Expect(d =&amp;gt; d.GetEditable&amp;lt;Category&amp;gt;()).Returns(editable.Object).Verifiable();
        editable.Expect(e =&amp;gt; e.DeleteAllOnSubmit(categories)).Verifiable();

        _database.Object.DeleteAll(categories);

        _database.Verify();
        editable.Verify();
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, lets create the repositories which uses this database:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:646f6637-b2d9-4d7b-b8d8-807d0600a816" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public interface IProductRepository
{
    void Add(Product product);

    void Remove(Product product);

    Product FindById(int id);

    ICollection&amp;lt;Product&amp;gt; FindByCategoryId(int categoryId);

    ICollection&amp;lt;Product&amp;gt; FindAll();
}

public class ProductRepository : IProductRepository
{
    private readonly IDatabase _database;

    public ProductRepository(IDatabase database)
    {
        _database = database;
    }

    public void Add(Product product)
    {
        _database.Insert(product);
    }

    public void Remove(Product product)
    {
        _database.Delete(product);
    }

    public Product FindById(int id)
    {
        return _database.ProductDataSource.SingleOrDefault(p =&amp;gt; p.ProductID == id);
    }

    public ICollection&amp;lt;Product&amp;gt; FindByCategoryId(int categoryId)
    {
        return _database.ProductDataSource.Where(p =&amp;gt; p.CategoryID == categoryId).ToList().AsReadOnly();
    }

    public ICollection&amp;lt;Product&amp;gt; FindAll()
    {
        return _database.ProductDataSource.ToList().AsReadOnly();
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the Unit Test for it:&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:16e33462-33ca-4045-abcf-eb09bc537a94" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public class ProductRepositoryTest
{
    private readonly Mock&amp;lt;IDatabase&amp;gt; _database;
    private readonly ProductRepository _repository;

    public ProductRepositoryTest()
    {
        _database = new Mock&amp;lt;IDatabase&amp;gt;();
        _repository = new ProductRepository(_database.Object);
    }

    [Fact]
    public void Add_Should_Use_Database()
    {
        _database.Expect(db =&amp;gt; db.Insert(It.IsAny&amp;lt;Product&amp;gt;())).Verifiable();

        _repository.Add(new Product());

        _database.Verify();
    }

    [Fact]
    public void Remove_Should_Use_Database()
    {
        _database.Expect(db =&amp;gt; db.Delete(It.IsAny&amp;lt;Product&amp;gt;())).Verifiable();

        _repository.Remove(new Product());

        _database.Verify();
    }

    [Fact]
    public void FindById_Should_Return_Correct_Product_For_The_Specified_Id()
    {
        SetupProductDataSource();

        var product = _repository.FindById(3);

        Assert.Equal(3, product.ProductID);
    }

    [Fact]
    public void FindByCategoryId_Should_Return_Correct_Products_For_The_Specified_CategoryId()
    {
        SetupProductDataSource();

        var products = _repository.FindByCategoryId(2);

        Assert.Equal(2, products.Count);
    }

    [Fact]
    public void FindAll_Should_All_Products()
    {
        SetupProductDataSource();

        var products = _repository.FindAll();

        Assert.Equal(5, products.Count);
    }

    private void SetupProductDataSource()
    {
        Category category1 = new Category{ CategoryID = 1, CategoryName = "Test 1" };
        Category category2 = new Category{ CategoryID = 2, CategoryName = "Test 2" };

        List&amp;lt;Product&amp;gt; products = new List&amp;lt;Product&amp;gt;
                                        {
                                            new Product{ ProductID = 1, ProductName = "Test 1", Category = category1},
                                            new Product{ ProductID = 2, ProductName = "Test 2", Category = category1},
                                            new Product{ ProductID = 3, ProductName = "Test 3", Category = category1},
                                            new Product{ ProductID = 4, ProductName = "Test 4", Category = category2},
                                            new Product{ ProductID = 5, ProductName = "Test 5", Category = category2}
                                        };

        _database.ExpectGet(db =&amp;gt; db.ProductDataSource).Returns(products.AsQueryable());
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I am skipping the &lt;font face="Courier New"&gt;CategoryRepository&lt;/font&gt; as it almost identical, but you can check it in the attached source codes at the bottom of this post. If I run these unit tests with NCover, we will get the following picture:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/NorthwindNCover_01228C8D.png"&gt;&lt;img title="Northwind-NCover" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="496" alt="Northwind-NCover" src="http://weblogs.asp.net/blogs/rashid/NorthwindNCover_thumb_5200051B.png" width="449" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As you can see that we have 100% coverage for both &lt;font face="Courier New"&gt;ProductRepository&lt;/font&gt; and &lt;font face="Courier New"&gt;CategoryRepository&lt;/font&gt; but 56% for the Database. But if you look it closely, you will find that we have 100% code coverage except the &lt;font face="Courier New"&gt;GetQueryable&lt;/font&gt; and &lt;font face="Courier New"&gt;GetEditable&lt;/font&gt; methods in the &lt;font face="Courier New"&gt;Database&lt;/font&gt; partial class .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download&lt;/strong&gt;: &lt;a href="http://weblogs.asp.net/blogs/rashid/LinqTSqlCodeCoverage.zip" target="_blank"&gt;LinqTSqlCodeCoverage.zip&lt;/a&gt;&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f02%2f19%2f100-unit-testable-linq-to-sql-repository.aspx&amp;amp;title=100%25+Unit+Testable+Linq+To+Sql+Repository"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/02/19/100-unit-testable-linq-to-sql-repository.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6916954" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/LINQ+to+SQL/default.aspx">LINQ to SQL</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Code+Coverage/default.aspx">Code Coverage</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Mock/default.aspx">Mock</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unit+Test/default.aspx">Unit Test</category></item><item><title>Domain Model (Developing KiGG v2.0 Part 1)</title><link>http://weblogs.asp.net/rashid/archive/2009/02/12/domain-model-developing-kigg-v2-0-part-1.aspx</link><pubDate>Thu, 12 Feb 2009 00:27:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6898096</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=6898096</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=6898096</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/02/12/domain-model-developing-kigg-v2-0-part-1.aspx#comments</comments><description>&lt;P&gt;As mention in my &lt;A href="http://weblogs.asp.net/rashid/archive/2009/01/20/introducing-dotnetshoutout-com.aspx" target=_blank mce_href="http://weblogs.asp.net/rashid/archive/2009/01/20/introducing-dotnetshoutout-com.aspx"&gt;previous post&lt;/A&gt; that I will be discussing the technical side of &lt;A href="http://codeplex.com/Kigg" target=_blank mce_href="http://codeplex.com/Kigg"&gt;KiGG&lt;/A&gt;. So this is the beginning and it will be a multi-part series. I will try to put as much detail as possible, do let me know if I missed anything.&lt;/P&gt;
&lt;P&gt;Just for a recap, KiGG is Web 2.0 style social news application where I am trying to exercise some of the best practice like TDD, DDD, SOLID etc with Microsoft supported tooling. If you want to see it in action just visit &lt;A href="http://dotnetshoutout.com/" mce_href="http://dotnetshoutout.com"&gt;http://dotnetshoutout.com&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;KiGG is already a fully functional application, but here I am starting from scratch, so the actual code might not look the same with following but it will show you how it is evolved as I am going to post more on it over the time. &lt;/P&gt;
&lt;P&gt;Let us begin with the core functionalities:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;User should be able to submit story. 
&lt;UL&gt;
&lt;LI&gt;User will select a category and can specify multiple tags when submitting story. &lt;/LI&gt;
&lt;LI&gt;User should not be able to submit a story which already exists (based upon Url). &lt;/LI&gt;
&lt;LI&gt;The system will ensure the story is a .NET related story, otherwise it will need moderator approval prior make it visible to everyone. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;User should be able to promote story. 
&lt;UL&gt;
&lt;LI&gt;When the story has not been promoted by him/her. &lt;/LI&gt;
&lt;LI&gt;When the story has not been marked as spam by him/her. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;User should be able to demote story. 
&lt;UL&gt;
&lt;LI&gt;When the story has not been submitted by him/her. &lt;/LI&gt;
&lt;LI&gt;When the story has been previously promoted by him/her. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;User should be able to mark story as spam. 
&lt;UL&gt;
&lt;LI&gt;When the story has not been promoted by him/her. &lt;/LI&gt;
&lt;LI&gt;When the story has not been marked as spam by him/her. &lt;/LI&gt;
&lt;LI&gt;When story is not published. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;User should be able to post comment. 
&lt;UL&gt;
&lt;LI&gt;The system will ensure the comment is not a spam. &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;User should be able to subscribe/unsubscribe comments of a Story. &lt;/LI&gt;
&lt;LI&gt;User should be able to Tag story. &lt;/LI&gt;
&lt;LI&gt;User should be able to view the original story by clicking the link and the count should be maintained. &lt;/LI&gt;
&lt;LI&gt;User Score should be increased/decreased based upon the above actions. &lt;/LI&gt;
&lt;LI&gt;User should be able to view the story list by published/upcoming/category/tag/user etc. &lt;/LI&gt;
&lt;LI&gt;Moderator should be able to Edit Story. &lt;/LI&gt;
&lt;LI&gt;Moderator should be able to Delete Story. &lt;/LI&gt;
&lt;LI&gt;Moderator should be able to Confirm a Story/Comment as Spam. &lt;/LI&gt;
&lt;LI&gt;Moderator should be able to Approve a Story as not spam which was previously marked as spam. &lt;/LI&gt;
&lt;LI&gt;Admin should be able to Lock/Unlock a User. &lt;/LI&gt;
&lt;LI&gt;Admin should be able to change role of a User. &lt;/LI&gt;
&lt;LI&gt;Admin should be able to Publish stories at periodic interval. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;With the above functionalities we can come up with an object model which consists classes like User, Story, Tag, Category, Vote, MarkAsSpam, Comment:&lt;/P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;A href="http://weblogs.asp.net/blogs/rashid/PreDomainObjects_459EB542.png" mce_href="http://weblogs.asp.net/blogs/rashid/PreDomainObjects_459EB542.png"&gt;&lt;IMG title=Pre-DomainObjects style="BORDER-TOP-WIDTH: 0px; DISPLAY: inline; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=493 alt=Pre-DomainObjects src="http://weblogs.asp.net/blogs/rashid/PreDomainObjects_thumb_758568D1.png" width=751 border=0 mce_src="http://weblogs.asp.net/blogs/rashid/PreDomainObjects_thumb_758568D1.png"&gt;&lt;/A&gt; 
&lt;P&gt;Now, lets refine this domain model with TDD (I will skip the red part of red-green-refactor to save space of this post, but you should always exercise the red part while developing in this way).&lt;/P&gt;
&lt;H3&gt;Promoting&lt;/H3&gt;
&lt;P&gt;When promoting the story we have to check two things, user has not previously promoted it and not marked it as spam. Lets write the tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:196bd658-2d59-4ede-8c3f-8666ebdf6b6a style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void HasPromoted_Should_Return_False_When_User_Has_Not_Previously_Promoted()
{
    var user = new User();

    Assert.False(_story.HasPromoted(user));
}

[Fact]
public void HasMarkedAsSpam_Should_Return_False_When_User_Has_Not_Previously_MarkedAsSpam()
{
    var user = new User();

    Assert.False(_story.HasMarkedAsSpam(user));
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:33de9fd9-3e98-43a2-bcbf-fa7e7c1eb6f0 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public bool HasPromoted(User byUser)
{
    return Votes.Any(v =&amp;gt; v.ByUser.Id == byUser.Id);
}

public bool HasMarkedAsSpam(User byUser)
{
    return MarkAsSpams.Any(m =&amp;gt; m.ByUser.Id == byUser.Id);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Now, create a new method that internally calls these two methods, so that client can only call this single method instead of calling those, test:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:5121cb18-8e88-4ea5-b8eb-49803ece83c6 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void CanPromote_Should_Return_True_When_Story_Has_Not_Been_Promoted()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.True(_story.CanPromote(user));
}

[Fact]
public void CanPromote_Should_Return_True_When_Story_Has_Not_Been_MarkedAsSpam_By_The_User()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.True(_story.CanPromote(user));
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:612dc092-e45c-4edb-ac81-4c5eb0d19b74 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public bool CanPromote(User byUser)
{
    return !HasPromoted(byUser) &amp;amp;&amp;amp; !HasMarkedAsSpam(byUser);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Now the actual promote, note that we have introduced a new property&amp;nbsp; Timestamp in Vote, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:bd7beb9a-f801-4465-8d4c-32f40007c690 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void Promote_Should_Return_True_When_User_Can_Promote()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.True(_story.Promote(DateTime.UtcNow, user));
}

[Fact]
public void Promote_Should_Add_User_Vote_In_Votes()
{
    var user = new User { Id = Guid.NewGuid() };

    _story.Promote(DateTime.UtcNow, user);

    Assert.True(_story.Votes.Count(v =&amp;gt; v.ByUser.Id == user.Id) &amp;gt; 0);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d27fb79d-b86b-442f-be19-16374c1ff674 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;private readonly List&amp;lt;Vote&amp;gt; _votes = new List&amp;lt;Vote&amp;gt;();

public ICollection&amp;lt;Vote&amp;gt; Votes
{
    get
    {
        return _votes.AsReadOnly();
    }
}

public bool Promote(DateTime at, User byUser)
{
    if (CanPromote(byUser))
    {
        Vote vote = new Vote
                        {
                            ByUser = byUser,
                            ForStory = this,
                            Timestamp = at
                        };

        _votes.Add(vote);

        return true;
    }

    return false;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Notice that I have exposed the Votes as read only collection, though the ReadOnlyCollection&amp;lt;T&amp;gt; of ObjectModel namespace should be more appropriate, but I would like to stick with the interface instead of concrete class. So adding vote in Votes will raise exception, the client always have to use the Promote method.&lt;/P&gt;
&lt;H3&gt;Demoting&lt;/H3&gt;
&lt;P&gt;Demoting is similar to promoting, we have to check that the User has not submitted the story and the story has been previously promoted by the user(You can only demote if you previously promoted it), tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:335011a9-7c8f-453f-a336-455093cf1be3 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void CanDemote_Should_Return_True_When_Story_Has_Been_Promoted_By_The_User()
{
    //Promote it first
    var user = new User { Id = Guid.NewGuid() };
    _story.Promote(DateTime.UtcNow, user);

    Assert.True(_story.CanDemote(user));
}

[Fact]
public void Demote_Should_Return_True_When_User_Can_Demote()
{
    //Promote it first
    var user = new User { Id = Guid.NewGuid() };
    _story.Promote(DateTime.UtcNow, user);

    Assert.True(_story.Demote(user));
}

[Fact]
public void Demote_Should_Remove_User_Vote_From_Votes()
{
    //Promote it first
    var user = new User { Id = Guid.NewGuid() };
    _story.Promote(DateTime.UtcNow, user);

    _story.Demote(user);

    Assert.True(_story.Votes.Count(v =&amp;gt; v.ByUser.Id == user.Id) == 0);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b09e54bb-a94e-493a-8b12-1f249183acf9 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public bool CanDemote(User byUser)
{
    return (PostedBy.Id != byUser.Id) &amp;amp;&amp;amp; HasPromoted(byUser);
}

public bool Demote(User byUser)
{
    if (CanDemote(byUser))
    {
        Vote vote = _votes.Single(v =&amp;gt; v.ByUser.Id == byUser.Id);

        _votes.Remove(vote);

        return true;
    }

    return false;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Marking as Spam&lt;/H3&gt;
&lt;P&gt;Marking as spam is also similar to story promoting, only a new checking that is if the story is published, so we will need a new property which will indicate whether the story is published, lets create a new property PublishedAt of nullable DateTime and create an extension method:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:747f52e8-1601-4abb-add3-75bed656e50a style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public static bool IsPublished(this Story story)
{
    return (story.PublishedAt.HasValue);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;we also introduced a new property Timestamp for MarkAsSpam like vote, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c6f713dd-4356-444b-9e28-3c0b041bacfd style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void CanMarkAsSpam_Should_Return_True_When_Story_Has_Not_Been_Published()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.True(_story.CanMarkAsSpam(user));
}

[Fact]
public void CanMarkAsSpam_Should_Return_True_When_Story_Has_Not_Been_Promoted_By_The_User()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.True(_story.CanMarkAsSpam(user));
}

[Fact]
public void CanMarkAsSpam_Should_Return_True_When_Story_Has_Not_Been_MarkedAsSpam_By_The_User()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.True(_story.CanMarkAsSpam(user));
}

[Fact]
public void MarkAsSpam_Should_Return_True_When_User_Can_Mark_As_Spam()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.True(_story.MarkAsSpam(DateTime.UtcNow, user));
}

[Fact]
public void MarkAsSpam_Should_Add_User_Marking_In_MarkAsSpams()
{
    var user = new User { Id = Guid.NewGuid() };

    _story.MarkAsSpam(DateTime.UtcNow, user);

    Assert.True(_story.MarkAsSpams.Count(m =&amp;gt; m.ByUser.Id == user.Id) &amp;gt; 0);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b70e86b4-74b1-47e7-836d-1abe5fe8dbcb style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;private readonly List&amp;lt;MarkAsSpam&amp;gt; _markAsSpams = new List&amp;lt;MarkAsSpam&amp;gt;();

public ICollection&amp;lt;MarkAsSpam&amp;gt; MarkAsSpams
{
    get
    {
        return _markAsSpams.AsReadOnly();
    }
}

public bool CanMarkAsSpam(User byUser)
{
    return !this.IsPublished() &amp;amp;&amp;amp; !HasPromoted(byUser) &amp;amp;&amp;amp; !HasMarkedAsSpam(byUser);
}

public bool MarkAsSpam(DateTime at, User byUser)
{
    if (CanMarkAsSpam(byUser))
    {
        MarkAsSpam markAsSpam = new MarkAsSpam
                                    {
                                        ByUser = byUser,
                                        ForStory = this,
                                        Timestamp = at
                                    };

        _markAsSpams.Add(markAsSpam);

        return true;
    }

    return false;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Post Comment&lt;/H3&gt;
&lt;P&gt;For comment we have to introduce few new properties, Id, Content and CreatedAt. We will skip the spam checking part for the future post, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e1b71ab2-9d24-4577-9314-5e6612af6825 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void PostComment_Should_Return_New_Comment()
{
    var user = new User{ Id = Guid.NewGuid() };

    var comment = _story.PostComment("This is a dummy content", DateTime.UtcNow, user);

    Assert.NotNull(comment);
}

[Fact]
public void PostComment_Should_Increase_Comments_Collection()
{
    var previousCount = _story.Comments.Count;

    var user = new User { Id = Guid.NewGuid() };

    _story.PostComment("This is a dummy content", DateTime.UtcNow, user);

    Assert.True(_story.Comments.Count &amp;gt; previousCount);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ea8040d5-6b10-438c-b634-52ab6e89ce90 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;private readonly List&amp;lt;Comment&amp;gt; _comments = new List&amp;lt;Comment&amp;gt;();

public ICollection&amp;lt;Comment&amp;gt; Comments
{
    get
    {
        return _comments.AsReadOnly();
    }
}

public Comment PostComment(string content, DateTime at, User byUser)
{
    Comment comment = new Comment
                          {
                              Id = Guid.NewGuid(),
                              ByUser = byUser,
                              ForStory = this,
                              CreatedAt = at,
                              Content = content
                          };

    _comments.Add(comment);

    return comment;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Subscribing/Unsubscribing Comments&lt;/H3&gt;
&lt;P&gt;When subscribing comment we will check if the user has already subscribed, if not we will subscribe otherwise we will ignore it, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:12d8afd1-9bc0-495c-85a2-4337ed992b26 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void ContainsCommentSubscriber_Should_Return_False_When_User_Does_Not_Exist_In_CommentSubscribers_Collection()
{
    var user = new User { Id = Guid.NewGuid() };

    Assert.False(_story.ContainsCommentSubscriber(user));
}

[Fact]
public void SubscribeComment_Should_Increase_CommentSubscribers_Collection()
{
    var user = new User { Id = Guid.NewGuid() };

    var previousCount = _story.CommentSubscribers.Count;

    _story.SubscribeComment(user);

    Assert.True(_story.CommentSubscribers.Count &amp;gt; previousCount);
}

[Fact]
public void SubscribeComment_Should_Not_Increase_CommentSubscribers_Collection_When_User_Already_Exists()
{
    var user = new User { Id = Guid.NewGuid() };

    _story.SubscribeComment(user);

    var previousCount = _story.CommentSubscribers.Count;

    _story.SubscribeComment(user);

    Assert.Equal(_story.CommentSubscribers.Count, previousCount);
}

[Fact]
public void UnsubscribeComment_Should_Decrease_CommentSubscribers_Collection()
{
    var user = new User { Id = Guid.NewGuid() };
    _story.SubscribeComment(user);

    var previousCount = _story.CommentSubscribers.Count;

    _story.UnSubscribeComment(user);

    Assert.True(_story.CommentSubscribers.Count &amp;lt; previousCount);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:2e94b6fa-bcde-4397-bff7-71395456ac38 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;private readonly List&amp;lt;User&amp;gt; _commentSubscribers = new List&amp;lt;User&amp;gt;();

public ICollection&amp;lt;User&amp;gt; CommentSubscribers
{
    get
    {
        return _commentSubscribers.AsReadOnly();
    }
}

public bool ContainsCommentSubscriber(User byUser)
{
    return _commentSubscribers.Any(cs =&amp;gt; cs.Id == byUser.Id);
}

public void SubscribeComment(User byUser)
{
    if (!ContainsCommentSubscriber(byUser))
    {
        _commentSubscribers.Add(byUser);
    }
}

public void UnSubscribeComment(User byUser)
{
    if (ContainsCommentSubscriber(byUser))
    {
        var s = _commentSubscribers.Single(cs =&amp;gt; cs.Id == byUser.Id);
        _commentSubscribers.Remove(s);
    }
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Viewing Story&lt;/H3&gt;
&lt;P&gt;We need the track how many times a story has been viewed, so let us introduce another property ViewCount, Test:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9adb8b45-796b-42c0-9440-313a8ce66bdb style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void View_Should_Increase_ViewCount()
{
    var previousCount = _story.ViewCount;

    _story.View();

    Assert.True(_story.ViewCount &amp;gt; previousCount);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:078a5cf0-beed-4c7b-9717-08e05d7e2240 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public int ViewCount
{
    get;
    private set;
}

public void View()
{
    ViewCount += 1;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Increasing/Decreasing User Score&lt;/H3&gt;
&lt;P&gt;User score should be increased/decreased based upon the action like submitting/promoting/demoting etc. So first let us create an Enum which will hold some predefined User Actions:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:bd048e8f-b8bb-46c8-a1e0-5d806a44fbb9 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public enum UserAction
{
    None = 0,
    AccountActivated = 1,
    StorySubmitted = 2,
    StoryViewed = 3,
    StoryPromoted = 4,
    StoryCommented = 5,
    StoryMarkedAsSpam = 6,
    SpamStorySubmitted = 7
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;With increasing/decreasing user score we also need to have the support to know the current score and query score for a given time period, so lets add a new class which holds the date, score and user action when increasing/decreasing score, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:3bd99c46-928c-42fe-8fc0-5143ee002fe9 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void CurrentScore_Should_Be_Zero_When_User_Is_Created()
{
    Assert.Equal(0, _user.CurrentScore);
}

[Fact]
public void IncreaseScoreBy_Should_Increase_CurrentScore()
{
    decimal previousScore = _user.CurrentScore;

    _user.IncreaseScoreBy(5, UserAction.StorySubmitted);

    Assert.Equal(previousScore + 5, _user.CurrentScore);
}

[Fact]
public void DecreaseScoreBy_Should_Decrease_CurrentScore()
{
    decimal previousScore = _user.CurrentScore;

    _user.DecreaseScoreBy(50, UserAction.SpamStorySubmitted);

    Assert.Equal(previousScore - 50, _user.CurrentScore);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in User:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:19408e57-07f6-463f-b9bf-12684ac62f12 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public DateTime CreatedAt
{
    get;
    set;
}

public decimal CurrentScore
{
    get
    {
        return GetScoreBetween(CreatedAt, DateTime.UtcNow);
    }
}

private decimal GetScoreBetween(DateTime from, DateTime to)
{
    return _userScores.Where(us =&amp;gt; us.Timestamp &amp;gt;= from &amp;amp;&amp;amp; us.Timestamp &amp;lt;= to).Sum(us =&amp;gt; us.Score);
}

public void IncreaseScoreBy(decimal score, UserAction reason)
{
    AddScore(score, reason);
}

public void DecreaseScoreBy(decimal score, UserAction reason)
{
    AddScore(-score, reason);
}

private void AddScore(decimal score, UserAction reason)
{
    _userScores.Add(
                        new UserScore
                        {
                            OfUser = this,
                            Reason = reason,
                            Score = score,
                            Timestamp = DateTime.UtcNow
                        });
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Tag Story&lt;/H3&gt;
&lt;P&gt;When submitting story, user should be able to specify tags for story and later on can view the stories with that specified tags, so we need to associate tag with both User and Story. Since it is a common behavior, we can create an interface which both Story and User has to implement:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a0c3af81-3dc6-444a-ad97-70a9b55fd4af style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public interface ITagContainer
{
    ICollection&amp;lt;Tag&amp;gt; Tags
    {
        get;
    }

    void AddTag(Tag tag);

    void RemoveTag(Tag tag);

    void RemoveAllTags();

    bool ContainsTag(Tag tag);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Though composition is better than inheritance, but for the time being lets keep it this way. Since both is the same I am only showing the Story, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6762dd35-6a59-4a48-98d5-d4b40c7d1d50 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void Tags_Should_Be_Empty_When_Story_Is_Created()
{
    Assert.Empty(_story.Tags);
}

[Fact]
public void Contains_Should_Return_True_When_Tag_Exists_In_Tags()
{
    var tag = new Tag
                  {
                      Id = Guid.NewGuid(),
                      Name = "Dummy Tag"
                  };

    _story.AddTag(tag);

    Assert.True(_story.ContainsTag(new Tag { Name = "Dummy Tag" }));
}

[Fact]
public void AddTag_Should_Increase_Tags_Collection()
{
    int previousCount = _story.Tags.Count;

    var tag = new Tag
                  {
                      Id = Guid.NewGuid(),
                      Name = "Dummy Tag"
                  };

    _story.AddTag(tag);

    Assert.True(_story.Tags.Count &amp;gt; previousCount);
}

[Fact]
public void AddTag_Should_Not_Increase_Tags_Collection_For_Duplicate_Tag()
{
    var tag1 = new Tag
                   {
                       Id = Guid.NewGuid(),
                       Name = "Dummy Tag"
                   };

    _story.AddTag(tag1);

    int previousCount = _story.Tags.Count;

    var tag2 = new Tag
                   {
                       Id = Guid.NewGuid(),
                       Name = "Dummy Tag"
                   };

    _story.AddTag(tag2);

    Assert.Equal(previousCount, _story.Tags.Count);
}

[Fact]
public void RemoveTag_Should_Decrease_Tags_Collection()
{
    var tag = new Tag
                  {
                      Id = Guid.NewGuid(),
                      Name = "Dummy Tag"
                  };

    _story.AddTag(tag);

    int previousCount = _story.Tags.Count;

    _story.RemoveTag(new Tag { Name = "Dummy Tag" });

    Assert.True(_story.Tags.Count &amp;lt; previousCount);
}

[Fact]
public void RemoveAllTags_Should_Make_Tags_Collection_Empty()
{
    _story.AddTag(new Tag { Id = Guid.NewGuid(), Name = "Dummy Tag1" });
    _story.AddTag(new Tag { Id = Guid.NewGuid(), Name = "Dummy Tag2" });

    _story.RemoveAllTags();

    Assert.Empty(_story.Tags);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e75a5986-4689-49c5-b664-f39e934d451c style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;private readonly List&amp;lt;Tag&amp;gt; _tags = new List&amp;lt;Tag&amp;gt;();

public ICollection&amp;lt;Tag&amp;gt; Tags
{
    get
    {
        return _tags.AsReadOnly();
    }
}

public void AddTag(Tag tag)
{
    if (!ContainsTag(tag))
    {
        _tags.Add(tag);
    }
}

public void RemoveTag(Tag tag)
{
    Tag sameNameTag = _tags.SingleOrDefault(t =&amp;gt; t.Name == tag.Name);

    if (sameNameTag != null)
    {
        _tags.Remove(sameNameTag);
    }
}

public void RemoveAllTags()
{
    _tags.Clear();
}

public bool ContainsTag(Tag tag)
{
    return _tags.Any(t =&amp;gt; t.Name == tag.Name);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Skipping few functionalities&lt;/H3&gt;
&lt;P&gt;We will skip story submit, edit, delete, confirm as spam, view story list for future post.&lt;/P&gt;
&lt;H3&gt;Changing Role of User&lt;/H3&gt;
&lt;P&gt;Admin should be able to change role of User. So we need to introduce another property in User. We will have some predefined role and the functionalities for each role should be static. First, let create an Enum&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6c946252-b145-421b-a29c-3afbcdeb8b9c style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public enum Roles
{
    User = 0,
    Bot = 1,
    Moderator = 2,
    Administrator = 4
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Next, the user will have a property Role and a method to change the role, we will skip the checking whether the caller is an admin for future when changing the role, test:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:45516966-6bed-4fd9-9b8e-c8a932ea4a0b style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void ChangeRole_Should_Update_Role()
{
    _user.ChangeRole(Roles.Administrator);

    Assert.Equal(Roles.Administrator, _user.Role);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;and in User:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:525b2117-e0b2-4b88-8731-529a852d88af style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public Roles Role
{
    get;
    private set;
}

public void ChangeRole(Roles role)
{
    Role = role;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H3&gt;Lock/Unlock User&lt;/H3&gt;
&lt;P&gt;Admin should be able to lock/unlock user. It should be same as Role, we will again skip the admin calling checking for future, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9514651b-a54e-46ce-a52d-f5dd185350bb style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void Lock_Should_Update_IsLocked()
{
    _user.Lock();

    Assert.True(_user.IsLocked);
}

[Fact]
public void Unlock_Should_Update_IsLocked()
{
    _user.Unlock();

    Assert.False(_user.IsLocked);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in User:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7bcc10a5-d82f-4a47-913c-9e314dd766b1 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public bool IsLocked
{
    get;
    private set;
}

public void Lock()
{
    IsLocked = true;
}

public void Unlock()
{
    IsLocked = false;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;H4&gt;Approving Story&lt;/H4&gt;
&lt;P&gt;User can Mark story as spam if they think the story is not relevant, also our spam checkers can block a story from appearing if they detect it as spam. But the Moderator should be the final judge for confirming a story as spam, if the Moderator finds a story is not spam, s/he will approve the story which makes sure the story appearance.&amp;nbsp; For marking the Story as approved we will introduce a new Property ApprovedAt, same as Story published, tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:be4317a6-c91a-4f06-abfe-0079f62ef1ed style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void Approve_Should_Update_ApprovedAt()
{
    var now = DateTime.UtcNow;

    _story.Approve(now);

    Assert.Equal(now, _story.ApprovedAt);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in Story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:75c5eec6-5ee2-48c2-81c5-a76101f9401f style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public DateTime? ApprovedAt
{
    get;
    private set;
}

public void Approve(DateTime at)
{
    ApprovedAt = at;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Note that we are again skipping the checking if the caller is Moderator in Approve method for future.&lt;/P&gt;
&lt;H3&gt;Publishing Story &lt;/H3&gt;
&lt;P&gt;Story publish is a process where popular stories appears in the front page, certainly there should be different strategies for calculating the popularity of story, which we will again it skip for future post, for the time being we will only focus once a story is qualified to publish how do we mark it. As mentioned in the Marking as Spam section that once a Story is published we will update its PublishedAt property, but updating only the PublishedAt does not serves our purpose as we also have to know the Rank to order it in the list. Tests:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9e99ca31-2646-45c2-a5d6-8c4ed0c05db2 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;[Fact]
public void Publish_Should_Update_PublishedAt()
{
    var now = DateTime.UtcNow;

    _story.Publish(now, 1);

    Assert.Equal(now, _story.PublishedAt);
}

[Fact]
public void Publish_Should_Update_Rank()
{
    _story.Publish(DateTime.UtcNow, 1);

    Assert.Equal(1, _story.Rank);
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;And in story:&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=scid:812469c5-0cb0-4c63-8c15-c81123a09de7:09f62218-55c6-4289-b378-27525e2bb982 style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE class=c# name="code"&gt;public DateTime? PublishedAt
{
    get;
    private set;
}

public int? Rank
{
    get;
    private set;
}

public void Publish(DateTime at, int rank)
{
    PublishedAt = at;
    Rank = rank;
}&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;The following is final object model of this part that we have done so far:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://weblogs.asp.net/blogs/rashid/DomainObjects_4B651F0F.png" mce_href="http://weblogs.asp.net/blogs/rashid/DomainObjects_4B651F0F.png"&gt;&lt;IMG title=DomainObjects style="BORDER-TOP-WIDTH: 0px; DISPLAY: inline; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=856 alt=DomainObjects src="http://weblogs.asp.net/blogs/rashid/DomainObjects_thumb_7D68D167.png" width=790 border=0 mce_src="http://weblogs.asp.net/blogs/rashid/DomainObjects_thumb_7D68D167.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;You can also download the complete code from the bottom of this post.&lt;/P&gt;
&lt;P&gt;There are few points in the above which I like to highlight&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Note that in above we are only focusing on the Domain Logic, we did not mentioned anything about database, UI or any other infrastructural stuffs. &lt;/LI&gt;
&lt;LI&gt;Almost all of the code blocks are 3/4 lines long which is easy to understand and unit test. &lt;/LI&gt;
&lt;LI&gt;There are certain functionalities in the above can be also achieved by using only properties instead of using method, for example in the User we can have IsLocked property with both getter and setter but instead we have created Lock, Unlock method and readonly property IsLocked which I think makes it more explicit and also expressive. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;In the next post, we will check how to map this domain model into the database and create repository with LinqToSql with 100% code coverage.&lt;/P&gt;
&lt;P&gt;Stay tuned!!!&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Download&lt;/STRONG&gt;: &lt;A href="http://weblogs.asp.net/blogs/rashid/KiGG/Kigg.DomainModel.zip" target=_blank mce_href="http://weblogs.asp.net/blogs/rashid/KiGG/Kigg.DomainModel.zip"&gt;Source Code&lt;/A&gt;&lt;/P&gt;
&lt;DIV class=wlWriterHeaderFooter style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;
&lt;DIV class=shoutIt&gt;&lt;A href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f02%2f12%2fdomain-model-developing-kigg-v2-0-part-1.aspx&amp;amp;title=Domain+Model+(Developing+KiGG+v2.0+Part+1)" rev=vote-for mce_href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f02%2f12%2fdomain-model-developing-kigg-v2-0-part-1.aspx&amp;amp;title=Domain+Model+(Developing+KiGG+v2.0+Part+1)"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/02/12/domain-model-developing-kigg-v2-0-part-1.aspx" mce_src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/02/12/domain-model-developing-kigg-v2-0-part-1.aspx"&gt;&lt;/A&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6898096" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DotNetShoutout/default.aspx">DotNetShoutout</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DDD/default.aspx">DDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/TDD/default.aspx">TDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/KiGG/default.aspx">KiGG</category></item><item><title>Custom Linq Provider</title><link>http://weblogs.asp.net/rashid/archive/2007/11/11/custom-linq-provider.aspx</link><pubDate>Sat, 10 Nov 2007 22:05:47 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:5015779</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=5015779</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=5015779</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2007/11/11/custom-linq-provider.aspx#comments</comments><description>&lt;p&gt;My ex-partner of crime &lt;a href="http://weblogs.asp.net/mehfuzh" target="_blank" rel="nofollow"&gt;Mehfuz&lt;/a&gt; recently wrote an excellent article on how to develop a custom Linq Provider. In this article he shows how to interact with the popular photo sharing site &lt;a href="http://www.flickr.com/" target="_blank" rel="nofollow"&gt;Flickr&lt;/a&gt; with a custom Linq provider. &lt;a href="http://dotnetslackers.com/articles/csharp/LINQProviderBasics.aspx" target="_blank"&gt;Check it out&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=5015779" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category></item></channel></rss>