title: Using signalR hub from MVC action
body: <p>Following <a href="http://www.codeproject.com/Tips/722331/ProgressBar-using-JQueryUI-and-SignalR" rel="nofollow">this tutorial</a>, I am attempting to display the progress of various steps in a long operation. I was able to successfully <em>simulate</em> a long operation within the hub based on the example, reporting updates back to the client with each step.</p>
  
  <p>Taking this a step further, I now want to display the status of a realtime, long-running process that occurs in an MVC action method with the <code>[HttpPost]</code> attribute.</p>
  
  <p>The problem is that I cant seem to update the client from a hub context. I realize that I must create a hub context to communicate using the hub. One difference that I know of is that I must use <code>hubContext.Clients.All.sendMessage();</code> VS. <code>hubContext.Clients.Caller.sendMessage();</code> listed in the example. Based on my findings in <a href="http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-server" rel="nofollow">ASP.NET SignalR Hubs API Guide - Server</a>
  I should be able to use <code>Clients.Caller</code> as stated in the example but I am limited to only using it in the hub class. Mainly, I just want to understand why I cant get a signal from the action method.</p>
  
  <p>I appreciate the help in advance.</p>
  
  <p><strong>I have created my OWIN <code>Startup()</code> class like so...</strong></p>
  
  <pre><code>using System;
  using System.Threading.Tasks;
  using Microsoft.Owin;
  using Owin;
  
  [assembly: OwinStartup(typeof(HL7works.Startup))]
  
  namespace HL7works
  {
      public class Startup
      {
          public void Configuration(IAppBuilder app)
          {
              app.MapSignalR();
          }
      }
  }
  </code></pre>
  
  <p><strong>My hub is written as such...</strong></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using Microsoft.AspNet.SignalR;
  
  namespace HL7works
  {
      public class ProgressHub : Hub
      {
          public string msg = string.Empty;
          public int count = 0;
  
          public void CallLongOperation()
          {
              Clients.Caller.sendMessage(msg, count);
          }
      }
  }
  </code></pre>
  
  <p><strong>My Controller...</strong></p>
  
  <pre><code>// POST: /Task/ParseToExcel/
  [HttpPost]
  public ActionResult ParseToExcel(HttpPostedFileBase[] filesUpload)
  {
      // Initialize Hub context
      var hubContext = GlobalHost.ConnectionManager.GetHubContext&lt;ProgressHub&gt;();
      hubContext.Clients.All.sendMessage("Initalizing...", 0);
  
      double fileProgressMax = 100.0;
      int currentFile = 1;
      int fileProgress = Convert.ToInt32(Math.Round(currentFile / fileProgressMax * 100, 0));
  
      try
      {
          // Map server path for temporary file placement (Generate new serialized path for each instance)
          var tempGenFolderName = SubstringExtensions.GenerateRandomString(10, false);
          var tempPath = Server.MapPath("~/" + tempGenFolderName + "/");
  
          // Create Temporary Serialized Sub-Directory
          System.IO.FileInfo thisFilePath = new System.IO.FileInfo(tempPath + tempGenFolderName);
          thisFilePath.Directory.Create();
  
          // Iterate through PostedFileBase collection
          foreach (HttpPostedFileBase file in filesUpload)
          {
  
              // Does this iteration of file have content?
              if (file.ContentLength &gt; 0)
              {
                  // Indicate file is being uploaded
                  hubContext.Clients.All.sendMessage("Uploading " + Path.GetFileName(file.FileName), fileProgress);
  
                  file.SaveAs(thisFilePath + file.FileName);
                  currentFile++;
              }
          }
  
          // Initialize new ClosedXML/Excel workbook
          var hl7Workbook = new XLWorkbook();
  
          // Start current file count at 1
          currentFile = 1;
  
          // Iterate through the files saved in the Temporary File Path
          foreach (var file in Directory.EnumerateFiles(tempPath))
          {
              var fileNameTmp = Path.GetFileName(file);
  
              // Update status
              hubContext.Clients.All.sendMessage("Parsing " + Path.GetFileName(file), fileProgress);
  
              // Initialize string to capture text from file
              string fileDataString = string.Empty;
  
              // Use new Streamreader instance to read text
              using (StreamReader sr = new StreamReader(file))
              {
                  fileDataString = sr.ReadToEnd();
              }
  
              // Do more work with the file, adding file contents to a spreadsheet...
  
  
              currentFile++;
          }
  
  
          // Delete temporary file 
          thisFilePath.Directory.Delete();
  
  
          // Prepare Http response for downloading the Excel workbook
          Response.Clear();
          Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
          Response.AddHeader("content-disposition", "attachment;filename=\"hl7Parse_" + DateTime.Now.ToString("MM-dd-yyyy") + ".xlsx\"");
  
          // Flush the workbook to the Response.OutputStream
          using (MemoryStream memoryStream = new MemoryStream())
          {
              hl7Workbook.SaveAs(memoryStream);
              memoryStream.WriteTo(Response.OutputStream);
              memoryStream.Close();
          }
  
          Response.End();
      }
      catch (Exception ex)
      {
          ViewBag.TaskMessage =
              "&lt;div style=\"margin-left:15px;margin-right:15px\" class=\"alert alert-danger\"&gt;"
              + "&lt;i class=\"fa fa-exclamation-circle\"&gt;&lt;/i&gt; "
              + "An error occurred during the process...&lt;br /&gt;"
              + "-" + ex.Message.ToString()
              + "&lt;/div&gt;"
              ;
      }
  
      return View();
  }
  </code></pre>
  
  <p><strong>In My View (Updated to reflect Detail's answer)...</strong></p>
  
  <pre><code>@using (Html.BeginForm("ParseToExcel", "Task", FormMethod.Post, new { enctype = "multipart/form-data", id = "parseFrm" }))
  {
  
      &lt;!-- File Upload Row --&gt;
      &lt;div class="row"&gt;
  
          &lt;!-- Select Files --&gt;
          &lt;div class="col-lg-6"&gt;
              &lt;input type="file" multiple="multiple" accept=".adt" name="filesUpload" id="filesUpload" /&gt;
          &lt;/div&gt;
  
  
          &lt;!-- Upload/Begin Parse --&gt;
          &lt;div class="col-lg-6 text-right"&gt;
              &lt;button id="beginParse" class="btn btn-success"&gt;&lt;i class="fa fa-download"&gt;&lt;/i&gt;&amp;nbsp;Parse and Download Spreadsheet&lt;/button&gt;
          &lt;/div&gt;
  
      &lt;/div&gt;
  
  }
  
  
  
   &lt;!-- Task Progress Row --&gt;
  &lt;div class="row"&gt;
  
      &lt;!-- Space Column --&gt;
      &lt;div class="col-lg-12"&gt;
          &amp;nbsp;
      &lt;/div&gt;
  
      &lt;!-- Progress Indicator Column --&gt;
      &lt;script type="text/javascript" language="javascript"&gt;
  
          $(document).ready(function () {
              $('.progress').hide();
  
              $('#beginParse').on('click', function () {
                  $('#parseFrm').submit();
              })
  
              $('#parseFrm').on('submit', function (e) {
  
                  e.preventDefault();
  
                  $.ajax({
                      url: '/Task/ParseToExcel',
                      type: "POST",
                      //success: function () {
                      //    console.log("done");
                      //}
                  });
  
                  // initialize the connection to the server
                  var progressNotifier = $.connection.progressHub;
  
                  // client-side sendMessage function that will be called from the server-side
                  progressNotifier.client.sendMessage = function (message, count) {
                      // update progress
                      UpdateProgress(message, count);
                  };
  
                  // establish the connection to the server and start server-side operation
                  $.connection.hub.start().done(function () {
                      // call the method CallLongOperation defined in the Hub
                      progressNotifier.server.callLongOperation();
                  });
              });
          });
  
          function UpdateProgress(message, count) {
  
              // get status div
              var status = $("#status");
  
              // set message
              status.html(message);
  
              // get progress bar
              if (count &gt; 0) {
                  $('.progress').show();
              }
  
              $('.progress-bar').css('width', count + '%').attr('aria-valuenow', count);
              $('.progress-bar').html(count + '%');
  
          }
  
  
      &lt;/script&gt;
  
      &lt;div class="col-lg-12"&gt;
          &lt;div id="status"&gt;Ready&lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="col-lg-12"&gt;
          &lt;div class="progress"&gt;
              &lt;div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width:20px;"&gt;
                  0%
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;!-- Task Message Row --&gt;
  &lt;div class="row"&gt;
      &lt;div clss="col-lg-12"&gt;
          @Html.Raw(ViewBag.TaskMessage)
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>Update: The solution to my problem ended up being Detail's answer but with the AJAX post method modified slightly to pass files to my action method ..</strong></p>
  
  <pre><code>e.preventDefault();
  
  $.ajax({
      url: '/Task/ParseToExcel',
      type: "POST",
      data: new FormData( this ),
      processData: false,
      contentType: false,
      //success: function () {
      //    console.log("done");
      //}
  });
  </code></pre>
  
  <p>Reference.. <a href="http://portfolio.planetjon.ca/2014/01/26/submit-file-input-via-ajax-jquery-easy-way/" rel="nofollow">http://portfolio.planetjon.ca/2014/01/26/submit-file-input-via-ajax-jquery-easy-way/</a></p>