Tuesday, 4 October 2011

Walkthrough example with NeatUpload and ASP.NET WebForms application

In my previous post I covered the minimum sample for running the plugin with an ASP.NET MVC3 application and now through this post I’ll use an ASP.NET application with WebForms. 
The source code for this code is available from here.
Setting up
Create an Empty ASP.NET Web Application by File | New Project | ASP.NET Empty Web Application. I have chosen “WebApplicationNeatUpload” as application name. Add the plugin .js file that you can download from here, in the folder “~/Scripts/” that I recommend to create for keep the things organized, but you are free for put it wherever you consider convenient. It’s also necessary to include the jquery core library you can go to (http://jquery.com for download it).
Add Reference to the Brettle.Web.NeatUpload.dll file and the appropriated modifications to the root web.config file as mentioned in previous post. For example, the section configuration/system.webServer for my sample application contains this (In the sample I use IISExpress and it reads the configuration from that section, if you use the traditional WebDev you should change this as indicated in the previous post):
<modules runAllManagedModulesForAllRequests="true">
    <add name="UploadHttpModule" type="Brettle.Web.NeatUpload.UploadHttpModule, Brettle.Web.NeatUpload" preCondition="managedHandler"/>
</modules>
<security>
    <requestFiltering>
        <requestLimits maxAllowedContentLength="1000000000"/>
    </requestFiltering>
</security>

One last thing we have to use from original project (NeatUpload) is the file (ProgressJsonHandler.ashx) which can be found in the example I attach with this post. The propose of this file is provide an entry point for call the library methods that store in session the current file progress information and of course the default path in the plugin is that, nevertheless you can call them manually for catch that information but that’s out the scope of this post. I’ll cover more detailed information of the module in further posts.
Starting with the code
Now let’s create a new WebForm, I named Default.aspx, in code behind we are going to add a Page_Load with the following line:

protected void Page_Load(object sender, EventArgs e)
{
    uploadaction.Value = ResolveClientUrl("~/StaticUploadFile.ashx");
}

This is just for set the value to the hidden field which stores the url for the handler that will receive the post data. And in the markup view let’s do something like this:
In the head section
<script src="Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.neatupload.js" type="text/javascript"></script>
<script type="text/javascript" defer="defer">
    $(function () {
        $("#file1").neatupload({
            postDataUrl: $("input[type=hidden][id=uploadaction]").val(),
            fnShowStatus: function (plugin, index, data) {
                $('span#progress-file').text(data.PercentComplete + "%");
            }
        });
    });
</script>

And in the body section
<form id="form1" runat="server">
<div>
    <asp:HiddenField runat="server" ID="uploadaction" />
    <div>
        <label for="newfield">
            Select File:
        </label>
        <div id="file1">
            place holder for the input -> file for upload
        </div>
    </div>
    <div>
        <span id="progress-file"></span>
    </div>
    <div>
        <input type="submit" value="save" />
    </div>
</div>
</form>

There are some elements to clarify. The scripts to include, the first is the version 1.5.1 minified of the jquery library and the second is the jquery.neatupload.js plugin, it’s important the order because any jquery plugin must load after the jquery core. The $("#file1") refers to any element with an id equals to file1 (for jquery syntax go to jquery.com). The text inside the div with id = file1 is just for be sure the plugin is running properly, so you can remove it.
In this case the only options set are postDataUrl and fnShowStatus, the remaining options use the defaults defined by the plugin.
The postDataUrl option define the url that will handle the post on the server which is stored in a hidden field, the result of ResolveClientUrl("~/StaticUploadFile.ashx"); give us the resolved route for the Action StaticUploadFile.ashx handler in the project, the important note here is the strategy of not setting this value hardcoded in JavaScript code block but store it somewhere and by JavaScript code retrieve it. If we ignore this we can get a maintenance issue caused by refactoring or name changes in the files or moving from one folder to another.

The function fnShowStatus allows to the user to execute custom code each time the progress changes, this function takes three parameters: plugin, index, and data. The plugin parameter is a reference to the object container and through plugin.options object we can access to the options either defaults or custom values set by the plugin’s user. The index is the unique identifier auto generated by the plugin at time of being inserted in the hidden queue; this value may be used to establish a correspondence between the hidden form and the visual elements. The data parameter holds a JSON returned by the handler that is polled by intervals, this JSON has multiple properties but the most important is PercentComplete which give us the percent value (0 - 100) and may be used for display to the user.
The label refers to newfield because this is the name that the input takes when it’s generated. Due to security issues the input must be moved away when the user clicks the add button, and a new one is created for replace it, the best option would be change the value by code but it’s impossible, so the name is always the same.
If we run the example at this point, nothing important are going to happen but the view is rendered and we can see the form (styles and CSS are out of this post, just basic HTML) with the two links mentioned before.
What happen on the server?
Someone must receive the data posted by hidden forms when the user clicks add and then upload. Since we are using WebForms approach, in my opinion, the easier way of perform this is using a Generic Handler (.ashx); however, you can choose a classic handler or even a Page. I made it with a Generic Handler so the code is the following:

<%@ WebHandler Language="C#" Class="WebApplicationNeatUpload.StaticUploadFile" %>
using System;
using System.Collections.Generic;
using System.Web;
using Brettle.Web.NeatUpload;

namespace WebApplicationNeatUpload
{
    public class StaticUploadFile : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            try
            {
                var tempPath = context.Server.MapPath("~/_temp_upload/");
                var value = string.Empty;
                for (var i = 0; i < UploadModule.Files.Count; i++)
                {
                    value = UploadModule.Files[i].FileName;
                    UploadModule.Files[i].SaveAs(tempPath + value);
                }
                context.Response.Write(value);
            }
            catch (Exception)
            {
                context.Response.Write("<h1>Error</h1>");
            }
        }

        public bool IsReusable
        {
            get
            {
                return true;
            }
        }
    }
}

This handler is responsible for receive the post data through the context parameter. In the example we don’t do anything complex (it’s just sample) but to copy the uploaded content to a file with the same name in the hardcoded path “~/_temp_upload/” and return the name of the last file uploaded. Here, I am going to make a key point, due to the concrete implementation of the plugin in the client, the submits are made one by one, so there won’t be more than one file per upload, but it’s important to know that NeatUpload module is capable of handling more than one file per request.
The class UploadModule is our face for retrieve the uploaded content through the Files collection and the SaveAs method allows us to save in a particular path. At this point you are able to make whatever you want with the uploaded content, save to disk, create records in database or even start complex mechanisms that process these files like video encoding.
In the next post I’ll show more different plugin configurations and examples.

5 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
    Replies
    1. I've removed this comment because the next is more specific and detailed, thank you.

      Delete
  2. it gives me error:
    An exception of type 'System.NullReferenceException' occurred in Brettle.Web.NeatUpload.DLL but was not handled in user code

    Additional information: Object reference not set to an instance of an object.

    AT UploadModule.Files.Count in public ActionResult UploadFileExtraData(FormCollection collection)method

    ReplyDelete
    Replies
    1. @Suyog Kale,
      I think you sould check if VS2010 SP1 is installed, because the sample uses IIS Express, if not then check the previous post where I explain the configurations for IIS 6 and IIS 7.
      If you use IIS Express is like IIS 7 al later, but if you use WebDeveloper Server (Casini) is like IIS 6.
      That might be the cause of your problem, I mean, you are using a version of IIS web server and the web.config is configured to use another.
      By the way, the code fragment in the comment corresponds to another post (examples-part-3)

      Delete
    2. Thanks for the quick response, acutly i am testing on Visual studio2010 and yet not deployed on IIS[but will be using IIS7 in future deployment]. and using Asp.Net development server. please help me to resolve this issue.

      Delete