Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Sunday, May 29, 2016

Sitecore WFFM MVC FileUploadField restrictions

Sitecore WFFM FileUploadField

There are already some blogpost around about custom FileUploadFields, but as things have changed a bit in the latest Web Forms for Marketers releases and certainly with the introduction of MVC in WFFM I thought it could be useful to share the custom field we created on a Sitecore 8.1 update-1 environment with MVC forms.

Let's start by creating some validation attributes...

Validation attributes


Validation for file size


We inherit from DynamicValidationBase and override ValidateFieldValue.
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class LimitFileSizeAttribute : DynamicValidationBase
{
    private const string FileSizeLimitKey = "filesizelimit";
    private const string ErrorMessageKey = "filesizelimiterror";

    protected override ValidationResult ValidateFieldValue(IViewModel model, object value, ValidationContext validationContext)
    {
        // Required attribute should handle null value
        if (value == null)
        {
            return ValidationResult.Success;
        }

        var fileBase = value as HttpPostedFileBase;
        if (fileBase == null)
        {
            return new ValidationResult(ErrorMessage);
        }

        var fileUploadField = validationContext.ObjectInstance as FileUploadField;
        var limit = GetLimit(fileUploadField);

        if (limit == -1) // Limit not set
        {
            return ValidationResult.Success;
        }

        if (fileBase.ContentLength > limit)
        {
             return new ValidationResult(GetErrorMessage(fileUploadField));
        }

        return ValidationResult.Success;
    }
 
    private static int GetLimit(IViewModel field)
    {
        if (field == null || !field.Parameters.ContainsKey(FileSizeLimitKey))
        {
            return -1;
        }

        var parameter = field.Parameters[FileSizeLimitKey];
        int intValue;
        if (int.TryParse(parameter, out intValue))
        {
            return intValue;
        }

        return -1;
    }

    private string GetErrorMessage(IViewModel field)
    {
        if (field != null && field.Parameters.ContainsKey(ErrorMessageKey))
        {
            return field.Parameters[ErrorMessageKey];
        }

        return ErrorMessage;
    }
}

The size limit and the error message are retrieved from the parameters on the field.

Validation for allowed extensions

We can create a similar class to validate the extension by using the Path.GetExtension(fileBase.FileName). Of course, other validations are also possible.


MVC Restricted FileUploadField

We inherit from the base FileUploadField in Sitecore.Forms.Mvc.ViewModels.Fields and override the "Value" property, just to add the custom created attributes.

public class RestrictedUploadField : Sitecore.Forms.Mvc.ViewModels.Fields.FileUploadField
{
    [LimitAllowedExtensions]
    [LimitFileSize]
    public override HttpPostedFileBase Value { get; set; }
}



Register in Sitecore

The new custom field needs to be registered in Sitecore:



Usage
Now we can start using our field in a mvc form. Do not forget to fill in the necessary parameters and/or Localized parameters - in case of our example code with the file size limit these are:
  • Parameters : <FileSizeLimit>10485760</FileSizeLimit>
  • Localized parameters : <FileSizeLimitError>File size must be under 10 mb</FileSizeLimitError>

I did not present you a complete FileUpload module here, but the given examples should provide enough information to get you started in your quest to create a customized file upload field in Sitecore WFFM with MVC.

Tuesday, April 5, 2016

Multiple static Sitecore MVC forms

Multiple Sitecore MVC forms

Reinoud Van Dalen wrote a famous blog post over a year ago about multiple Sitecore MVC forms on a single page. His fix was based on some good work from Kevin Brechbühl and it helped us a lot. But recently we bumped into an issue on a Sitecore 8.1 project with mvc forms that were added on a more static way with @Html.Sitecore.Rendering().

Html.Sitecore.Rendering()

We created controller renderings for our forms in Sitecore and used their id's to display the statically bound rendering using @Html.Sitecore.Rendering(). We noticed that when we add such a rendering with Sitecore in a placeholder the code worked fine and the RenderingToken was set. But once the same rendering was placed statically, the CurrentRendering.UniqueId was an empty guid.

One could wonder why we place our forms statically in a View but we have our reasons. The views containing the static bound form-renderings can be placed in placeholders or also statically, that does not make a difference - the UniqueId stays empty.

A fix

We fixed this by making a small change to the original code:

RenderingToken


public static class SitecoreHelperExtensions
{
    public static MvcHtmlString RenderingToken(this SitecoreHelper helper)
    {
        if (helper?.CurrentRendering == null)
        {
            return null;
        }

        var tagBuilder = new TagBuilder("input");
        tagBuilder.Attributes["type"] = "hidden";
        tagBuilder.Attributes["name"] = "uid";
        tagBuilder.Attributes["value"] = helper.CurrentRendering.UniqueId +
                                            helper.CurrentRendering.RenderingItemPath;

        return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.SelfClosing));
    }
}

ValidRenderingTokenAttribute


[AttributeUsage(AttributeTargets.Method)]
public sealed class ValidRenderingTokenAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        var rendering = RenderingContext.CurrentOrNull;
        if (rendering == null || controllerContext == null)
        {
            return false;
        }

        var id = controllerContext.HttpContext.Request.Form["uid"];
        return id.Equals(rendering.Rendering.UniqueId + rendering.Rendering.RenderingItemPath, StringComparison.OrdinalIgnoreCase);
    }
}

The only thing we did was adding the RenderingItemPath to the hidden token.
The "bonus" from Reinouds code to be able to include the same form multiple times on a page still exists as long as the form is added with Sitecore on a placeholder for at least all but one occasions. It is not possible to add the same form twice statically though.


Thanks again to Reinoud for sharing his code on multiple mvc forms - hopefully this little addition can help people who need to add forms statically.