如何使用 SignalR 向客户端报告文件进度?

How to report file progress to clients using SignalR?

我编写了一个组件,用于获取 excel 文件并将其数据存储到数据库中。因为我希望这个 class 支持不同的环境(例如在控制台应用程序中使用它)所以我决定创建一些事件:

public interface IDataSeeder
{
    Task Seed(string fileName);
    event EventHandler<UserSucceedEventArgs> UserAdded;
    event EventHandler<UserErrorEventArgs> Error;
    event EventHandler<UserUpdateEventArgs> UserUpdated;
    event EventHandler<FinishDataSeederEventArgs> ProcessCompleted;
}

每个事件都会在 Seed 方法中的不同位置触发。它在我的控制台应用程序中就像一个魅力。
现在我想在我的 ASP.NET MVC 应用程序中使用这个组件,为此我决定使用 SignalR 将事件的数据推送到客户端,所以我创建了一个这样的集线器:

public class ProgressHub : Hub
{
    public static void UserAdded(UserSucceedEventArgs e)
    {
        var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
        ctx.Clients.All.userAdded(e);
    }

    public static void Error(UserErrorEventArgs e)
    {
        var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
        ctx.Clients.All.error(e);
    }

    public static void UserUpdated(UserUpdateEventArgs e)
    {
        var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
        ctx.Clients.All.userUpdated(e);
    }

    public static void ProcessCompleted(FinishDataSeederEventArgs e)
    {
        var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
        ctx.Clients.All.processCompleted(e);
    }
}

然后我创建了这个用于获取上传文件的操作方法并将其传递给我的组件:

[HttpPost]
public async Task<ActionResult> AddFromExcel(HttpPostedFileBase excelFile)
{
    if (excelFile != null)
    {
        var fileName = Utilities.UploadFile.UploadFile.UploadCommonFile(excelFile, "users");
        _dataSeeder.UserAdded += DataSeeder_Succeed;
        _dataSeeder.Error += DataSeeder_Error;
        _dataSeeder.UserUpdated += DataSeeder_Update;
        _dataSeeder.ProcessCompleted += DataSeeder_Finish;
        await _dataSeeder.Seed(Server.MapPath($"~/Content/Files/users/{fileName}"));
        return RedirectToAction("AddFromExcel");
    }
    return RedirectToAction("List");
}

private static void DataSeeder_Finish(object sender, FinishDataSeederEventArgs e)
{
    ProgressHub.ProcessCompleted(e);
}

private static void DataSeeder_Update(object sender, UserUpdateEventArgs e)
{
    ProgressHub.UserUpdated(e);
}

private static void DataSeeder_Error(object sender, UserErrorEventArgs e)
{
    ProgressHub.Error(e);
}

private static void DataSeeder_Succeed(object sender, UserSucceedEventArgs e)
{
    ProgressHub.UserAdded(e);
}

正如您在每个事件处理程序中看到的那样,我使用我的信号器中心通知客户端。

所有这些过程就像一个消息系统,但我不知道如何在 Web 应用程序中实现它。我的代码的一个缺陷是,在附加事件处理程序后,我立即将用户重定向到另一个操作方法,我知道它一定是一个异步过程,但我不知道如何使我的事件异步。

有什么想法吗?

您需要做的是将 SignalR 服务器调用与 JavaScript 函数相匹配,这些函数将向连接的客户端显示结果:

<script type="text/javascript">
   // the proxy to your hub
   var hub = $.connection.ProgressHub;

   // the function that will be called when you call
   // ctx.Clients.All.userAdded(e);
   hub.client.userAdded = function (data) {
      // show the data
      alert(data);
   };

   // follow suit with the rest of the functions
   hub.client.error = function (data) {
      alert(data);
   };

   // etc

</script>