这个问题的背景是,用户通过浏览器上传文件或Excel数据到系统中,页面需要时时显示后台处理进度,以增强用户的体验。

在GitHub上找到一个一个项目,基本实现了这个功能,具体效果如下图

代码实现过程大概如下:

第一步 :定义一个HomeController类,用来处理浏览器的上传文件和进度情况

 public class HomeController : Controller
{
//
// GET: /Home/ public ActionResult Index()
{
return View();
} public ActionResult Homepage()
{
return View();
} [HttpPost]
public ActionResult GetUniqueIdentifier()
{
return Json(Guid.NewGuid().ToString());
} [HttpPost]
public ActionResult SingleFileUpload()
{
return View();
} [HttpPost]
public ActionResult MultipleFileUpload()
{
return View();
} [HttpPost]
public ActionResult DoUploadSingleFile(HttpPostedFileBase berkas, string guid)
{
bool result = false;
string filePath = Server.MapPath("~/Temporary/") + berkas.FileName; int fileLength = berkas.ContentLength;
HttpContext.Cache[guid + "_total"] = fileLength;
byte[] fileContent = new byte[fileLength];
int bufferLength = * ;
byte[] buffer = new byte[bufferLength];
int bytesRead = ; FileStream outputFileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite);
using (Stream inputFileStream = berkas.InputStream)
{
while ((bytesRead = inputFileStream.Read(buffer, , buffer.Length)) > )
{
outputFileStream.Write(buffer, , bytesRead);
outputFileStream.Flush(); HttpContext.Cache[guid + "_current"] = Convert.ToInt32(HttpContext.Cache[guid + "_current"]) + bytesRead;
Debug.WriteLine(HttpContext.Cache[guid + "_current"].ToString());
Thread.Sleep();
} inputFileStream.Close();
inputFileStream.Dispose();
} outputFileStream.Close();
outputFileStream.Dispose();
result = true; return Json(result);
} [HttpPost]
public ActionResult TrackProgress(string guid)
{
try
{
double paramCurrentFileSize = Convert.ToDouble(HttpContext.Cache[guid + "_current"]);
double paramTotalFileSize = Convert.ToDouble(HttpContext.Cache[guid + "_total"]);
int uploadProgress = Convert.ToInt32(paramCurrentFileSize * / paramTotalFileSize); return Json(uploadProgress);
}
catch (Exception)
{
return Json();
}
}
}

DoUploadSingleFile方法用来将用户传来的文件保存到Temporary目录下,将文件的总大小和已经写入的文件数量分别放到Cache中,以便接下来读取这两个数据。

TrackProgress方法就是讲DoUploadSingleFile方法总保存的两个数读出并计算比例。

第二步,Web页面,主要存放三部分,主要是上传组件和进度显示,通过JS绑定了按钮和上传送事件。

@using X_Cust_File_Upload.Helpers

@{
Layout = null;
ViewBag.Title = "SingleFileUpload";
} @*@PageHelper.Script("angular-js/js/angular.js", false)
@PageHelper.Script("underscore-js/js/underscore.js", false)*@
@PageHelper.Script("single-file-upload.js", true) <div class="title">
Single File Upload
</div> <div class="content">
<form method="post" enctype="multipart/form-data" id="form_upload" name="form_upload" style="display: none;">
<input type="file" name="berkas" id="berkas" />
</form> <div class="control-group">
<div class="input-prepend">
<button class="btn" id="buttonSelectFile"><i class="icon icon-folder-open"></i></button>
<input type="text" name="berkas_name" id="berkas_name" class="span3 uneditable-input" placeholder="Select File to Upload" />
</div> <button class="btn btn-primary" id="buttonUploadFile"><i class="icon icon-upload"></i> Upload File</button> <div id="notification-area" class="alert info pull-right notification-area">
</div>
</div>
</div> <script type="text/javascript">
$(document).ready(function () {
$("#buttonSelectFile").on("click", function (event) {
$("#berkas").trigger("click");
}); $("#berkas").on("change", function (event) {
$("#berkas_name").val($("#berkas").val());
}); $("#buttonUploadFile").on("click", function (event) {
var notificationArea = new NotificationArea($("#notification-area")); var fileUpload = new FileUpload();
fileUpload.uploadSingleFile($("#form_upload"), "87shd-09ld2-9sdkl-09dlp-02kdm", "@Url.Content("~/Home/DoUploadSingleFile")", notificationArea, "@Url.Content("~/Home/TrackProgress")");
});
});
</script>

第三步,主要是ajax上传事件,即single-file-upload.js文件,在上传数据的时候,开启一个定时器,每个1s向TrackProgress方法发送一次请求,获取已经上传的进度。

function NotificationArea($container) {
this.showProgressNotification = function ($progress, $isVisible) {
$container.html("<span>Progress : " + $progress + " %</span>"); if ($isVisible == false) {
$container.fadeIn();
}
}; this.showErrorNotification = function () {
$container.removeAttr("class");
$container.addClass("alert error pull-right");
$container.html("<span>Upload error.</span>");
}; this.showSuccessNotification = function () {
$container.removeAttr("class");
$container.addClass("alert info pull-right");
$container.html("<span>Uploaded successfully.</span>");
};
} function FileUpload() {
this.guid = "";
this.onUploadProgress = false;
this.notificationObject = null;
this.trackUrl = ""; this.uploadSingleFile = function ($form, $guid, $url, $notificationObject, $trackUrl) {
if ($form != null) {
this.guid = $guid;
//this.notificationObject = $notificationObject;
this.trackUrl = $trackUrl;
var trackTimer = setInterval(function () {
trackUploadProgress($trackUrl, $notificationObject, $guid);
}, 1000); $form.ajaxSubmit({
url: $url,
data: {
guid: $guid
},
beforeSend: function () {
$notificationObject.showProgressNotification(0, false);
},
success: function (data) {
console.log("sukses"); if (data == true) {
clearTimeout(trackTimer);
$notificationObject.showSuccessNotification();
}
else {
$notificationObject.showErrorNotification();
}
},
error: function (xhr, ajaxOptions, error) {
$notificationObject.showErrorNotification();
},
complete: function () {
clearTimeout(trackTimer);
}
});
}
};
} function trackUploadProgress($url, $notificationObject, $guid) {
console.log("Upload progress"); $.ajax({
url: $url,
type: "post",
data: {
guid: $guid
},
success: function (data) {
$notificationObject.showProgressNotification(data, true);
}
});
}

到此,主要功能已经完成,上传文件可以看到大致的进度。

但是我将这个功能集成到自己的系统时候遇见了一个很奇怪的问题:进度一直不提示,直到数据上传成功了,提示显示100%。这个问题的原因还不确定,请院子里的大牛帮忙分析下。

在原有的系统上增加权限验证功能,如果用户没有登录系统是不能上传数据的,但也就是这个功能,造成了上面的问题。我的做法如下:

第四步,增加AuthorizeAttribute认证子类,主要功能是用来判断用户是否登录系统,如果没有登录,跳转到登录页面,让用户登录。

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
} protected override bool AuthorizeCore(HttpContextBase httpContext)
{ if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (!httpContext.User.Identity.IsAuthenticated)//未登录的话 跳转到登录界面
return false;
return true;
} protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult("/Auth/LogOn");
}
}

第五步,用户登录成功后,跳转到上传页面,这个工程使用ajax登录,JS代码如下:

$.ajax({
type: "POST",
url: "LogOn",
data: { name: $("#UserName").val(), pwd: $("#Password").val(), vlidateCode: $.trim($("#ValidateCode").val())},
dataType: "json",
success: function (data) {
if(data.isSuccess)
{
window.location = data.url;
}
else
{
alert(data.message);
changeCheckCode();
}
$("#Loading").hide();
}
});

后台登录过程为AuthorController类,主要设置用户已经登录标志,

 [HttpPost]
public JsonResult LogOn(string name, string pwd, string vlidateCode)
{
FormsAuthentication.SetAuthCookie(name, false);
var json = new { isSuccess = true, url = "../Home" };
return Json(json);
}

第六步,在HomeController类上添加认证属性

  [CustomAuthorize(Roles="T1")]
public class HomeController : Controller
{
........
}

原作者程序地址:http://files.cnblogs.com/files/crazyguo/x-cust-file-upload-master.zip

我增加后的程序:http://files.cnblogs.com/files/crazyguo/My.7z

  

Asp.Net MVC页面显示后台处理进度问题的更多相关文章

  1. ASP.NET MVC搭建项目后台UI框架—5、Demo演示Controller和View的交互

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  2. ASP.NET MVC搭建项目后台UI框架—7、统计报表

    ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NET M ...

  3. ASP.NET MVC搭建项目后台UI框架—8、将View中选择的数据行中的部分数据传入到Controller中

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  4. ASP.NET MVC搭建项目后台UI框架—1、后台主框架

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  5. ASP.NET MVC搭建项目后台UI框架—2、菜单特效

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  6. ASP.NET MVC搭建项目后台UI框架—3、面板折叠和展开

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  7. ASP.NET MVC搭建项目后台UI框架—4、tab多页签支持

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  8. ASP.NET MVC搭建项目后台UI框架—6、客户管理(添加、修改、查询、分页)

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  9. jsp实时显示后台批处理进度 - out分块,简单的长连接方式

    这两天在实现一个批处理操作,但是想让前台实时显示后台批处理进度,本想着用复杂一些的框架可以实现异步信息调用 但是鉴于是内部管理系统,且只有一两个人用到这个功能,所以做了一个简单的长连接方式的实时响应 ...

随机推荐

  1. Python 再谈变量作用域与变量引用

    再谈变量作用域与变量引用 by:授客 QQ:1033553122 module3.py #!/usr/bin/env python # -*- coding:utf-8 -*-   __author_ ...

  2. 喜闻乐见-Android简介

    本文主要是对Android系统做一个简介,包括其架构.启动流程.沙箱机制.APK.Darlvik以及ART. 1. 架构 Android是基于Linux内核开发出的一个移动操作系统,系统结构大致可以分 ...

  3. Sqlserver精简安装选项

  4. (网页)angular js 终极购物车(转)

    转自CSDN: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...

  5. Tensorflow激活函数

    注意: 1.大多情况下使用Relu激活函数这种激活函数计算快,且在梯度下降中不会卡在plateaus(平稳段),对于大的输入,也不会饱和. 2.logistic function和hyperbloic ...

  6. IP负载均衡

    推荐一篇关于LVS的好文: https://www.cnblogs.com/gaoxu387/p/7941381.html 一.原博主要内容: 1.概述 IP负载均衡:四层负载,是基于IP+端口的负载 ...

  7. MySQL面试题之死锁

    什么是死锁?锁等待?如何优化这类问题?通过数据库哪些表可以监控? 死锁是指两个或多个事务在同一资源上互相占用,并请求加锁时,而导致的恶性循环现象.当多个事务以不同顺序试图加锁同一资源时,就会产生死锁. ...

  8. WPFの获取屏幕分辨率并自适应

    double x = SystemParameters.WorkArea.Width;//得到屏幕工作区域宽度 double y = SystemParameters.WorkArea.Height; ...

  9. 【转】windows 控制台cmd乱码的解决办法

    windows 控制台cmd乱码的解决办法 我本机的系统环境: OS Name: Microsoft Windows 10 企业版 OS Version: 10.0.14393 N/A Build 1 ...

  10. 【SpringMVC】关于classpath和contextConfigLocation

    [SpringMVC]关于classpath和contextConfigLocation 2017年11月16日 12:05:47 yongh701 阅读数:3624    版权声明:本文为博主原创文 ...