C# ASP .NET web applications have grown to encompass varying degrees of complexity and enterprise-level flexibility. With the latest release of the Microsoft ASP .NET MVC Model View Controller (Release Candidate) framework, C# web applications can be designed using the fluent view template language, Razor, to rapidly develop MVC Views and web application user interfaces. By combining the ASP .NET MVC Razor framework with a database layer, featuring the new NoSQL solution RavenDB, we can develop an enterprise-suitable solution for querying the NoSQL database and managing entities.
In this article, we’ll create an example C# ASP .NET MVC Razor web application, using the RavenDB NoSQL database as the backend. Our web application will automatically generate random flying creatures and monsters, each with their own randomly generated magical weapon. The flying creatures will be created and stored in the NoSQL document database and displayed within an AJAX jQuery based datagrid. The backend will feature an enterprise solution for managing the RavenDB NoSQL database connection using the Repository design pattern combined with the Unit Of Work (UnitOfWork) pattern.
Did you Say NoSQL?
NoSQL is a term describing databases which differ from traditional relational database systems, in that they usually provide a different querying mechanism. They do not utilize the SQL query language nor do they traditionally deal with relational tables or foreign keys.
In this example, we’ll be using the RavenDB NoSQL implementation, which offers a familiar .NET LINQ query language and programming interface framework. The RavenDB framework follows very similar to database solutions including the Microsoft Entity Framework, LINQ2SQL, and NHibernate.
It’s important to note, developing a database schema for a NoSQL solution is quite different than developing for traditional relational databases. In relational databases, it is common to normalize and link tables together with foreign keys in order to reduce redundancy. In NoSQL document databases, reducing redundancy is less of a concern. Specifically, RavenDB provides the ability to distribute database entities (also called “Documents”) across multiple repositories, databases, and servers, via the technique of “sharding”. Due to this ability, storage space and relational structure is less of a concern. Similarly, query speed, data retrieval, and data design is improved due to the ability to store documents in their entirety as a single entity. For additional details, see Document Structure Design Considerations with RavenDB NoSQL.
Double Negatives are Fun: No Database Schema Required with NoSQL
One of the most interesting aspects of NoSQL solutions is the ability to get started with a C# ASP .NET web application design without creating a database schema. Tables, columns, and foreign key relations are developed implicitly within the C# .NET code, rather than directly inside a database client. The RavenDB NoSQL server takes care of storing the Document entities and generating indexes for search queries. Due to this flexibility, we can jump directly into developing our solution.
Yes, You Have to Download Some Stuff
Getting Started with RavenDB NoSQL
The first step to setting up RavenDB NoSQL is to download and install the RavenDB database server. After downloading, extract the contents of the zip file to C:\RavenDB or similar directory. Next, install the database service by opening a command-line prompt and typing: raven.server /install
Once the database service is installed, you can optionally configure the IIS web client, which allows querying the database using LINQ and performing administrative tasks in the NoSQL database. To install the IIS web client, simply open IIS Manager and create a new virtual directory, pointing to the RavenDB install folder at C:\RavenDB\Web. Enable running of ASP scripts and set the target .NET Framework to 4.0 (either on the Application Pool or in the virtual folder options, depending on your version of IIS Manager). You’ll also want to verify the Web folder has Read and Write access for the ASP Internet user. You can access the RavenDB client at http://localhost:8080\.
Creating our Repository and Interfaces
The first step of developing our C# ASP .NET MVC (RC) Razor web application is to develop our data layer for handling the NoSQL database connection. We can begin by declaring several interfaces to define our Repository and UnitOfWork design patterns. These two combined design patterns will allow us to easily utilize the RavenDB database in a multiple-threaded environment, such as a web application. The design will also provide an easy TDD (Test Driven Development) and unit-testable solution, by allowing us to swap in or out additional database backends or unit test classes.
We’ll be using the same design as described in the previous article, Using the Entity Framework Repository and UnitOfWork Pattern in C# ASP .NET.
The Repository Interface
Our Repository interface will allow us to query and manage the RavenDB NoSQL database with basic database functionality. We’ve defined the interface using .NET generics, which allows us to easily convert the solution to utilize other concrete classes for unit testing, TDD, or alternative database backend solutions.
The UnitOfWork Interface
The UnitOfWork design pattern will allow us to maintain a single NoSQL database session per web request. The connection will be opened upon beginning the web request and closed upon ending it. The UnitOfWork pattern requires a single method for committing the NoSQL database transaction.
The UnitOfWork Factory Interface
The UnitOfWork Factory interface will allow us to implement multiple types of database managers, including alternative database solutions (Entity Framework, SQL Server, MySQL, Oracle, etc).
Implementing the UnitOfWork Pattern
We can define the concrete class for handling the UnitOfWork pattern in the NoSQL RavenDB backend solution, by defining the class as shown below. Note, the usage of the HttpContext to store and retrieve the concrete unit of work (ie., database session) within the same web request, which optimizes performance and provides thread-safe management of the RavenDB database connection. This class utilizes StructureMap to provide an IoC container for instanting the required classes upon demand.
Implementing the RavenDB UnitOfWork Concrete Class
While we have defined the generic UnitOfWork class manager above, we now need to define the concrete implementation for the RavenDB NoSQL database backend. We can do this by implementing the IUnitOfWork interface and implementing the methods for creating the database session, committing, and cleanup. Note, we utilize the RavenDB IDocumentStore to open a new session (NoSQL database connection), and call the SaveChanges() method to commit (which is similar in design to the Entity Framework and NHibernate framework). Due to the concrete implementation, we’ll need to reference the RavenDB database client.
Implementing the RavenDB UnitOfWork Factory Concrete Class
So far, we’ve defined the UnitOfWork manager and the RavenDB UnitOfWork class. Our enterprise design requires a UnitOfWork Factory class in order to instantiate the proper concrete class for handling the NoSQL database connections. We can do this by implementing the IUnitOfWorkFactory interface, as shown below. Note how we reference the RavenDB IDocumentStore object to obtain the database context. This context is then passed on to the RavenUnitOfWork concrete class for actually opening the database session, saving, and disposing.
The Chief RavenDB Repository Class
One final class remains in order to complete our Repository and Unit Of Work design pattern for the Raven DB NoSQL database manager, and that is the concrete repository class. We can implement the NoSQL repository class by implementing the IRepository interface as a .NET generic class and implementing the methods for actually querying the RavenDB NoSQL database documents, loading, saving, and deleting. We utilize .NET generics in the repository class in order to provide individual concrete repository classes for each entity type (Document) that we wish to perform database operations on. This allows for defining custom operations or business rules within each repository, prior to executing the actual NoSQL database operation (such as, preventing a delete on an entity if a certain condition exists, or saving an additional entity if a condition exists, etc). Note, all database query operations follow a similar framework pattern as the Entity Framework and NHibernate, in utilizing the Context or Session (IDocumentSession) object to perform operations.
A Global Addition to Enable the Repository and UnitOfWork Pattern
We require one more item in our C# ASP .NET MVC Razor web application in order to bring the repository and unit of work pattern to life. Our design operates per web request, and as such, we’ll need to instantiate the RavenDB repository class and provide it to our factory so that it knows which concrete type to instantiate. We’ll also need to close and dispose of the database connection when the web request ends. We can solve both of these issues within the Global.asax.cs file, as shown below:
Note in the above code, we’ve provided the concrete class to StructureMap (our IoC container framework) so that it knows which repository class to use when an IUnitOfWorkFactory type is requested. We’ve also provided an initialization method to StructureMap, which gets executed when the RavenUnitOfWorkFactory class is instantiated. Specifically, the initialization method opens the DocumentStore (database connection) at the server URL and returns the session connection.
Convincing RavenDB to be Friends with ASP .NET MVC Routes
Note, during initialization of the request in Application_Start(), we change the RavenDB IdentityPartsSeparator to a dash, rather than the default slash character. This property is used by RavenDB when auto-generating Identity keys for the database entities (Documents). A typical identifier might look like “people/123”. The slash would create problems in the C# ASP .NET MVC framework when attempting to parse the URL on an entity operation, as the “people” and “123” parts would appear as separate controllers/actions. We can resolve this by converting the slash to a dash, which properly displays in the MVC URL route as “people-123”, and is passed as a parameter to our controller methods.
Who’s the Real EndRequest?
We can resolve this issue by filtering out the request to our actual application EndRequest. We can do this by examining the Request.Url object and checking for specific file types to ignore. The above method should be expanded to your particular solution and file-types, but in general, the opening and close of the connection is a light-weight process.
Now the Fun Starts
We’ve completed the repository and unitofwork pattern for RavenDB. We can now move on to defining our actual entities and user interface. We’ll begin by creating a Creature and Weapon entity, and then provide a concrete repository manager for each entity (utilizing the generic repository that we’ve created above).
One of the benefits of NoSQL is that there is no need to create a database schema. We can simply create the entity classes and persist them to the database as a complete document. The NoSQL database takes care of generating indexes, distributed sharding, and handling storage. This allows us to rapidly develop of business logic layer and avoid heavy database schema design work up front.
The Creature Entity
Our Creature entity will be a basic entity containing a Name, Age, and a child entity of type Weapon. We also provide an Id property, which will be populated automatically by the RavenDB database server. We could also provide our own identifier, such as a Guid, if we prefer.
The Weapon Entity
The Weapon entity is another basic entity, including basic data types and an enum.
The NoSQL RavenDB is Not Relational
The NoSQL RavenDB is not relational. That wasn’t a typo, but an intentional repeated statement. The RavenDB server stores entities as complete documents. This allows high-speed querying and fetch rates by returning all required data about a specific entity, needed for processing by the C# ASP .NET web application. For example, when we query for a Creature entity, we’ll also obtain the Weapon entity embedded inside the Creature document. A second query to pull the child entity, Weapon, is not required. Thus, we perform a single database read operation as opposed to two. This is called denormalization, which may seem alien to traditional relational database design. However, RavenDB NoSQL is not a relational database server. As such, it is able to automatically distribute documents across servers via sharding and optimize query execution. There is no foreign key relationship between our two entities, as each Creature will exist as an independent document, and always contain a complete Weapon entity. For more details, see RavenDB Denormalized References.
Creating a Creature Repository Manager
We can now implement a concrete repository for the Creature entity by using the generic repository we designed above. Note, each concrete repository will contain a private reference to the IRepository interface, binding it to our specific entity. This allows us to customize each repository with any needed business rules prior to executing database operations.
The Weapon entity manager follows a similar implementation, so we’ll skip the details for brevity.
Our MVC Razor MasterPage Layout
The Main MVC Razor View
We can now create our main MVC Razor View, based upon the master page created above. Our view will be strongly bound to a list of Creature entities, which will be populated in a datagrid (using the jQuery flexigrid control combined with AJAX).
The most important part to the above C# MVC Razor view code is the partial control for the CreatureGrid. This is where we actually output the available Creature entities and display them within a table. The jQuery flexigrid takes care of formatting the table as a datagrid.
The MVC Razor Creature Grid Partial View
The Razor PartialView for our CreatureGrid simply contains HTML markup to display a table. We use inline Razor code to include a for-loop, which allows us to iterate of the Creature entities, and display the details in the table. The table will later be formatted as a datagrid via jQuery with the flexigrid control.
Say This 5 Times Fast: Creature Controller
Last, but not least, is the final piece of the puzzle - the CreatureController. This implements our main .NET MVC view controller class. Within the controller, we define the code to initially populate the datagrid and utilize our repository and unitofwork design pattern framework to load and save NoSQL entities.
Note, in the above code we follow a basic pattern for using the repository and unitofwork pattern with RavenDB NoSQL. We execute any database operations via our entity manager classes, which all operate within the same database session context (within the same web request). Once we’re finished, we commit the UnitOfWork by calling UnitOfWork.Commit(). The UnitOfWork then takes care of completing the session context and flushing to the NoSQL database. The UnitOfWork does not need to be contained within only 1 method. We could have spread the database operations throughout multiple methods or classes and all database operations would continue to be maintained within the same unit of work, committing once we’ve completed the transaction.
Download @ GitHub and Wiki
The C# ASP .NET MVC framework, combined with the Razor view template engine, provides a rapid development environment for creating model view controller based web applications. By taking advantage of alternate database platform technologies, such as NoSQL, we further optimize .NET MVC web application solutions in a multitude of ways. The RavenDB NoSQL database server allows storage of entities as complete documents, without the requirement for up-front design of a database schema. While the choice between utilizing traditional relational database platforms versus NoSQL platforms will differ depending on the project at hand, technology advances in general, help to create more powerful and maintainable C# ASP .NET web application solutions.
About the Author
This article was written by Kory Becker, founder and chief developer of Primary Objects, a software and web application development company. You can contact Primary Objects regarding your software development needs at http://www.primaryobjects.com