<?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 : Shrinkr</title><link>http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx</link><description>Tags: Shrinkr</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>MvcExtensions - PerRequestTask</title><link>http://weblogs.asp.net/rashid/archive/2010/05/19/mvcextensions-perrequesttask.aspx</link><pubDate>Wed, 19 May 2010 13:48:37 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7489644</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7489644</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7489644</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2010/05/19/mvcextensions-perrequesttask.aspx#comments</comments><description>&lt;p&gt;In the &lt;a href="http://weblogs.asp.net/rashid/archive/2010/05/12/mvcextensions-bootstrapping.aspx"&gt;previous post&lt;/a&gt;, we have seen the &lt;code&gt;BootstrapperTask&lt;/code&gt; which executes when the application starts and ends, similarly there are times when we need to execute some custom logic when a request starts and ends. Usually, for this kind of scenario we create &lt;code&gt;HttpModule&lt;/code&gt; and hook the begin and end request events. There is nothing wrong with this approach, except HttpModules are not at all IoC containers friendly and tight coupled with &lt;code&gt;HttpContext&lt;/code&gt; and its tail, also defining the HttpModule execution order is bit cumbersome, you either have to modify the &lt;code&gt;machine.config&lt;/code&gt; or clear the HttpModules and add it again in &lt;code&gt;web.config&lt;/code&gt;. Instead, you can use the &lt;code&gt;PerRequestTask&lt;/code&gt; which is very much container friendly as well as supports execution orders. Lets few examples where it can be used.&lt;/p&gt;  &lt;h3&gt;Remove www Subdomain&lt;/h3&gt;  &lt;p&gt;Lets say we want to remove the www subdomain, so that if anybody types http://www.mydomain.com it will automatically redirects to http://mydomain.com.&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:b5dc37fa-47f8-412a-a9b8-6f1c5fcbf7c7" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class RemoveWwwSubdomain : PerRequestTask
{
    public RemoveWwwSubdomain()
    {
        Order = DefaultOrder - 1;
    }

    protected override TaskContinuation ExecuteCore(PerRequestExecutionContext executionContext)
    {
        const string Prefix = "http://www.";

        Check.Argument.IsNotNull(executionContext, "executionContext");

        HttpContextBase httpContext = executionContext.HttpContext;

        string url = httpContext.Request.Url.ToString();

        bool startsWith3W = url.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
        bool shouldContinue = true;

        if (startsWith3W)
        {
            string newUrl = "http://" + url.Substring(Prefix.Length);

            HttpResponseBase response = httpContext.Response;

            response.StatusCode = (int)HttpStatusCode.MovedPermanently;
            response.Status = "301 Moved Permanently";
            response.RedirectLocation = newUrl;
            response.SuppressContent = true;
            shouldContinue = false;
        }

        return shouldContinue ? TaskContinuation.Continue : TaskContinuation.Break;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, first, we are setting the order so that we do not have to execute the remaining tasks of the chain when we are redirecting, next in the &lt;code&gt;ExecuteCore,&lt;/code&gt; we checking the whether www is present, if present we are sending a permanently moved http status code and breaking the task execution chain otherwise we are continuing with the chain.&lt;/p&gt;

&lt;h3&gt;Blocking IP Address&lt;/h3&gt;

&lt;p&gt;Lets take another scenario, your application is hosted in a shared hosting environment where you do not have the permission to change the IIS setting and you want to block certain IP addresses from visiting your application. Lets say, you maintain a list of IP address in database/xml files which you want to block, you have a &lt;code&gt;IBannedIPAddressRepository&lt;/code&gt; service which is used to match banned IP Address.&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:785eebb6-688a-4719-95f4-b81807051d30" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class BlockRestrictedIPAddress : PerRequestTask
{
    protected override TaskContinuation ExecuteCore(PerRequestExecutionContext executionContext)
    {
        bool shouldContinue = true;
        HttpContextBase httpContext = executionContext.HttpContext;

        if (!httpContext.Request.IsLocal)
        {
            string ipAddress = httpContext.Request.UserHostAddress;

            HttpResponseBase httpResponse = httpContext.Response;

            if (executionContext.ServiceLocator.GetInstance&amp;lt;IBannedIPAddressRepository&amp;gt;().IsMatching(ipAddress))
            {
                httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;
                httpResponse.StatusDescription = "IPAddress blocked.";

                shouldContinue = false;
            }
        }

        return shouldContinue ? TaskContinuation.Continue : TaskContinuation.Break;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Managing Database Session&lt;/h3&gt;

&lt;p&gt;Now, let see how it can be used to manage NHibernate session, assuming that &lt;code&gt;ISessionFactory&lt;/code&gt; of NHibernate is &lt;a href="http://weblogs.asp.net/rashid/archive/2010/05/16/mvcextensions-custom-service-registration.aspx"&gt;already registered&lt;/a&gt; in our container.&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:a7c9d716-6f61-4acf-87c1-5424ddb12e1c" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class ManageNHibernateSession : PerRequestTask
{
    private ISession session;

    protected override TaskContinuation ExecuteCore(PerRequestExecutionContext executionContext)
    {
        ISessionFactory factory = executionContext.ServiceLocator.GetInstance&amp;lt;ISessionFactory&amp;gt;();

        session = factory.OpenSession();

        return TaskContinuation.Continue;
    }

    protected override void DisposeCore()
    {
        session.Close();
        session.Dispose();
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;As you can see &lt;code&gt;PerRequestTask&lt;/code&gt; can be used to execute small and precise tasks in the begin/end request, certainly if you want to execute other than begin/end request there is no other alternate of &lt;code&gt;HttpModule&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;That’s it for today, in the next post, we will discuss about the Action Filters, so 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%2f2010%2f05%2f19%2fmvcextensions-perrequesttask.aspx&amp;amp;title=MvcExtensions+-+PerRequestTask"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2010/05/19/mvcextensions-perrequesttask.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7489644" 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/MVC/default.aspx">MVC</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/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MvcExtensions/default.aspx">MvcExtensions</category></item><item><title>MvcExtensions – Bootstrapping</title><link>http://weblogs.asp.net/rashid/archive/2010/05/12/mvcextensions-bootstrapping.aspx</link><pubDate>Wed, 12 May 2010 12:29:38 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7480454</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7480454</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7480454</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2010/05/12/mvcextensions-bootstrapping.aspx#comments</comments><description>&lt;p&gt;When you create a new ASP.NET MVC application you will find that the &lt;code&gt;global.asax&lt;/code&gt; contains the following lines:&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:31fdbc0c-d349-483b-9ee5-1bdd5f4b4d38" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace MvcApplication1
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterRoutes(RouteTable.Routes);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As the application grows, there are quite a lot of plumbing code gets into the &lt;code&gt;global.asax&lt;/code&gt; which quickly becomes a design smell. Lets take a quick look at the code of one of the open source project that I recently visited:&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:2d3eeb36-4a0f-4357-92a4-abe056beae10" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute("Default","{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" });
        }        
        protected override void OnApplicationStarted()
        {
            Error += OnError;
            EndRequest += OnEndRequest;
            
             var settings = new SparkSettings()
                .AddNamespace("System")
                .AddNamespace("System.Collections.Generic")
                .AddNamespace("System.Web.Mvc")
                .AddNamespace("System.Web.Mvc.Html")
                .AddNamespace("MvcContrib.FluentHtml")
                .AddNamespace("********")
                .AddNamespace("********.Web")
                .SetPageBaseType("ApplicationViewPage")
                .SetAutomaticEncoding(true);
                               
#if DEBUG
            settings.SetDebug(true);
#endif
            var viewFactory = new SparkViewFactory(settings);
            ViewEngines.Engines.Add(viewFactory);
#if !DEBUG            
            PrecompileViews(viewFactory);
#endif            

            RegisterAllControllersIn("********.Web");

            log4net.Config.XmlConfigurator.Configure();            
            RegisterRoutes(RouteTable.Routes);

            Factory.Load(new Components.WebDependencies());
            ModelBinders.Binders.DefaultBinder = new Binders.GenericBinderResolver(Factory.TryGet&amp;lt;IModelBinder&amp;gt;);

            ValidatorConfiguration.Initialize("********");
            HtmlValidationExtensions.Initialize(ValidatorConfiguration.Rules);
        }

        private void OnEndRequest(object sender, System.EventArgs e)
        {
            if (((HttpApplication)sender).Context.Handler is MvcHandler)
            {
                CreateKernel().Get&amp;lt;ISessionSource&amp;gt;().Close();
            }
        }
        private void OnError(object sender, System.EventArgs e)
        {
            CreateKernel().Get&amp;lt;ISessionSource&amp;gt;().Close();
        }
        protected override IKernel CreateKernel()
        {
            return Factory.Kernel;
        }
        
        private static void PrecompileViews(SparkViewFactory viewFactory)
        {
            var batch = new SparkBatchDescriptor();
            batch.For&amp;lt;HomeController&amp;gt;().For&amp;lt;ManageController&amp;gt;();
            viewFactory.Precompile(batch);                  
        }&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see there are quite a few of things going on in the above code, Registering the ViewEngine, Compiling the Views, Registering the Routes/Controllers/Model Binders, Settings up Logger, Validations and as you can imagine the more it becomes complex the more things will get added in the application start.&lt;/p&gt;

&lt;p&gt;One of the goal of the MVCExtensions is to reduce the above design smell. Instead of writing all the plumbing code in the application start, it contains &lt;code&gt;BootstrapperTask&lt;/code&gt; to register individual services. Out of the box, it contains &lt;code&gt;BootstrapperTask&lt;/code&gt; to register Controllers, Controller Factory, Action Invoker, Action Filters, Model Binders, Model Metadata/Validation Providers, ValueProvideraFactory, ViewEngines etc and it is intelligent enough to automatically detect the above types and register into the ASP.NET MVC Framework. Other than the built-in tasks you can create your own custom task which will be automatically executed when the application starts. When the &lt;code&gt;BootstrapperTasks&lt;/code&gt; are in action you will find the &lt;code&gt;global.asax&lt;/code&gt; pretty much clean like 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:27324caf-e71a-4906-b8ec-e6067997e393" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class MvcApplication : UnityMvcApplication
{
    public void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs e)
    {
        Check.Argument.IsNotNull(e, "e");

        HttpException exception = e.Exception.GetBaseException() as HttpException;

        if ((exception != null) &amp;amp;&amp;amp; (exception.GetHttpCode() == (int)HttpStatusCode.NotFound))
        {
            e.Dismiss();
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The above code is taken from my another open source project &lt;a href="http://shrinkr.codeplex.com"&gt;Shrinkr&lt;/a&gt;, as you can see the &lt;code&gt;global.asax&lt;/code&gt; is longer cluttered with any plumbing code. One special thing you have noticed that it is inherited from the &lt;code&gt;UnityMvcApplication&lt;/code&gt; rather than regular &lt;code&gt;HttpApplication&lt;/code&gt;. There are separate version of this class for each IoC Container like &lt;code&gt;NinjectMvcApplication&lt;/code&gt;, &lt;code&gt;StructureMapMvcApplication&lt;/code&gt; etc.&lt;/p&gt;

&lt;p&gt;Other than executing the built-in tasks, the Shrinkr also has few custom tasks which gets executed when the application starts. For example, when the application starts, we want to ensure that the default users (which is specified in the &lt;code&gt;web.config&lt;/code&gt;) are created. The following is the custom task that is used to create those default users:&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:1d90067b-7cc3-48e3-b173-c6aba6d36c08" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class CreateDefaultUsers : BootstrapperTask
{
    protected override TaskContinuation ExecuteCore(IServiceLocator serviceLocator)
    {
        IUserRepository userRepository = serviceLocator.GetInstance&amp;lt;IUserRepository&amp;gt;();
        IUnitOfWork unitOfWork = serviceLocator.GetInstance&amp;lt;IUnitOfWork&amp;gt;();
        IEnumerable&amp;lt;User&amp;gt; users = serviceLocator.GetInstance&amp;lt;Settings&amp;gt;().DefaultUsers;

        bool shouldCommit = false;

        foreach (User user in users)
        {
            if (userRepository.GetByName(user.Name) == null)
            {
                user.AllowApiAccess(ApiSetting.InfiniteLimit);

                userRepository.Add(user);
                shouldCommit = true;
            }
        }

        if (shouldCommit)
        {
            unitOfWork.Commit();
        }

        return TaskContinuation.Continue;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are several other Tasks in the Shrinkr that we are also using which you will find in that &lt;a href="http://shrinkr.codeplex.com/"&gt;project&lt;/a&gt;. To create a custom bootstrapping task you have create a new class which either implements the &lt;code&gt;IBootstrapperTask&lt;/code&gt; interface or inherits from the abstract &lt;code&gt;BootstrapperTask&lt;/code&gt; class, I would recommend to start with the &lt;code&gt;BootstrapperTask&lt;/code&gt; as it already has the required code that you have to write in case if you choose the &lt;code&gt;IBootstrapperTask&lt;/code&gt; interface. As you can see in the above code we are overriding the &lt;code&gt;ExecuteCore&lt;/code&gt; to create the default users, the MVCExtensions is responsible for populating the&amp;#160; &lt;a href="http://commonservicelocator.codeplex.com"&gt;ServiceLocator&lt;/a&gt; prior calling this method and in this method we are using the service locator to get the dependencies that are required to create the users (I will cover the custom dependencies registration in the next post). Once the users are created, we are returning a special &lt;code&gt;enum,&lt;/code&gt; &lt;code&gt;TaskContinuation&lt;/code&gt; as the return value, the &lt;code&gt;TaskContinuation&lt;/code&gt; can have three values &lt;code&gt;Continue&lt;/code&gt; (default), &lt;code&gt;Skip&lt;/code&gt; and &lt;code&gt;Break&lt;/code&gt;. The reason behind of having this enum is, in some&amp;#160; special cases you might want to skip the next task in the chain or break the complete chain depending upon the currently running task, in those cases you will use the other two values instead of the &lt;code&gt;Continue&lt;/code&gt;. The last thing I want to cover in the bootstrapping task is the Order. By default all the built-in tasks as well as newly created task order is set to the &lt;code&gt;DefaultOrder&lt;/code&gt;(a static property), in some special cases you might want to execute it before/after all the other tasks, in those cases you will assign the Order in the Task constructor. For Example, in Shrinkr, we want to run few background services when the all the tasks are executed, so we assigned the order as DefaultOrder + 1. Here is the code of that Task:&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:a106aaaa-50e0-44d0-8747-65259a4fc98d" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class ConfigureBackgroundServices : BootstrapperTask
{
    private IEnumerable&amp;lt;IBackgroundService&amp;gt; backgroundServices;

    public ConfigureBackgroundServices()
    {
        Order = DefaultOrder + 1;
    }

    protected override TaskContinuation ExecuteCore(IServiceLocator serviceLocator)
    {
        backgroundServices = serviceLocator.GetAllInstances&amp;lt;IBackgroundService&amp;gt;().ToList();

        backgroundServices.Each(service =&amp;gt; service.Start());

        return TaskContinuation.Continue;
    }

    protected override void DisposeCore()
    {
        backgroundServices.Each(service =&amp;gt; service.Stop());
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;That’s it for today, in the next post I will cover the custom service registration, so 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%2f2010%2f05%2f12%2fmvcextensions-bootstrapping.aspx&amp;amp;title=MvcExtensions+%e2%80%93+Bootstrapping"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2010/05/12/mvcextensions-bootstrapping.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7480454" 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/MVC/default.aspx">MVC</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/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MvcExtensions/default.aspx">MvcExtensions</category></item><item><title>Releasing Shrinkr – An ASP.NET MVC Url Shrinking Service</title><link>http://weblogs.asp.net/rashid/archive/2010/04/19/releasing-shrinkr-an-asp-net-mvc-url-shrinking-service.aspx</link><pubDate>Mon, 19 Apr 2010 12:16:02 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7449559</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7449559</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7449559</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2010/04/19/releasing-shrinkr-an-asp-net-mvc-url-shrinking-service.aspx#comments</comments><description>&lt;p&gt;Few months back, I started blogging on developing a Url Shrinking Service in ASP.NET MVC, but could not complete it due to my engagement with my professional projects. Recently, I was able to manage some time for this project to complete the remaining features that &lt;a href="http://mosesofegypt.net/"&gt;we&lt;/a&gt; planned for the initial release. So I am announcing the official release, the source code is hosted in &lt;a href="http://shrinkr.codeplex.com"&gt;codeplex&lt;/a&gt;, you can also see it live in action &lt;a href="http://rdir.in/"&gt;over here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;The features that we have implemented so far:&lt;/p&gt;  &lt;p&gt;Public:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;OpenID Login. &lt;/li&gt;    &lt;li&gt;Base 36 and 62 based Url generation. &lt;/li&gt;    &lt;li&gt;301 and 302 Redirect. &lt;/li&gt;    &lt;li&gt;Custom Alias. &lt;/li&gt;    &lt;li&gt;Maintaining Generated Urls of User. &lt;/li&gt;    &lt;li&gt;Url Thumbnail. &lt;/li&gt;    &lt;li&gt;Spam Detection through Google Safe Browsing. &lt;/li&gt;    &lt;li&gt;Preview Page (with google warning). &lt;/li&gt;    &lt;li&gt;REST based API for URL shrinking (json/xml/text). &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Control Panel:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Application Health monitoring. &lt;/li&gt;    &lt;li&gt;Marking Url as Spam/Safe. &lt;/li&gt;    &lt;li&gt;Block/Unblock User. &lt;/li&gt;    &lt;li&gt;Allow/Disallow User API Access. &lt;/li&gt;    &lt;li&gt;Manage Banned Domains &lt;/li&gt;    &lt;li&gt;Manage Banned Ip Address. &lt;/li&gt;    &lt;li&gt;Manage Reserved Alias. &lt;/li&gt;    &lt;li&gt;Manage Bad Words. &lt;/li&gt;    &lt;li&gt;Twitter Notification when spam submitted. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Behind the scene it is developed with:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Entity Framework 4 (Code Only) &lt;/li&gt;    &lt;li&gt;ASP.NET MVC 2 &lt;/li&gt;    &lt;li&gt;AspNetMvcExtensibility &lt;/li&gt;    &lt;li&gt;Telerik Extensions for ASP.NET MVC (yes you can you use it freely in your open source projects) &lt;/li&gt;    &lt;li&gt;DotNetOpenAuth &lt;/li&gt;    &lt;li&gt;Elmah &lt;/li&gt;    &lt;li&gt;Moq &lt;/li&gt;    &lt;li&gt;xUnit.net &lt;/li&gt;    &lt;li&gt;jQuery &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;We will be also be releasing&amp;#160; a minor update in few weeks which will contain some of the popular twitter client plug-ins and samples how to use the REST API, we will also try to include the nHibernate + Spark version in that release. In the next release, not sure about the timeline, we will include the Geo-Coding and some rich reporting for both the User and the Administrators.&lt;/p&gt;  &lt;p&gt;Enjoy!!!&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%2f2010%2f04%2f19%2freleasing-shrinkr-an-asp-net-mvc-url-shrinking-service.aspx&amp;amp;title=Releasing+Shrinkr+%e2%80%93+An+ASP.NET+MVC+Url+Shrinking+Service"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2010/04/19/releasing-shrinkr-an-asp-net-mvc-url-shrinking-service.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7449559" 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/MVC/default.aspx">MVC</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/Unity/default.aspx">Unity</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/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category><category domain="http://weblogs.asp.net/rashid/archive/tags/aspnetmvcextensibility/default.aspx">aspnetmvcextensibility</category></item><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>7</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>16</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>Shrinkr - Url Shrinking Service Developed with Entity Framework 4.0, Unity, ASP.NET MVC And jQuery (Part 1)</title><link>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</link><pubDate>Thu, 10 Sep 2009 14:22:41 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7199318</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>21</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7199318</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7199318</wfw:comment><comments>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#comments</comments><description>&lt;p&gt;Creating a full blown url shrinking service was pocking around in my mind for quite some time(of course by using Twitter). Since I heard quite a few good things on Entity Framework 4.0, so I decided to start with it. The first thing I usually do when developing an application is creating the domain model. But to create the domain model, we first have to define the basic functionalities:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The system will only use Open ID for authentication. &lt;/li&gt;    &lt;li&gt;User should be able to shrink url without logging in. &lt;/li&gt;    &lt;li&gt;When shrinking url, user should be able to specify alias, if alias is not specified, the system will auto generate it. &lt;/li&gt;    &lt;li&gt;Shrinked url will also have a associated webpage preview image. &lt;/li&gt;    &lt;li&gt;The system will maintain statistic of shrinked url like number of visit, referrer domain, geographic data etc. (requires login) &lt;/li&gt;    &lt;li&gt;The user should be able to reset shrinked url statistics. (requires login) &lt;/li&gt;    &lt;li&gt;Should have a REST service for creating shrinked url which will work upon the daily limit that was previously set. &lt;/li&gt;    &lt;li&gt;It should have nice web 2.0 style interface and should support adaptive rendering. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;For the above functionalities, I come up with the following Domain Entities:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/DomainObjects_39419D04.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DomainObjects" border="0" alt="DomainObjects" src="http://weblogs.asp.net/blogs/rashid/DomainObjects_thumb_72485439.png" width="1224" height="751" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;As you can see most of entities are nothing but some getter/setter properties, please don’t think it as a &lt;a href="http://martinfowler.com/bliki/AnemicDomainModel.html" target="_blank"&gt;anemic domain model&lt;/a&gt;, in fact the url shrinking service does not have the kind of behaviors that you can put into your entities. When creating the entities one important thing I did was making the properties &lt;code&gt;virtual&lt;/code&gt;, so that Entity Framework can lazy load the associated objects (although it is not necessary for the intrinsic data types). For example, the following shows the codes of &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Alias&lt;/code&gt;:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;User&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:d3645167-d2ad-4251-a728-4e443c3dceeb" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;

    public class User : IEntity
    {
        private ApiSetting apiSetting;

        public User()
        {
            CreatedAt = SystemTime.Now();
            LastActivityAt = SystemTime.Now();
            Aliases = new List&amp;lt;Alias&amp;gt;();
        }

        public virtual long Id
        {
            get;
            set;
        }

        public virtual string Name
        {
            get;
            set;
        }

        public virtual string Email
        {
            get;
            set;
        }

        public virtual bool IsLockedOut
        {
            get;
            set;
        }

        public virtual DateTime CreatedAt
        {
            get;
            set;
        }

        public virtual DateTime LastActivityAt
        {
            get;
            set;
        }

        public Role Role
        {
            [DebuggerStepThrough]
            get
            {
                return (Role) InternalRole;
            }

            [DebuggerStepThrough]
            set
            {
                InternalRole = (int) value;
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual int InternalRole
        {
            get;
            set;
        }

        public virtual IList&amp;lt;Alias&amp;gt; Aliases
        {
            get;
            private set;
        }

        public virtual ApiSetting ApiSetting
        {
            [DebuggerStepThrough]
            get
            {
                if (apiSetting == null)
                {
                    apiSetting = new ApiSetting();
                }

                return apiSetting;
            }

            [DebuggerStepThrough]
            set
            {
                Check.Argument.IsNotNull(value, "value");

                apiSetting = value;
            }
        }

        public virtual bool CanAccessApi
        {
            get
            {
                bool canAccess=  (ApiSetting != null) &amp;amp;&amp;amp;
                                 (ApiSetting.Allowed.GetValueOrDefault()) &amp;amp;&amp;amp;
                                 (ApiSetting.DailyLimit == ApiSetting.InfiniteLimit || ApiSetting.DailyLimit &amp;gt; 0);

                return canAccess;
            }
        }

        public virtual void AllowApiAccess(int dailyLimit)
        {
            if (dailyLimit != ApiSetting.InfiniteLimit)
            {
                Check.Argument.IsNotNegative(dailyLimit, "dailyLimit");
            }

            if (string.IsNullOrEmpty(ApiSetting.Key))
            {
                ApiSetting.Key = Guid.NewGuid().ToString().ToUpperInvariant();
            }

            ApiSetting.Allowed = true;
            ApiSetting.DailyLimit = dailyLimit;
        }

        public virtual bool HasExceedsDailyLimit()
        {
            DateTime lastOneDay = SystemTime.Now().AddDays(-1);

            bool exceeded = CanAccessApi &amp;amp;&amp;amp;
                            ((ApiSetting.DailyLimit != ApiSetting.InfiniteLimit) &amp;amp;&amp;amp;
                             (ApiSetting.DailyLimit &amp;lt;= Aliases.Count(alias =&amp;gt; alias.CreatedAt &amp;gt; lastOneDay &amp;amp;&amp;amp; alias.CreatedByApi)));

            return exceeded;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alias:&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:38b46359-38b1-41ab-a04b-afc51755d404" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr
{
    using System;
    using System.Collections.Generic;

    public class Alias : IEntity
    {
        public Alias()
        {
            Visits = new List&amp;lt;Visit&amp;gt;();
            CreatedAt = SystemTime.Now();
        }

        public virtual long Id
        {
            get;
            set;
        }

        public virtual string Name
        {
            get;
            set;
        }

        public virtual string IPAddress
        {
            get;
            set;
        }

        public virtual DateTime CreatedAt
        {
            get;
            set;
        }

        public virtual IList&amp;lt;Visit&amp;gt; Visits
        {
            get;
            private set;
        }

        public virtual User User
        {
            get;
            set;
        }

        public virtual ShortUrl ShortUrl
        {
            get;
            set;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, define the Repositories, in the above entities there are two aggregate root &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;ShortUrl&lt;/code&gt;, so we will create repositories for those two:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repositories:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/Repositories_5361BA8E.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Repositories" border="0" alt="Repositories" src="http://weblogs.asp.net/blogs/rashid/Repositories_thumb_362BECB7.png" width="654" height="518" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last thing in the domain model is the Services. Please don’t confuse the Service with the Web Service or something else, here Service refers to some domain logic which does not belongs to entities or repositories, usually these services are called from the presentation layer in our case the ASP.NET MVC Controllers. In this application, we do have few things that directly does not belongs to the above entities or repositories, For example, shrinking url, ensuring unique alias etc etc. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Services:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/Services_3E7F9C41.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Services" border="0" alt="Services" src="http://weblogs.asp.net/blogs/rashid/Services_thumb_247BB652.png" width="504" height="248" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;If you are wondering about the purpose of &lt;code&gt;FindByUser&lt;/code&gt; and &lt;code&gt;GetByAlias&lt;/code&gt; method of the above &lt;code&gt;IShortUrlService&lt;/code&gt; as they already exits in &lt;code&gt;IShortUrlRepository&lt;/code&gt;, let me tell you that returning Domain Entities directly in presentation layer is not a good practise, instead you should create some Data Transfer Objects AKA DTO for returning those. The above two methods should do those kind of mappings - flattering the object hierarchy, so that we can easily map it in the UI and do serialization when required. In this application we will have the following two dtos:&lt;/p&gt;

&lt;p&gt;
  &lt;br /&gt;&lt;strong&gt;DTOs:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/DataTransferObjects_17A16034.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DataTransferObjects" border="0" alt="DataTransferObjects" src="http://weblogs.asp.net/blogs/rashid/DataTransferObjects_thumb_756954AD.png" width="564" height="325" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;So far we have discussed about application domain model, In the next post, we will disscuss about the domain model mapping to database with Entity Framework 4.0.&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%2f10%2fshrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx&amp;amp;title=Shrinkr+-+Url+Shrinking+Service+Developed+with+Entity+Framework+4.0%2c+Unity%2c+ASP.NET+MVC+And+jQuery+(Part+1)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=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" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7199318" 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/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+Of+Work/default.aspx">Unit Of Work</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></channel></rss>