RSS

Monthly Archives: September 2013

ASP.NET MVC – Solution Template

I have built a number of large enterprise-grade projects in asp.net MVC over the last few years. Whenever I build new projects now I use the following structure for my solution. It allows for easy unit testing, custom membership and role providers and abstracts out the database operations into repositories.

I am always open to comments and improvements though so feel free to contact me via this site with any suggestions.

Anyway, here it is:

Solution Structure

  • Website
  • Website.Tests
  • ServiceInterface
  • ServiceImplementation
  • ServiceImplementation.Tests
  • RepositoryInterface
  • RepositoryImplementation
  • RepositoryImplementation.Tests
  • Mocks
  • Providers
  • Providers.Tests
  • DomainEntities
  • Extensions
  • Extensions.Tests

Website

This project is the asp.net MVC project as set up by the asp.net MVC project template.

Website.Tests

Contains tests for controller methods in the website. The mocked service implementation should be injected into these controllers so you are basically testing for control flow and nothing else.

ServiceInterface

Contains method signatures for ‘services’. Each fundamental domain entity class (ie such as ‘User’) should possess it’s own service interface. Methods should encapsulate well-defined use-cases such as ‘Register’, ‘PostComment’, ‘CreateGroup’ etc.

ServiceImplementation

Implementations of classes in the ServiceInterface project. Ideally these implementations will in a ‘user context’. In other words all operations are performed from that user’s perspective. Therefore Get() fetches the currently logged in user, PostComment(comment) posts a comment by the logged in user etc. The logged in user can be injected into the service instance on construction. Obviously some methods such as Register are performed anonymously.

Service implementations will more often than not require several Repository instances injecting into them on construction.

ServiceImplementation.Tests

These unit tests will test the logic and return values of the service implementation. In order to isolate the methods, you should inject the appropriate mocked repositories rather than using a repository implementation that is tied to the database.

RepositoryInterface

Classes in this project should contain simple CRUD methods to access the database and materialise the row data into instances of the classes in the DomainEntities project. It’s possible to use a generic base interface to specify the CRUD methods and just derive from that, adding any methods that are specific to each interface.

RepositoryImplementation

Contains implementations of classes in the RepositoryInterface project and will include database-specific code and/or use of any ORM tools.

RepositoryImplementation.Tests

Unit tests the repository implementation – should use a test database which is cleared after the tests have run, making execution of these tests idempotent.

Mocks

Use Mock factory classes to serve up mocks which implement classes in ServiceInterface and RepositoryInterface here. You can then call the factory methods from your test projects.

Providers

ASP.NET uses providers to perform authentication, authorisation and to provide profile information (though I’ve never actually used the latter). These providers are then specified in the web.config file.

You could use the RepositoryImplementation assembly to provide access to any data from the database here. Again, be sure to provide a way to inject any repositories so you can unit test the providers in isolation.

If you want to be able to use the providers in other solutions, just factor out a simple repository interface/class rather than use your existing repositories.

Providers.Tests

Unit tests for providers – inject repository mocks in order to isolate the functionality.

DomainEntities

Classes that provide simple business rules and logic which are used throughout the application. Anything more complicated should be factored into the ServiceImplementation. For example, methods such as User.Block(), ForumPost.Reply(Reply reply) are good candidates to include here. Any logic that alters the state of other classes as well as the one containing the method should be included in the Service Implementation rather than here.

Extensions

Any useful extension methods can go here – you can then re-use this project in other solutions.

Extensions.Tests

Nuff said.

Hope this gives someone out there a bit of a head start when setting up a nice new ASP.NET project.

 
Leave a comment

Posted by on September 24, 2013 in Uncategorized