2014年4月25日 星期五

File upload with Html5 & WebApi & SignalR (2)

File upload with Html5 & WebApi & SignalR (2)
Author : JB


   


   1.  Web API with async upload method.
   2.  Add SignalR framework to the Web API.
   3.  Implement the front-end.


   1. Import the SignalR architecture to the Web API from Nuget.



Add a OWIN Startup class





The startup class should has the setting of SignalR Hub’s connect routine.

[assembly: OwinStartup(typeof(Icash.Tms.Service.Startup))]
namespace Icash.Tms.Service
{
    public class Startup
    {

         public void Configuration(IAppBuilder app)
        {
            try
            {
                //app.MapSignalR();
                app.Map("/SignalR", map =>
                {
                    map.UseCors(CorsOptions.AllowAll);
                    var hubConfiguration = new HubConfiguration
                    {
                        EnableJSONP = true,
                        EnableDetailedErrors = true
                    };
                    map.RunSignalR(hubConfiguration);
                });
            }
            catch (System.Exception)
            {
               
                throw;
            }
        }
    }
}




   2. We will implement the hub’s method


[HubName("uploaderhub")]
public class UploaderHub : Hub
{
//從其他類別呼叫需用以下方法取得UploaderHub Instance
static IHubContext HubContext =
                      
GlobalHost.ConnectionManager.GetHubContext<UploaderHub>();
/// <summary>
/// 更新上傳進度
/// </summary>
/// <param name="connId">SignalR Connection Id</param>
/// <param name="name">FileName</param>
/// <param name="message">Message for client</param>
public void UpdateProgress(
         
String connId, String name, int percentage, String message)
    {
        
//Sernd back to certain client with Connection id
         HubContext.Clients.Client(connId).
updateProgress(name, percentage, message)
        
//Send back to all connections
        
//HubContext.Clients.All.updateProgress(name, message);
    }
}

The
updateProgress method will be used in the Front-end to enable the SignalR hub.


   3. Modify the upload (POST) method in Controller, first we must
   know the “Connection Id” from the front-end. So we will make
   the Connection id as a request parameter from url.

private readonly String CENTER_FILE_PATH = @"D:\TEMP\FileCenter";

// POST api/file/Upload
[HttpPostActionName("Upload")]
public async Task<HttpResponseMessage> Post()
{

   try
   
{
     
//Get the POST params
     
NameValueCollection nvc =
                
HttpUtility.ParseQueryString(Request.RequestUri.Query);
      var userId = nvc["user"] ?? String.Empty; // User Id (optional)
      var typeName = nvc["type"] ?? String.Empty; //sub-folder (optional)
      var connId = nvc["connId"] ?? String.Empty; //connection id for SingleR

      
//Create if necessary
      this.createCenterDirectory(uploadPath);
      //Check if the request contains multipart/form-data.
      if (!Request.Content.IsMimeMultipartContent())
     {
         throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
     }
     //Start Reading multi-part from request
     var streamProvider = new MultipartFormDataStreamProvider(uploadPath);
     await Request.Content.ReadAsMultipartAsync(streamProvider);
   
     
//For each MultipartFileData, save a log and copy it to the local storage
      this.handleMultiFileData(
                    streamProvider,
                    uploadPath,
                    typeName, userId, connId);
   
      return Request.CreateResponse(HttpStatusCode.OK);
    }
    catch (System.Exception ex)
    {
 }
}      

private void handleMultiFileData(

    MultipartFormDataStreamProvider streamProvider,String uploadPath,
   
String typeName, String userId, String connId)      
{
  
int current = 1;
   int cntFiles = streamProvider.FileData.Count;
   foreach (MultipartFileData fileData in streamProvider.FileData)
   {
       String fileName = fileData.Headers.ContentDisposition.FileName;
       if (fileName.StartsWith("\"") && fileName.EndsWith("\""))
       {
           fileName = fileName.Trim('"');
       }
       if (fileName.Contains(@"/") || fileName.Contains(@"\"))
       {
           fileName = Path.GetFileName(fileName);
       }

      
//Send Progress from SignalR hub
       this.sendProgressFromHub(connId, fileName, current, cntFiles);
       current++;
      
//Start writing file-data to storage
      
String tagetFilePath = Path.Combine(uploadPath, fileName);
      File.Move(fileData.LocalFileName, tagetFilePath);
   }
}

/// <summary>
/// 送出目前上傳進度給SignalR Hub
/// </summary>
/// <param name="connId">Connection id</param>
/// <param name="fileName">檔名</param>
/// <param name="current">current file index</param>
/// <param name="total">total file count</param>
/// <param name="msg">Message</param>
private void sendProgressFromHub(
String connId, String fileName, int current, int total, String msg = "")
{
try
{
  
int percentage =
        (
int)System.Math.Round(((double)current / (double)total * 100), 2);
  
String percStr = percentage.ToString() + "%";
  
if (String.IsNullOrEmpty(msg))
   {
      msg =
String.Format("{0:n0}/{1:n0}({2})", current, total, percStr);
   }
new UploaderHub().UpdateProgress(connId, fileName, percentage, msg);
}
}


  4. The webApi with signalR is done! We will write the Front-end in
  the next article.



沒有留言:

張貼留言