Skip to content

Setup ASP.NET MVC 5 project

Jeremy Cook edited this page May 9, 2016 · 2 revisions

Prerequisites:

  • ASP.NET MVC 5 web application with No Authentication on .NET 4.5.x

Note: A version of this tutorial for MVC 4 is available in video format: http://www.youtube.com/watch?v=mHJzmsFPrM4

Package installation

In NuGet Package Manager console, paste the lines below:

Install-Package BetterCMS
Install-Package BetterCms.Module.Newsletter
Install-Package BetterCms.Module.Users

This will install the Better CMS NuGet package and all the dependent packages.

Add a Helpers folder and these helper classes in it

The namespace of the helper classes should be like [YourProjectNamespace].Helpers.

Helpers\AuthenticationHelper.cs:

using System;
using System.Web;
using System.Web.Security;

public static class AuthenticationHelper
{
    public static void CreateTicket(string[] roles, string userName = "Better CMS test user")
    {
        var authTicket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMonths(1), true, string.Join(",", roles));

        var cookieContents = FormsAuthentication.Encrypt(authTicket);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieContents)
        {
            Expires = authTicket.Expiration,
            Path = FormsAuthentication.FormsCookiePath
        };

        HttpContext.Current.Response.Cookies.Add(cookie);
    }

    public static void Logout()
    {
        HttpContext.Current.Session.Clear();
        FormsAuthentication.SignOut();
    }

    public static void Auth(HttpApplication http)
    {
        //var authCookie = http.Request.Cookies[FormsAuthentication.FormsCookieName];

        //if (authCookie != null)
        //{
        //    var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        //    if (authTicket != null)
        //    {
        //        var identity = new FormsIdentity(authTicket);
        //        var principal = Roles.Enabled ? new RolePrincipal("BetterCmsRoleProvider", identity) : new RolePrincipal(identity, roleCokie.Value);
        //        http.Context.User = principal;
        //    }
        //}
    }
}

Helpers\OptionsHelper.cs:

using System.Collections.Generic;
using System.Linq;
using BetterCms.Core.DataContracts;

public static class OptionsHelper
{
    public static string GetValue(IList<IOptionValue> options, string key)
    {
        var option = options.FirstOrDefault(o => o.Key == key);
        if (option != null && option.Value != null)
        {
            return option.Value.ToString();
        }

        return null;
    }
}

Update Global.asax.cs

After a successful Better CMS package installation, update your Global.asax.cs file with the following usings, changing [YourProjectNamespace] to match your MVC project's root namespace:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;

using BetterCms.Core;
using BetterCms.Core.Environment.Host;
using BetterCms.Core.Modules.Projections;
using BetterCms.Events;

using Common.Logging;

using [YourProjectNamespace].Helpers;

and code:

public class MvcApplication : HttpApplication
{
    private static readonly ILog Log = LogManager.GetCurrentClassLogger();

    private static List<string> usersToForceRelogin = new List<string>();

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

        RouteConfig.RegisterRoutes(RouteTable.Routes);

        AddCategoryEvents();
        AddContentEvents();
        AddLayoutEvents();
        AddPageEvents();
        AddRedirectEvents();
        AddSitemapEvents();
        AddTagEvents();
        AddWidgetEvents();
        AddLanguageEvents();
        AddBlogPostEvents();
        AddBlogAuthorEvents();
        AddMediaManagerEvents();
        AddUsersEvents();
        AddNewsletterEvents();
    }

    private void AddContentEvents()
    {
        BetterCms.Events.RootEvents.Instance.ContentRestored += args => Log.Info("ContentRestored:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PageContentInserted += args => Log.Info("PageContentInserted:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PageContentDeleted += args => Log.Info("PageContentDeleted:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PageContentSorted += args => Log.Info("PageContentSorted:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PageContentConfigured += args => Log.Info("PageContentConfigured:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.HtmlContentCreated += args => Log.Info("HtmlContentCreated:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.HtmlContentUpdated += args => Log.Info("HtmlContentUpdated:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.HtmlContentDeleted += args => Log.Info("HtmlContentDeleted:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.ContentDraftDestroyed += args => Log.Info("ContentDraftDestroyed:" + args.Item.ToString());
    }

    private void AddLayoutEvents()
    {
        BetterCms.Events.PageEvents.Instance.LayoutCreated += args => Log.Info("LayoutCreated:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.LayoutDeleted += args => Log.Info("LayoutDeleted:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.LayoutUpdated += args => Log.Info("LayoutUpdated:" + args.Item.ToString());
    }

    private void AddLanguageEvents()
    {
        BetterCms.Events.RootEvents.Instance.LanguageCreated += args => Log.Info("LanguageCreated:" + args.Item.ToString());
        BetterCms.Events.RootEvents.Instance.LanguageDeleted += args => Log.Info("LanguageDeleted:" + args.Item.ToString());
        BetterCms.Events.RootEvents.Instance.LanguageUpdated += args => Log.Info("LanguageUpdated:" + args.Item.ToString());
    }

    private void AddNewsletterEvents()
    {
        BetterCms.Events.NewsletterEvents.Instance.SubscriberCreated += args => Log.Info("SubscriberCreated:" + args.Item.ToString());
        BetterCms.Events.NewsletterEvents.Instance.SubscriberDeleted += args => Log.Info("SubscriberDeleted:" + args.Item.ToString());
        BetterCms.Events.NewsletterEvents.Instance.SubscriberUpdated += args => Log.Info("SubscriberUpdated:" + args.Item.ToString());
    }

    private void AddMediaManagerEvents()
    {
        BetterCms.Events.MediaManagerEvents.Instance.MediaFileUploaded += args => Log.Info("MediaFileUploaded:" + args.Item.ToString());
        BetterCms.Events.MediaManagerEvents.Instance.MediaFileUpdated += args => Log.Info("MediaFileUpdated:" + args.Item.ToString());
        BetterCms.Events.MediaManagerEvents.Instance.MediaFileDeleted += args => Log.Info("MediaFileDeleted:" + args.Item.ToString());
        BetterCms.Events.MediaManagerEvents.Instance.MediaFolderCreated += args => Log.Info("MediaFolderCreated:" + args.Item.ToString());
        BetterCms.Events.MediaManagerEvents.Instance.MediaFolderUpdated += args => Log.Info("MediaFolderUpdated:" + args.Item.ToString());
        BetterCms.Events.MediaManagerEvents.Instance.MediaFolderDeleted += args => Log.Info("MediaFolderDeleted:" + args.Item.ToString());
        BetterCms.Events.MediaManagerEvents.Instance.MediaArchived += args => Log.Info("MediaArchived:" + args.Item.ToString());
        BetterCms.Events.MediaManagerEvents.Instance.MediaUnarchived += args => Log.Info("MediaUnarchived:" + args.Item.ToString());
    }

    private void AddBlogPostEvents()
    {
        BetterCms.Events.BlogEvents.Instance.BlogCreated += args => Log.Info("BlogCreated:" + args.Item.ToString());
        BetterCms.Events.BlogEvents.Instance.BlogChanging += args => Log.Info("BlogChanging: BeforeUpdate: " + args.BeforeUpdate.ToString() + "; AfterUpdate: " + args.AfterUpdate.ToString());
        BetterCms.Events.BlogEvents.Instance.BlogUpdated += args => Log.Info("BlogUpdated:" + args.Item.ToString());
        BetterCms.Events.BlogEvents.Instance.BlogDeleted += args => Log.Info("BlogDeleted:" + args.Item.ToString());
    }

    private void AddBlogAuthorEvents()
    {
        BetterCms.Events.BlogEvents.Instance.AuthorCreated += args => Log.Info("AuthorCreated:" + args.Item.ToString());
        BetterCms.Events.BlogEvents.Instance.AuthorUpdated += args => Log.Info("AuthorUpdated:" + args.Item.ToString());
        BetterCms.Events.BlogEvents.Instance.AuthorDeleted += args => Log.Info("AuthorDeleted:" + args.Item.ToString());    
    }

    private void AddWidgetEvents()
    {
        BetterCms.Events.PageEvents.Instance.WidgetCreated += args => Log.Info("WidgetCreated:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.WidgetUpdated += args => Log.Info("WidgetUpdated:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.WidgetDeleted += args => Log.Info("WidgetDeleted:" + args.Item.ToString());
    }
        
    private void AddCategoryEvents()
    {
        BetterCms.Events.RootEvents.Instance.CategoryCreated += args => Log.Info("CategoryCreated:" + args.Item.ToString());
        BetterCms.Events.RootEvents.Instance.CategoryUpdated += args => Log.Info("CategoryUpdated:" + args.Item.ToString());
        BetterCms.Events.RootEvents.Instance.CategoryDeleted += args => Log.Info("CategoryDeleted:" + args.Item.ToString());
    }

    private void AddTagEvents()
    {
        BetterCms.Events.RootEvents.Instance.TagCreated += args => Log.Info("TagCreated:" + args.Item.ToString());
        BetterCms.Events.RootEvents.Instance.TagUpdated += args => Log.Info("TagUpdated:" + args.Item.ToString());
        BetterCms.Events.RootEvents.Instance.TagDeleted += args => Log.Info("TagDeleted:" + args.Item.ToString());
    }

    private void AddRedirectEvents()
    {
        BetterCms.Events.PageEvents.Instance.RedirectCreated += args => Log.Info("RedirectCreated:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.RedirectUpdated += args => Log.Info("RedirectUpdated:" + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.RedirectDeleted += args => Log.Info("RedirectDeleted:" + args.Item.ToString());
    }

    private void AddPageEvents()
    {
        BetterCms.Events.RootEvents.Instance.PageRendering += Events_PageRendering;
        BetterCms.Events.PageEvents.Instance.PageCreated += args => Log.Info("PageCreated: " + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PageCloned += args => Log.Info("PageCloned: " + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PageDeleted += args => Log.Info("PageDeleted: " + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PagePropertiesChanged += args => Log.Info("PagePropertiesChanged: " + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PagePublishStatusChanged += args => Log.Info("PagePublishStatusChanged: " + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PageSeoStatusChanged += args => Log.Info("PageSeoStatusChanged: " + args.Item.ToString());
        BetterCms.Events.PageEvents.Instance.PagePropertiesChanging += args => Log.Info("PagePropertiesChanging: BeforeUpdate: " + args.BeforeUpdate.ToString() + "; AfterUpdate: " + args.AfterUpdate.ToString());
        BetterCms.Events.RootEvents.Instance.PageNotFound += args => Log.Info("PageNotFound:" + args.Item.ToString());
        BetterCms.Events.RootEvents.Instance.PageAccessForbidden += args => Log.Info("PageAccessForbidden:" + args.Item.ToString());
    }

    private void AddSitemapEvents()
    {
        BetterCms.Events.SitemapEvents.Instance.SitemapNodeCreated += args => Log.Info("SitemapNodeCreated: " + args.Item.ToString());
        BetterCms.Events.SitemapEvents.Instance.SitemapNodeUpdated += args => Log.Info("SitemapNodeUpdated: " + args.Item.ToString());
        BetterCms.Events.SitemapEvents.Instance.SitemapNodeDeleted += args => Log.Info("SitemapNodeDeleted: " + args.Item.ToString());
        BetterCms.Events.SitemapEvents.Instance.SitemapCreated += args => Log.Info("SitemapCreated: " + args.Item.Title);
        BetterCms.Events.SitemapEvents.Instance.SitemapUpdated += args => Log.Info("SitemapUpdated: " + args.Item.Title);
        BetterCms.Events.SitemapEvents.Instance.SitemapDeleted += args => Log.Info("SitemapDeleted: " + args.Item.Title);
    }

    private void AddUsersEvents()
    {
        BetterCms.Events.UserEvents.Instance.UserCreated += args => Log.Info("UserCreated:" + args.Item.ToString());
        BetterCms.Events.UserEvents.Instance.UserUpdated += args => Log.Info("UserUpdated:" + args.Item.ToString());
        BetterCms.Events.UserEvents.Instance.RoleCreated += args => Log.Info("RoleCreated:" + args.Item.ToString());
        BetterCms.Events.UserEvents.Instance.RoleDeleted += args => Log.Info("RoleDeleted:" + args.Item.ToString());
        BetterCms.Events.UserEvents.Instance.RoleUpdated += args => Log.Info("RoleUpdated:" + args.Item.ToString());

        BetterCms.Events.UserEvents.Instance.UserDeleted += args =>
            {
                Log.Info("UserDeleted: " + args.Item.ToString());
                usersToForceRelogin.Add(args.Item.UserName);
            };

        BetterCms.Events.UserEvents.Instance.UserProfileUpdated += args =>
        {
            Log.Info("UserProfileUpdated: " + args.AfterUpdate.ToString());

            if (args.BeforeUpdate != null && args.AfterUpdate != null && args.AfterUpdate.UserName != args.BeforeUpdate.UserName)
            {
                AuthenticationHelper.Logout();

                var roles = Roles.GetRolesForUser(args.AfterUpdate.UserName);
                AuthenticationHelper.CreateTicket(roles, args.AfterUpdate.UserName);
            }
        };
    }

    void Events_PageRendering(PageRenderingEventArgs args)
    {
        // args.RenderPageData.Metadata.Add(new MetaDataProjection("test-metadata", "hello world!"));
    }

    /// <summary>
    /// Handles the AuthenticateRequest event of the Application control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        // Users module covers it:

        //var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
        //var roleCokie = Request.Cookies[Roles.CookieName];

        //if (authCookie != null)
        //{
        //    try
        //    {
        //        var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        //        if (authTicket != null)
        //        {
        //            var identity = new FormsIdentity(authTicket);
        //            var principal = roleCokie == null ? new RolePrincipal("BetterCmsRoleProvider", identity) : new RolePrincipal(identity, roleCokie.Value);
        //            Context.User = principal;
        //        }
        //    }
        //    catch
        //    {
        //        Session.Clear();
        //        FormsAuthentication.SignOut();
        //    }
        //}

        // Super simple example how to force deleted user reauthentication.
        if (User != null && usersToForceRelogin.Contains(User.Identity.Name))
        {
            if (HttpContext.Current.Session != null)
            {
                HttpContext.Current.Session.Clear();
            }

            if (Roles.Enabled)
            {
                Roles.DeleteCookie();
            }

            if (FormsAuthentication.IsEnabled)
            {
                FormsAuthentication.SignOut();
            }

            Response.Redirect(FormsAuthentication.LoginUrl);
        }
    }
}

Register Routes

Better CMS adds default pages with / path - be sure to update your site routes configuration to not takeover the site root path. Do not forget to remove the default route registration, too.

Setup Database

You only need to create a database instance and update the connection string in Web.config to point to it (use named instance called BetterCms). Update Config/cms.config tag <database [...]/> with the correct information. All the necessary database structure (tables and etc.) will be created when the application starts. The default (if not set) database type is MsSql2008.

  <database
     schemaName="dbo"
     connectionStringName="DefaultConnection"
     databaseType="MsSql2008" >
  </database>

Other available DB types: MsSql2000, MsSql2005, Oracle10, Oracle9, PostgreSQL82. Currently only MS Sql Server and Azure is supported.

Example connectionString section in web.config for local development:

<connectionStrings>
  <add name="DefaultConnection"
       connectionString="Data Source=.\sqlexpress; Initial Catalog=BetterCms; Integrated Security=True"
       providerName="System.Data.SqlClient"/>
</connectionStrings>

Example connectionString section in web.config for production:

<connectionStrings>
  <add name="DefaultConnection"
       connectionString="Data Source=SomeSqlHost\NamedInstance; Initial Catalog=BetterCms; User ID=myUsername;
Password=myPassword;"
       providerName="System.Data.SqlClient"/>
</connectionStrings>

Note: If you have changed the database and would like for Better CMS to create all the structures in the new one, please delete the App_Data/BetterCMS/versions.info.cache file (this will force CMS to check the versions information in the database).

Authentication, role manager, and membership

Configure authentication, role manager, and membership in web.config's system.web section.

<system.web>
  <authentication mode="Forms">
    <forms loginUrl="/login" defaultUrl="/" />
  </authentication>
  <roleManager enabled="true" defaultProvider="BetterCmsRoleProvider" cacheRolesInCookie="true">
    <providers>
      <clear />
      <add name="BetterCmsRoleProvider" type="BetterCms.Module.Users.Provider.CmsRoleProvider" />
    </providers>
  </roleManager>
  <membership defaultProvider="CmsMembershipProvider">
    <providers>
      <clear />
      <add name="CmsMembershipProvider" type="BetterCms.Module.Users.Provider.CmsMembershipProvider" />
    </providers>
  </membership>
</system.web>

RAMMFAR

Enable RAMMFAR in web.config's system.webServer section (Note: this is a temporary solution). This is required for such files as main.js to be loaded correctly:

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true" />
</system.webServer>

After these steps, Better CMS is ready to use.

Note: Do not forget about cache.

Clone this wiki locally