8

CSV ファイルをインポートして処理する ASP.NET MVC 4 アプリケーションに取り組んでいます。アップロードには標準のフォームとコントローラーを使用しています。私が現在行っていることの概要は次のとおりです。

コントローラ ロジック

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 分以上座っているのは避けたいと思います。新しいファイルのアップロード フォルダーを監視し、何か新しいものが追加されたときに処理するコンソール アプリケーションを追加することを検討しましたが、この道をたどる前に、コミュニティから受け取った情報を確認したいと考えています。

この操作を処理するより効率的な方法はありますか?

このアクションを実行して、ユーザーが楽しい方法で続行できるようにし、処理が完了したときにユーザーに通知する方法はありますか?

4

2 に答える 2

11

私が抱えていた問題の解決策は少し複雑ですが、IFrameの修正と同様に機能します。その結果、処理を処理するポップアップウィンドウが表示され、ユーザーはサイト全体をナビゲートし続けることができます。

ファイルはサーバー(UploadCSVコントローラー)に送信され、処理の最初のキックオフを処理するためのJavaScriptが少し含まれた成功ページが返されます。ユーザーが[処理の開始]をクリックすると、新しいウィンドウが開き(ImportProcessing / Index)、初期ステータスが読み込まれ(ステータスの更新を取得する間隔ループが開始されます)、[StartProcessing]アクションが呼び出され、開始されます。処理プロセス。

私が使用している「FileProcessor」クラスは、ImportProcessingコントローラー内の静的辞書変数に格納されています。キーに基づいたステータス結果を可能にします。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/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>

この新しいウィンドウが開くと、ファイル処理が開始されます。更新は、カスタム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: "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>
于 2012-12-05T21:09:09.733 に答える
0

考えただけですが、CSVファイルの処理をスレッド化し、そのタスクの完了時に、基本的にクライアント側でモーダルダイアログまたはある種のjavascriptアラートを提供する別のメソッドを呼び出して、処理が完了したことをユーザーに通知することができます。

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

またはそれらの線に沿った何か。ある種のサーバー側の処理が行われている間、ユーザーが画面を見続けるのは確かに意味がないので、最終的にはある種のスレッドを調べたいと思うでしょう。

于 2012-12-04T19:29:51.877 に答える