在ASP.NET post方法中获取signalr的context.connectionId

时间:2018-01-01 16:42:26

标签: c# asp.net asp.net-mvc azure signalr

我有一个应用程序,有一个过程上传excel文件和更新我的数据库的内容,但有时文件是如此之大,过程需要超过230秒,并且azure返回500服务器错误。我打算解决这个问题的方法是让应用程序在上传时打开signalR连接,然后在进度条通过文件时提供更新。问题是,我似乎无法启动和运行基本的signalR功能。当我尝试从Context获取connectionId时,我得到一个null值,因为Context为null。我已经尝试了在论坛和教程中找到的所有内容,但是没有运气。

以下是我的StartUp.cs中的代码:

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(LIMS.Startup))] //maybe this is needed
//[assembly: OwinStartupAttribute(typeof(LIMS.Startup))]
namespace LIMS
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
            ConfigureSignalR(app);
        }
    }
}

然后我在App_Start文件夹中有一个Startup.SignalR.cs文件,其中包含以下代码:

using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LIMS
{
    public partial class Startup
    {
        public void ConfigureSignalR(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

我的cshtml文件如下所示:

@{
    ViewBag.Title = "LabSampleImport";
}

<h2>Lab Sample Import</h2>

<h3 class="text-warning">@ViewBag.Message @TempData["Message"]</h3>

@using (Html.BeginForm("LabSampleImport", "LabData", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    <span><input type="file" name="file" style="display:inline" /></span>
    <p>
        Use the Button above to select the Excel file on your hard drive with the lab sample information you wish to add and/or edit.
        Once you have selected the correct file, click the "Upload Selected File" button below to initiate the import. When the import is complete,
        a file with the same name will download back to your device through your browser. There will be a comment column in the file to indicate the result of each lab sample/row.
    </p>
    <span><input type="submit" name="submitButton" value="Upload Selected File" class="btn btn-default" /></span>
    <hr />
    <input type="submit" name="submitButton" value="Download a Template" class="btn btn-default" />

}


<script src="Scripts/jquery.signalR-2.2.2.js"></script>
<script src="/signalr/hubs"></script>
<script language="javascript">

    theHub.client.initProgressBar = function () {
        alert("The server has just informed this webpage that a progress bar should be displayed.");
    }

    theHub.client.updateProgressBar = function (percentage) {
        alert("The server has just informed this webpage that a progress bar should be updated.");
    }

    theHub.client.clearProgressBar = function (percentage) {
        alert("The server has just informed this webpage that a progress bar should be cleared.");
    }
</script>

我的ProgressHub.cs文件如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;

namespace LIMS.Hubs
{
    public class ProgressHub : Hub
    {
        public void NotifyStart(string connectionId)
        {
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
            hubContext.Clients.Client(connectionId).initProgressBar();
        }
        public void NotifyProgress(string connectionId, int percentage)
        {
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
            hubContext.Clients.Client(connectionId).updateProgressBar(percentage);
        }
        public void NotifyEnd(string connectionId)
        {
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
            hubContext.Clients.Client(connectionId).clearProgressBar();
        }
    }
}

由于Context为null而给出错误的控制器方法如下所示:

// POST: LabData/LabSampleImport
[HttpPost, ActionName("LabSampleImport")]
[ValidateAntiForgeryToken]
[Authorize(Roles = "canAddSamples")]
public async Task<ActionResult> LabSampleImportOption(HttpPostedFileBase file, string submitButton)
{
    if (submitButton == "Upload Selected File")
    {
        //upload file
        if (file != null && file.ContentLength > 0)
        {
            ProgressHub hub1 = new ProgressHub();
            //This is where Context is inexplicably null
            var connectionId = hub1.Context.ConnectionId;
            //and this is where app goes kaplooey due to a null reference exception
            hub1.NotifyStart(connectionId);

            // A bit of placeholder work
            Thread.Sleep(5000);
            hub1.NotifyProgress(connectionId, 20);
        }
    }
}

我发现的其他类似问题的帖子似乎都集中在启动文件执行ConfigureAuth(app)和app.MapSignalR()的顺序。我相信这不是问题,但仍然不知道为什么Context是null。我已经考虑过在客户端获取connectionID并将其传递给方法,但由于从表单帖子中的按钮调用控制器方法,我没有看到让razor在帖子中设置connectionID参数的方法直到游戏后期才能确定连接ID的说明。那我错过了什么?

1 个答案:

答案 0 :(得分:0)

以简单的方式,您可以将当前连接ID($.connection.hub.id)存储在隐藏的输入中,并利用jQuery Form使用AJAX提交表单,而无需刷新当前页面,这将返回您的新的连接ID。您需要按如下方式修改视图页面:

@using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <span><input type="file" name="file" style="display:inline" /></span>

    <!--add the hidden input for storing the current connection Id-->
    <input type="hidden" name="connectionId" id="connectionId"/>

    <span><input type="submit" name="submitButton" value="Upload Selected File" class="btn btn-default" /></span>
    <hr />
    <input type="submit" name="submitButton" value="Download a Template" class="btn btn-default" />
}

<强>的javascript:

$(function () {
    // Reference the auto-generated proxy for the hub.
    var chat = $.connection.progressHub;

    chat.client.initProgressBar = function () {
        console.log("The server has just informed this webpage that a progress bar should be displayed.");
    }

    chat.client.updateProgressBar = function (percentage) {
        console.log("current uploading process:" + percentage + "%");
    }

    chat.client.clearProgressBar = function (percentage) {
        console.log("The server has just informed this webpage that a progress bar should be cleared.");
    }

    // Start the connection.
    $.connection.hub.start().done(function () {
        var cid = $.connection.hub.id;
        $("#connectionId").val(cid);
        console.log("connection Id:" + cid);
    });

    $('form').ajaxForm({
        complete: function (xhr) {
            alert(xhr.responseText);
        }
    });
});

上传文件的操作:

public ActionResult UploadFile(HttpPostedFileBase file, string submitButton, string connectionId)
{
    ProgressHub.NotifyStart(connectionId);

    Thread.Sleep(2000);
    ProgressHub.NotifyProgress(connectionId, 20);
    Thread.Sleep(2000);
    ProgressHub.NotifyProgress(connectionId, 50);
    Thread.Sleep(2000);
    ProgressHub.NotifyProgress(connectionId, 100);

    return Json("Done", JsonRequestBehavior.AllowGet);
}

<强> TEST:

enter image description here