Tuesday, February 6, 2018

MVC File Upload using Client side and Server Side

Purpose :-

We can achieve file upload either using any of the below options

  • File Upload using html input file field with Jquery Ajax to call server side web api
  • File Upload using MVC Razor Html.BeginForm to call asp.net mvc acction controller or web api
Below code base cover above implementation.


Key technical specifications :-


  1. Enctype =multipart/form-data
  2. List if using out of box asp.net
  3. Request.Form pass through Ajax Jquery or some sort of js library to read file in asp.net
  4. MultiPartFormBoundary 
  5. ContentType MediaTypeHeaderValue("application/octet-stream")

Implementation



<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
    $(function () {
        $("#Upload").click(function () {
            var xhr = new XMLHttpRequest();
            var fd = new FormData($(this));
            var files = document.getElementById('fileInput').files;
            for (var i = 0; i < files.length; i++) {
                fd.append("file" + i, document.getElementById('fileInput').files[i]);
            }
            fd.append("title", "File Upload Proof of concepts");
            xhr.open("POST", "/api/SomeController/TestUpload", true);
            xhr.send(fd);
            xhr.addEventListener("load", function (event) {
               
            }, false);
        });
    });
</script>
<div>
       <h1>Attached Supporting Documents</h1>
       
<!--Client side Jquery Ajax file upload option-->
       <fieldset>
           <legend>Please attached your detailed invoice, receipt and certificate as required.</legend>
           <form name="form1" id="frm" method="post" enctype="multipart/form-data">
               <label for="file">Filename:</label>
               <input type="file" id="fileInput" multiple="multiple" />
               <input type='button' id='Upload' value="Upload" />
           </form>
           <legend>You must attach these in either.Jpeg,GIF, PNG or PDF(Maximum 3MB in total) before you can send your claim.</legend>
       </fieldset>
       <!--MVC Razor Server side file upload option 2-->
       @using (Html.BeginRouteForm("myBupa_api", new { controller = "SomeController", action = "TestClaimUpload" }, FormMethod.Post, 
new { enctype = "multipart/form-data" }))
       {
           <span>Select File:</span>
           <input type="file" name="postedFiles" multiple="multiple" />
           <hr />
           <input type="submit" value="Upload" />
           <br />
       }
   </div>
[HttpPost]
      public virtual JsonResult TestUpload(List<System.Web.HttpPostedFileBase> postedFiles)
      {
//Handle above input parameter filecollection if used Html.BeginRouteForm
CancellationToken cancellationToken = default(CancellationToken)
//Handle if call is made through Ajax JQuery
          if (Request.Files != null)
          {
              postedFiles = new List<System.Web.HttpPostedFileBase>();
              for (int i = 0; i < Request.Files.Count; i++)
              {
                  postedFiles.Add(Request.Files[i]);
              }
          }
// Construct URL
       
         var _url = new Uri("http://some web api url to be post to");
        
         // Create HTTP transport objects
         HttpRequestMessage _httpRequest = new HttpRequestMessage();
         HttpResponseMessage _httpResponse = null;
         _httpRequest.Method = new HttpMethod("POST");
         _httpRequest.RequestUri = new Uri(_url);
         // Set if there is any Headers
         _httpRequest.Headers.TryAddWithoutValidation("X-Some-Session-Header", xCorrelationSession);
        
         _httpRequest.Headers.TryAddWithoutValidation("X-Some-Correlation-Request", xCorrelationRequest);
        //Set Custom Header if any key value
         // Serialize Request
         string _requestContent = null;
         var MultiPartFormBoundary = "-----------------------------17599237688550";
         var MultipartContentType = "multipart/form-data";
         MultipartFormDataContent _multiPartContent = new MultipartFormDataContent(MultiPartFormBoundary);
//JsonData may be some form field data
         if (jsonData != null)
         {
             StringContent _jsonData = new StringContent(SafeJsonConvert.SerializeObject(jsonData, this.Client.SerializationSettings).Trim('"'), 
Encoding.UTF8);
             _multiPartContent.Add(_jsonData, "jsonData");
         }
         if (postedFiles!= null)
         {
             foreach (var file in postedFiles)
             {                         
                 StreamContent _file = new StreamContent(file.InputStream);
                 var encodedUploadSafeFileName = WebUtility.UrlEncode(file.FileName).Replace("(", "").Replace(")", "");
                 _file.Headers.Add("Content-Disposition", $"form-data; name=\"Receipts\"; filename={encodedUploadSafeFileName}");
                 _file.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                 _multiPartContent.Add(_file, "attachment", file.FileName);
             }
         }
       
         var multiPartStream = await _multiPartContent.ReadAsStreamAsync();
         var content = new StreamContent(multiPartStream);
            content.Headers.Add("Content-Type", $"{MultipartContentType}; boundary={MultiPartFormBoundary}");
         var progressContent = content;
         _httpRequest.Content = progressContent;
          
cancellationToken.ThrowIfCancellationRequested();
         _httpResponse = await this.Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false);
                 
HttpStatusCode _statusCode = _httpResponse.StatusCode;
         cancellationToken.ThrowIfCancellationRequested();
         string _responseContent = null;
         if ((int)_statusCode == 400)
         {
            var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode));
             _responseContent = _httpResponse.Content.AsString();
             ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent);
             _httpRequest.Dispose();
             if (_httpResponse != null)
             {
                 _httpResponse.Dispose();
             }
             throw ex;
         }
         if ((int)_statusCode != 200 && (int)_statusCode != 400)
         {
             var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode));
             ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent);
             _responseContent = _httpResponse.Content.AsString();
             ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent);
            _httpRequest.Dispose();
             if (_httpResponse != null)
             {
                 _httpResponse.Dispose();
             }
             throw ex;
         }
         // Create Result
         var _result = new HttpOperationResponse<SomeObject>();
         _result.Request = _httpRequest;
         _result.Response = _httpResponse;
         // Deserialize Response
         if ((int)_statusCode == 200)
         {
             _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
             try
             {
                 _result.Body = SafeJsonConvert.DeserializeObject<SomeObject>(_responseContent, this.Client.DeserializationSettings);
             }
             catch (JsonException ex)
             {
                 _httpRequest.Dispose();
                 if (_httpResponse != null)
                 {
                     _httpResponse.Dispose();
                 }
                 throw new SerializationException("Unable to deserialize the response.", _responseContent, ex);
             }
         }
/*         
if (_shouldTrace)
         {
             ServiceClientTracing.Exit(_invocationId, _result);
         }*/
         return _result;
}