Umbraco 8: Authentication & Authorization

User Handling, & Security

In the last installment, we learned about the different kinds of controllers that Umbraco provides us. Now we will delve into User and Member management, and how to code authentication & authorization into your Umbraco website.

Security

Umbraco has two distinct user types. User security for the back office and member security for the front end. Both are quite easy to work with and are built upon Forms Authentication. One of the great things about Umbraco is its versatility. For either users or members, you can use a different provider than Forms Authentication or you can even roll your own. User Authentication works right out of the box without you having to do any real work, but member authentication & authorization will require a bit of custom coding on your part.

Securing the Backoffice

I’m not going to talk a lot about back office security because that is the main topic of my next article, but I will give a basic overview. Umbraco back office authentication & authorization is built upon ASP.Net Identity, which most of us should be pretty familiar with at this point. Being built on Identity means that it can support any OAuth provider that you throw its way. There is one important thing to note. Umbraco released a github project called UmbracoIdentityExtensions, and I’ve tried working with it in v8 & it is rather buggy to say the least at this point. I’m pretty sure that they will release something else down the road.

Securing the Frontend

Frontend security in Umbraco is straightforward and can be handled absolutely any way that you please. Umbraco really does a lot of the heavy-lifting for you!  I’m going to keep it as simple as possible in this tutorial.

We will need to do the following first:

  • Create a login page.
  • Create a registration page.
  • Create an authentication error page for when the user fails to authenticate correctly or doesn’t have sufficient privileges.
  • Create a couple of secured pages that are only accessible to certain types of users.

I believe in making code as modular as possible, so the login page will just be of the “Simple Page” document type & we will create a login macro.

So, let’s get started:

  • Login to the Umbraco Backoffice
  • Now we need to create our member groups. click on Members, right click on Member Groups, and click on Create, now simply type Admin and click Save.
  • Follow the same steps from above and create a Member Group called Standard.
  • Right click on Home and create the following pages and put whatever content in there that you like for the moment:
    1. Administration
    2. My Account
    3. Login
    4. AuthError
  • Now Click on Administration, Click on Actions, Click on Public Access
    1. For Select the groups who have access to the page Administration, click on Add and select the newly created Admin group.
    2. For Login Page select the Login page that you created above.
    3. For Error Page select the AuthError page that you created above.
    4. Click Save
  • Now Click on the My Account, Click on Actions, Click on Public Access
    1. For Select the groups who have access to the page Administration, click on Add and select the newly created Admin group, then add Standard.
    2. For Login Page select the Login page that you created above.
    3. For Error Page select the AuthError page that you created above.
    4. Click Save.
  • Have a look at our site now…

  • It looks like our Macro and Document Type aren’t smart enough to magically figure out when a page that we’ve created should not be displayed. The programmer of this site should be shot! Oh wait… never mind. Everyone makes mistakes. Let’s kill two birds with one stone, by updating that macro right now to intelligently display a login or logout button. and we’ll quickly discuss how to hide pages that you don’t want in the navigation menu. So, if you click on the Administration or My Account page, you’ll see that it redirects you to our presently completely useless Login page. Let’s go ahead and remedy that.
  • First let’s go back to the backoffice, go to settings, click on Document Types, select Simple Page, and click Add property with the following properties:
    Name: Hide From Navigation Menu
  • Click Add editor, then select Checkbox, accept the default values and click Submit.
  • Click Save.
  • Click Content, Click Auth Error, click “Hide From Navigation Menu,” and click Save and publish.
  • Do the same thing for Login
  • First, let’s deal with that pesky weird items in the navigation menu issue. To fix, that… all we need to do is reference our newly created property in our ~/Views/MacroPartials/Navigation.cshtml partial, like so:

@inherits Umbraco.Web.Macros.PartialViewMacroPage
@using Umbraco.Web
@{ var selection = Model.Content.Root().Children.Where(x => x.IsVisible() && (bool)x.GetProperty("hideFromNavigationMenu").Value() == false).ToArray(); }
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item" @(Model.Content.Root().IsAncestorOrSelf(Model.Content) ? "active" : null)>
<a class="nav-link" href="@Model.Content.Root().Url">@Model.Content.Root().Name</a>
</li>
@if (selection.Length > 0)
{
foreach (var item in selection)
{
<li class="nav-item @(item.IsAncestorOrSelf(Model.Content) ? "active" : null)">
<a class="nav-link" href="@item.Url">@item.Name</a>
</li>
}
}
</ul>
</div>

I know that a magician never reveals his secrets, but the real magic happens here:
@{ var selection = Model.Content.Root().Children.Where(x => x.IsVisible() && (bool)x.GetProperty("hideFromNavigationMenu").Value() == false).ToArray(); }

  • Now that is finished, we will go ahead and create that custom login header for the navigation menu. For the moment, we will only worry about when the user is not logged in. Start by creating a partial view in the ~/Views/Partials directory called _LoginHeader.
  • This will be a pretty simple partial where you simply display a different link if a user is logged in or not & it will look like this:

@inherits Umbraco.Web.Mvc.UmbracoViewPage<Umbraco.Web.Models.PartialViewMacroModel>
<div class="my-2 my-lg-0">
@if (Umbraco.MemberIsLoggedOn())
{
<text>
<ul class="nav navbar-nav">
<li class="nav-item navbar-text">
Welcome, @Umbraco.Member(Umbraco.MembershipHelper.GetCurrentMemberId()).Name
</li>
<li class="nav-item">
<a class="nav-link" href="/Umbraco/Surface/Authentication/Logout">Logout</a>
</li>
</ul>
</text>
}
else
{
<text>
<ul class="nav navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/login">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/register">Register</a>
</li>
</ul>
</text>
}
</div>

  • Now we simply need to add the partial to our navigation menu macro partial (~/Views/MacroPartials/Navigation.cshtml). You do this by adding the following line just before the closing div of your navbar:
    @Html.Partial(@”~/Views/Partials/_LoginHeader.cshtml”)
  • Finally, to create the login page. For this, we are going to create a new model, authentication controller and a macro. Let’s start with the model. Go ahead and create a class called LoginViewModel.cs in the ~/Models directory. The code you write should look a little something like this, but feel free to play around with it:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace USD.Umbraco.Article3.UI.Models
{
public class LoginViewModel
{
public LoginViewModel(string username, string password, string returnUrl)
{
Username = username;
Password = password;
ReturnUrl = returnUrl;
}
public LoginViewModel()
{
}
[Required]
[DisplayName("Email Address")]
[DataType(DataType.EmailAddress)]
public string Username { get; set; }
[Required]
[DisplayName("Password")]
[DataType(DataType.Password)]
public string Password { get; set; }
[DataType(DataType.Url)]
public string ReturnUrl { get; set; }
}
}

  • Now we just need to add login and logout methods to AuthenticationController.cs and create the login view. We’re not going to worry about creating a logout page, I’m just going to show you how to call an action without Umbraco getting in the way and trying to display a page (quite simple really, but the documentation doesn’t make this apparent).

Here is what your controller code should look like:

using System;
using System.Web.Mvc;
using System.Web.Security;
using Umbraco.Web.Mvc;
using USD.Umbraco.Article3.UI.Models;
namespace USD.Umbraco.Article3.UI.Controllers
{
public class AuthenticationController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.Username, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Username, false); // set to true for "remember me."
Redirect(model.ReturnUrl.IndexOf(@"login", StringComparison.InvariantCulture) > 0 ? "/" : model.ReturnUrl);
}
else
{
this. ModelState.AddModelError(String.Empty, @"Invalid Username or password.");
}
}
return CurrentUmbracoPage();
}
[HttpGet]
public void Logout()
{
FormsAuthentication.SignOut();
Response.Redirect(@"/", true);
}
}
}

Now for the view. For modularity & simplicity sake, let’s create a normal MVC partial called _Login.cshtml in the ~/Views/Partials directory and code it like so:

@inherits Umbraco.Web.Mvc.UmbracoViewPage<USD.Umbraco.Article3.UI.Models.LoginViewModel>
<div class="container">
@using (Html.BeginUmbracoForm(
@"Login",
@"Authentication",
System.Web.Mvc.FormMethod.Post,
new { id = "loginForm" }))
{
@Html.AntiForgeryToken()
<input type="hidden" name="ReturnUrl" value="@this.Request.RawUrl" />
<div class="row">
<div class="col-md-3">
<div class="form-group">
@Html.LabelFor(m => m.Username)
</div>
</div>
<div class="col-md-3">
<div class="form-group">
@Html.TextBoxFor(m => m.Username, new { placeholder = "Username", @class="form-control" })
@Html.ValidationMessageFor(m => m.Username)
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="form-group">
@Html.LabelFor(m => m.Password)
</div>
</div>
<div class="col-md-3">
<div class="form-group">
@Html.PasswordFor(m => m.Password, new { placeholder = "Password", @class = "form-control" })
@Html.ValidationMessageFor(m => m.Username)
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<button name="login" id="login" type="submit" class="btn btn-primary">Login</button>
</div>
</div>
}
</div>

  • Once again, in order to keep this modular, we’re going to create a macro for this, so login to the back office and head to the settings tab, right click on Partial View Macro Files, and click New Partial View Macro. Let’s call this one Login and use the following code:

@inherits Umbraco.Web.Macros.PartialViewMacroPage
@Html.Partial(@"~/Views/Partials/_Login.cshtml", new USD.Umbraco.Article3.UI.Models.LoginViewModel(string.Empty, string.Empty, this.Url.ToString()))

Macros do not allow you to pass in models, only Umbraco parameters.

  • At this point, you should be able to login. Don’t forget to create a member in the back office. Page access is automatically handled by Umbraco, which follows the rules we set up before.

  • If you’ve logged in, logout and try logging in again without any username or password. You’ll notice that it totally bypasses our validation rules specified in the model. This is because we haven’t installed unobtrusive ajax and we need to make a couple of changes to the web.config file.
  • First, let’s install the necessary javascript files. Type the following two commands into Package Manager Console:
    • Install-Package jQuery.Validation
    • Install-Package Microsoft.jQuery.Unobtrusive.Validation
  • Now, we’ll need to update ~/Views/Master.cshtml. Add the following code after the base jquery script:
    <script src="~/Scripts/jquery.validate.js"></script>

<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

  • You would think that it would work now… wrong. 😒You need to add the following lines to your web.config file:
    1. <add key="ClientValidationEnabled" value="true"/>
    2. <add key="UnobtrusiveJavaScriptEnabled" value="true"/>

This is something that confused me initially. These two lines were already included in earlier versions of Umbraco. They were set to false, but they were included.

  • Voila! Just like that any validation settings that you specify in your models will be enforced in the UI.
  • Now, we just need to do the member registration page and we can call this lesson a wrap. First, we’re going to once again create a new macro. So, once again, go to the back office, go to settings, right click on partial view macro files and create a new one called RegisterForm leave it blank for the moment, & click save (because I prefer working in Visual Studio – don’t forget in a few moments to show all files and include it in the project).
  • Now go up to Macros, click RegisterForm and just click “Use in rich text editor and the grid” and click save.
  • Now we want to put this somewhere, so you’ll want to go to the Content tab, right click on Home & Create a new “Simple Page” called Register.
  • Click “Hide from Navigation Menu” and then simply go up and include our new macro and hit save.
  • For the login, we took a more traditional Forms Authentication approach. For this page, however… I’m going to do something a little more “Umbraco-centric” and we won’t even have to add a controller, because really… all of this functionality is already baked into Umbraco, so there is no need to even create a controller. I chose to hand code the login page to show just how easy it is to customize Umbraco to suit your needs. So, open ~/Views/MacroPartials/RegisterForm.cshtml and paste the following code:

@inherits Umbraco.Web.Macros.PartialViewMacroPage
@using System.Web.Mvc.Html
@using Umbraco.Web
@using Umbraco.Web.Controllers
@{
var registerModel = Members.CreateRegistrationModel();
registerModel.LoginOnSuccess = true;
registerModel.UsernameIsEmail = true;
registerModel.RedirectUrl = "/";
var success = TempData["FormSuccess"] != null;
}
@if (success) //BUG This is a bug that I have reported to Umbraco and will fix it for them.
{
<p>>Thank you for registering!</p>
}
else
{
using (Html.BeginUmbracoForm<UmbRegisterController>
("HandleRegisterMember"))
{
<div class="container">
<fieldset>
@Html.ValidationSummary("registerModel", true)
<div class="row">
<div class="col-md-3">
<div class="form-group">
@Html.LabelFor(m => registerModel.Name)
</div>
</div>
<div class="col-md-3">
<div class="form-group">
@Html.TextBoxFor(m => registerModel.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(m => registerModel.Name)
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="form-group">
@Html.LabelFor(m => registerModel.Email)
</div>
</div>
<div class="col-md-3">
<div class="form-group">
@Html.TextBoxFor(m => registerModel.Email, new { @class = "form-control" })
@Html.ValidationMessageFor(m => registerModel.Email)
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="form-group">
@Html.LabelFor(m => registerModel.Password)
</div>
</div>
<div class="col-md-3">
<div class="form-group">
@Html.PasswordFor(m => registerModel.Password)
@Html.ValidationMessageFor(m => registerModel.Password)
</div>
</div>
</div>
@if (registerModel.MemberProperties != null)
{
@*
It will only displays properties marked as "Member can edit" on the "Info" tab of the Member Type.
*@
for (var i = 0; i < registerModel.MemberProperties.Count; i++)
{
@Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name)
@*
By default this will render a textbox but if you want to change the editor template for this property you can
easily change it. For example, if you wanted to render a custom editor for this field called "MyEditor" you would
create a file at ~/Views/Shared/EditorTemplates/MyEditor.cshtml", then you will change the next line of code to
render your specific editor template like:
@Html.EditorFor(m => profileModel.MemberProperties[i].Value, "MyEditor")
*@
@Html.EditorFor(m => registerModel.MemberProperties[i].Value)
@Html.HiddenFor(m => registerModel.MemberProperties[i].Alias)
<br />
}
}
@Html.HiddenFor(m => registerModel.MemberTypeAlias)
@Html.HiddenFor(m => registerModel.RedirectUrl)
@Html.HiddenFor(m => registerModel.UsernameIsEmail)
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</div>
</fieldset>
</div>
}
}

It’s just that simple! Note: Don’t try to use the success variable. In past versions of Umbraco, they were setting TempData[“FormSuccess”] behind the scenes. It seems they aren’t doing that anymore. I need to see what they say about this “bug.” I left it in there because if they confirm it is a bug, I’ll fix it and it will work in a future version of Umbraco.

Summation

In this article, we covered just how easy it is to configure authentication and authorization in Umbraco 8. It isn’t terribly dissimilar than the way it has worked since version six. We also covered simple and unobtrusive form validation. I didn’t complete the “My Account” page on purpose to give readers the opportunity to try to solve this on their own. In the the source for article 4, I’ll include some code for the “My Account” page. It is important to remember that member authentication in Umbraco is based on Forms Authentication with very few mild differences.

The full source code for this article can be found at: https://bitbucket.org/uniquesoftware/blogposts/src/master/USD.Umbraco.Article3.UI

As always, the username & password to the Umbraco back office is:
Username: info@coderpro.net
Password: Q1w2e3r4t5y6!

If you have any questions, please feel free to drop me a line anytime.

Coming Up Next Time

In the next lesson, we will start working on some more advanced topics. We will use IdentityServer4 & ASP.Net Core to write a custom membership provider that allows for single sign on & third-party authentication for both the back-office and members. We will also extend the back office so that you can manage IdentityServer users directly from the back office. Until then: Happy Coding!

Umbraco 8 – More Than Just Content

In the last installment, we learned about the basics of Umbraco and what is new in Umbraco 8. Now we are going to delve into coding basic functionality and making our code as modular as possible.

Before we delve into the code, let’s talk a little about the different types of controllers available to us and which one is appropriate in a given circumstance.

Umbraco Controllers

In addition to the standard ASP.Net MVC controller, Umbraco provides us with two other types of controllers. The RenderMvc Controller and Surface Controller. In a nutshell, both controllers give you control over Umbraco that you simply would not have with a standard MVC controller.

Surface Controller

Surface controllers inherit from standard MVC controllers, so you have all the functionality of a standard MVC controller, plus Umbraco specific functionality. A surface controller is interacting with the front-end pages and are particularly useful for rendering child actions. Any time you have a custom form, you will want to use a surface controller. Surface controllers provide access to important Umbraco objects such as UmbracoHelper and UmbracoContext. Surface controllers are auto-routed, so you never have to manually setup your own routes. Umbraco handles all of this behind the scenes. If you want to “hijack” a route, you would use the RenderMvc Controller.

RenderMvc Controller

This type of controller is the total opposite of the surface controller. This gives you greater control over how your views are rendered. These controllers provide you with the ability to execute custom code before your views are rendered instead of simply blindly executing the pages and providing you with no control with what happens before the view is rendered. For instance, you can apply granular security rules to your pages & if coded correctly, you can even implement item level security so that only display certain parts of pages to certain users. This also provides you with an opportunity to manipulate the model associated with a page before the page is rendered.

Tying it all together

In Umbraco surface controllers and RenderMvc controllers give you the ability to do more than just serve content and allow for you to also customize the way that Umbraco serves up content instead of simply boxing you in. You really shouldn’t ever have to use a standard controller unless you are doing something completely outside of Umbraco.

Adding some functionality

Macros

Macros are simply reusable units of code. Umbraco comes with several useful snippet’s out of the box, one of which we will be using momentarily. Macros can either be used in a Rich Text Editor or called programmatically. In this post we will be adding a new page to the site, so we should have a navigation menu & this is one of those snippets that Umbraco gives us right out of the box.

To add the navigation menu to Umbraco, the first thing that you’ll want to do is login to the back office, go to settings, right click on partial view macros and select “New partial view macro from snippet,” and then click on Navigation. You will then be shown the partial view that is about to be created. You can customize this if you like, but for the moment, we will leave it as it is. All we are going to do now is name the partial “Navigation” and click save. Since we will never be calling this from within a rich text editor, it’s time to hook this up to our site. For the moment, the only view that we have is ~/Views/Homepage.cshtml, so that’s what we are going to edit. Go ahead and delete lines 51 thru 67 and replace it with:

@Umbraco.RenderMacro(@"Navigation")

Bam, we’re done! It’s not displaying anything right now because we don’t have any other pages, but I don’t want it to display only other pages, it should obviously display the root page & of course this is a Bootstrap 4 site, so it should be styled as such. So, let’s go back to ~/MacroPartials/Navigation.cshtml view and add the root page (Homepage) & make it look pretty. When we are finished with the changes, Navigation.cshtml should look like this:

@inherits Umbraco.Web.Macros.PartialViewMacroPage
@using Umbraco.Web
@{ var selection = Model.Content.Root().Children.Where(x => x.IsVisible()).ToArray(); }
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item" @(Model.Content.Root().IsAncestorOrSelf(Model.Content) ? "active" : null)>
<a class="nav-link" href="@Model.Content.Root().Url">@Model.Content.Root().Name</a>
</li>
@if (selection.Length > 0)
{
foreach (var item in selection)
{
<li class="nav-item @(item.IsAncestorOrSelf(Model.Content) ? "active" : null)">
<a class="nav-link" href="@item.Url">@item.Name</a>
</li>
}
}
</ul></div>

Now that we have a navigation page, it’s time to get into making the site functional, right? Wrong!  We don’t want to continually copy and paste the same code into every type of page that we have. So, we are going to want to create a layout page & have our pages inherit from that.

Layout pages aren’t specific to Umbraco. Practically every ASP.Net MVC site uses them and all the MVC devs out there already know what they are. In case you don’t, layout pages are simply pages that other pages inherit from. Even your layout page can have a layout page ad infinitum.

I prefer to use Visual Studio as often as I can instead of the back office, so if Visual Studio is running, stop it, right click on views in the solution explorer => Add => MVC 5 View and click Add. Now just simply name the view “Master” and hit enter. First, erase the junk that Visual Studio put in there while it was scaffolding and then you will want to extract the elements that most pages will have in common from your ~/Views/Homepage.cshtml file. Because your master page can serve up any type of page, you won’t be able to pass a document type into your @inherits. So, you will also have to replace all instances of this.Model.[attribute] with Model.Root.GetProperty(“[property name]”).GetValue() or some derivative thereof. In the end, your Master view will look like this:

@inherits Umbraco.Web.Mvc.UmbracoViewPage
@{
Layout = null;
var siteRoot = Model.Root();
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="Brandon Osborne">
<meta name="generator" content="Jekyll v3.8.5">
<title>@Model.Root().GetProperty("siteTitle").Value()</title>
<link rel="canonical" href="https://getbootstrap.com/docs/4.3/examples/jumbotron/">
<!-- Bootstrap core CSS -->
<link href="~/Content/bootstrap.css" rel="stylesheet" crossorigin="anonymous">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="~/Content/Site.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="#">@siteRoot.GetProperty(@"SiteName").Value()</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
@Umbraco.RenderMacro(@"Navigation")
@if (!Convert.ToBoolean(siteRoot.GetProperty("HideSearch").GetValue()))
{
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
}
</nav>
@RenderBody()
<footer class="container">
<p>@siteRoot.GetProperty(@"FooterContent").GetValue()</p>
</footer>
<script src="~/Scripts/jquery-3.3.1.slim.js" crossorigin="anonymous"></script>
<script src="~/Scripts/bootstrap.bundle.js" crossorigin="anonymous"></script>
</body>
</html>

Your Homepage view will now look like this:

@inherits Umbraco.Web.Mvc.UmbracoViewPage<ContentModels.Homepage>
@using ContentModels = Umbraco.Web.PublishedModels;
@{
Layout = "Master.cshtml";
}
<main role="main">
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1 class="display-3">@this.Model.SiteName</h1>
<p>@this.Model.HeaderContent</p>
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-md-4">
<h2>@this.Model.LeftColumnHeader</h2>
<p>@this.Model.LeftColumnContent</p>
</div>
<div class="col-md-4">
<h2>@this.Model.CenterColumnHeader</h2>
<p>@this.Model.CenterColumnContent</p>
</div>
<div class="col-md-4">
<h2>@this.Model.RightColumnHeader</h2>
<p>@this.Model.RightColumnContent</p>
</div>
</div>
<hr>
</div> <!-- /container -->
</main>

Now we can get to coding a page and macro that provides some functionality. Every site needs a contact page, so let’s start with that. The first thing we will want to do is once again, create a document type and template for the contact page. So, once again login to the back office and go to settings. Right click on Document Types, Click Create, Select Document Type. Now we will start building our Doc Type. Select an icon that gives you the warm and fuzzies and name this document type Simple Page. Click on add group & name your group Content. We are going to make this simple, so you only need to create 2 properties.

  • Page Title – Textbox – Default settings
  • Body Content – Richtext Editor – Default settings.

Now you need to tell Umbraco where this new doc type can go, so click on Homepage click permission, click “Add child” and select Simple Page. This tells Umbraco that a simple page can go under the Home.

Before we build the contact form macro, let’s just quickly build out a simple contact page. Of course, right now we only have an empty template for that page, so we will define the Layout property as we previously did for homepage and simply add the title and a little body content to the page. Here is what your contact view should look like:

@inherits Umbraco.Web.Mvc.UmbracoViewPage<ContentModels.SimplePage>
@using ContentModels = Umbraco.Web.PublishedModels;
@{
Layout = "Master.cshtml";
var pageTitle = string.IsNullOrEmpty(this.Model.PageTitle) ? this.Model.Name : this.Model.PageTitle;
}
<main role="main">
<div class="container">
<h2 class="display-4">@pageTitle</h2>
</div>
<div class="container">
<p>
@this.Model.BodyContent
</p>
</div>
</main>

After this, all we need to do is add some content and it will display automagically. So, let’s add a contact page to the site in the back office. So, simply go to the content tab in the back office, right click on Homepage and click Create, click Simple Page, enter Contact as the name, then enter whatever page title and body content that you like. As promised, everything displays as we said it would. Now let’s go about adding that contact us form. We created this as a very generic page because we don’t need a special contact us page in Umbraco because we can simply create a macro that can be rendered from within a Rich Text Editor.

Implementing Macros & Surface Controllers

Now that we have created our page and added content to it, the only thing remaining for us to do is create a macro and surface controller. First, let’s create the macro. Log back in to the back office, go to settings, right click on “Partial View Macro Files,” select “New partial view macro.” First name the macro ContactForm and then we will want to create a form that includes FirstName, LastName, EmailAddress, and Message, and of course, the form will call a surface controller yet to be created. Before we do that, let’s make some changes to the macro settings. Right click on the macro folder under settings, click reload, and select ContactForm. First, set “Use in rich text editor and the grid” to true so we can simply add it to the body content. Now, click on Parameters, add, and create a single parameter with the following values:

Name: Reply To | Alias: replyTo | Editor: Email address

That is all we need to do for the macro from a configuration standpoint. Now all we need to do is code our new view model for the contact form, partial view, and surface controller.

First, we will want to create a view model. So, add a new class to the ~/Models/ directory and let’s call it ContactViewModel.cs. I want to follow an Occam’s Razor approach in these early posts, so we will keep it simple. The code for your model should look like this:

using System.ComponentModel.DataAnnotations;
namespace Umbraco.Demo.UI.Models
{
using System.Web.Mvc;
public class Contact
{
[MinLength(2), MaxLength(25)]
[Required]
[DataType(DataType.Text)]
public string FirstName { get; set; }
[MinLength(2), MaxLength(50)]
[Required]
[DataType(DataType.Text)]
public string LastName { get; set; }
[MinLength(5), MaxLength(100)]
[Required]
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string FromEmailAddress { get; set; }
[MinLength(5), MaxLength(100)]
[Required]
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string ToEmailAddress { get; set; }
[MinLength(25), MaxLength(2000)]
[Required]
[DataType(DataType.MultilineText)]
public string Message { get; set; }
}
}

*NB: If Visual Studio complains about System.ComponentModel.DataAnnotations, go back to Package Manager Console and type the following: Install-Package EntityFramework.

At this point, we need to write some code for our partial view that was created at ~/Views/MacroPartials/ContactForm.cshtml and it should look like the following:

@inherits Umbraco.Web.Macros.PartialViewMacroPage
@{
var contactModel = new Umbraco.Demo.UI.Models.ContactViewModel() { FromEmailAddress = this.Model.MacroParameters["replyTo"].ToString() };
contactModel.FromEmailAddress = this.Model.MacroParameters["replyTo"].ToString();
}
@using (Html.BeginUmbracoForm(@"SendContactMessage", @"Communication", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(x => contactModel.FromEmailAddress, new { })
<div class="container">
<div class="row">
<div class="col col-md-6">
<div class="form-group">
@Html.TextBoxFor(x => contactModel.FirstName, new { placeholder = "First Name", @class = "form-control" })
</div>
</div>
<div class="col col-md-6">
<div class="form-group">
@Html.TextBoxFor(x => contactModel.LastName, new { placeholder = @"Last Name", @class = "form-control" })
</div>
</div>
</div>
<div class="row">
<div class="col col-md-12">
<div class="form-group">
@Html.TextBoxFor(x => contactModel.ToEmailAddress, new { placeholder = @"Your Email Address", @class = @"form-control" })
</div>
</div>
</div>
<div class="row">
<div class="col col-md-12">
<div class="form-group">
@Html.TextAreaFor(x => contactModel.Message, new { placeholder = @"Message", @class = @"form-control", rows = 10 })
</div>
</div>
</div>
<div class="row">
<div class="col col-md-3">
<button type="submit" name="submitContact" id="submitContact" title="Submit Contact Form" class="btn btn-primary">Send</button>
</div>
</div>
</div>
}

As of the time of writing, I personally discovered a now-confirmed bug in Umbraco 8 that causes redirects not to work correctly (along with ViewBag or TempData) when you render a macro inside of a rich text editor, so in order to sidestep this issue for now, we’re simply going to edit ~/Views/SimplePage.cshtml to the following:

@inherits Umbraco.Web.Mvc.UmbracoViewPage<ContentModels.SimplePage>
@using ContentModels = Umbraco.Web.PublishedModels;
@{
Layout = "Master.cshtml";
var pageTitle = string.IsNullOrEmpty(this.Model.PageTitle) ? this.Model.Name : this.Model.PageTitle;
var success = Request.QueryString["success"];
}
<main role="main">
<div class="container">
<h2 class="display-4">@pageTitle</h2>
</div>
@if (!string.IsNullOrEmpty(success))
{
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="@(success == "True" ? "alert-success" : "alert-danger")">Your message was @(Request.QueryString["Success"] == "True" ? " successfully sent!" : " not sent! Check your form input and try again later.")</div>
</div>
</div>
</div>
}
<div class="container">
<p>
@this.Model.BodyContent
</p>
</div>
</main>

Last, but not least, we need to create our surface controller that will finally give our macro and contact page it’s functionality. The code should look like this:

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CommunicationController.cs" company="Unique Software Development">
// Copyright 2019 Unique Software Development, Inc.
// </copyright>
// <summary>
// The communication controller controls all actions relating to communications (System.Net).
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Umbraco.Demo.UI.Controllers
{
using System.Net.Mail;
using System.Web.Mvc;
using Umbraco.Web.Mvc;
/// <summary>
/// The communication controller.
/// </summary>
public class CommunicationController : SurfaceController
{
public void Index()
{
}
/// <summary>
/// The send contact message.
/// </summary>
/// <param name="contactModel">
/// The contact model.
/// </param>
[HttpPost]
[ValidateAntiForgeryToken]
public void SendContactMessage(Models.ContactViewModel contactModel)
{
var success = false;
if (ModelState.IsValid)
{
var smtpClient = new System.Net.Mail.SmtpClient("localhost", 25);
// Send message to us.
smtpClient.Send(new MailMessage()
{
Body = contactModel.Message,
From = new MailAddress(contactModel.ToEmailAddress, $"{ contactModel.FirstName } { contactModel.LastName }"),
To = { new MailAddress(contactModel.FromEmailAddress) },
IsBodyHtml = false,
Subject = @"Contact Us Form Response"
});
// Send thank you to user.
smtpClient.Send(new MailMessage()
{
Body = @"Thank you for your message! We will get back to you in the next 24 hours.",
From = new MailAddress(contactModel.ToEmailAddress, $"{ contactModel.FirstName } { contactModel.LastName }"),
To = { new MailAddress(contactModel.FromEmailAddress) },
IsBodyHtml = false,
Subject = @"Thank You For Your Message!"
});
success = true;
}
// The point of this exercise is to show you how to create a surface controller, not teach MVC.
// This is obviously incredibly ugly from an MVC / C# point of view.
Response.Redirect($"~/contact/?success={success}", false);
}
}
}

Voila! Now you have a contact us page and a contact us macro that can easily be included on any page either by rendering the macro directly in your view or inside any rich text editor.

Conclusion

We covered the different types of controllers and macros in this article. We also created our first surface controller that serves as a simple contact us form that can be rendered into any view or any rich text editor property type.

The full source code for this article can be found at: https://bitbucket.org/uniquesoftware/blogposts/src/master/Umbraco/Article2

If you have any questions, please feel free to drop me a line anytime.

Coming Up Next Time

In the next lesson, you will learn how to allow users to self-register and self-manage their accounts & how you can manage them in the back office. Until then:  Happy Coding!

Umbraco 8 – Getting Started

Umbraco has changed a lot since I started working with it in version 4 back in 2013. In this series we are going to delve deep into Umbraco from the basics of creating your first site all the way to writing plugins and customizing the backend of this wonderful ASP.Net MVC based CMS

Intended Audience

What you need:

  • Net MVC Experience
  • C# Experience
  • HTML5 Experience
  • Javascript Experience
  • Visual Studio 2015+
  • Eagerness to learn about something cool
  • Coffee, Mountain Dew, Redbull, or some other source of caffeine.

What you don’t need:

  • Any Umbraco experience whatsoever.

What’s New?

Just like v7, version 8 brings us even more exciting changes, mostly to the backend, but also to the code. If you’ve worked with Umbraco before, beware before you decide to upgrade. They’ve also changed the code and in many instances the reasoning isn’t immediately apparent. They’ve even changed the spelling of methods, so it will most definitely break your code, even if you are upgrading from v7. It will undoubtedly break. It is most definitely worth starting a new project with v8, but if you are upgrading a large site just for the sake of it, be ready for some headaches.

Get to It Already!

Without further-adieu, here are some of the exciting changes Umbraco 8 has in store for you:

Backend UI Overhaul

The backend has changed considerably from v7. Not only did they change the colors, but they also moved the main navigation menu from the left so that you have more screen real estate to do what matters. One more important thing of note: If you’re looking for the developer menu, stop. They have merged it into the settings screen. You can now also adjust the size of the left navigation menu, making even more room for you to edit your content (or see those extra long document titles that were cut off in previous versions leaving you wondering what you were about to click on).

Infinite Editing

This is my favorite new feature and really speeds up development and content editing. No more are you writing content and realize that you need an image, so you have to stop what you’re doing, save, go to media, then find what you were editing and continue. It’s not just for media though, you can even add new properties to your document type without leaving the content editor. You just click the info tab, make whatever changes you need, click save and you’re right where you left off. Umbraco 8 means never losing context, or more importantly, your train of thought again!

Language Variants

Handling sites that are multi-lingual has become so much simpler in Umbraco v8. Your translators can now compare languages side by side once again providing you with the opportunity to write content and not be constantly distracted by clicking around multiple documents. For more information regarding language variants, please visit: https://umbraco.com/blog/umbraco-8-language-variants/

Content Apps

Content Apps, as its name implies are basically extensions added to your content node. This doesn’t mean that it is a direct part of your editing experience, it’s more of a companion. It can give you information or statistics on the content that you’ve written. I understand that from reading either this paragraph or even what Umbraco says about it, neither of us are doing it justice.

It’s better to see an example:
See Preflight by Nathan Woulfe.

If you want to learn more about Content Apps, check out the documentation.

Codebase Cleanup

This is something that must have taken a long time, which is why they say that version 8 was “5 years in the making.” I honestly have mixed opinions about this one, but I suppose it is something that had to happen, and we just have to grin and bear it. Now that I’ve deployed a couple of Umbraco 8 sites, I can say that it does seem cleaner and the code does make more sense, is better documented, and is much easier to extend than it was previously. If you have extended Umbraco in the past, you’ll see that a lot of the legacy code has been removed and they are using more modern technology. The process of writing packages is also much simpler than it used to be!

Your First Umbraco Site

Installing

Installing Umbraco is a breeze. It’s so simple you could probably train your dog to do it. There are a couple of ways to install Umbraco: 1) Download an archive from their website or B) Install a nuget package. I prefer the second way because I love how nuget keeps all of my references in check, downloads them when they are missing, and well… it’s just nerdier that way.

Step 1: You want to open Visual Studio and create an ASP.Net Web Application (.net framework). It is important that you select the empty template and add a reference to MVC. You don’t need to do anything else.

Step 2: Now you simply want to install the Umbraco nuget package.

To do that, we simply type the following into the Package Manager Console:
install-package UmbracoCms

Step 3: Now we simply run the solution and do the initial configuration.

Initial Configuration

  • First you create the administrator account by filling out a simple form and then click customize.
  • Click continue
  • Next you select your database. Since this is a demo, I’m going to use SQL Server compact. Never use SQL Server compact for a production website.
  • Click No thanks. I do not want to install a starter website. This is important because the rest of this article will teach you how to build your own website from scratch.

After this concludes, you will have a barebones Umbraco installation. Next we will talk about how to actually make a site!

Putting It All Together

So, now you have installed an Umbraco solution, I’m sure you’re wondering what to do with it. In this section we shall do just that. I’ll walk you through writing the views and some basics of the Umbraco backend.

The Umbraco Back Office

The backend of Umbraco has been completely overhauled in this release and is much more intuitive.

Content

In this tab we will create, edit, and delete the content of your site & possibly view the data contained in Content Apps. The content you will be maintaining will come from the Document Types created in the Settings section.

Media

This is simply where the media for your website is stored. Available media types are: File, Folder, Image, and Video. *NB: The exact extensions allowed is controlled in the ~/config/UmbracoSettings.config file.

Settings

This is without a doubt the most important tab in the interface. This is where most of a developer’s time will be spent. I’ll walk you through the more important subtabs. In much later articles, I’ll walk you through the rest.

Document Types are the bread and butter of your site. You can basically look at it like the definition of the pages (i.e. labels, textbox, rich textbox controls, etc) that will go on your site. Document Types may or may not have templates associated with them.

Templates in MVC terminology are just views and nothing more. They are written in regular Razor syntax & can reference the document type values associated with it.

Packages

You can basically think of packages as plugins for the back office.

Users

Users are the Administrators, Editors, Translators, or Writers of your site. This basically defines their permissions to the Umbraco backend.

Members

If your site uses authentication, then here is were you can manage your members.

Forms

This is a paid extension from Umbraco that enables you or even your writers to create forms without coding. We won’t be focusing on this.

Building Our First Site

Now we are finally at the part we’ve all been waiting on. Now we will be creating our first document two types and a few templates. For this we will just be using a basic bootstrap 4.3.1 theme.

First things first, enter the following into your Package Manager Console:
install-package bootstrap

Now we’re ready to rock and roll. Run the project in Visual Studio again and we’ll create our first document type and template.

First, we will be creating our home page type and template. When we create a second page, we’ll create a master template from which all others derive.

  • Login to Umbraco
  • Go to Settings
  • Right Click on Document Types and Click Create.
  • In the panel on the right type Homepage and select the icon you want for this page by clicking the box to the left.
  • Now we’ll add a group. A group is simply a way of grouping your content fields (it could be something like Header, Body, Footer & then all the properties inside them). This site is going to be simple, so we’ll call our first group Content.
  • Add the following properties and select the default settings for each:
    1. Site Title – Editor: Textbox – Click Submit.
    2. Site Name – Editor: Textbox – Click Submit.
    3. Hide Search – Editor: Checkbox – I think you know what to do.
    4. Header Text – Editor Textbox
    5. Header Content – Editor: Rich Text Editor
    6. Left Column Header – Editor Textbox
    7. Left Column Content – Editor Rich Text Editor
    8. Center Column Header – Editor Textbox
    9. Center Column Content – Editor Rich Text Editor
    10. Right Column Header – Editor Textbox
    11. Right Column Content – Editor Rich Text Editor
    12. Footer Content – Editor Rich Text Editor

That’s it! You’ve created your first Document Type and Umbraco also created your first empty template (which is really nothing more than a view).

  • For the homepage, we’re going to use the Jumbotron template from bootstrap 4. View source & copy all the source code from this page.
  • Now click on Settings => Templates => Homepage & simply paste the HTML from the template.
  • Change line 20 to: <link href=”~/Content/bootstrap.css” rel=”stylesheet” crossorigin=”anonymous”>
  • Delete line 117 & update 116 to the following: <script src=”~/Scripts/jquery-3.3.1.slim.js” crossorigin=”anonymous”></script>
  • Update what is now line 117 to the following: <script src=”~/Scripts/bootstrap.bundle.js” crossorigin=”anonymous”></script>

Also delete the following lines:
<!-- Custom styles for this template -->
<link href="jumbotron.css" rel="stylesheet">

Now we have our code all setup and ready to be displayed on the site. We just have to do a few things in the back office first.

13. First, we need to tell where this new document type can go and potentially who can access it. To do that we go to Settings => Document Types => Homepage => Permissions (on top right) and turn the Allow as root slider to the on position.

14. Go to Content, Right Click the Content submenu, click create, then finally click Homepage.

15. Name the page Home and click Save & Publish for the moment.

  • Now look at http://localhost:<random_port_number>/Yay! We’re done!
    Really?
    Being the developer, do *you* want to make all the content changes?Now we must update the Homepage.cshtml view to grab the content data from Umbraco. So… go ahead and close that page and let’s get to it.

16. Go back to Visual Studio, click the “Show all files” button, go down to views, right click and select ‘Include in project.’ *NB: You could do this in the Umbraco interface also, but it isn’t a fun process, trust me.

17. Open Homepage.cshtml
Notice how the @inherits line at the top doesn’t know what ContentModels.Homepage is. Many people think this is because Umbraco uses dynamic types, but this simply isn’t true. Umbraco uses something called “Models Builder” that creates and updates the model when you update your pages and other things in the back office. Here I’ll show you: In Visual Studio make sure you’re showing all files. Right click ~/App_Data/Models/models.generated.cs & click include in project. This is a great little tip to make your coding easier. Note that your project will not run or build while this file is included in the project. When you’re ready to run your project, you must exclude this file again. Also, never manually edit this file because it will just be overwritten the next time you publish or build

18. Now it’s time to make your content dynamic. To accomplish this, your finished code in HomePage.cshtml would look like the following:

@inherits Umbraco.Web.Mvc.UmbracoViewPage<ContentModels.Homepage>
@using ContentModels = Umbraco.Web.PublishedModels;
@{
Layout = null;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Jekyll v3.8.5">
<title>@this.Model.SiteTitle</title>
<link rel="canonical" href="https://getbootstrap.com/docs/4.3/examples/jumbotron/">
<!-- Bootstrap core CSS -->
<link href="~/Content/bootstrap.css" rel="stylesheet" crossorigin="anonymous">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="jumbotron.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="#">@this.Model.SiteName</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
</ul>
@if (!this.Model.HideSearch)
{
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
}
</div>
</nav>
<main role="main">
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1 class="display-3">@this.Model.SiteName</h1>
<p>@this.Model.HeaderContent</p>
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-md-4">
<h2>@this.Model.LeftColumnHeader</h2>
<p>@this.Model.LeftColumnHeader</p>
</div>
<div class="col-md-4">
<h2>@this.Model.CenterColumnHeader</h2>
<p>@this.Model.CenterColumnContent</p>
</div>
<div class="col-md-4">
<h2>@this.Model.RightColumnHeader</h2>
<p>@this.Model.RightColumnContent</p>
</div>
</div>
<hr>
</div> <!-- /container -->
</main>
<footer class="container">
<p>@this.Model.FooterContent</p>
</footer>
<script src="~/Scripts/jquery-3.3.1.slim.js" crossorigin="anonymous"></script>
<script src="~/Scripts/bootstrap.bundle.js" crossorigin="anonymous"></script>
</body>
</html>

Conclusion

We just scratched the surface of the greatness that is Umbraco, particularly the latest & greatest version.

The full source code for this article can be found at: https://bitbucket.org/uniquesoftware/blogposts/src/master/

I hope this guide provided you with a useful introduction to the new version of Umbraco. If you have any questions, please feel free to drop me a line anytime.

Coming Up Next Time

In our next lesson, you will learn how to make your Umbraco site do something besides just serve up content. You’ll accomplish this first with surface controllers and we will also learn about how to write modular and reusable code by using macros. Until then:  Happy Coding!

NEXT: Umbraco 8 – Part 2