-
Notifications
You must be signed in to change notification settings - Fork 158
Example 09
Backloads. Extensibility feature allows you full control through the processing pipeline while your code keeps clean and easy to maintain. You just need to derive from an interface related to a specific extension point within the processing pipeline, read, process and write back the values Backload provides you and your done. You can add or remove your assemblies while the MVC Application is running. So you can test new processings or change settings without stopping or recompiling the upload handler.
In this example you will learn how one Backload instance serves multiple file upload plugins at the same time (Jquery File Upload Plugin and Moxiecodes PlUpload) by extensions without touching the main code of the handler. For demo purposes only, we also extended the default functionality of PlUpload to be more like a file manager plugin instead of only being a filuploader. So, we added the handling of existing server side files and server side file deletion. Note: The settings in this example for the client side plugins are for modern browsers only (JQuery > 2.0). Older Browsers (e.g. IE8 and below) are not supported until you switch back to JQuery 1.9.
PlUpload is a commercial file upload plugin from Moxiecode (TinyMCE). While PlUpload does not support handling of existing files and file deletion server side out of the box, we've included this functionality in this example. Look into the script (~/Scripts/main-plupload.js) to see how we've done it. In short: We extended the file class with the urls, hook to some events and make an ajax call to retrieve existing files. We also need to provide a thumbnail for existing files. So, together with the Backload component, you have now a full file manager plugin.
When you run the solution in [Example 09] (https://github.com/blackcity/Backload/tree/master/Examples/Example09) you will see the JQuery File Upload Plugin and PlUpload side by side at the same time handled by the Backload component:
####Convention based extension handling vs. conditional handling We have two upload plugins in our form, but the extension in the example code is only for PlUpload. To ensure that our extension only handles PlUpload requests, there are two options : Convention or conditional based handling. In our example we use handling based on convention, where the convention is:
The namespace of our extension contains
Plugin.PlUpload
(not case sensitive)
With our request we send a plugin=plupload
querystring. When the plugin
querystring is set with a none empty value, the extension manager only calls extensions where the fully qualified name contains Plugin.[queryvalue]
. If you do not want to use convention based handling, just do not send a plugin querystring or leave it empty (plugin=
)
You may use conditional handling instead. Here, the extension code is always called, and you make the decision based on a condition if to handle the request or not in your code. Typically you parse the request (querystring or body) for a condition. Example:
string control = request.QueryString["control"]; if ((string.IsNullOrEmpty(control)) || (control != "plupload")) return false;
####How to use the example First of all, we extended the functionality of PlUpload. You are able to upload, delete and list existing files on the server. In order to test the demo, upload a file to the server and refresh the page to verify that the file is uploaded (After refreshing you should again see the file). Then delete it (In order to delete a file, click on the small sign on the right upper corner in thumbnail view or on the far right in list view. Refresh the page again. The file should be gone now.
There's nothing fancy in the JavaScript code to do this. First, we make an ajax call to the Backload controller to retrieve existing files, we fill plupload.File
objects with the data, add it to the list and append a thumbnail in the right place. Next we attached a handler to the FilesRemoved
event in order to make an ajax call (DELETE) to the server when the file was deletet in the plugin. The file object provided in the handler already has the delete url. Finally we've attached a handler to the FileUploaded
event, in order to extend the plupload.File
object with the deleteUrl, the fileUrl and a thumbnail.
The extension that handles the custom response for the PlUpload plugin is straightforward. We take already exsiting values and create a PlUpload friendly Json response. Very easy. Again, we use convention based extension handling. As you can see in the extensions code, we have no condition to distinguish between calls from the jQuery File Upload Plugin and PlUpload. This is handled by the Backload component, as we followed the convention to use the naming schema Plugin.PlUpload
within the namespace of our extension and we send a plugin=plupload
querystring in the request.
namespace Backload.Extension.Contoso.Plugin.PlUpload { [Export(typeof(IOutgoingResponse))] public class OutgoingResponse : IOutgoingResponse { public JsonResult Result { get; set; } public List<ExtensionLogger> Logger { get; set; } public bool ProcessStep(System.Web.HttpRequestBase request, string httpMethod) { // Just for demo purposes we use a dynamic object to get the current response data (which is in JsonResult.Data). // Note: dynamic means no Intellisense and type checking at compile time. // Otherwise can simply cast Result.Data to Backload.FileUploadStatus to access the strongly typed values at debug time. dynamic data = this.Result.Data; var processed = false; // Flag. Set to true, if the extension has manipulated the result. if (httpMethod != "DELETE") { var result = new PlFiles(); for (int i = 0; i < data.files.Count; i++) { var file = data.files[i]; result.files.Add(new PlFile(file.extra_info.original_name, file.size, file.type, file.delete_url, file.thumbnail_url, file.url, file.error)); processed = true; } this.Result = Helper.Json(result); } else { // Here we use an anonymous type to return some data. PlUpload does not handle server side file deletion, but we made the // ajax request and so we can return whatever we want. var result = new { success = string.IsNullOrEmpty(data.files[0].error), message = data.files[0].error, name = data.files[0].name }; this.Result = Helper.Json(result); processed = true; } return processed; } } }
####Conclusion In this example you learned how to leverage the IOutgoingResponse interface to completely and conditionally change the json response for a different fileupload plugin. To handle multiple different plugins at the same time just write your extensions for the plugins you want to serve and drop it into the extensions folder.
Code examples: Example09
Backload. (Standard version): Copyright 2013, Steffen Habermehl, License (Standard version): MIT license
Professional and Enterprise (source code) version are available under a commercial license.
Follow us on Twitter: @Backload_MVC