Menu

Save User Input to MongoDB with Umbraco

February 16, 2015 by Christopher Sherman

There are many reasons why you may accept user input on an Umbraco CMS site, but what if you want to save that data to a document-oriented storage solution like MongoDB? In this article, I’ll explain how to add a surface controller that does just that in the context of a contact form. I will use MongoLab on Microsoft Azure as my database host, but you can also set up a local MongoDB server on your development machine.

To get started, log in to Azure and select NEW > MARKETPLACE. Select MongoLab from the list of services. When prompted, select the Sandbox instance so we get the database instance for free. Finish up the Marketplace prompts and ensure that your instance has started.

Click on your newly created MongoLab instance. From the dashboard, select CONNECTION INFO and copy the URI to a safe place. We’ll need this later for configuring a connection from our CMS.

Open your Umbraco project in Visual Studio.

  1. On the main menu, click Tools > Nuget Package Manager > Package Manager Console.
  2. In the Package Manager Console, type Install-Package MongoRepository.

This Nuget package gives us a nice repository data access layer on top of the MongoDB C-Sharp driver.

Once the package finishes installing, open your Web.config file and find the connection string that the package added. The connection string is named MongoServerSettings and you need to replace its connectionString attribute with the URI you copied from the MongoLab instance.

Next, add a folder to your project named Models. Within this folder, add a class named ContactViewModel. Inside this class, replace the existing code with the code below, being sure to change the namespace to that of your project.

using System.ComponentModel.DataAnnotations;
using MongoRepository;

namespace YourProjectName.Models
{
public class ContactViewModel : Entity
{
[Required][stringlength(200, minimumlength = 2)]
public string Name { get; set; }

        [Required]
        [EmailAddress]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Email address")]
        public string EmailAddress { get; set; }

        [Required]
        [StringLength(2500, MinimumLength = 10)]
        [DataType(DataType.MultilineText)]
        public string Message { get; set; }
    }

}

Now that we have our data model, let’s create the controller to handle POSTs from a contact form. Create a folder in your project named Controllers. Within this folder, add a class named ContactSurfaceController.cs.

In this controller we’ll validates requests against our data model and save valid requests to our MongoDB instance. As confirmation, we return successful messages for display to the user via the ViewBag. If you also want to send an email notification, check out my tutorial on building an Umbraco contact form with email notification.

using System.Web.Mvc;
using YourProjectName.Models;
using MongoRepository;
using System.Web.Configuration;

namespace YourProjectName.Controllers
{
public class ContactSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public MongoRepository<ContactViewModel> contactRepository = new MongoRepository<ContactViewModel>();

        [HttpPost]
        public ActionResult CreateContactMessage(ContactViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return CurrentUmbracoPage();
            }

            var contactMessage = contactRepository.Add(model);
            ViewBag.Contact = contactMessage;

            return CurrentUmbracoPage();
        }
    }

}

Next, we need a PartialView with our contact form markup.

  1. In Umbraco back office, navigate to the Settings menu item.
  2. Within Settings, create a partial view named ContactForm.
  3. In the template field of your view, use the code below.
@model YourProjectName.Models.ContactViewModel

@using (Html.BeginUmbracoForm<YourProjectName.Controllers.ContactSurfaceController>(
"CreateContactMessage"))
{
<h2>
Contact details
</h2>

    if (!ViewData.ModelState.IsValid)
    {
        <div class="row">
            <div class="large-12 columns">
                @Html.ValidationSummary(true, "Houston, we have a problem. Check things over and try again.")
            </div>
        </div>
    }

    <fieldset>
        <div class="row">
            <div class="large-12 columns">
            </div>
        </div>

        <div class="row">
            <div class="large-6 medium-8 small-10 columns">
                @Html.LabelFor(x => x.Name)<span class="required">*</span>
                @Html.TextBoxFor(x => x.Name, new Dictionary<string, Object> { { "required", "" } })
                <small class="error">Your name is required.</small>
                @Html.ValidationMessageFor(x => x.Name)
            </div>
        </div>

        <div class="row">
            <div class="large-6 medium-8 small-10 columns">
                @Html.LabelFor(x => x.EmailAddress)<span class="required">*</span>
                @Html.TextBoxFor(x => x.EmailAddress, new Dictionary<string, Object> { { "required", "" }, { "pattern", "email" } })
                <small class="error">A valid email address is required.</small>
                @Html.ValidationMessageFor(x => x.EmailAddress)
            </div>
        </div>

        <div class="row">
            <div class="large-10 medium-12 small-12 columns">
                @Html.LabelFor(x => x.Message)<span class="required">*</span>
                @Html.TextAreaFor(x => x.Message, new Dictionary<string, Object> { { "required", "" }, { "rows", "5" } })
                <small class="error">Don't forget to enter a message.</small>
                @Html.ValidationMessageFor(x => x.Message)
            </div>
        </div>
    </fieldset>

    <div class="row">
        <div class="large-12 columns">
            <input type="submit" class="button" value="Submit" />
        </div>
    </div>

}

Finally, we’ll add a template on which we’ll display our partial view.

  1. Within Settings in Umbraco back office, create a template named Contact.
  2. In the template of your view, use the code below.
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
Layout = "\_Layout.cshtml";
}

<header>
    <div class="row">
        <div class="large-12 columns">
            <h1>
                @Umbraco.Field("headline")
            </h1>
            <h3>@Umbraco.Field("tagline")</h3>
        </div>
    </div>
</header>

<div class="row">
    <div class="large-12 columns">
        <section class="page-container">
            @{
                if (ViewBag.Contact != null)
                {
                    var viewModel = (YourProjectName.Models.ContactViewModel)ViewBag.Contact;

                    <div class="row">
                        <div class="large-8 medium-7 small-12 columns">
                            <h2>
                                Thanks for the message
                            </h2>

                            <div class="contact-confirmation">
                                <p>
                                    @Html.Raw(Umbraco.ReplaceLineBreaksForHtml(viewModel.Message))
                                </p>
                                <p>
                                    @viewModel.Name (@viewModel.EmailAddress)
                                </p>
                            </div>
                        </div>
                    </div>
                }
                else
                {
                    <div class="row">
                        <div class="large-8 medium-7 small-12 columns">
                            @Html.Partial("ContactForm", new YourProjectName.Models.ContactViewModel())
                        </div>
                    </div>
                }
            }
        </section>
    </div>

</div>

MongoDB Umbraco Razor