MVC

Table of contents

1. General

2. Naming Conventions

3. Models / Domain Models

4. View Models

5. View

6. Controllers

7. Routing

8. Attributes

9. Extensions and Tools

General

For a general guide on ASP.NET MVC, click on the following imageimage-1602129428352.png

image-1601320574138.png

TODO : what happens in web.config? Add Example zip folder to General page

https://signature.signifyhr.co.za/books/tools/page/v8---mvc-development

Naming Conventions

The following naming convention must be followed when creating any of the MVC pattern sections. All names must be created using Pascal-Case.

Model

Controller

Attributes

All custom filter attributes must be named according to its function e.g. BypassSessionAuthorisation

View

e.g. for the HomeController

image-1602128806399.png

View Models

Routing 

The registrations file for a areas route must be named {AreaName}AreaRegistration e.g LearningStoreRegistration.cs

 

 

Model/ Domain Model

Go To Naming Conventions

For information regarding models, click the images below

image-1602130700401.png

ViewModel

Go To Naming Conventions

For information regarding view models, click the images below

image-1602130609554.png

TODO : properties defined and properties inherited, private set properties, constructors

Example PathwayViewModel

View

Go To Naming Conventions

For information regarding razor views, click the images below

image-1602130864155.png

Responsible for presenting viewmodels, viewbags and other data structures in the format of the end user requirements

Reusing Views

Layouts

Common presentational areas (e.g. page header, footer) can be put in a layout view.

Partial Views

Views without a layout that reuse fragments of presentational code e.g. used in modals.

Helpers Classes

In views we often need some code snippets to do tiny tasks such as formatting data or generating HTML tags. 

The method in the helper class

image-1602126711528.png

The implementation of the class  and method in the view

image-1602126828227.png

 

TODO: add examples from v8 mvc page

Ensure list data bound during post (use for instead of for each)

Difference between Html.Form and Ajax.Form

Use of hidden field variables and where they should be placed in a view

Controller

Go To Naming Conventions

For information regarding Controllers, click the images below

image-1602130775935.png

 

namespace SignifyHR.Areas.Portal.Controllers
{
    public class HomeController : BaseController
    {
        [UserTranslationFilter]
        public ActionResult Index(PortalTabs? activeTab)
        {
            var model = new HomeViewModel(SessionHandler, activeTab)
            {
                Title = TranslationResources.PageHeadingsLmsPortal,
            };

            return View(model);
        }
 }

https://signature.signifyhr.co.za/books/tools/page/v8---mvc-development/edit

When to use ActionResult and JSONResult

AllowGet

Follow C# standards

Routing

Go To Naming Conventions

For a guide regarding routing, click on the image below

image-1602129606089.png

Area specific routing is implemented in the Area Registration cs file and can have custom routing as required by the area e.g. LearningStoreAreaRegistration.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SignifyHR.Areas.LearningStore
{
    public class LearningStorereaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "LearningStore";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
             name: "LearningStore.Pages",
             url: "LearningStore/{id}/{slug}",
             defaults: new { controller = "Page", action = "Index", slug = UrlParameter.Optional },
             constraints: new { id = @"\d+" },
             namespaces: new[] { "SignifyHR.Areas.LearningStore.Controllers" }
            );
            
            context.MapRoute(
             name: "LearningStore.DEFAULT",
             url: "LearningStore/{controller}/{action}",
             defaults: new { controller = "Home", action = "Index" },
             namespaces: new[] { "SignifyHR.Areas.LearningStore.Controllers" }
            );

        }
    }
}

Attributes

Go To Naming Conventions

The ASP.NET MVC framework supports four different types of filters executed in the following order:

  1. Authorisation filters – Implements the IAuthorizationFilter attribute.
  2. Action filters – Implements the IActionFilter attribute.
  3. Result filters – Implements the IResultFilter attribute.
  4. Exception filters – Implements the IExceptionFilter attribute.

The common authorisation filters that is used in Signify are

image-1601322053620.png

Example of use

Applying a filter on a single method in the controller

image-1602127617546.png

Applying a filter on the controller as a whole

image-1602127647291.png

Extensions and Tools

Logging

Using NLog

public class HomeViewModel : PortalMasterModel
{
    private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
    private static readonly Logger _lmsLogger = LogManager.GetLogger("LMS");
 
    public HomeViewModel()
    {
        // Using the class name as the name of the logger
        _logger.Info("Initializing HomeViewModel");
 
        // Using a new logger instance with a property automatically added
        _lmsLogger.WithProperty("ActiveTab", activeTab).Info("Initializing HomeViewModel");
 
        // Setting a property permanently on a logger
        _logger.SetProperty("Key", "Value");
        _logger.Info("Testing EventProperties");
 
        // Adding properties automatically in the message
        _logger.Info("Testing dynamic EventProperty Key={PropertyName}", "PropertyValue");
 
        // Logging an exception
        _logger.WarnException("Exception", new System.Exception("Example Exception"));
    }
}
Example of log levels
Level Message Logger Properties Callsite Exception
Info Initializing HomeViewModel SignifyHR.Areas.Portal.ViewModels.HomeViewModel   SignifyHR.Areas.Portal.ViewModels.HomeViewModel..ctor  
Info Initializing HomeViewModel LMS ActiveTab=TrainingRequirements SignifyHR.Areas.Portal.ViewModels.HomeViewModel..ctor  
Info Testing EventProperties SignifyHR.Areas.Portal.ViewModels.HomeViewModel Key=Value SignifyHR.Areas.Portal.ViewModels.HomeViewModel..ctor  
Info Testing dynamic EventProperty Key="PropertyValue" SignifyHR.Areas.Portal.ViewModels.HomeViewModel PropertyName=PropertyValue|Key=Value SignifyHR.Areas.Portal.ViewModels.HomeViewModel..ctor  
Warn Exception SignifyHR.Areas.Portal.ViewModels.HomeViewModel Key=Value SignifyHR.Areas.Portal.ViewModels.HomeViewModel..ctor System.Exception: Example Exception
Log Levels
Level Typical Use
Fatal Something bad happened; application is going down
Error Something failed; application may or may not continue
Warn Something unexpected; application will continue
Info Normal behavior like mail sent, user updated profile etc.
Debug For debugging; executed query, user authenticated, session expired
Trace For trace debugging; begin method X, end method X
Rules

A rule is a logger element with the following attributes:

NLog.config
!--
    Create a rule to only log entries from the LMS HomeViewModel logger,
    using the logDatabase target, and applicable on log levels Info and above
-->
<logger name="SignifyHR.Areas.Portal.ViewModels.HomeViewModel" minlevel="Info" writeTo="logDatabase" enabled="true" final="true" />

 

API Conventions

Propagate errors. If an error occurred, return a 500. The status code should tell you what happened, not the result of the call itself. Follow the DefaultApiConventions, which state that the action should return void and produce a 200, 404, or 400 status. In MVC these rules don't have to be followed as strictly, but with the APIs it is non-negotiable for standardisation.

[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesDefaultResponseType]
[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
public static void Delete(
[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Suffix)]
[ApiConventionTypeMatch(ApiConventionTypeMatchBehavior.Any)]
object id) { } 

https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/DefaultApiConventions.cs