2012-12-04 47 views
7

我在一个ASP.NET MVC 4应用程序,导入并处理CSV文件的工作。我正在使用标准表单和控制器进行上传。这里是什么,我现在在做一个概述:上传和ASP.NET MVC 4建筑的思考过程CSV文件

控制器逻辑

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" /> 
} 

导入文件可以包含大量的记录(平均40K +)并且可能需要很长时间才能完成。我宁愿没有一个用户坐在导入屏幕上5分钟以上处理每个文件。我曾考虑添加一个控制台应用程序来观察新文件的上传文件夹,并在添加新内容时进行处理,但希望查看我从社区获得的输入,然后开始沿着这条路径前进。

是否有处理这种操作的更有效的方法?

有没有执行此操作方式,使用户能够继续他/她快乐的方式,然后通知用户何时处理完毕?

回答

10

的解决方案,我是有这个问题有点复杂,但工作原理类似IFrame的修复。结果是一个处理处理的弹出窗口,允许用户继续在整个站点中导航。

文件被提交给服务器(UploadCSV控制器),成功页面返回用JavaScript代码来处理处理的初始开球。当用户点击“开始处理”,打开一个新的窗口(ImportProcessing /索引),该加载初始状态(开球的间隔环,其检索状态更新),然后使得到“StartProcessing”动作的呼叫时,拉开处理过程。

,我使用被容纳在ImportProcessing控制器内的静态dictionairy变量“FileProcessor”级;允许基于密钥的状态结果。在操作完成或遇到错误后,FileProcessor会立即被删除。

上传控制器:

[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(); 
     } 

上传成功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/[email protected]&[email protected]", "ProcessStatusWin", "width=400, height=250, status=0, toolbar=0, scrollbars=0, resizable=0"); 
      window.location = "/Department/Import/Index"; 
     } 
    }); 
</script> 

一旦打开了这个新窗口,文件处理开始。更新从自定义的FileProcessing类中检索。

ImportProcessing控制器:

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指数:

@{ 
    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> 

最后的状态检查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: "[email protected]", 
       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> 
0

只是一个想法,但你可以线程您的CSV文件,并在该任务调用,基本上提供了一个模式对话框或某种形式的客户端让用户JavaScript警告的另一种方法完成的处理知道处理有完成。

Task.Factory.StartNew(() => ProcessCsvFile(fp)).ContinueWith((x) => NotifyUser()); 

或沿着这些线的东西。我认为最终你会想看看某种线程,因为用户在某种服务器端处理发生时被卡在屏幕上看起来没有任何意义。

+0

感谢您的输入,我将在这一段时间内玩弄一下,看看它会发生什么。如果它适合我​​,我会确保接受这个答案。 – TNCodeMonkey

+0

我周围搜索试图找到使用此方法的最佳方法,但意识到这不是我所需要的。无论线程是什么,它都无法弥补这一事实,即该职位将一直保持开放状态,直到行动回归。我在解决方案的底部添加了一个答案。 – TNCodeMonkey