Amazon.com Widgets MVC

WilliaBlog.Net

I dream in code

About the author

Robert Williams is an internet application developer for the Salem Web Network.
E-mail me Send mail
Code Project Associate Logo
Go Daddy Deal of the Week: 30% off your order at GoDaddy.com! Offer expires 11/6/12

Recent comments

Archive

Authors

Tags

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.


Moving Files in Visual Studio and SVN

I'm writing this down because (1) I've had to figure it out a few times already and don't want to figure it out again, and (2) it may save you some snortin' and cussin' if you run across it yourself. It is astonishingly annoying.

If you have an MVC 3 project in Visual Studio 2010 and while refactoring you move a file - for example you move a view model to the shared area, you may suddenly encounter a compile error in some random temporary file like the one below:

The type or namespace name 'xxx' does not exist in the namespace 'xxx' (are you missing an assembly reference?)    c:\Users\[user name]\AppData\Local\Temp\Temporary ASP.NET Files\temp\eab6c63b\948de17e\App_Web_hadnllup.0.cs

Cleaning the solution and/or deleting the temporary files will not resolve the problem. This can happen whether you simply drag and drop the file to the new location, then change the namespace yourself, or if you right click on the file and choose Refactor > Move and have Visual Studio move the file and update the namespaces for you. The latter process (in theory) will update all references to the file within your project automatically, while with the former, you would typically try to compile the project and then fix all the broken items that now appear in the Error list as a result of the namespace change. However, unless you do a global find and replace, you will probably still end up getting the cryptic error above because chances are that the @model declaration in one or more of your Views is still pointing to the old namespace for that viewmodel file. Update the view(s) and the error will go away and all will be fine.

Now, if you use SVN, things are a little more complicated: If you move the file using either of the techniques described above, what will happen is SVN will delete the original file and create a new one for the new location, which is fine, unless you were hoping to preserve the full subversion history of that file. If you want to preserve the file history in SVN and move the file, this is how you do it: in Windows Explorer, right-click and drag the file from its old location to its new location, then select "SVN move versioned item" from the context menu. This will not only move the actual file itself, but it will also make sure that all the file history stays with it after you check in your changes. Back in Visual Studio, use the Solution Explorer in VS2010 to "exclude from project" the (now-missing) copy of the file in its old location, and then "include in project" the file in its new location. You may need to refresh the view in solution explorer and/or make sure you are viewing all the files by clicking the "Show all Files" icon at the top (next to the refresh icon) in order to see these files.

After you update the namespace to reflect the new location, I recommend using a global find and replace before you try to compile to save yourself a lot of trouble.

To summarize, if you find yourself getting obsolete, broken references in auto-generated files that you can't permanently delete, look in your Views folder for the bad references.


Posted by Williarob on Wednesday, May 25, 2011 7:33 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Mock a database repository using Moq

The concept of unit testing my code is still fairly new to me and was introduced when I started writing applications with the Microsoft MVC Framework in Visual Studio 2008.

Intimidated somewhat by the Moq library's heavy reliance on lambdas, my early tests used full Mock classes that I would write myself, and which implemented the same interface as my real database repositories. I'd only write the code for the methods I needed, all other methods would simply throw a "NotImplementedException". However, I quickly discovered that the problem with this approach is that whenever a new method was added to the interface, my test project would no longer build (since the new method was not implemented in my mock repository) and I would have to manually add a new method that threw another "NotImplementedException". After doing this for the 5th or 6th time I decided to face my fears and get to grips with using the Moq library instead. Here is a simple example, of how you can mock a database repository class using the Moq library.

Let's assume that your database contains a table called Product, and that either you or Linq, or LLBLGen, or something similar has created the following class to represent that table as an object in your class library:

The Product Class

namespace MoqRepositorySample

{

    using System;

 

    public class Product

    {

        public int ProductId { get; set; }

 

        public string Name { get; set; }

 

        public string Description { get; set; }

 

        public double Price { get; set; }

 

        public DateTime DateCreated { get; set; }

 

        public DateTime DateModified { get; set; }

    }

}

 

Your Product Repository class might implement an interface similar to the following, which offers basic database functionality such as retrieving a product by id, by name, fetching all products, and a save method that would handle inserting and updating products.

 

The IProductRepository Interface

 

namespace MoqRepositorySample

{

    using System.Collections.Generic;

 

    public interface IProductRepository

    {

        IList<Product> FindAll();

 

        Product FindByName(string productName);

 

        Product FindById(int productId);

 

        bool Save(Product target);

    }

}

 

The test class that follows demonstrates how to use Moq to set up a mock Products repository based on the interface above. The unit tests shown here focus primarily on testing the mock repository itself, rather than on testing how your application uses the repository, as they would in the real world.

 

Microsoft Unit Test Class

 

namespace TestProject1

{

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

 

    using Moq;

 

    using MoqRepositorySample;

 

    ///<summary>

    /// Summary description for UnitTest1

    ///</summary>

    [TestClass]

    public class UnitTest1

    {

        ///<summary>

        /// Constructor

        ///</summary>

        public UnitTest1()

        {

            // create some mock products to play with

            IList<Product> products = new List<Product>

                {

                    new Product { ProductId = 1, Name = "C# Unleashed", Description = "Short description here", Price = 49.99 },

                    new Product { ProductId = 2, Name = "ASP.Net Unleashed", Description = "Short description here", Price = 59.99 },

                    new Product { ProductId = 3, Name = "Silverlight Unleashed", Description = "Short description here", Price = 29.99 }

                };

 

            // Mock the Products Repository using Moq

            Mock<IProductRepository> mockProductRepository = new Mock<IProductRepository>();

 

            // Return all the products

            mockProductRepository.Setup(mr => mr.FindAll()).Returns(products);

 

            // return a product by Id

            mockProductRepository.Setup(mr => mr.FindById(It.IsAny<int>())).Returns((int i) => products.Where(x => x.ProductId == i).Single());

 

            // return a product by Name

            mockProductRepository.Setup(mr => mr.FindByName(It.IsAny<string>())).Returns((string s) => products.Where(x => x.Name == s).Single());

 

            // Allows us to test saving a product

            mockProductRepository.Setup(mr => mr.Save(It.IsAny<Product>())).Returns(

                (Product target) =>

                {

                    DateTime now = DateTime.Now;

 

                    if (target.ProductId.Equals(default(int)))

                    {

                        target.DateCreated = now;

                        target.DateModified = now;

                        target.ProductId = products.Count() + 1;

                        products.Add(target);

                    }

                    else

                    {

                        var original = products.Where(q => q.ProductId == target.ProductId).Single();

 

                        if (original == null)

                        {

                            return false;

                        }

 

                        original.Name = target.Name;

                        original.Price = target.Price;

                        original.Description = target.Description;

                        original.DateModified = now;

                    }

 

                    return true;

                });

 

            // Complete the setup of our Mock Product Repository

            this.MockProductsRepository = mockProductRepository.Object;

        }

 

        ///<summary>

        /// Gets or sets the test context which provides

        /// information about and functionality for the current test run.

        ///</summary>

        public TestContext TestContext { get; set; }

 

        ///<summary>

        /// Our Mock Products Repository for use in testing

        ///</summary>

        public readonly IProductRepository MockProductsRepository;

 

        ///<summary>

        /// Can we return a product By Id?

        ///</summary>

        [TestMethod]

        public void CanReturnProductById()

        {

            // Try finding a product by id

            Product testProduct = this.MockProductsRepository.FindById(2);

 

            Assert.IsNotNull(testProduct); // Test if null

            Assert.IsInstanceOfType(testProduct, typeof(Product)); // Test type

            Assert.AreEqual("ASP.Net Unleashed", testProduct.Name); // Verify it is the right product

        }

 

        ///<summary>

        /// Can we return a product By Name?

        ///</summary>

        [TestMethod]

        public void CanReturnProductByName()

        {

            // Try finding a product by Name

            Product testProduct = this.MockProductsRepository.FindByName("Silverlight Unleashed");

 

            Assert.IsNotNull(testProduct); // Test if null

            Assert.IsInstanceOfType(testProduct, typeof(Product)); // Test type

            Assert.AreEqual(3, testProduct.ProductId); // Verify it is the right product

        }

 

        ///<summary>

        /// Can we return all products?

        ///</summary>

        [TestMethod]

        public void CanReturnAllProducts()

        {

            // Try finding all products

            IList<Product> testProducts = this.MockProductsRepository.FindAll();

 

            Assert.IsNotNull(testProducts); // Test if null

            Assert.AreEqual(3, testProducts.Count); // Verify the correct Number

        }

 

        ///<summary>

        /// Can we insert a new product?

        ///</summary>

        [TestMethod]

        public void CanInsertProduct()

        {

            // Create a new product, not I do not supply an id

            Product newProduct = new Product

                { Name = "Pro C#", Description = "Short description here", Price = 39.99 };

 

            int productCount = this.MockProductsRepository.FindAll().Count;

            Assert.AreEqual(3, productCount); // Verify the expected Number pre-insert

 

            // try saving our new product

            this.MockProductsRepository.Save(newProduct);

 

            // demand a recount

            productCount = this.MockProductsRepository.FindAll().Count;

            Assert.AreEqual(4, productCount); // Verify the expected Number post-insert

 

            // verify that our new product has been saved

            Product testProduct = this.MockProductsRepository.FindByName("Pro C#");

            Assert.IsNotNull(testProduct); // Test if null

            Assert.IsInstanceOfType(testProduct, typeof(Product)); // Test type

            Assert.AreEqual(4, testProduct.ProductId); // Verify it has the expected productid

        }

 

        ///<summary>

        /// Can we update a prodict?

        ///</summary>

        [TestMethod]

        public void CanUpdateProduct()

        {

            // Find a product by id

            Product testProduct = this.MockProductsRepository.FindById(1);

 

            // Change one of its properties

            testProduct.Name = "C# 3.5 Unleashed";

 

            // Save our changes.

            this.MockProductsRepository.Save(testProduct);

 

            // Verify the change

            Assert.AreEqual("C# 3.5 Unleashed", this.MockProductsRepository.FindById(1).Name);

        }

    }

}

 

Download the Sample project and run the tests yourself:

MoqRepositorySample.zip (691.96 kb)


Categories: ASP.Net | C# | CodeProject | Moq | MVC | Unit Testing
Posted by Williarob on Tuesday, December 15, 2009 8:17 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Asynchronous Programming with ASP.Net MVC Futures

Using the AsyncController

Introduction

The AsyncController is an experimental class offered inside the latest MVC Futures dll to allow developers to write asynchronous action methods.  The usage scenario for this is for action methods that have to make long-running requests, such as going out over the network or to a database, and don’t want to block the web server from performing useful work while the request is ongoing.

In general, the pattern is that the web server schedules Thread A to handle some incoming request, and Thread A is responsible for everything up to launching the action method, then Thread A goes back to the available pool to service another request.  When the asynchronous operation has completed, the web server retrieves a Thread B (which might be the same as Thread A) from the thread pool to process the remainder of the request, including rendering the response.  The diagram below illustrates this point.

Configuration

The asynchronous types are declared in the Microsoft.Web.Mvc namespace in the assembly Microsoft.Web.Mvc.dll.  The first change a developer needs to make is to declare a route as asynchronous.  There are MapAsyncRoute() extension methods to assist with this; these are analogs of the normal MapRoute() extension methods already provided by the MVC framework.  In Global.asax:

routes.MapAsyncRoute(

    "Default",

    "{controller}/{action}/{id}",

    new { controller = "Home", action = "Index", id = "" }

);

A route declared with MapAsyncRoute() can correctly handle both synchronous and asynchronous controllers, so there is no need to create complex routing logic such that sync controllers are serviced by the normal MapRoute() handler and async controllers are serviced by the MapAsyncRoute() handler.  However, a sync route [MapRoute()] cannot in general correctly execute async controllers and methods.

Secondly, if you are using IIS6 or IIS7 classic mode, you need to replace the standard *.mvc handler with its asynchronous counterpart.  Replace these lines in Global.asax (they don’t necessarily appear adjacent to one another):

<add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

With these:

<add verb="*" path="*.mvc" validate="false" type="Microsoft.Web.Mvc.MvcHttpAsyncHandler, Microsoft.Web.Mvc"/>

<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="Microsoft.Web.Mvc.MvcHttpAsyncHandler, Microsoft.Web.Mvc"/>

Writing asynchronous action methods

In general, any asynchronous controllers that you author should subclass the AsyncController type.  Remember to import the Microsoft.Web.Mvc namespace.

public class MyAsyncController : AsyncController {

    // ...

}

The default constructor of the MyAsyncController sets the ActionInvoker property to an instance of the AsyncControllerActionInvoker.  This specialized invoker can understand several asynchronous patterns.  You can mix and match these patterns inside of your controllers.  If an ambiguity is found, we do our best to throw a detailed exception.

The AsyncController understands three async patterns.  These patterns can be mixed and matched within a single AsyncController.  Additionally, an AsyncController can contain normal (synchronous) action methods.  This makes it easy to change the base class of your controller from Controller to AsyncController in order to add async methods while allowing your original sync methods to run correctly.

The IAsyncResult pattern

The IAsyncResult pattern is a well-known pattern in the .NET Framework and is documented heavily.  A method pair signature which implements the IAsyncResult pattern is shown below.

public IAsyncResult BeginFoo(int id, AsyncCallback callback, object state);

public ActionResult EndFoo(IAsyncResult asyncResult);

This is the asynchronous analog of a synchronous method with the signature public ActionResult Foo(int id).  Note that the BeginFoo() method takes the same parameters as the Foo() method plus two extra – an AsyncCallback and a state object – and returns an IAsyncResult.  The EndFoo() method takes a single parameter – an IAsyncResult – and has the same return type as the Foo() method.

Standard model binding takes place for the normal parameters of the BeginFoo() method.  The invoker will pass a callback and state object for the BeginFoo() method to consume when its asynchronous task has finished.  When the callback is called, we automatically invoke the EndFoo() method and capture the result, then execute the result just as we would have in a synchronous request.

Only filter attributes placed on the BeginFoo() method are honored.  If a filter attribute is placed on EndFoo(), it will be ignored.  If an [ActionName] attribute is placed on the BeginFoo() method in order to alias it, we will look for an EndFoo() method based on the method name of BeginFoo(), not the aliased action name.  For example:

[ActionName("Bar")]

public IAsyncResult BeginFoo(int id, AsyncCallback callback, object state);

public ActionResult EndFoo(IAsyncResult asyncResult);

This will cause the BeginFoo() method to match requests for Bar rather than Foo.  Note that the completion method is still called EndFoo() instead of EndBar() since it matches the name of the entry method, not the entry alias.

The event pattern

In this pattern, the action method is divided into a setup method and a completion method.  The signatures are below:

public void Foo(int id);

public ActionResult FooCompleted(...);

When a request comes for Foo, we execute the Foo() method.  When the asynchronous operations are completed, we invoke the FooCompleted() method and execute the returned ActionResult.

The invoker will model bind parameters to the Foo() method in the standard way.  Parameters to FooCompleted() are not provided using model binders.  Rather, they come from the AsyncController.AsyncManager.Parameters dictionary, which can be populated as part of the asynchronous setup.  Keys in the dictionary correspond to parameter names of the FooCompleted() method, and any parameters which do not have corresponding keys in the dictionary are given a value of default(T).

The invoker must keep track of the number of outstanding asynchronous operations so that it does not invoke the FooCompleted() method prematurely.  To do this, a counter has been provided, accessible from AsyncController.AsyncManager.OutstandingOperations.  This counter can be incremented or decremented to signal that an operation has kicked off or concluded, and when the counter hits zero the invoker will invoke the completion routine.  For example:

public void Foo(int id) {

    AsyncManager.Parameters["p"] = new Person();

    AsyncManager.OutstandingOperations.Increment();

    ThreadPool.QueueUserWorkItem(o => {

        Thread.Sleep(2000); // simulate some work

        AsyncManager.OutstandingOperations.Decrement();

    }, null);

}

public ActionResult FooCompleted(Person p) {

    // consume 'p'

}

There is also an AsyncController.AsyncManager.RegisterTask() method that is helpful for wrapping calls to IAsyncResult pattern methods from within an event pattern method.  The RegisterTask() method also handles incrementing and decrementing the counter correctly.  For example:

public void Foo(int id) {

    AsyncManager.RegisterTask(

        callback => BeginGetPersonById(id, callback, null),

        ar => {

            AsyncManager.Parameters["p"] = EndGetPersonById(ar);

        });

    AsyncManager.RegisterTask(

        callback => BeginGetTotalUsersOnline(callback, null),

        ar => {

            AsyncManager.Parameters["numOnline"] = EndGetTotalUsersOnline(ar);

        });

}

public ActionResult FooCompleted(Person p, int numOnline) {

    // ...

}

This will kick off two asynchronous tasks and wait for both to finish before executing the FooCompleted() method with the values that were returned.

Only filter attributes placed on the Foo() method are honored.  If a filter attribute is placed on FooCompleted(), it will be ignored.  If an [ActionName] attribute is placed on the Foo() method in order to alias it, we will look for an FooCompleted() method based on the method name of Foo(), not the aliased action name.  For example:

[ActionName("Bar")]

public void Foo(int id);

public ActionResult FooCompleted(...);

This will cause the Foo() method to match requests for Bar rather than Foo.  Note that the completion method is still called FooCompleted() instead of BarCompleted() since it matches the name of the entry method, not the entry alias.

The Foo() method is allowed to return anything.  The invoker ignores the return value of this method; it only cares about the return value of the FooCompleted() method.  This is to allow writing Foo() methods that are easier to unit test.

The delegate pattern

This pattern is very similar to the event pattern, except that the method Foo() returns a parameterless delegate type and there is no FooCompleted() method.  For example:

public Func<ActionResult> Foo(int id) {

    Person p = null;

    int numOnline = 0;

    AsyncManager.RegisterTask(

        callback => BeginGetPersonById(id, callback, null),

        ar => {

            p = EndGetPersonById(ar);

        });

    AsyncManager.RegisterTask(

        callback => BeginGetTotalUsersOnline(callback, null),

        ar => {

            numOnline = EndGetTotalUsersOnline(ar);

        });

    return () => {

        ViewData["p"] = p;

        ViewData["numOnline"] = numOnline;

        return View();

    };

}

Or, more succinctly:

public Func<ActionResult> Foo(int id) {

    AsyncManager.RegisterTask(

        callback => BeginGetPersonById(id, callback, null),

        ar => {

            ViewData["p"] = EndGetPersonById(ar);

        });

    AsyncManager.RegisterTask(

        callback => BeginGetTotalUsersOnline(callback, null),

        ar => {

            ViewData["numOnline"] = EndGetTotalUsersOnline(ar);

        });

    return View;

}

Since this pattern supports only parameterless delegates instead of parameterful delegates, the earlier discussion about AsyncController.AsyncManager.Parameters is not applicable.

Timeouts

There is a Timeout property accessible from AsyncController.AsyncManager.Timeout that specifies the number of milliseconds to wait for a response from the action method before canceling the request.  The default value is 30000 (equal to 30 seconds).  If the action method has not returned by the specified time, we throw a TimeoutException.  Action filters and exception filters may handle this particular exception type if they wish.  Setting the Timeout property to System.Threading.Timeout.Infinite signifies that we will never throw this exception.

The timeout duration can be specified on a per-controller or per-action basis by attributing a class or method with [AsyncTimeout] or [NoAsyncTimeout].

Known issues

-          Asynchronous actions generally cannot be called by synchronous invokers or handlers.  If you receive an exception message about an action being unable to be executed synchronously, ensure that you’re using the MapAsyncRoute() extension method in your Global.asax and that your controller subclasses AsyncController.

-          The asynchronous invoker will not match any method beginning with Begin or End or ending with Completed.  This is to prevent web calls to the BeginFoo(), EndFoo(), and FooCompleted() methods directly.  If you need to make an action with this name accessible to web users, use the [ActionName] attribute to alias the method:

[ActionName("Begin")]

public ActionResult DoSomething();

The above is an example of a normal synchronous method that has been renamed to Begin to work around the invoker’s blocking of this name.

-          If the route that normally handles requests for the application root (/) is an asynchronous route, the Default.aspx file should be removed from the web application.  The Default.aspx file included in the template only works with synchronous requests.


Categories: ASP.Net | Asynchronous | C# | MVC
Posted by Williarob on Thursday, June 18, 2009 6:03 AM
Permalink | Comments (0) | Post RSSRSS comment feed