by Vesselin Vassilev
Last Updated On Jul 29, 2017
In general, you need to configure save action that will receive the uploaded files. An optional remove action is also available. Let's see how this can be done in Sitefinity.
Goal
Create a front-end widget that will allow a logged in user to upload one or more files asynchronously to a Sitefinity Document Library.
Implementation
I'll use Sitefinity Feather to create an ASP.NET MVC widget.
Controller
The main controller itself will be very simple - it will just register the widget to the Page Toolbox (via the ControllerToolboxItem attribute) and return the View where the client side code will reside.
using
System.Web.Mvc;
using
Telerik.Sitefinity.Mvc;
namespace
SitefinityWebApp.Mvc.Controllers
{
[ControllerToolboxItem(Name =
"FileAsyncUploader"
, Title =
"File Async Uploader"
, SectionName =
"Custom MVC"
, CssClass =
"sfMvcIcn"
)]
public
class
FileAsyncUploaderController: Controller
{
[HttpGet]
public
ActionResult Index()
{
return
View(
"Index"
);
}
[HttpPost]
public
ActionResult Upload()
{
// save the file to Sitefinity
return
new
EmptyResult();
}
}
}
using
System;
using
System.Linq;
using
System.Web.Hosting;
using
System.Web.Http;
using
System.Web.Optimization;
using
System.Web.Routing;
using
Telerik.Sitefinity.Services;
namespace
SitefinityWebApp
{
public
class
Global : System.Web.HttpApplication
{
protected
void
Application_Start(
object
sender, EventArgs e)
{
SystemManager.ApplicationStart += SystemManager_ApplicationStart;
}
private
void
SystemManager_ApplicationStart(
object
sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private
void
RegisterRoutes(RouteCollection routes)
{
routes.MapHttpRoute(
name:
"MyCustomApi"
,
routeTemplate:
"ajax/{controller}/{action}/{id}"
,
defaults:
new
{ id = RouteParameter.Optional }
);
}
}
}
using
System;
using
System.Net;
using
System.Net.Http;
using
System.Web.Http;
using
Telerik.Sitefinity.Abstractions;
using
System.Linq;
using
System.Collections.Generic;
using
System.Web;
using
System.IO;
using
Telerik.Sitefinity.Libraries.Model;
using
Telerik.Sitefinity.Modules.Libraries;
using
Telerik.Sitefinity.Workflow;
using
Telerik.Sitefinity.Data;
using
System.Text.RegularExpressions;
using
Telerik.Sitefinity.Security.Claims;
using
Telerik.Sitefinity.GenericContent.Model;
namespace
SitefinityWebApp.Mvc.Api
{
public
class
FilesController : ApiController
{
[HttpPost]
public
HttpResponseMessage Upload()
{
var user = ClaimsManager.GetCurrentIdentity();
if
(!user.IsAuthenticated)
{
return
Request.CreateErrorResponse(HttpStatusCode.Forbidden,
"You must be authenticated to upload files"
);
}
var error =
string
.Empty;
var files = HttpContext.Current.Request.Files;
if
(files !=
null
)
{
var manager = LibrariesManager.GetManager();
using
(var reg =
new
ElevatedModeRegion(manager))
{
// create a library with the name of the logged in user
var libTitle = user.Name;
var library = GetOrCreateDocumentsLibrary(libTitle);
for
(
int
i = 0; i < files.Count; i++)
{
var file = files[i];
try
{
// Some browsers send file names with full path.
// This needs to be stripped.
var fileName = Path.GetFileName(file.FileName);
var ext = Path.GetExtension(file.FileName).ToLower();
var docId = Guid.NewGuid();
var doc = manager.CreateDocument(docId);
var utcNow = DateTime.UtcNow;
doc.Parent = library;
doc.Title = fileName;
doc.DateCreated = utcNow;
doc.PublicationDate = utcNow;
doc.LastModified = utcNow;
var urlName = CreateSitefinityUrlFromString(fileName);
doc.UrlName = doc.MediaFileUrlName = urlName;
manager.Upload(doc, file.InputStream, ext);
manager.RecompileItemUrls(doc);
manager.SaveChanges();
var bag =
new
Dictionary<
string
,
string
>();
bag.Add(
"ContentType"
,
typeof
(Document).FullName);
WorkflowManager.MessageWorkflow(docId,
typeof
(Document),
null
,
"Publish"
,
false
, bag);
}
catch
(Exception ex)
{
Log.Write(ex.ToString());
error =
"Failed to upload: "
+ file.FileName + ex.ToString();
}
}
}
}
// Return an empty string to signify success or an error message otherwise
return
Request.CreateResponse(HttpStatusCode.OK, error);
}
[HttpPost]
public
HttpResponseMessage Remove([FromBody] RemoveFileModel filesToRemove)
{
var user = ClaimsManager.GetCurrentIdentity();
if
(!user.IsAuthenticated)
{
return
Request.CreateErrorResponse(HttpStatusCode.Forbidden,
"You must be authenticated to upload files"
);
}
var manager = LibrariesManager.GetManager();
using
(var region =
new
ElevatedModeRegion(manager))
{
var library = manager.GetDocumentLibraries()
.Where(l => l.Title == user.Name)
.Single();
var fileNames = filesToRemove.fileNames;
var docToDelete = library.Documents()
.Where(d => d.Status == ContentLifecycleStatus.Master)
.Where(d => fileNames.Contains(d.Title.ToString()))
.ToList();
docToDelete.ForEach(d => manager.DeleteDocument(d));
manager.SaveChanges();
}
return
Request.CreateResponse(HttpStatusCode.OK);
}
public
Library GetOrCreateDocumentsLibrary(
string
title)
{
var librariesManager = LibrariesManager.GetManager();
Library library =
null
;
using
(var region =
new
ElevatedModeRegion(librariesManager))
{
var libs = librariesManager.GetDocumentLibraries().Where(l => l.Title == title);
if
(libs.Count() == 0)
{
library = librariesManager.CreateDocumentLibrary();
library.Title = title;
library.DateCreated = DateTime.UtcNow;
library.LastModified = DateTime.UtcNow;
library.UrlName = CreateSitefinityUrlFromString(title);
librariesManager.RecompileAndValidateUrls(library);
librariesManager.SaveChanges();
}
else
{
library = libs.First();
}
}
return
library;
}
public
string
CreateSitefinityUrlFromString(
string
title,
bool
isTitleNotUnique =
false
)
{
var url = Regex.Replace(title.ToLower(), @
"[^\w\-\!\$\'\(\)\=\@\d_]+"
,
"-"
);
if
(isTitleNotUnique)
{
url += Guid.NewGuid().ToString();
}
return
url;
}
}
public
class
RemoveFileModel
{
// the name of the files to be deleted
public
string
[] fileNames {
get
;
set
; }
}
}
@using Telerik.Sitefinity.Frontend.Mvc.Helpers;
@using Telerik.Sitefinity.Modules.Pages;
@Html.Script(ScriptRef.KendoWeb, "bottom")
@Html.StyleSheet("//kendo.cdn.telerik.com/2017.2.504/styles/kendo.common-bootstrap.min.css", "head")
@Html.StyleSheet("//kendo.cdn.telerik.com/2017.2.504/styles/kendo.bootstrap.min.css", "head")
<
div
class
=
"row"
>
<
div
class
=
"col-md-4"
>
<
div
class
=
"form-group"
>
<
label
>Upload Files</
label
>
<
input
name
=
"files"
id
=
"files"
type
=
"file"
/>
</
div
>
</
div
>
</
div
>
<
script
>
$(function() {
var saveUrl = '/ajax/files/upload';
var removeUrl = '/ajax/files/remove';
$("#files").kendoUpload({
multiple: true,
async: {
saveUrl: saveUrl,
removeUrl: removeUrl,
autoUpload: true,
batch: true
}
});
})
</
script
>