Sunday, May 31, 2015

Saving Form data with the Web Forms For Marketers MVC Form API

As many people have noticed with the Web Forms For Marketers MVC Forms the data does not serialize correctly so using custom save actions you cannot get the data from the form correctly.

There are a few rather complex workarounds for this mostly involving parsing the form from the form values in the http response.

The easiest solution to this issue is to create your own Form Processor which you can inject with a configuration file.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <wffm>
      <formProcessors>
        <processor type="MyNamespace.Forms.MVC.Processors.FormProcessor, MyNamespace.Forms.MVC" />
      </formProcessors>
    </wffm>
  </sitecore>
</configuration>

The processor itself is actually quite easy to write you simply need a class that inherits Sitecore.Forms.MVC.Processors.FormProcessor, then you can implement your save action in the FormSuccessValidation event.

namespace MyNamespace.Forms.MVC.Processors
{
    public class FormProcessor : FormProcessor
    {
        public FormProcessor()
        {
            SuccessValidation += FormSuccessValidation;
        }
 
        private void SaveForm(FormModel form)
        {
            var Fields = form.Sections.SelectMany(i => i.Fields);
        }
 
        public void FormSuccessValidation(object source, FormEventArgs args)
        {
            SaveForm(args.Form);
        }
    }
}

You can see from my code that you can access the fields through the given model in the form.Sections property.  

I find that this is much easier to implement than a custom save action (though it will not show up in the drop down list which may be a problem for some people, you can use this to store the data to access in a custom save action).  

If you have any questions related to Web Forms For Marketers please don't hesitate to ask as I have spent a lot of time in that code lately.

Error 500.19 Configuration File Too Long Sitecore Web.config

It is quite well known that the web.config file in Sitecore is monstrous.  It takes very little to make it large enough to get the 500.19 .NET error with the file being too large.  Most resolutions to this involve modifying the registry, but it does not really have to be that difficult.

The easiest solution is to take the Sitecore node out of the file and put it in a separate file similar to how the connection strings are pulled out.

The easiest way to get the whole node selected would be to use a text editor that supports regular expressions and use the expression (<sitecore)[\s\S]*(</sitecore>) to select it.  Then you simply cut it and past it into a file (I generally put it in a file called Sitecore.config in the App_Config folder).

After this you need to put an empty Sitecore node where you removed the old one from and add a configsource attribute that points to the new config file.

<sitecore configSource="App_Config/Sitecore.config" />

Tuesday, April 14, 2015

Language Fallback: A word of caution

The concept of Language Fallback in Sitecore is great, actually having the ability to have Sitecore return content in a different language if none exists in the current context is tremendously helpful.  Even the concept behind this functionality is pretty straight forward. 

The module simply checks if there is a version in the current language.  If not it checks if there is a fallback for the current language and repeats the process on that language if there is until it either finds a version of the item or creates an empty item to return. 

Due to the simplicity of this module it has continued to work with every version of Sitecore since it was introduced, and will likely continue working for years to come.

Unfortunately, if you think about the recursion in this module there is a large problem that can happen.  Endless loops can occur when languages eventually fall back to the original language.

The current module in the marketplace written by Alex Shyba does not have checks to ensure that you do not have an endless loop.  Nikola Gotsev and I ran into this problem a while back where we had a language that would fall back to another language that fell back to the first language.  Not knowing this content error had happened led us into a bit of a nightmare of disabling modules and checking changes to find what brought our environment to its’ knees.

Nikola actually posted a fix for this last month.  This fix simply includes checking if we have already fallen back to a specific language (by enumerating fallback languages in a list).  This solves the problem no matter how complex the chain is.

Thursday, April 9, 2015

Dynamic Key Placeholders Revisited

A little over a year ago I did a post on Dynamic Key Placeholders, since then I have noticed there was some information lacking, such as what versions of Sitecore it works with, and how to get Placeholder Settings to work.
From my testing this should work in every version of Sitecore from 6.5 to 8.0, and likely will continue working in previous and future versions as well.

The Old Way  
By default when using dynamic key placeholders you can create placeholder settings for each index of the key.  Such as if the original key was Placeholder, you would need to create settings for Placeholder1, Placeholder2, etc… This can lead to a lot of work, and a cluttered collection of placeholder settings.
 
A New Way to Do It
An easier way would be to create an override of the GetAllowedRenderings processor to allow for an experience more like the original when creating placeholder settings.

A Quick Modification to the Original
In the original source for the dynamic key placeholders we need to make a simple modification.  In the part of the code that we set the key I have added the # symbol in there to allow us to split it apart far easier to create an override for Placeholder Settings.  You can use any symbol you want, but keep I will continue with this one for the rest of the post.
                // Count represents how many of the same container have already been added to the page
                if (renderings.Any())
                {
                    _dynamicKey = _key + "#" + renderings.Count();
                }


Our New Processor
The big changes though are in the addition of overriding the GetAllowedRenderings processor.  The change is not too complex as we are basically mirroring what Sitecore is already doing, but with the exception of overriding the placeholder key.
To override the key we want to split the key first into the segments by the / character and then for each segment we use the split on the # to remove our index from the dynamic key giving us the original key.
After that we want to try to get the placeholder item using our cleaned up key.  Of course if there is a device specified we should get the item in the context of that device.
If the Item exists we should get the list of renderings it supports.

    public class GetAllowedRenderings : Sitecore.Pipelines.GetPlaceholderRenderings.GetAllowedRenderings
    {
        /// <summary>
        /// This is a method based on the original Sitecore method to allow for dynamic placeholder keys
        /// </summary>
        /// <param name="args">The Placeholder Rendering Args (Device, Key, Database, etc...)</param>
        public new void Process(GetPlaceholderRenderingsArgs args)
        {
            Assert.IsNotNull((object)args, "args");

            //Remove the dynamic indexing from the key
            var key = string.Join("/", args.PlaceholderKey.Split('/').Select(i => i.Split('#')[0]));

            //Get the placeholder item, if there is a Device selected get it using that Device Context
            Item placeholderItem = null;
            if (ID.IsNullOrEmpty(args.DeviceId))
            {
                placeholderItem = Client.Page.GetPlaceholderItem(key, args.ContentDatabase, args.LayoutDefinition);
            }
            else
            {
                using (new DeviceSwitcher(args.DeviceId, args.ContentDatabase))
                {
                    placeholderItem = Client.Page.GetPlaceholderItem(key, args.ContentDatabase, args.LayoutDefinition);
                }
            }
           
            //If there was a placeholder item (Placeholder Settings) set the allowed renderings
            if (placeholderItem != null)
            {
                args.HasPlaceholderSettings = true;
                bool allowedControlsSpecified;
                args.PlaceholderRenderings = this.GetRenderings(placeholderItem, out allowedControlsSpecified);
                if (allowedControlsSpecified)
                    args.Options.ShowTree = false;
            }
        }
    }


Our Configuration Change
Finally we have the configuration file to enable this override, this is simply done by replacing the processor in the getPlaceholderRenderings pipeline.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <getPlaceholderRenderings>                              
        <processor patch:instead="*[@type='Sitecore.Pipelines.GetPlaceholderRenderings.GetAllowedRenderings, Sitecore.Kernel']" type="[Your Method], [Your Assembly] />
      </getPlaceholderRenderings>
    </pipelines>
  </sitecore>   
</configuration>
You can find the source from this post at https://github.com/musicman89/Sitecore-Dynamic-Key-Placeholders

Update (4/10/2015):
You can find a Shared Source Module created at the Sitecore Hackathon 2015 that incorporates this concept at https://marketplace.sitecore.net/en/Modules/Integrated_Dynamic_Placeholders.aspx by Jamie Stump and Mark Servais, do note that I had no involvement in the creation of this module.

Thank you Jamie Stump for pointing this out.

Thursday, February 6, 2014

Media Items are not displaying... Why?

In Sitecore, there are many reasons why your media may not show up.  Depending on the reason it could even cause a problem in your page preview.

Versioning
There are two categories of Media templates in Sitecore; versioned and unversioned.

If you image will not display, make sure that it is either of an unversioned template (you can swap between the two) or that a version exists in the language you are trying to view it in.

Publishing
While this may seem obvious, you may not think about it when adding an image to a field on a template.

When the item you referenced the image on is published, it does not automatically publish the related media item.

Using workflows, there is a work around for this one.  With a little extra code that is.

Alex Shyba wrote an article describing how to automate the publish of related media items which can be found here.

Of course no solution is going to be perfect, so double check the publish status of an image if it is not showing up.

Friday, January 24, 2014

Dynamic Key Placeholders

Dynamic Key Placeholders
This is an overview of Dynamic Key Placeholders and how to create them a video will be created later of this content.  The code for this was posted by Daveleigh at trueclarity.wordpress.com in his article about this subject, note the original implementation of this was based on that found in the article by Nick over at Techniphoria414

Placeholder Limitations
When developing a site in Sitecore there may be a time where you need to have the same layout on a page multiple times.  

The problem with this is that all Placeholder paths must be unique.  Note that I said paths as you can have the same placeholder key on a page multiple time as long as it is nested under different placeholders.  

This can cause a problem when you need to have something like a 2 column layout followed by a 3 column layout and another 2 column layout on the same page.  If you have a layout designed for a news tout, and want multiple on the page.

Usually this is solved by creating multiple sublayouts with different placeholders.  This is not the easiest way to accomplish things, and can actually get quite confusing.  Fortunately there is an easy solution.  That would be DynamicKeyPlaceholders.

What is it?
Dynamic Key Placeholders is an override on the Sitecore Placeholder that increments the key with every instance causing your placeholders to always be unique.  

How It works
A dynamic placeholder looks confusing at first look, but the process is actually quite simple.
  • Find the current placeholder
    • Get the Placeholder Stack
    • Peek at the top of the stack (the last item added)
  • Get current container within that placeholder
    • Get the Renderings from the Context Page (Sitecore.Context.Page.Renderings)
    • Filter them by the current Placeholder Key
    • Check if they have already been added to the page
    • Take the last rendering from the list (the current rendering)
  • How many times does this rendering exist in the current placeholder
    • Filter the Renderings in the current Placeholder by RenderingItem to find all instances of this Rending
    • Take the count of this result
  • Create our Placeholder with Dynamic Key
    • Create a Sitecore Placeholder
    • Set the Key to our Key name with the rendering count appended
    • Add the Placeholder to the page and expand it
How to Implement it
The implementation of dynamic key placeholders is actually more simple than the code behind it. 
  • Add the code to your library (found at the bottom of this post)
  • Register the prefix on your page (Replace Italicized text with your implementation specific values)
    • <add tagPrefix="Prefix Name" namespace="Your Namespace" assembly="Your Assembly Name" />
  • Add your placeholder (Replace Italicized text with your implementation specific values)
    • <Prefix Name:DynamicKeyPlaceholder ID="PlaceholderId" runat="server" Key="KeyName" />
  • Use your placeholder as usual keeping in mind the incrementing key
Dynamic Key Placeholders are not only simple to implement, but prove to be very useful.  They allow you to have very dynamic layouts and offer more flexibility to your clients.

Code:
using System.Collections.Generic;
    using System.Linq;
    using System.Web.UI;
    using Sitecore.Common;
    using Sitecore.Layouts;
    using Sitecore.Web.UI;
    using Sitecore.Web.UI.WebControls;

    /// <summary>
    ///
    /// </summary>
    public class DynamicKeyPlaceholder : WebControl, IExpandable
    {
        protected string _key = Placeholder.DefaultPlaceholderKey;
        protected string _dynamicKey = null;
        protected Placeholder _placeholder;

        /// <summary>
        ///
        /// </summary>
        public string Key
        {
            get { return _key; }
            set { _key = value.ToLower(); }
        }

        protected string DynamicKey
        {
            get
            {
                if (_dynamicKey != null)
                {
                    return _dynamicKey;
                }
                _dynamicKey = _key;

                // Find the last placeholder processed.
                Stack<Placeholder> stack = Switcher<Placeholder,
                    PlaceholderSwitcher>.GetStack(false);
                Placeholder current = stack.Peek();

                // Group of containers which sit in the current placeholder (i.e. they have the same placeholder id).
                var renderings = Sitecore.Context.Page.Renderings.Where(rendering => (rendering.Placeholder == current.ContextKey || rendering.Placeholder == current.Key) && rendering.AddedToPage).ToArray();

                // Current container
                var thisRendering = renderings.Last();

                // get all repeating containers in the current placeholder
                renderings = renderings.Where(i => i.RenderingItem != null && i.RenderingItem.ID == thisRendering.RenderingItem.ID).ToArray();

                // Count represents how many of the same container have already been added to the page
                if (renderings.Any())
                {
                    _dynamicKey = _key + renderings.Count();
                }
                return _dynamicKey;
            }
        }

        protected override void CreateChildControls()
        {
            _placeholder = new Placeholder {Key = DynamicKey};
            Controls.Add(_placeholder);
            _placeholder.Expand();
        }

        protected override void DoRender(HtmlTextWriter output)
        {
            base.RenderChildren(output);
        }

        #region IExpandable Members

        /// <summary>
        ///
        /// </summary>
        public void Expand()
        {
            EnsureChildControls();
        }

        #endregion
    }