Home » Customization » Show Submitted Web Forms for Marketers Form Field Values on a Confirmation Page in Sitecore

Show Submitted Web Forms for Marketers Form Field Values on a Confirmation Page in Sitecore

Sitecore Technology MVP 2016
Sitecore MVP 2015
Sitecore MVP 2014

Enter your email address to follow this blog and receive notifications of new posts by email.

Tweets

Recently on my About page, someone had asked me how to show submitted form field values in Web Forms for Marketers.

I had done such a thing in a past project, and thought I would share how I went about accomplishing this.

This solution reuses an instance of a storage class I had used in a previous post.

This is the interface for that storage class:

namespace Sitecore.Sandbox.Utilities.Storage
{
    public interface IRepository<TKey, TValue>
    {
        bool Contains(TKey key);

        TValue this[TKey key] { get; set; }

        void Put(TKey key, TValue value);

        void Remove(TKey key);

        void Clear();

        TValue Get(TKey key);
    }
}

This is the implementation of the storage class:

using System.Web;
using System.Web.SessionState;

using Sitecore.Diagnostics;

namespace Sitecore.Sandbox.Utilities.Storage
{
    public class SessionRepository : IRepository<string, object>
    {
        private HttpSessionStateBase Session { get; set; }

        public object this[string key]
        {
            get
            {
                return Get(key);
            }
            set
            {
                Put(key, value);
            }
        }

        public SessionRepository()
            : this(HttpContext.Current.Session)
        {
        }

        public SessionRepository(HttpSessionState session)
            : this(CreateNewHttpSessionStateWrapper(session))
        {
        }

        public SessionRepository(HttpSessionStateBase session)
        {
            SetSession(session);
        }

        private void SetSession(HttpSessionStateBase session)
        {
            Assert.ArgumentNotNull(session, "session");
            Session = session;
        }

        public bool Contains(string key)
        {
            return Session[key] != null;
        }

        public void Put(string key, object value)
        {
            Assert.ArgumentNotNullOrEmpty(key, "key");
            Assert.ArgumentCondition(IsSerializable(value), "value", "value must be serializable!");
            Session[key] = value;
        }

        private static bool IsSerializable(object instance)
        {
            Assert.ArgumentNotNull(instance, "instance");
            return instance.GetType().IsSerializable;
        }

        public void Remove(string key)
        {
            Session.Remove(key);
        }

        public void Clear()
        {
            Session.Clear();
        }

        public object Get(string key)
        {
            return Session[key];
        }

        private static HttpSessionStateWrapper CreateNewHttpSessionStateWrapper(HttpSessionState session)
        {
            Assert.ArgumentNotNull(session, "session");
            return new HttpSessionStateWrapper(session);
        }
    }
}

The class above basically serializes a supplied object, and puts it into session using a key given by the calling code.

Plus, you can remove objects saved in it using a key.

I modified this class from the original version: I declared the constructors public so that I can reference them in a Sitecore configuration file (you will see this configuration file further down in this post).

I then created a POCO to house form field values for serialization purposes:

using System;
using System.Collections.Generic;

namespace Sitecore.Sandbox.Form.Submit.DTO
{
    [Serializable]
    public class Field
    {
        public string Name { get; set; }

        public string Value { get; set; }
    }
}

Field values belong to a form, so I built another POCO class to store a collection of Sitecore.Sandbox.Form.Submit.DTO.Field class instances, and also hold on to the submitted form’s ID:

using System;
using System.Collections.Generic;

namespace Sitecore.Sandbox.Form.Submit.DTO
{
    [Serializable]
    public class FormSubmission
    {
        public Guid ID { get; set; }

        public List<Field> Fields { get; set; }
    }
}

Now we need a custom Web Forms for Marketers SaveAction — all custom SaveActions must implement Sitecore.Form.Core.Client.Data.Submit.ISaveAction which is defined in Sitecore.Forms.Core.dll — to create and store instances of the POCO classes defined above:

using System.Collections.Generic;

using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.Web;

using Sitecore.Form.Core.Client.Data.Submit;
using Sitecore.Form.Core.Controls.Data;
using Sitecore.Form.Submit;

using Sitecore.Sandbox.Form.Submit.DTO;
using Sitecore.Sandbox.Utilities.Storage;

namespace Sitecore.Sandbox.Form.Submit
{
    public class StoreForm : ISaveAction
    {
        static StoreForm()
        {
            RepositoryKey = Settings.GetSetting("RepositoryKey");
            Assert.IsNotNullOrEmpty(RepositoryKey, "RepositoryKey must be set in your configuration!");

            Repository = Factory.CreateObject("repository", true) as IRepository<string, object>;
            Assert.IsNotNull(Repository, "Repository must be set in your configuration!");
        }

        public void Execute(ID formid, AdaptedResultList fields, params object[] data)
        {
            StoreFormSubmission(formid, fields);
        }

        protected virtual void StoreFormSubmission(ID formid, AdaptedResultList fields)
        {
            FormSubmission form = CreateNewFormSubmission(formid, fields);
            Repository[GetRepositoryKey()] = form;
        }

        protected virtual FormSubmission CreateNewFormSubmission(ID formid, AdaptedResultList fields)
        {
            return new FormSubmission
            {
                ID = formid.Guid,
                Fields = CreateNewFields(fields)
            };
        }

        protected virtual List<Field> CreateNewFields(AdaptedResultList results)
        {
            Assert.ArgumentNotNull(results, "results");
            List<Field> fields = new List<Field>();
            foreach (AdaptedControlResult result in results)
            {
                fields.Add(new Field{ Name = result.FieldName, Value = result.Value });
            }

            return fields;
        }

        protected virtual string GetRepositoryKey()
        {
            return string.Concat(RepositoryKey, "_", WebUtil.GetSessionID());
        }

        private static string RepositoryKey { get; set; }
        
        private static IRepository<string, object> Repository { get; set; }
    }
}

The SaveAction above creates instances of the POCO classes above using the submitted form field values, and passes these to an instance of a IRepository: this is defined in the configuration file below jointly with a substring of the unique storage key (this is a concatenation of the key defined in the following configuration file and the user’s session ID to guarantee a unique key):

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <repository type="Sitecore.Sandbox.Utilities.Storage.SessionRepository" />
    <settings>
      <setting name="RepositoryKey" value="MyRepository"/>
    </settings>
  </sitecore>
</configuration>

I then registered the ISaveAction class above in Web Forms for Marketers:

store-form-save-action

I then wired it up to my test form:

add-store-form-to-form

For testing, I created the following sublayout — no, it’s not the prettiest code I have ever written but I needed something quick for testing — which I mapped to a confirmation page:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Form Submission Confirmation.ascx.cs" Inherits="Sandbox.layouts.sublayouts.FormSubmissionConfirmation" %>
<asp:Repeater ID="rptConfirmation" runat="server">
    <HeaderTemplate>
        <h2>What you gave us:</h2>
    </HeaderTemplate>
    <ItemTemplate>
        <%# Eval("Name") %>: <%# Eval("Value") %>
    </ItemTemplate>
    <SeparatorTemplate>
        <br />
    </SeparatorTemplate>
</asp:Repeater>

The following class serves as the code-behind for the sublayout:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using Sitecore.Configuration;
using Sitecore.Diagnostics;
using Sitecore.Sandbox.Form.Submit.DTO;
using Sitecore.Sandbox.Utilities.Storage;
using Sitecore.Web;

namespace Sandbox.layouts.sublayouts
{
    public partial class FormSubmissionConfirmation : System.Web.UI.UserControl
    {
        private static string RepositoryKey { get; set; }
        
        private static IRepository<string, object> Repository { get; set; }

        static FormSubmissionConfirmation()
        {
            RepositoryKey = Settings.GetSetting("RepositoryKey");
            Assert.IsNotNullOrEmpty(RepositoryKey, "RepositoryKey must be set in your configuration!");

            Repository = Factory.CreateObject("repository", true) as IRepository<string, object>;
            Assert.IsNotNull(Repository, "Repository must be set in your configuration!");
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            string key = GetRepositoryKey();
            FormSubmission submission = Repository.Get(key) as FormSubmission;
            Repository.Remove(key);
            if (submission == null || !submission.Fields.Any())
            {
               Visible = false;
                return;
            }
            
            rptConfirmation.DataSource = submission.Fields;
            rptConfirmation.DataBind();
        }

        protected virtual string GetRepositoryKey()
        {
            return string.Concat(RepositoryKey, "_", WebUtil.GetSessionID());
        }
    }
}

The code-behind above gets the FormSubmission instance from the IRepository instance defined in the configuration file shown above, and passes the Field POCO instances within it to a repeater.

Let’s see this in action!

I navigated to my test form, and filled it in:
filled-in-form

After submitting the form, I was redirected to my confirmation page. As you can see the form values I had entered are displayed:

form-confirmation

One thing to note: the solution above only works when your Web Forms for Marketers confirmation page is its own page, and you set your form to redirect to it after submitting the form.

If you have any thoughts on this, or know of other ways to show submitted Web Forms for Marketers form field values on a confirmation page, please share in a comment.

Advertisements

1 Comment

  1. […] Community over on slack (join the movement)!  Mike Reynolds (@mike_i_reynolds) pointed me to an older post of his explaining how I might specify my implementation of ICmsContext (via a config patch) in the […]

Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: