MVC-4 FileUpload success message - c#

I am having few problems with displaying a success message after a file has been uploaded.
I first tried with using the ViewBag.Message , and it works good and display the Success message after the file has been uploaded, which is what I want. But then I cant find a way on how to , after a few seconds change that message back to: "Choose a file to upload !" , so that the user understand he can now upload a new file.
I tried to implement a javascript feature to handle the success message instead. The problem with that is that the success message then shows up before the file upload is completed, which is no good, and if its a very small file, the message will only show for a millisecond.
Do you have any suggestion on how I can fine tune this ? Im not sure if I should try work further using javascript or viewbag, or something different ?
What I am looking for is a success message that are display for around 5 seconds after a successful upload, it then changes back to the "Choose a file to upload message" again.
https://github.com/xoxotw/mvc_fileUploader
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;
namespace Mvc_fileUploader.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
//ViewBag.Message = "Choose a file to upload !";
return View("FileUpload");
}
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase fileToUpload)
{
if (ModelState.IsValid)
{
if (fileToUpload != null && fileToUpload.ContentLength > (1024 * 1024 * 2000)) // 1MB limit
{
ModelState.AddModelError("fileToUpload", "Your file is to large. Maximum size allowed is 1MB !");
}
else
{
string fileName = Path.GetFileName(fileToUpload.FileName);
string directory = Server.MapPath("~/fileUploads/");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string path = Path.Combine(directory, fileName);
fileToUpload.SaveAs(path);
ModelState.Clear();
//ViewBag.Message = "File uploaded successfully !";
}
}
return View("FileUpload");
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
FileUpload view:
#{
ViewBag.Title = "FileUpload";
}
<h2>FileUpload</h2>
<h3>Upload a File:</h3>
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.ValidationSummary();
<input type="file" name="fileToUpload" /><br />
<input type="submit" onclick="successMessage()" name="Submit" value="upload" />
//#ViewBag.Message
<span id="sM">Choose a file to upload !</span>
}
<script>
function successMessage()
{
x = document.getElementById("sM");
x.innerHTML = "File upload successful !";
}
</script>

Few things,
First, you need a Model to indicate a successful upload, we can just use a bool in your instance to indicate it.
Add this at the top of your view:
#model bool
Then you can do (keeping your view as is):
#{
ViewBag.Title = "FileUpload";
}
<h2>FileUpload</h2>
<h3>Upload a File:</h3>
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.ValidationSummary();
<input type="file" name="fileToUpload" /><br />
<input type="submit" onclick="successMessage()" name="Submit" value="upload" />
<span id="sM">Choose a file to upload !</span>
}
We can manipulate the sM in JS dependent upon the model value
<script>
#if(Model)
{
var x = document.getElementById("sM");
x.innerHTML = "File upload successful !";
setTimeout("revertSuccessMessage()", 5000);
}
function revertSuccessMessage()
{
var x = document.getElementById("sM");
x.innerHTML = "Choose a file to upload !";
}
</script>
Then in your else statement in your action method, just make sure you return true on success, otherwise false. Like so
else
{
string fileName = Path.GetFileName(fileToUpload.FileName);
string directory = Server.MapPath("~/fileUploads/");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string path = Path.Combine(directory, fileName);
fileToUpload.SaveAs(path);
ModelState.Clear();
return View("FileUpload", true);
}
return View("FileUpload", false);

You could do the following:
$('form').submit(function(e) {
var form = $(this);
if (form.valid()) {
e.preventDefault();
$.ajax(form.attr('action'), {
data: new FormData(form[0]),
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
var progress = $('progress', form);
if (myXhr.upload && progress.length > 0) {
progress.show();
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable)
progress.attr({ value: e.loaded, max: e.total });
}, false);
}
return myXhr;
},
success: function(e) {
alert('Upload complete!');
},
// Options to tell JQuery not to process data or worry about content-type
contentType: false,
processData: false
});
}
});
However it will only work in modern browsers. You could use Modernizr to detect this. For example, if you wrap the code within the form's submit event handler with the following, it will fall back to a regular submit if it is not supported.
if (Modernizr.input.multiple) {
...
}
This also supports progress indication. Simply put a progress tag within the form.
The above code simply alerts the the user when the upload is complete. I use a nice little library called toastr instead.

Perhaps you could just use alert() on it's success? Not the most elegant solution but it sounds like it may suffice. Otherwise, you should look into JQuery

Related

Pass last insert id to toastr - Asp.Net MVC 4

I am new to MVC and trying to pass the last created Id (once the save button has been clicked in the form).
Can anyone please tell me if it is possible to pass this value to the toastr display, and how this can be done, so once the save button is pressed it returns that Id number?
Additionally to my comment, here's a more complex answer.
Roughly it contains the following items:
Views: CreateItem, NewItemHandler
Controllers: ItemHandler
Javascript: site.js and jQuery
The CreateItem view is the dialog where the user enters their item values. In my case a simple form with two input fields and the mandatory submit button.
#{
ViewBag.Title = "CreateItem";
}
<h2>CreateItem</h2>
<form id="newItemForm">
Item name: <input id="itemname" type="text" name="fname"><br>
Item weight: <input id="itemweight" type="text" name="lname"><br>
<input type="submit" value="Submit">
</form>
The JavaScript should stop the redirection when clicking on submit, this is done by returning false within $("newItemForm").submit(...). Furthermore we no need to tell the server that it needs to create our item, so we have to create our own submit request, which I did with jQuery.post():
$('#newItemForm').submit(function () {
sendPostAndShowResult();
return false;
});
function sendPostAndShowResult() {
var name = $("#itemname").text();
var weight = $("#itemweight").text();
$.post("/Item/NewItemHandler",
{ "name": name, "weight": weight }
).done(function (data) {
alert("The ID of your new item is: " + $.trim(data)); //replace with toast
})
.fail(function () {
alert("Error while processing the request!");
});
}
Just a hint: I didn't use toast here, since I never used it, but I guess it shouldn't be too difficult to adapt.
The final piece of the puzzle is the NewItemHandler, which creates the item, figures out the ID and returns the value:
The View is quite easy. Since we don't need a Layout, it has been set to "".
#{
Layout = "";
}
#Html.Raw(Session["ItemID"])
As you see, we just need to get the "ItemID" into our Session object, this is done by the Controller.
[HttpPost]
public ActionResult NewItemHandler(string name, string weight)
{
int id = GenerateNewItem(name, weight);
Session["ItemID"] = id;
return View();
}
EDIT: I tried to adapt this approach to your solution:
You need to remove the return RedirectToAction() with return View(); in your Controller. This then returns (Save.cshtml) a response, with the ID in an ohterwise empty file (Layout = "").
Your Save.cshtml is empty I guess, so replace it with
#{
Layout = "";
}
#Html.Raw(Session["ItemID"])
In your controller the Save Method should look remotely like this.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(BidstonHwrc bidstonhwrc)
{
_context.BidstonHwrc.Add(bidstonhwrc);
try
{
_context.SaveChanges(); //either all changes are made or none at all
}
catch (Exception e)
{
Console.WriteLine(e);
}
int id = bidstonhwrc.Id;
Session["ItemID"] = id;
return View();
}
In your MCN Form you need to give your <form> tag an ID, via Razor:
#using (Html.BeginForm("Save", "BidstonHwrc",FormMethod.Post, new { id = "SaveBidstonHwrc" }))
The javascript code should look like this, simply adapt the IDs:
$('#SaveBidstonHwrc').submit(function () {
sendPostAndShowResult();
return false;
});
function sendPostAndShowResult() {
//foreach Model/ViewModel Property one line e.g.
var Id = $("Id").text();
var McnNumber = $("McnNumber").text();
$.post("/BidstonHwrc/Save",
{ "Id": Id, "McnNumber": McnNumber }
).done(function (data) {
alert("The ID of your new item is: " + $.trim(data)); //replace with toast
$(location).attr('href', '/Home/Index') //Redirect to Home
})
.fail(function () {
alert("Error while processing the request!");
});
}
I uploaded a project that should represent your solution a bit.
You can download it here (28MB): Project download

MVC 4 - Captcha.Mvc

I have a Captcha control for my MVC 4 page and I cannot get it to show a message if the input was incorrect. I'm used to doing things through jquery and on success do something, but when I do something like that here I lose the ModelState.IsValid.
So, when I run this code the Captcha control loads fine on the page it shows the 5 letters in an image with a line that says 'Refresh' and a textbox beneath that for input with a submit button on my index page to post to the controller.
When I get input wrong it refreshes the image with no message saying anything was wrong, I know it was wrong because my controller says ModelState.IsValid is false but I want to load a new image and display that the input was incorrect.
When I get input correct it refreshes the image still with no message or anything. I want it to stay there and say that the input was correct and disable the textbox.
My question: How can I do what I described above?
My code is below:
Controllers/HomeController.cs
using System.Web.Mvc;
using CaptchaDemo.MVC4.ViewModels;
using CaptchaMvc;
using CaptchaMvc.Attributes;
using CaptchaMvc.Infrastructure;
namespace CaptchaDemo.MVC4.Controllers
{
public class HomeController : Controller
{
// GET: /Home/
public ActionResult Index()
{
CaptchaUtils.CaptchaManager.StorageProvider = new CookieStorageProvider();
ViewBag.Title = "Captcha MVC 4 Demo";
return View();
}
public ActionResult _Captcha()
{
CaptchaViewModel model = new CaptchaViewModel();
return View(model);
}
public ActionResult AjaxForm()
{
return View(new CaptchaViewModel());
}
[HttpPost, CaptchaVerify("Captcha is not valid")]
public ActionResult AjaxForm(CaptchaViewModel model)
{
if (ModelState.IsValid)
{
ModelState.Clear();
TempData["Message"] = "Message: captcha is valid.";
model.strMessage = "efefwf";
if (Request.IsAjaxRequest())
return PartialView("_Captcha", model);
//return Json(model, JsonRequestBehavior.AllowGet);
return View(model);
}
TempData["ErrorMessage"] = "Error: captcha is not valid.";
if (Request.IsAjaxRequest())
return PartialView("_Captcha", model);
return View(model);
}
}
}
ViewModels/CaptchaViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CaptchaDemo.MVC4.ViewModels
{
public class CaptchaViewModel
{
public string strMessage { get; set; }
}
}
Views/Home/Index.cshtml
#using (Html.BeginForm("AjaxForm", "Home", FormMethod.Post, new { #id = "AjaxCaptchaForm", #class = "ajax" }))
{
<div id="update">#Html.Partial("_Captcha")</div>
<input type="submit" />
}
<script type="text/javascript">
$(document).ready(function () {
$('#AjaxCaptchaForm').submit(function () {
$.post($(this).attr("action"), $(this).serialize(), function (results) {
$("#update").html(results);
});
return false;
});
});
</script>
Views/Shared/_Captcha.cshtml
#using CaptchaMvc.HtmlHelpers
#model CaptchaDemo.MVC4.ViewModels.CaptchaViewModel
#Html.ValidationSummary(true)
#Html.ValidationMessageFor(model => model.strMessage)
#Html.Captcha(5)
<span>#Model.strMessage</span>
In case someone still need help with this:
There are two options one:
#Html.Captcha("Refresh", "Captcha is not valid "
, 4, "The Captcha is required", true)
The last true set the bool addValidationSpan.
Another option:
<span class="field-validation-valid text-danger" data-valmsg-for="CaptchaInputText" data-valmsg-replace="true" id="vali_CaptchaInputText"></span>
<span class="field-validation-valid text-danger" data-valmsg-for="CaptchaDeText" data-valmsg-replace="true" id="vali_CaptchaDeText"></span>
Also the <script src="~/Scripts/jquery-2.1.4.js"></script> need to be loaded before this line is rendered.
#Html.Captcha(5) renders an input with id="CaptchaInputText". To display a native warning message you need to append you model with CaptchaInputText property and add
#Html.ValidationMessageFor(m => m.CaptchaInputText, String.Empty, new { #class = "validation-error", #style = "color:red;" })
into your view.

Ajax postback partialview not getting loaded with updated image

I am trying to create a sample MVC4 webpage with partialViews
on my parent page ,eg., Index.cshtml page I am displaying a partialView page which will allow the user to view/update profile photo
When the index page loads ,I need this partial page to show up the photo if photo is available
once the page is loaded ,when the user uploads a new photo,I need only the partialView page to do an ajax postback and show up the new photo .
I am able to load the page with photo fetched from DB,
I am able to Save new photo to db by clicking "#btnPhotoUpload" button.
But after saving the photo ,the partialview is not getting refreshed automatically.Please help me how to get my partialview page to refesh and display the updated photo.
Here is my index page ie., "Index.cshtml"
#model MvcSamples.Models.ViewModels.UserInfoViewModel
#{
ViewBag.Title = "Ajax Partial Postback demo";
ViewBag.UserId = 1;
}
<h2>PersonalInfo example</h2>
<div id="photoForm">
#Html.Partial("_UserPhoto")
</div>
<div id="OtherDetails">
#Html.Partial("_UserDetails")
</div>
Here is my PartialView, i.e. _UserPhoto.cshtml
#model MvcSamples.Models.ViewModels.UserInfoViewModel
#using (Ajax.BeginForm("SaveProfilePhoto", "Example", new { id = "1" }, new AjaxOptions { UpdateTargetId = "photoForm", OnSuccess = "onSuccess" }, new { encType = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<a>
<img id="imgPhoto" width="100px" height="100px"/>
<label for="photo">Photo:</label>
<input type="file" name="photo" id="photo" />
<input id="btnPhotoUpload" type="button" value="Apply" />
</a>
<script type="text/javascript">
$(document).ready(function () {
$("#imgPhoto").attr('src', "#Url.Action("GetProfileImage", "Example", new { id = ViewBag.UserId })");
$("#btnPhotoUpload").click(function (event) {
//on-click code goes in here.
event.preventDefault();
SavePhotoToDb();
});
function SavePhotoToDb() {
var json;
var data;
$.ajax({
type: "POST",
url: "/Example/SaveProfilePhoto",
data: new FormData($("#form0").get(0)),
dataType: "html",
contentType: false,
processData: false,
success: saveItemCompleted(data),
error: saveItemFailed
});
}
function saveItemCompleted(data) {
$("#photoForm").html(data);
}
function saveItemFailed(request, status, error) {
}
});
</script>
}
Here is my controller ExampleController:
namespace MvcSamples.Controllers
{
public class ExampleController : Controller
{
IUserDetails usr = new UserDetails();
// GET: /Example/
[HttpGet]
public ActionResult Index()
{
//usr.GetProfilePhoto(WebSecurity.GetUserId(User.Identity.Name));
if (!string.IsNullOrWhiteSpace(User.Identity.Name))
{
ViewBag.UserId = WebSecurity.GetUserId(User.Identity.Name);
}
UserInfoViewModel model = new UserInfoViewModel();
model.GenderList = usr.FillGenderTypesDropDownList();
return View(model);
}
[HttpPost]
public ActionResult SaveProfilePhoto(HttpPostedFileBase photo, UserInfoViewModel model)
{
string path = #"C:\Temp\";
if (photo != null)
{
model.UserId = 1;//WebSecurity.GetUserId(User.Identity.Name);
ViewBag.UserId = model.UserId;
var binary = new byte[photo.ContentLength];
photo.InputStream.Read(binary, 0, photo.ContentLength);
UserPicModel upModel = new UserPicModel();
upModel.UserPhoto = binary;
upModel.UserId = model.UserId;
usr.InsertProfilePhoto(upModel);
}
return PartialView("_UserPhoto", model);
}
public FileResult GetProfileImage(int id)
{
byte[] barrImg = usr.GetProfilePhoto(id);
return File(barrImg, "image/png");
}
}
}
Update:
As #David Tansey suggested ,I added code to refresh image inside SaveCompleted(data).
function RefreshImage() {
$("#imgPhoto").attr('src', function () {
// the datetime portion appended to the url avoids caching issues
// and ensures that a fresh image will be loaded every time
var d = new Date();
return this.src + '?' + d.getTime();
});
}
But the above code is refreshing the image only after I click the upload button twice .
Actually I need this to refresh the image immediately after the $("#btnPhotoUpload").click. Any suggestions?
I also tried disabling cache at the controller but no luck:
[OutputCacheAttribute(VaryByParam = "*", Duration = 0, NoStore = true)]
I am pretty sure the problem is that the browser is caching the image file and does not 'perceive' the need to bring it across the wire again after you upload a new one.
Look at the following post for a description of how to attach a dummy (yet dynamic) query string value to prevent the caching from occuring. I think this approach will solve your problem.
asp.net mvc jquery filling image
Hope that helps.

MVC-4 Change ViewBag.Message on server side?

I am beginner in MVC coding.
When the application starts, the ViewBag.Message is: Choose a file to upload.
After a successful upload, it changes to: File uploaded successfully!
Is there a way I can make it to return and show the "Choose a file to upload" message again after around 5 seconds, without using any javascript ?
I thought if mvc had some built in time function I could use maybe ?
https://github.com/xoxotw/mvc_fileUploader
My view:
#{
ViewBag.Title = "FileUpload";
}
<h2>FileUpload</h2>
<h3>Upload a File:</h3>
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.ValidationSummary();
<input type="file" name="fileToUpload" /><br />
<input type="submit" name="Submit" value="upload" />
#ViewBag.Message
}
My controller:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Mvc_fileUploader.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Choose a file to upload!";
return View("FileUpload");
}
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase fileToUpload)
{
if (ModelState.IsValid)
{
if (fileToUpload != null && fileToUpload.ContentLength > (1024 * 1024 * 1)) // 1MB limit
{
ModelState.AddModelError("fileToUpload", "Your file is to large. Maximum size allowed is 1MB !");
}
else
{
string fileName = Path.GetFileName(fileToUpload.FileName);
string directory = Server.MapPath("~/fileUploads/");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string path = Path.Combine(directory, fileName);
fileToUpload.SaveAs(path);
ModelState.Clear();
ViewBag.Message = "File uploaded successfully!";
}
}
return View("FileUpload");
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
The short answer is No. I am guessing because you are "new" you want to focus on the MVC part but MVC and JavaScript are very much interlinked, think client (JavaScript) and server (MVC) and you should really master both to make good websites.
Normally the server doesn't fire events to the browser and instead the browser would make the requests. There are ways to get the server to raise events on the client using things like SignalR but that would be overkill in this scenario.
Finally... what you are trying to achieve is very much a client-side action, i.e. To inform the user to do something. If you did it in MVC you would waste network bandwidth and add delays (think of server calls as expensive) when really it is a client action and so should be done in JavaScript.
Don't shy away from JavaScript. Embrace it. Look into JQuery that takes a lot of the heavy lifting away for you.

Upload and Process CSV File in ASP.NET MVC 4 Architectural Considerations

I am working on an ASP.NET MVC 4 Application that imports and processes a CSV file. I am using a standard form and controller for the upload. Here is an overview of what I am doing currently:
Controller Logic
public ActionResult ImportRecords(HttpPostedFileBase importFile){
var fp = Path.Combine(HttpContext.Server.MapPath("~/ImportUploads"), Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(fp);
var fileIn = new FileInfo(fp);
var reader = fileIn.OpenText();
var tfp = new TextFieldParser(reader) {TextFieldType = FieldType.Delimited, Delimiters = new[] {","}};
while(!tfp.EndOfData){
//Parse records into domain object and save to database
}
...
}
HTML
#using (Html.BeginForm("ImportRecords", "Import", FormMethod.Post, new { #id = "upldFrm", #enctype = "multipart/form-data" }))
{
<input id="uploadFile" name="uploadFile" type="file" />
<input id="subButton" type="submit" value="UploadFile" title="Upload File" />
}
The import file can contain a large number of records (average 40K+) and can take quite some time to complete. I'd rather not have a user sitting at the import screen for 5+ minutes for each file processed. I have considered adding a console application to watch the uploads folder for new files, and process when something new is added, but would like to see what input I receive from the community before starting my journey down this path.
Is there a more efficient way to handle this operation?
Is there a way to perform this action, allowing the user to continue about his/her merry way, and then notify the user when processing is done?
The solution to the issue I was having is a bit complex, but works similar to the IFrame fix. The result is a pop-up window that handles the processing, allowing the user to continue navigation throughout the site.
The file is submitted to the server (UploadCSV controller), a Success page is returned with a bit of JavaScript to handle the initial kick-off of the processing. When the user clicks "Begin Processing", a new window is opened (ImportProcessing/Index) that loads the initial status (kicking off an interval loop that retrieves status updates) and then makes a call to the "StartProcessing" action, kicking off the processing process.
The "FileProcessor" class that I am using is housed in a static dictionairy variable within the ImportProcessing controller; allowing for status results based on the key. The FileProcessor is promptly removed after the operation is complete or an error is encountered.
Upload Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UploadCSV(HttpPostedFileBase uploadFile)
{
var filePath = string.Empty;
if (uploadFile.ContentLength <= 0)
{
return View();
}
filePath = Path.Combine(Server.MapPath(this.UploadPath), "DeptartmentName",Path.GetFileName(uploadFile.FileName));
if (new FileInfo(filePath).Exists)
{
ViewBag.ErrorMessage =
"The file currently exists on the server. Please rename the file you are trying to upload, delete the file from the server," +
"or contact IT if you are unsure of what to do.";
return View();
}
else
{
uploadFile.SaveAs(filePath);
return RedirectToAction("UploadSuccess", new {fileName = uploadFile.FileName, processType = "sonar"});
}
}
[HttpGet]
public ActionResult UploadSuccess(string fileName, string processType)
{
ViewBag.FileName = fileName;
ViewBag.PType = processType;
return View();
}
Upload Success HTML:
#{
ViewBag.Title = "UploadSuccess";
}
<h2>File was uploaded successfully</h2>
<p>Your file was uploaded to the server and is now ready to be processed. To begin processing this file, click the "Process File" button below.
</p>
<button id="beginProcess" >Process File</button>
<script type="text/javascript">
$(function () {
$("#beginProcess").click(BeginProcess);
function BeginProcess() {
window.open("/SomeController/ImportProcessing/Index?fileName=#ViewBag.FileName&type=#ViewBag.PType", "ProcessStatusWin", "width=400, height=250, status=0, toolbar=0, scrollbars=0, resizable=0");
window.location = "/Department/Import/Index";
}
});
</script>
Once this new window is opened up, the file processing begins. Updates are retrieved from a custom FileProcessing class.
ImportProcessing Controller:
public ActionResult Index(string fileName, string type)
{
ViewBag.File = fileName;
ViewBag.PType = type;
switch (type)
{
case "somematch":
if (!_fileProcessors.ContainsKey(fileName)) _fileProcessors.Add(fileName, new SonarCsvProcessor(Path.Combine(Server.MapPath(this.UploadPath), "DepartmentName", fileName), true));
break;
default:
break;
}
return PartialView();
}
ImportProcessing Index:
#{
ViewBag.Title = "File Processing Status";
}
#Scripts.Render("~/Scripts/jquery-1.8.2.js")
<div id="StatusWrapper">
<div id="statusWrap"></div>
</div>
<script type="text/javascript">
$(function () {
$.ajax({
url: "GetStatusPage",
data: { fileName: "#ViewBag.File" },
type: "GET",
success: StartStatusProcess,
error: function () {
$("#statusWrap").html("<h3>Unable to load status checker</h3>");
}
});
function StartStatusProcess(result) {
$("#statusWrap").html(result);
$.ajax({
url: "StartProcessing",
data: { fileName: "#ViewBag.File" },
type: "GET",
success: function (data) {
var messag = 'Processing complete!\n Added ' + data.CurrentRecord + ' of ' + data.TotalRecords + " records in " + data.ElapsedTime + " seconds";
$("#statusWrap #message").html(messag);
$("#statusWrap #progressBar").attr({ value: 100, max: 100 });
setTimeout(function () {
window.close();
}, 5000);
},
error: function (xhr, status) {
alert("Error processing file");
}
});
}
});
</script>
Finally the Status Checker html:
#{
ViewBag.Title = "GetStatusPage";
}
<h2>Current Processing Status</h2>
<h5>Processing: #ViewBag.File</h5>
<h5>Updated: <span id="processUpdated"></span></h5>
<span id="message"></span>
<br />
<progress id="progressBar"></progress>
<script type="text/javascript">
$(function () {
var checker = undefined;
GetStatus();
function GetStatus() {
if (checker == undefined) {
checker = setInterval(GetStatus, 3000);
}
$.ajax({
url: "GetStatus?fileName=#ViewBag.File",
type: "GET",
success: function (result) {
result = result || {
Available: false,
Status: {
TotalRecords: -1,
CurrentRecord: -1,
ElapsedTime: -1,
Message: "No status data returned"
}
};
if (result.Available == true) {
$("#progressBar").attr({ max: result.Status.TotalRecords, value: result.Status.CurrentRecord });
$("#processUpdated").text(result.Status.Updated);
$("#message").text(result.Status.Message);
} else {
clearInterval(checker);
}
},
error: function () {
$("#statusWrap").html("<h3>Unable to load status checker</h3>");
clearInterval(checker);
}
});
}
});
</script>
Just a thought but you could thread the processing of your CSV files and on completion of that task call another method that basically provides a modal dialog or some kind of javascript alert on the client side letting the user know that the processing has completed.
Task.Factory.StartNew(() => ProcessCsvFile(fp)).ContinueWith((x) => NotifyUser());
or something along those lines. I think that ultimately you are gonna wanna look at some kind of threading because it certainly does not make sense for a user to be stuck looking at a screen while some kind of server side processing takes place.

Categories

Resources