2012-12-04 44 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