Learn More





DNN Community Blog

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.

Module Development in DNN 8: 2 - Creating your first MVC Action/View

In my previous blog I reviewed the development environment I will be using for my blog series on Module Development in DNN 8.  As a reminder you can find all the sample code on Github at In this blog we will create our first  MVC Action and View.

The Model

As mentioned in my previous blog I will be describing how to create a module to manage contacts on my site.  The Contact List module will be scoped to the portal – i.e. all contacts for a portal will be available in any instance of the module.  A Contact will have 5 simple properties:

  • First Name
  • Last Name
  • Email Address
  • Phone Number
  • Twitter Handle

As the domain is not what we are really focusing on in this series I have kept it simple.  As we will be creating both an MVC module (as well as a SPA module in future blog posts) I have created a separate project for the Model (API) located in the Dnn.ContactList.Api project (Figure 1).

Figure 1 – The Model project


The Api uses the DAL 2 data access layer and implements a simple “Repository” facade over that framework.  As with many of DNN's APIs the ContactRepository is implemented using the ServiceLocator pattern so the methods can be Unit Tested.

The IContactRepository interface provides a simple CRUD API, as shown in Figure 2.

Figure 2 – The IContactRepository interface

   1:  public interface IContactRepository
   2:  {
   3:      int AddContact(Contact contact);
   5:      void DeleteContact(Contact contact);
   7:      Contact GetContact(int contactId, int portalId);
   9:      IQueryable<Contact> GetContacts(int portalId);
  11:      IPagedList<Contact> GetContacts(string searchTerm, int portalId, int pageIndex, int pageSize);
  13:      void UpdateContact(Contact contact);
  14:  }

The MVC Controller

So now we have everything set up we are ready to create our first MVC Action and View.  Following the MVC convention we will create a class in the Controllers folder called ContactController.  This class must inherit from the DnnController base class found in the DotNetNuke.Web.Mvc project.  This base class inherits from the core MVC Controller base class, but adds extra support for the DNN Module and Portal context.  You can think of this class as the equivalent to PortalModuleBase in WebForms module development.

Figure 3 – The ContactController class

   1:  public class ContactController : DnnController
   2:  {
   3:      private readonly IContactRepository _repository;
   5:      public ContactController() : this(ContactRepository.Instance) { }
   7:      public ContactController(IContactRepository repository)
   8:      {
   9:          Requires.NotNull(repository);
  11:          _repository = repository;
  12:      }
  13:  }

This class has two constructors.  The parameter-less constructor is used by the MVC framework to instantiate the controller, and the second constructor will be used by our Unit Tests.  Use of either constructor will set the private IContactRepository variable.

In the future (DNN NeXt) we will be able to dispense with the parameter-less constructor and allow ASP.NET 5’s Dependency Resolver to inject the appropriate implementation of the interface.  I have used this approach rather than calling DotNetNuke.Instance.<<Method>> in each action method as this will be the pattern used in DNN NeXt.

The Index Action

Next we need to add an action method – the default method is usually called Index by convention.  As we are not really using ASP.NET routing the name is not that important, as DNN actually determines the controller and action to call from the “ControlSrc” property of the Module Control (Contact/Index.mvc).

The Index action is listed in Figure 4.

Figure 4 – The Index Action

   1:  [HttpGet]
   2:  public ActionResult Index()
   3:  {
   4:      var contacts = _repository.GetContacts(PortalSettings.PortalId);
   6:      return View(contacts.ToList());
   7:  }

This is a fairly simple MVC Action method.  In the first line we use the HttpGet attribute to indicate that this method should only be called by HTTP “GET” calls. In line 2 we return an ActionResult – the DNN MVC framework captures this result and renders it in the MvcHostControl.  In line 4 we call the GetContacts method of the repository interface to get all the contacts for the portal.  Note, that just like PortalModuleBase the DnnController base class provides access to the PortalSettings object.  Finally in line 6 we return a strongly typed View, passing in our List of contacts.

The Index View

We now turn our attention to the View.  DNN supports all the MVC 5.1 conventions for Views.  Thus, you can provide a _ViewStart.cshtml razor script which will execute for all Views before any other View code, and it supports the use of layout views.  Figure 5 shows this layout.

Figure 5 – MVC View Conventions

Lets look at each of these Razor files.

Figure 6 – _ViewStart.cshtml

   1:  @{
   2:      Layout = "~/DesktopModules/MVC/Dnn/ContactList/Views/Shared/_Layout.cshtml";
   3:  }

The _ViewStart.cshtml file is used to set the Layout property for all the Views.  This allows the module developer to use some common “chrome” for all the Views in the module.

Figure 7 – _Layout.cshtml

   1:  <div class="masterLayout">
   2:      @RenderBody()
   3:  </div>

For this module the shared layout is very simple (being just a wrapper to the required RenderBody() method), but this could be used to register extra css or JavaScript files.

The main view code (Index.cshtml) is shown in Figure 8.

Figure 8 – Index.cshtml

   1:  @inherits DotNetNuke.Web.Mvc.Framework.DnnWebViewPage<IList<Dnn.ContactList.Api.Contact>>
   3:  <div>
   4:      @foreach (var contact in Model)
   5:      {
   6:          <div class="contactCard">
   7:              <div>
   8:                  <span>@contact.FirstName</span>
   9:                  <span>@contact.LastName</span>
  10:              </div>
  11:              <div>
  12:                  <span>Email:</span>
  13:                  <span>@contact.Email</span>
  14:              </div>
  15:              <div>
  16:                  <span>Phone:</span>
  17:                  <span>@contact.Phone</span>
  18:              </div>
  19:              <div>
  20:                  <span>Twitter:</span>
  21:                  <span>@contact.Twitter</span>
  22:              </div>
  23:          </div>
  24:      }
  25:  </div>

The first thing to note is Line 1.  DNN Views need to inherit from the DnnWebViewPage class.  This is because we need to modify some of the helper methods, as well as provide support for DNN context (ModuleContext and PortalSettings).  The rest of the code is fairly straightforward Razor script.  We loop over all the contacts in the Model property (which is a List of Contact objects), and render the properties of the contact.  With some simple styling we can see the View output in Figure 9.

Figure 9 – The View output

So thats our first MVC Action/View.  In my next blog post (on MVC modules) I will show how we can add support for other Actions/Views.

For more information


Jaydeep Bhatt
Great, where is the next Article?
Jaydeep Bhatt Saturday, June 06, 2015 6:48 AM (link)
Jaydeep Bhatt
btw, will "DNN NeXt" support the current WebForm based Modules? OR it will be pure MVC?
Jaydeep Bhatt Saturday, June 06, 2015 6:51 AM (link)
Scippy One
To make working MVC project with DNN 8 CTP4 I had to make some steps in addition to those listed in the articles:
- execute the script Install.sql under src/Dnn.ContactList.Api/Scripts/
- fix the _ViewStart.cshtml adding at first line: @inherits System.Web.WebPages.StartPage
- compile the MVC project in release mode
- install the module package under yourwebsite/Install/Module folder

I want also to thank Charles for these wonderful articles. These are aids that make the community grow in the right direction!...
I hope in the future to find many more!
Scippy One Tuesday, September 15, 2015 11:50 AM (link)
Scippy One
Another little fix to do to run github project is that in Install.sql script the table name is "dnn_Contacts" but in Contact.cs the table name is simply "Contacs", so you need to fix the script before execute it or to fix the class Contact with the right table name.
Scippy One Friday, September 18, 2015 8:48 AM (link)
Victor Ogundowo
Nice Article, Charles! Please I have some few questions to ask.
1. If I download the latest DNN 8.0 CTP 4, can I start building the MVC modules inside the WAP, rather than going through the examples you gave in your articles.
2. Can I configure Ninject to Injection my dependences in the constructor of my controller because i used this in all my MVC project.
Victor Ogundowo Friday, September 18, 2015 9:01 AM (link)
Charles Nurse
@Scippy One - thanks for suggesting the fixes needed.

@Victor- (2) because we have to take over the Controller activation then we do not currently support dependency resolution. (1) No - the WAP is not an MVC project as the core is still a WebForms app.

@Jaydeep - We continue to support all other modes of Module development - MVC and the new HTML 5 mode just add extra capabilities.
Charles Nurse Wednesday, September 30, 2015 10:53 AM (link)
Wael Musleh
When inherits from DotNetNuke.Web.Mvc.Framework.DnnWebViewPage the HtmlHelper(@Html) is overrides and all the methods in System.Web.WebPages.Html.HtmlHelper is gone (ex. DropDownList, Raw, CheckBox, ListBox)
Wael Musleh Tuesday, November 17, 2015 10:35 PM (link)
tianxi xi
Im now developing some stuff using new MVC features supported by DNN8. In webforms we can use controls like DnnJsInclude or DnnCssInclude to include client scripts throught Client Resources Management API. Now, it's possible to use the same capabilities in a MVC module?
tianxi xi Wednesday, January 20, 2016 9:19 PM (link)
Scippy One
You can use:

ClientResourceManager.RegisterStyleSheet(Dnn.DnnPage, "~/DesktopModules/MVC/YourModule/YourClass.css");

ClientResourceManager.RegisterScript(Dnn.DnnPage, "~/DesktopModules/MVC/YourModule/YourJavascript.js");
Scippy One Tuesday, January 26, 2016 11:48 AM (link)

Comment Form

Only registered users may post comments.


2sic Daniel Mettler (125)
Aderson Oliveira (15)
Alec Whittington (11)
Alex Shirley (10)
Andrew Nurse (30)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (22)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (203)
Chris Paterra (55)
Clinton Patterson (28)
Cuong Dang (21)
Daniel Bartholomew (2)
Dave Buckner (2)
David Poindexter (3)
David Rodriguez (2)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (74)
Geoff Barlow (6)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (270)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matthias Schlomann (15)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Mike Horton (19)
Mitchel Sellers (28)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Peter Donker (52)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott S (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (2)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (37)
Will Strohl (163)
William Severance (5)
Try Evoq
For Free
Start Free Trial
a Demo
See Evoq Live
Need More Information?