Upload files with Xforms

Posted by Jeroen Wijdeven on 2015-08-13

No this post is not about my hate love relationship with xforms. We all know the drill you always need something that’s
not possible out of the box. I call that a challenge. The latest one was, “Can I add a file upload field”. Yes of course you can. In this post I explain how I did this.

The first step is to create an xform with an input element and set the cssClass to “upload”.

If you already did some customization on your xform you are already familier to have a file named “inputelement.cshtml” in your “~/views/shared/xformelements” folder. If you don’t, just create that directory and
add that file “inputfragment.cshtml” to it. You can find the original one in the folder “\Util\Views\Shared\EditorTemplates\” which is part of the the “EPiServer.CMS.Shell.UI.zip”.

Customize this file and add an file box to it, see an example below

@model EPiServer.XForms.Parsing.InputFragment 
<label for="@Model.Reference">@Model.Label</label>
@if (!string.IsNullOrWhiteSpace(Model.Class) && Model.Class.ToLower() == "upload")
{
    @*This is where the magic happens*@
    <input type="file" name="@Model.Reference" />
}
else
{
    @Html.TextBox(Model.Reference, Server.HtmlDecode(Model.Value) ?? string.Empty, new { size = Model.Size, placeholder = Model.Title })
}
@Html.ValidationMessage(Model.ValidationReference) // EPiServer 7.5 and upwards

As you can see the magic is done by adding a class on the element in your xforms designer. When the class is named “upload” the field is rendered as a file box. Easy as that.

Now you have rendered an upload field. You need to process the files as well.
Assuming you handle the success action of the xform like so:

@Html.PropertyXForm("Form", new XFormParameters() { SuccessAction = "Success", PostAction = "DoSubmit" })

Add the next action to your controller:

[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Success(BasePageData currentPage, XFormPostedData xFormpostedData)
{
    //do all kind of other custom stuff..

    #region get files

    //process all files
    if (Request.Files.Count > 0)
    {
        var file = Request.Files[0];

        if (file != null && file.ContentLength > 0)
        {
            //save file to a predefined path for example ~/app_data/
            var fileName = Path.GetFileName(file.FileName);
            if (fileName != null)
            {
                var path = Path.Combine(Server.MapPath("~/App_data/"), fileName);
                file.SaveAs(path);
            } //or use blobstorage: http://world.episerver.com/blogs/Johan-Bjornfot/Dates1/2013/12/Working-with-Media-programmatically/
        }
    }

    #endregion

    //do your other stuff which handles your action correctly, I always use 
    // the next snippet, since we return our own viewmodel..

    //Return to the right page..
    if(xFormpostedData.XForm.PageGuidAfterPost != Guid.Empty)
    {
        return Redirect(UrlResolver.GetUrl(ContentRepository.Get<PageData>(xFormpostedData.XForm.PageGuidAfterPost).ContentLink));
    }

    //default, return to default view and create the viewmodel.
    return View(CreateViewModel(currentPage));
}

That’s pretty much it.


Comments: