Episerver 7 : Creating an Episerver Sign-Up Form

I have a requirement to implement a custom log-in block.  As the block could be placed anywhere on the site, data messaging becomes more of a key feature.  How will you render the control on a page, then post back to the page that calls it and trigger any Model State errors.

My log-in block will need to have similiar properties

 [ContentType(DisplayName = "Login Control",
        Description = "Login Control",
        GUID = "797AEC21-AB32-4F89-BED3-C14DA89D5252")]
    public class LoginControlBlock : BlockData
    {
        [Ignore]
        public LoginModel LoginModel { get; set; }

        [Display(Name = "Block Name",
            GroupName = SystemTabNames.Content,
            Order = 100)]
        [Required]
        public virtual string BlockName { get; set; }

        [Display(Name = "Block Description",
            GroupName = SystemTabNames.Content,
            Order = 200)]
        [Required]
        public virtual XhtmlString BlockDescription { get; set; }

        [Display(Name = "User Name Label",
            GroupName = SystemTabNames.Content,
            Order = 300)]
        [Required]
        public virtual string UserNameLabel { get; set; }

        [Display(Name = "User Name Placeholder",
            GroupName = SystemTabNames.Content,
            Order = 400)]
        [Required]
        public virtual string UserNamePlaceholder { get; set; }

        [Display(Name = "Password Label",
            GroupName = SystemTabNames.Content,
            Order = 500)]
        [Required]
        public virtual string PasswordLabel { get; set; }

        [Display(Name = "Forgot Your Password Text",
            GroupName = SystemTabNames.Content,
            Order = 700)]
        [Required]
        public virtual string ForgotYourPasswordText { get; set; }

        [Display(Name = "Forgot Your Password Url",
            GroupName = SystemTabNames.Content,
            Order = 800)]
        [Required]
        public virtual Url ForgotYourPasswordUrl { get; set; }

        [Display(Name = "Remember Me Text",
            GroupName = SystemTabNames.Content,
            Order = 900)]
        [Required]
        public virtual string RememberMeText { get; set; }

        [Display(Name = "Sign-In Text",
            GroupName = SystemTabNames.Content,
            Order = 1000)]
        [Required]
        public virtual string SignInText { get; set; }

        [Display(Name = "Sign-In Form Url",
            GroupName = SystemTabNames.Content,
            Order = 1100)]
        [Required]
        public virtual Url SignInFormUrl { get; set; }

Redirection

As our block can be sat on any page, we need a way to send the users back to where they came from.  To do this you will need to pass in the return Url, or, in Episerver, a better and more secure way is to pass a reference to the Episerver page.  After the Login method is called, the controller will need to redirect the user to the page they made the original request from (in failure at least).  The problem with this is that if we do a re-direct we lose the Model state.

To overcome this we can use TempData which is part of the MVC framework.  I’m not a big fan of Temp data but as it only persists for the following page request it will do.  I found a great way to pass values between two controllers called the PRG Pattern for Data Modification.  The basic premise is that you use attributes on the action methods you want to share the Temp data between.  This practice is a lot more robust as you do not not need to manually store and retrieve information from Temp Data but you can use ActionFilters to do it automatically.

The code to do this is here:

public class ExportModelStateToTempData : ModelStateTempDataTransfer
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (!filterContext.Controller.ViewData.ModelState.IsValid)
            {
                if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
                    filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }

            base.OnActionExecuted(filterContext);
        }
    }
    public abstract class ModelStateTempDataTransfer : ActionFilterAttribute
    {
        protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName;
    }
public class ImportModelStateFromTempData : ModelStateTempDataTransfer
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            var modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

            if (modelState != null)
            {
                if (filterContext.Result is ViewResult || filterContext.Result is PartialViewResult)
                {
                    filterContext.Controller.ViewData.ModelState.Merge(modelState);
                }
                else
                {
                    filterContext.Controller.TempData.Remove(Key);
                }
            }

            base.OnActionExecuted(filterContext);
        }
    }

Now we have our action filters we can then decorate our actions as follows:


        [ImportModelStateFromTempData]
        public override ActionResult Index(LoginControlBlock currentBlock)
        {
            var viewModel = new LoginControlBlockViewModel(currentBlock, BaseDependencies);
            return PartialView("Index", viewModel);
        }

        [ExportModelStateToTempData]
        public ActionResult Login(LoginModel model, ContentReference currentPage)
        {
            return RedirectToAction("Index", new { node = currentPage });
        }

Also, one thing to note about the code is how the re-direct works.  With Episerver, as long as you se the node, you can still use RedirectToAction.  In this case I set a hidden field in the form and use the CurrentPage property to pass it in.

Download The Fully Working Solution

A working website with all the code can be found from my Github page to help you on your way 🙂

https://github.com/jondjones/EpiserverLoginBlock

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

1 reply

Trackbacks & Pingbacks

  1. […] If you are trying to get a form to work in a block.. this is not the way to go.  In those scenarios, you may need to configure a custom route, or, another method I have used previously is to enable, like detailed here, Creating an EpiServer Sign-Up Form. […]

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *