Christian Weiss

thoughts on web development and IT security

Introducing the ASP.NET MVC “Feature Folders” Project Structure

What’s the problem with the default ASP.NET MVC folder structure?

Which of these requirements is more common?

  • Change something in every view, controller or model of your project
  • Add a new field to your model X, show this field to the user, make it editable, the value must be validated against some fancy rules, …

I guess we are on the same page if we see the second one as more common. I would go as far as to say that if you have the first requirement you’re either working on a major relaunch or you’re not using layout pages, css, abstract classes, [insert random reusability gadget here] correctly.

By default, the ASP.NET MVC project structure advices you to keep every concept in its own area – you therefore might end up with a structure like this:

  • Content
    • CustomerImages
      • AnIconSpecialToCustomers.png
    • Customers.css
  • Controllers
    • CustomersController.cs
  • Models
    • Customer.cs
  • Repositories
    • CustomerRepository.cs
  • Scripts
    • Customers.js
  • Views
    • Customers
      • Create.cshtml
      • Index.cshtm
  • ViewModels
    • Customers
      • IndexViewModel.cs
      • CreateViewModel.cs

As soon as you have more than 3 controllers, this becomes hard to navigate. ASP.NET MVC’s solution for having a better structure is to use “Areas”, however in my opinion they do not solve the problem I’m talking about. To complete the second requirement I’ve mentioned, you still have to navigate through many folders, because most probably, you don’t have a distinct views-guy, a distinct model-guy, a distinct controller-guy, … in your company. It’s a lot more common that e.g. only one or two people are working on all of these mentioned files.

Grouping files by feature

When I’m talking about a feature, I understand it as a sum of files that are needed to create a user benefit. Therefore, with structuring files by feature, the project structure could look like this:

  • Customers
    • Images
      • AnIconSpecialToCustomers.png
    • Create.cshtml
    • CreateViewModel.cs
    • Customer.cs
    • CustomerRepository.cs
    • Customers.css
    • Customers.js
    • CustomersController.cs
    • Index.cshtml
    • IndexViewModel.cs

Think again of our second requirement and of some of the advantages with this structure:

  • You immediately get an overview about how the feature might be implemented.
  • You immediately see which files might be affected by the requirement. You don’t have to check every concept folder to see if there even is a corresponding file. (there might not be a js-file for every feature, …)
  • Every affected file is in one folder. The required navigation in the Solution Explorer is kept to a minimum.
  • In your source control system, you can look at the entire change history of this feature on one folder.
  • If you have to implement a new similar feature, you can copy this one folder and use it as a starting point

Why is there a M in ASP.NET MVC?

I would like to make an exception of my previous structure: It’s important to understand that the ASP.NET MVC framework itself (System.Web.Mvc) does NOT give you any built-in support for “models”. If you require persistent data, you are allowed to use whatever technology you want (Entity Framework, NHibernate, raw ADO.NET, …). Yes, the project templates by default already reference Entity Framework, but again, this is a separate library and ASP.NET MVC has no dependency on it.

In my opinion this is a very good thing! The traditional three-tier architecture (data, business logic, presentation) still is one of the most important concepts for structuring software systems. ASP.NET MVC clearly targets the presentation tier and shouldn’t cover responsibilities from other tiers.

For this reason, we have to move the files “Customer.cs” and “CustomerRepository.cs” into a separate library. However, everything else in our folder belongs to the presentation layer.

What’s next?

I plan to do follow-up posts that address the challenges and also possible solutions for this structure, so stay tuned!

Testable and reusable cookie access with ASP.Net MVC RC

All good things come in threes, so I’m writing another post about how to access cookie or sessions. I got inspired by a comment from Chris Marisic, who suggested to use a more testable way for this stuff!

Previous posts about this topic:

Intro

Using static wrapper properties is a quick and easy way, but you can’t unit test them because they access HttpContext.Current directly. This time I will show you, how you can build a fully unit testable and strongly typed way to access your cookies. As there has been Christmas time 2 days ago (ASP.Net MVC RC1 was released *g*) I’m using the latest MVC bits for my example!

A Reusable Cookie Container

The cookie container is responsible for getting values out of and into the cookie collections. It does not know which concrete values I’m using in my application! This is implemented in a different level, so you can use this class for all of your applications!

In my implementation it’s possible to store “objects” in cookies. I’ve implemented it this way because I don’t want to convert all my DateTime, int, … cookies every time! But I also don’t want someone to save Lists or any other complex types, so my SetValue() method validates the type of the value and throws an exception, if it’s not a value type or nullable value type. That’s a little type checking, but I think it is worth it because cookies are set quite rarely!

Here’s the interface:

public interface ICookieContainer
{
    bool Exists(string key);
    
    string GetValue(string key);
    T GetValue<T>(string key);
    
    void SetValue(string key, object value, DateTime expires);
}

I will just show the fundamental code here. If you want to see the whole implementation, please take a look at the code sample. (see bottom)

As you can see below, I’ve used the abstracted versions of HttpRequest and HttpResponse, which you get, if you use ASP.Net MVC. That’s just one of thousand things I love about ASP.Net MVC. These classes can be used easily in unit tests. Notice that everything can be injected here. There’s no direct access to HttpContext.Current!

public class CookieContainer : ICookieContainer
{
    private readonly HttpRequestBase _request;
    private readonly HttpResponseBase _response;

    public CookieContainer(HttpRequestBase request, HttpResponseBase response)
    {
        // "Check" is a helper class, I've got from the "Kigg" project
        Check.IsNotNull(request, "request");
        Check.IsNotNull(response, "response");

        _request = request;
        _response = response;
    }

    public string GetValue(string key)
    {
        Check.IsNotEmpty(key, "key");

        HttpCookie cookie = _request.Cookies[key];
        return cookie != null ? cookie.Value : null;
    }

    public void SetValue(string key, object value, DateTime expires)
    {
        Check.IsNotEmpty(key, "key");

        string strValue = CheckAndConvertValue(value);

        HttpCookie cookie = new HttpCookie(key, strValue) {Expires = expires};
        _response.Cookies.Set(cookie);
    }
    
    // ... see code sample for full implementation
}

Here’s a sample unit tests that proves the testability of this code. I use Moq as my mocking framework.

public static class Mocks
{
    public static Mock<HttpRequestBase> HttpRequest()
    {
        var httpRequest = new Mock<HttpRequestBase>();
        httpRequest.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
        return httpRequest;
    }

    public static Mock<HttpResponseBase> HttpResponse()
    {
        var httpResponse = new Mock<HttpResponseBase>();
        httpResponse.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
        return httpResponse;
    }
}

// This method is from my CookieContainerTests class

[TestMethod]
public void SetValue_UpdatesExistingCookie()
{
    // Arrange
    const string cookieName = "myCookie";
    const string cookieValue = "myValue";
    DateTime cookieExpires = new DateTime(2009, 1, 1, 0, 0, 0);

    var httpRequest = Mocks.HttpRequest();
    var httpResponse = Mocks.HttpResponse();
    var cookieContainer = new CookieContainer(httpRequest.Object, httpResponse.Object);
    
    httpResponse.Object.Cookies.Add(new HttpCookie(cookieName, "oldValue"));

        // Act
    _cookieContainer.SetValue(cookieName, cookieValue, cookieExpires);

    // Assert
    HttpCookie cookie = httpResponse.Object.Cookies["myCookie"];
    Assert.IsNotNull(cookie);
    Assert.AreEqual(cookie.Name, cookieName);
    Assert.AreEqual(cookie.Value, cookieValue);
    Assert.AreEqual(cookie.Expires, cookieExpires);
}

That’s it! Now you have a testable and reusable cookie container!

How to use it in your application

It’s really easy to integrate this into your app! Just create an interface that defines all your application-specific properties you want to save in cookies and a concrete implementation of this interface that interacts with the cookie container.

public interface IAppCookies
{
    string UserEmail { get; set; }
    DateTime? LastVisit { get; set; }
}

public class AppCookies : IAppCookies
{
    private readonly ICookieContainer _cookieContainer;

    public AppCookies(ICookieContainer cookieContainer)
    {
        _cookieContainer = cookieContainer;
    }

    public string UserEmail
    {
        get { return _cookieContainer.GetValue("UserEmail"); }
        set { _cookieContainer.SetValue("UserEmail", value, DateTime.Now.AddDays(10)); }
    }

    public DateTime? LastVisit
    {
        get { return _cookieContainer.GetValue<DateTime?>("LastVisit"); }
        set { _cookieContainer.SetValue("LastVisit", value, DateTime.Now.AddDays(10)); }
    }
}

You can now inject this IAppCookies interface to your MVC Controller:

public class HomeController : Controller
{
    private readonly IAppCookies _cookies;

    public HomeController(IAppCookies cookies)
    {
        _cookies = cookies;
    }

    public ActionResult Index()
    {
        DateTime currentTime = DateTime.Now;

        IndexViewModel viewModel = new IndexViewModel
        {
            CurrentTime = currentTime,
            LastVisit = (_cookies.LastVisit ?? currentTime),
            UserEmail = _cookies.UserEmail
        };

        _cookies.LastVisit = currentTime;

        return View(viewModel);
    }

    public class IndexViewModel
    {
        public string UserEmail { get; set; }
        public DateTime LastVisit { get; set; }
        public DateTime CurrentTime { get; set; }
    }
}

Wow, you’re still reading :-)

That’s all I want to show here! If you want to see more about how the IOC is set up (I’m using StructureMap) or anything else, take a look at the full code:

I looking forward to hearing your feedback on this!

Thanks for reading,
Christian Weiss