Skip to content Skip to sidebar Skip to footer

Rest Api to Upload Large Files to Salesforce

Introduction

Sending large files to an MVC/Spider web-API Server can be problematic. This commodity is nigh an alternative. The approach used is to break a large file up into modest chunks, upload them, then merge them back together on the Server via file transfer past partitioning. The article shows how to ship files to an MVC Server from both a webpage using JavaScript, and a Spider web-course httpClient, and tin be implemented using either MVC or Web API.

In my experience, the larger the file you lot need to upload to a website/API, the bigger the potential problems yous encounter. Fifty-fifty when you put the correct settings in place, adapt your spider web.config, make certain you use the right multiplier for maxRequestLength and maxAllowedContentLength and of course don't forget nigh executionTimeout (eek!), things tin can still get incorrect. Connections can neglect when the file is *about* transferred, servers unexpectedly (Murphy'south constabulary) run out of space, etc., the list goes on. The diagram beneath demonstrates the basic concept discussed in this commodity.

Background

The concept for this solution is very elementary. The attached code works (I have information technology started in product), and tin can be improved by you in many ways. For instance, for the purposes of this article the original big file is broken into app. 1mb chunks, and uploaded to the server sequentially, one chunk at a time. This could, for example, be made more efficient by threading, and sending chunks in parallel. It could also be made more than robust past adding fault tolerance, machine-resume into a residual-api architecture etc. I leave you to implement these features yourself if yous need them.

The lawmaking consists of two parts - the initial file-split/partitioning into chunks, and the last merge of the chunks back into the original file. I will demonstrate the file-split using both C# in a web-course, and JavaScript, and the file-merge using C# server-side.

File split

The concept of splitting a file is very bones. We transverse the file in a binary stream, from position zero, upward to the concluding byte in the file, copying out chunks of binary data along the way and transferring these. Generally we gear up an arbitrary (or carefully thought out!) chunk size to extract, and use this every bit the amount of information to accept at a time. Anything left over at the end is the final clamper.

In the example below, a chunk size of 128b is set up. For the file shown, this gives us 3 x 128b chunks, and i ten 32b. In this example in that location are iv file chunks resulting from the split up and to transfer to the server.

C# File Split

The accompanying demo "WinFileUpload" is a unproblematic Windows forms application. Its sole function is to demonstrate splitting a sample big file (50 MB) in C#, and using a HTTPClient to post the file to a web-server (in this instance, an MVC Server).

For this C# instance, I have a class called Utils  that takes some input variables such as maximum file chunk size, temporary folder location, and the name of the file to split. To split the file into chunks, we call the method "SplitFile". SplitFile works its way through the input file and breaks information technology into carve up file chunks. Nosotros then upload each file clamper it using "UploadFile".

  1. Utils ut = new  Utils();
  2. ut.FileName ="hs-2004-15-b-full_tif.bmp" ;
  3. ut.TempFolder = Path.Combine(CurrentFolder,"Temp" );
  4. ut.MaxFileSizeMB = ane;
  5. ut.SplitFile();
  6. foreach  ( string  File in  ut.FileParts)
  7.   {
  8.     UploadFile(File);
  9.   }
  10. MessageBox.Bear witness("Upload complete!" );

The file upload method takes an input file-name, and uses a HTTPClient to upload the file. Annotation the fact that we are sending MultiPartFormData to behave the payload.

  1. public bool  UploadFile( string  FileName)
  2. {
  3. bool  rslt = false ;
  4. using  (var client = new  HttpClient())
  5.     {
  6. using  (var content = new  MultipartFormDataContent())
  7.         {
  8.          var fileContent =new    ByteArrayContent(Arrangement.IO.File.ReadAllBytes(FileName));
  9.          fileContent.Headers.ContentDisposition =new
  10.              ContentDispositionHeaderValue("zipper" )
  11.                {
  12.                 FileName = Path.GetFileName(FileName)
  13.                };
  14.          content.Add(fileContent);
  15.         var requestUri ="http://localhost:8170/Home/UploadFile/" ;
  16. try
  17.             {
  18.                 var event = client.PostAsync(requestUri, content).Effect;
  19.                 rslt =true ;
  20.             }
  21. catch  (Exception ex)
  22.             {
  23.                 rslt =false ;
  24.             }
  25.         }
  26.     }
  27. render  rslt;
  28. }

So, that's the supporting lawmaking out of the way. One of the critical things to be aware of adjacent is the file naming convention that is being used. It consists of the original file-name, plus a code-parsable tail "_part." that will be used server-side to merge the unlike file chunks dorsum into a single contiguous file again. This is simply the convention I put together - you can change it to your ain requirements, but be sure you lot are consistent with it.

The convention for this example is,

Name = original proper noun + ".part_N.Ten" (N = file role number, X = total files).

Here is an example of a picture show file split into three parts.

  1. MyPictureFile.jpg.part_1.3
  2. MyPictureFile.jpg.part_2.3
  3. MyPictureFile.jpg.part_3.iii

It doesn't thing what guild the file chunks are sent to the Server. The important thing is that some convention, like the above is used, so that the Server knows (a) what file part it is dealing with and (b) when all parts have been received and can be merged back into one large original file again.

Next, here is the meat of the C# lawmaking that scans the file, creating multiple chunk files ready to transfer.

  1. public bool  SplitFile()
  2. {
  3. bool  rslt = false ;
  4. string  BaseFileName = Path.GetFileName(FileName);
  5. int  BufferChunkSize = MaxFileSizeMB * (1024 * 1024);
  6. const int  READBUFFER_SIZE = 1024;
  7. byte [] FSBuffer = new byte [READBUFFER_SIZE];
  8. using  (FileStream FS = new  FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
  9.     {
  10. int  TotalFileParts = 0;
  11. if  (FS.Length < BufferChunkSize)
  12.         {
  13.             TotalFileParts = 1;
  14.         }
  15. else
  16.         {
  17. float  PreciseFileParts = (( float )FS.Length / ( float )BufferChunkSize);
  18.             TotalFileParts = (int )Math.Ceiling(PreciseFileParts);
  19.         }
  20. int  FilePartCount = 0;
  21. while  (FS.Position < FS.Length)
  22.         {
  23. string  FilePartName = String.Format( "{0}.part_{1}.{2}" ,
  24.             BaseFileName, (FilePartCount + 1).ToString(), TotalFileParts.ToString());
  25.             FilePartName = Path.Combine(TempFolder, FilePartName);
  26.             FileParts.Add(FilePartName);
  27. using  (FileStream FilePart = new  FileStream(FilePartName, FileMode.Create))
  28.             {
  29. int  bytesRemaining = BufferChunkSize;
  30. int  bytesRead = 0;
  31. while  (bytesRemaining > 0 && (bytesRead = FS.Read(FSBuffer, 0,
  32.                  Math.Min(bytesRemaining, READBUFFER_SIZE))) > 0)
  33.                 {
  34.                     FilePart.Write(FSBuffer, 0, bytesRead);
  35.                     bytesRemaining -= bytesRead;
  36.                 }
  37.             }
  38.           FilePartCount++;
  39.         }
  40.     }
  41. return  rslt;
  42. }

That'south it for the C# client-side - nosotros will run across the event and how to handle things server-side later on in the article. Adjacent, let'due south look at how to do the same thing in Javascript, from a web-browser.

JavaScript File Split

NB - The JavaScript code, and the C# Merge code are contained in the attached demo file "MVCServer"

In our browser, we take an input command of blazon "file", and a button to phone call a method that initiates the file-split up and data transfer.

  1. < input blazon = "file" id = "uploadFile" proper name = "file" /> < a class = "btn btn-primary" href = "#" id = "btnUpload" > Upload file </ a >

On document set up, we bind to the click effect of the button to call the main method.

  1. $(document).ready( function  () {
  2.     $('#btnUpload' ).click( part  () {
  3.         UploadFile($('#uploadFile' )[0].files);
  4.         }
  5.     )
  6. });

Our UploadFile method does the work of splitting the file into chunks, and every bit in our C# instance, passing the chunks off to another method for transfer. The main difference here is that in C#, we created individual files, in our JavaScript example, nosotros are taking the chunks from an assortment instead.

  1. office  UploadFile(TargetFile)
  2. {
  3. var  FileChunk = [];
  4. var  file = TargetFile[0];
  5. var  MaxFileSizeMB = 1;
  6. var  BufferChunkSize = MaxFileSizeMB * (1024 * 1024);
  7. var  ReadBuffer_Size = 1024;
  8. var  FileStreamPos = 0;
  9. var  EndPos = BufferChunkSize;
  10. var  Size = file.size;
  11. while  (FileStreamPos < Size)
  12.     {
  13.         FileChunk.push(file.piece(FileStreamPos, EndPos));
  14.         FileStreamPos = EndPos;
  15.         EndPos = FileStreamPos + BufferChunkSize;
  16.     }
  17. var  TotalParts = FileChunk.length;
  18. var  PartCount = 0;
  19. while  (chunk = FileChunk.shift())
  20.     {
  21.         PartCount++;
  22. var  FilePartName = file.proper name + ".part_"  + PartCount + "."  + TotalParts;
  23.         UploadFileChunk(chunk, FilePartName);
  24.     }
  25. }

The UploadFileChunk takes the office of the file handed by the previous method, and posts information technology to the Server in a similar manner to the C# instance.

  1. office UploadFileChunk(Chunk, FileName)
  2. {
  3.     var FD =new  FormData();
  4.     FD.suspend('file' , Chunk, FileName);
  5.     $.ajax({
  6.         type:"Mail service" ,
  7.         url:'http://localhost:8170/Home/UploadFile/' ,
  8.         contentType:simulated ,
  9.         processData:false ,
  10.         information: FD
  11.     });
  12. }

File merge

NB -The JavaScript code, and the C# Merge code are independent in the fastened demo file "MVCServer"

Over on the Server, be that MVC or Web-API, nosotros receive the private file chunks and need to merge them dorsum together again into the original file.

The commencement thing we exercise is put a standard Post handler in place to receive the file chunks being posted upwards to the Server. This code takes the input stream, and saves it to a temp folder using the file-name created by the client (C# or JavaScript). Once the file is saved, the code then calls the "MergeFile" method which checks if it has enough file chunks available yet to merge the file together. Annotation that this is merely the method I take used for this commodity. You may make up one's mind to handle the merge trigger differently, for example, running a task on a timer every few minutes, passing off to some other process, etc. It should exist inverse depending on your own required implementation.

  1. [HttpPost]
  2. public  HttpResponseMessage UploadFile()
  3. {
  4. foreach  ( cord  file in  Request.Files)
  5.     {
  6.         var FileDataContent = Asking.Files[file];
  7. if  (FileDataContent != goose egg  && FileDataContent.ContentLength > 0)
  8.         {
  9.             var stream = FileDataContent.InputStream;
  10.             var fileName = Path.GetFileName(FileDataContent.FileName);
  11.             var UploadPath = Server.MapPath("~/App_Data/uploads" );
  12.             Directory.CreateDirectory(UploadPath);
  13. string  path = Path.Combine(UploadPath, fileName);
  14. try
  15.             {
  16. if  (Organisation.IO.File.Exists(path))
  17.                     Organisation.IO.File.Delete(path);
  18. using  (var fileStream = Arrangement.IO.File.Create(path))
  19.                 {
  20.                     stream.CopyTo(fileStream);
  21.                 }
  22.                 Shared.Utils UT =new  Shared.Utils();
  23.                 UT.MergeFile(path);
  24.             }
  25. catch  (IOException ex)
  26.             {
  27.             }
  28.         }
  29.     }
  30. render new  HttpResponseMessage()
  31.     {
  32.         StatusCode = Organisation.Net.HttpStatusCode.OK,
  33.         Content =new  StringContent( "File uploaded." )
  34.     };
  35. }

Each time we call the MergeFile method, it get-go checks to run across if we take all of the file chunk parts required to merge the original file back together once again. It determines this by parsing the file-names. If all files are present, the method sorts them into the correct order, and then appends one to some other until the original file that was split, is back together over again.

  1. public bool  MergeFile( string  FileName)
  2. {
  3. bool  rslt = false ;
  4. string  partToken = ".part_" ;
  5. cord  baseFileName = FileName.Substring(0, FileName.IndexOf(partToken));
  6. string  trailingTokens = FileName.Substring(FileName.IndexOf(partToken) + partToken.Length);
  7. int  FileIndex = 0;
  8. int  FileCount = 0;
  9. int .TryParse(trailingTokens.Substring(0, trailingTokens.IndexOf( "." )), out  FileIndex);
  10. int .TryParse(trailingTokens.Substring(trailingTokens.IndexOf( "." ) + one), out  FileCount);
  11. cord  Searchpattern = Path.GetFileName(baseFileName) + partToken + "*" ;
  12. cord [] FilesList = Directory.GetFiles(Path.GetDirectoryName(FileName), Searchpattern);
  13. if  (FilesList.Count() == FileCount)
  14.     {
  15. if  (!MergeFileManager.Instance.InUse(baseFileName))
  16.         {
  17.             MergeFileManager.Instance.AddFile(baseFileName);
  18. if  (File.Exists(baseFileName))
  19.                 File.Delete(baseFileName);
  20.             List<SortedFile> MergeList =new  Listing<SortedFile>();
  21. foreach  ( string  File in  FilesList)
  22.             {
  23.                 SortedFile sFile =new  SortedFile();
  24.                 sFile.FileName = File;
  25.                 baseFileName = File.Substring(0, File.IndexOf(partToken));
  26.                 trailingTokens = File.Substring(File.IndexOf(partToken) + partToken.Length);
  27. int .TryParse(trailingTokens.
  28.                    Substring(0, trailingTokens.IndexOf("." )), out  FileIndex);
  29.                 sFile.FileOrder = FileIndex;
  30.                 MergeList.Add together(sFile);
  31.             }
  32.             var MergeOrder = MergeList.OrderBy(s => due south.FileOrder).ToList();
  33. using  (FileStream FS = new  FileStream(baseFileName, FileMode.Create))
  34.             {
  35. foreach  (var chunk in  MergeOrder)
  36.                 {
  37. try
  38.                     {
  39. using  (FileStream fileChunk =
  40. new  FileStream(chunk.FileName, FileMode.Open))
  41.                         {
  42.                             fileChunk.CopyTo(FS);
  43.                         }
  44.                     }
  45. catch  (IOException ex)
  46.                     {
  47.                     }
  48.                 }
  49.             }
  50.             rslt =true ;
  51.             MergeFileManager.Instance.RemoveFile(baseFileName);
  52.         }
  53.     }
  54. return  rslt;
  55. }

Using the file split on the client-side, and file-merge on the server-side, we now have a very workable solution for uploading large files in a more secure style than simply sending up in one large block of data. For testing, I used some large image files converted to a BMP from a hubble pic hither.

That'due south it - Happy uploading !

collinscapper1986.blogspot.com

Source: https://www.c-sharpcorner.com/article/upload-large-files-to-mvc-webapi-using-partitioning/

Post a Comment for "Rest Api to Upload Large Files to Salesforce"