Sending Data to a Android Device through, USB-Connection - c#

First, thank you for reading my Post. I am currently working in my Thesis and need to implement a WPF-Application, which can send Data to a Android Device on the Public Folder. The app communicates with a App on the Android Device(exactly a Scanner). A Part of the WPF already existed, the WPF can read the Data, which are on the Scanners public folder stored. It is using the https://github.com/jtorjo/external_drive_lib. And i need help on how i can create a Method to send (Create) and update the Data on the PC, which i am inputing on the WPF with textboxes. So that they get stored on the Android Device and are visble.
Here is some Code from a AndroidDeviceService Class, which only reads the Data from the public folder:
//Gets all the connected android devices
private List<AndroidDevice> GetAndroidDevices()
{
List<IDrive> androidDrives = drive_root.inst.drives.Where(d => d.type.is_portable() && d.type.is_android() && d.is_connected()).ToList();
List<AndroidDevice> scannerAppDevices = new List<AndroidDevice>();
foreach (var drive in androidDrives)
{
scannerAppDevices.Add(new AndroidDevice(drive));
}
return scannerAppDevices;
}
//Tries to get a folder on the drive or returns null
public IFolder TryToGetFolder(IDrive drive, string folderPath)
{
if (drive.is_connected())
{
try
{
return drive.try_parse_folder(folderPath);
}
catch
{
return null;
}
}
else
return null;
}
//Tries to get a file in a folder or returns null
public IFile TryToGetFile(IFolder folder, string filename)
{
return folder.files.Where(f => f.name == filename).FirstOrDefault();
}
//Tries to read the text of a file or returns null
public string TryToGetFileText(IFile file)
{
//Uses the tempDir to copy the file to it
string tempDir = _tempDir + "temp-" + DateTime.Now.Ticks;
Directory.CreateDirectory(tempDir);
file.copy_sync(tempDir);
//Read file from tempDir
StreamReader reader = new StreamReader(tempDir + "\\" + file.name);
return reader.ReadToEnd();
}
//Tries to delete a file
public void TryToDeleteFile(IFile file)
{
if(file != null)
{
if (file.exists)
file.delete_sync();
}
}
Then i am using the methods in the ScannerAppCommunicationService:
/*
* Takes an AndroidDevice, gets the communication file, deserialize it and returns a List of CWCProducts
*/
public List<CWCProduct> GetProductsFromScanner(AndroidDevice scannerAppDevice)
{
IFile file = GetScannerAppFile(scannerAppDevice, CWC_FILENAME);
if (file == null)
throw new NoFileOnScannerException("No File, therefore no Products on the Scanner!");
try
{
string fileText = _deviceService.TryToGetFileText(file);
CWCFile cwcFile = Utilities.JsonDeserialize<CWCFile>(fileText);
return cwcFile.products.ToCWCProducts();
}
catch
{
throw new FileDecodeException($"Decoding Text from {CWC_FILENAME} File failed!");
}
}
//Deletes the communication file from the AndroidDevice
public void DeleteProductsOnScanner(AndroidDevice scannerAppDevice)
{
IFile file = GetScannerAppFile(scannerAppDevice, CWC_FILENAME);
if (file == null)
throw new NoFileOnScannerException("No File, therefore no Products on the Scanner!");
_deviceService.TryToDeleteFile(file);
}
//Gets a file from the public ScannerApp folder on the AndroidDevice
private IFile GetScannerAppFile(AndroidDevice scannerAppDevice, string filename)
{
IFolder folder = _deviceService.TryToGetFolder(scannerAppDevice.Drive, SCANNERAPP_FOLDERNAME);
if (folder == null)
throw new ScannerAppNotFoundOnDeviceException("ScannerApp not found on this device or the device has been disconnected!");
return _deviceService.TryToGetFile(folder, filename);
}
I already tried some Methods:
`//Tries to Send a file from the WPF to the Android Device
public bool SendFileToAndroid(AndroidDevice device, string filePath, string destinationFolder)
{
if (!device.Drive.is_connected())
return false;
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "adb",
Arguments = $"push {filePath} {destinationFolder}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
process.WaitForExit();
return true;
}
catch
{
return false;
}
}
//Trys to Update a File on the Android Advice
public bool TryToUpdateFile(AndroidDevice scannerAppDevice, string destinationFolder)
{
string filePath = "";
IFolder folder = scannerAppDevice.Drive.try_parse_folder(filePath);
IFile file = TryToGetFile(folder, filePath);
if (file != null)
{
//Delete the old file
TryToDeleteFile(file);
}
//Send the new file
return SendFileToAndroid(scannerAppDevice, filePath, destinationFolder);
}`
//Creates a File in the Public Folder of the Adroid Advice
public void CreateFileInPublicFolder(AndroidDevice scannerAppDevice, object data)
{
// Serialize the data to json
string jsonData = Utilities.JsonSerialize(data);
// Create a temporary file to store the json data
string tempFilePath = Path.GetTempPath() + "tempJsonFile.json";
File.WriteAllText(tempFilePath, jsonData);
// Set the destination folder for the file
string destinationFolder = SCANNERAPP_FOLDERNAME;
// Send the file to the android device
if (!_deviceService.SendFileToAndroid(scannerAppDevice, tempFilePath, destinationFolder))
{
throw new FileTransferException("Error while trying to transfer the file to the android device");
}
// Delete the temporary file
File.Delete(tempFilePath);
}
public void UpdateFileOnScanner(AndroidDevice scannerAppDevice, string newFileContent)
{
IFile file = GetScannerAppFile(scannerAppDevice, CWC_FILENAME);
if (file == null)
throw new NoFileOnScannerException("File not found on the scanner!");
try
{
_deviceService.TryToUpdateFile(scannerAppDevice, newFileContent);
}
catch
{
throw new FileUpdateException($"Failed to update file {CWC_FILENAME} on the scanner!");
}
}

Related

Is that possible to find a file in SharePoint site without specifying the drive contains it?

I'm now getting a file from specific drive on SharePoint,but the customer asked to search for the file without specifying a drive.
public static byte[] SharePointDownload(string token, string fileName, string sharepointTargetLibrary)
{
string baseSiteId = GetSiteId(token);
string folderId;
if (string.IsNullOrEmpty(baseSiteId))
{
return null;
}
else
{
folderId = GetFolderId(token, baseSiteId, sharepointTargetLibrary);
if (string.IsNullOrEmpty(folderId))
{
return null;
}
}
try
{
WebClient wc = new WebClient();
byte[] result;
wc.Headers[HttpRequestHeader.Authorization] = "Bearer " + token;
wc.Headers[HttpRequestHeader.Accept] = "application/json";
result = wc.DownloadData(string.Format(#"https://graph.microsoft.com/v1.0/sites/{0}/drives/{1}/root:/{2}:/content", baseSiteId, folderId, fileName));
wc.Dispose();
if (result.Length>0)
{
return result;
}
else
{
return null;
}
}
catch (Exception ex)
{
LoggerHelper.Log(ex.Message);
return null;
}
}
now i want to know if this line
result=wc.DownloadData(string.Format(#"https://graph.microsoft.com/v1.0/sites/{0}/drives/{1}/root:/{2}:/content", baseSiteId, folderId, fileName));
can get rid of folderId and searches with the fileName only specified
Using Microsoft Graph, you search a drive
GET /sites/{site-id}/drive/root/search(q='{search-text}')

Cannot access disposed object application connecting to WebAPI

I have content of video and object being created an pass into a http client web api. When ever I pass the image to the client it works find it gets to the post method, but when it comes to the video the client has trouble posting the video. I checked the video size length to make sure it meets the content length and it well under the specific ranges. The error that I receive is that the object has been disposed. If you look at the code the object is never disposed.
Here's the code on the app
public async Task<bool> AddToQueueAsync(Incident i, ContentPage page, MediaFile file)
{
HttpResponseMessage result = null;
Uri webserviceURL = i.IncidentType == IncidentType.Trooper ? trooperURL : gspURL;
var fileStream = File.Open(file.Path, FileMode.Open);
try
{
using (var client = new HttpClient())
{
using (fileStream)
{
using (var stream = new StreamContent(fileStream))
{
using (var content = new MultipartFormDataContent("----MyBoundary"))
{
if(i.MediaType == "Video")
{
content.Add(stream,"file", Guid.NewGuid().ToString() + ".mp4");
}
else
{
content.Add(stream, "file", Guid.NewGuid().ToString() + ".png");
}
content.Add(new StringContent(JsonConvert.SerializeObject(i)), "metadata");
result = await client.PostAsync(webserviceURL, content);
}
}
}
}
Here is the code on the web api:
[HttpPost]
public IHttpActionResult StarGSPDATA() {
try {
if(!Request.Content.IsMimeMultipartContent()) {
Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
starGSPDATAinfo suspicousInfo;
string homeDir = AppDomain.CurrentDomain.BaseDirectory;
string dir = $"{homeDir}/uploads/";
Directory.CreateDirectory(dir);
var file = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files[0] : null;
if(HttpContext.Current.Request.Form.Count > 0) {
suspicousInfo = MetaDataFromRequest(HttpContext.Current.Request.Form);
} else {
suspicousInfo = new starGSPDATAinfo();
}
if(file != null && file.ContentLength > 0) {
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(dir, fileName);
suspicousInfo.MediaFilePath = fileName;
try {
file.SaveAs(path);
} catch(Exception e) {
Console.WriteLine($"not saving: {e.ToString()}");
}
} else {
throw new HttpResponseException(
new HttpResponseMessage(
HttpStatusCode.NoContent));
}
CleanData(suspicousInfo);
db.starGSPDATAinfoes.Add(suspicousInfo);
db.SaveChanges();
return Created("http://localhost:50641/api/StarGSPDATA/", JsonConvert.SerializeObject(suspicousInfo));
} catch(Exception e) {
return InternalServerError(e);
}
}
It works for an image but not for a video Please help thank you!
Here is a picture of the error

Web API Upload Files

I have some data to save into a database.
I have created a web api post method to save data. Following is my post method:
[Route("PostRequirementTypeProcessing")]
public IEnumerable<NPAAddRequirementTypeProcessing> PostRequirementTypeProcessing(mdlAddAddRequirementTypeProcessing requTypeProcess)
{
mdlAddAddRequirementTypeProcessing rTyeProcessing = new mdlAddAddRequirementTypeProcessing();
rTyeProcessing.szDescription = requTypeProcess.szDescription;
rTyeProcessing.iRequirementTypeId = requTypeProcess.iRequirementTypeId;
rTyeProcessing.szRequirementNumber = requTypeProcess.szRequirementNumber;
rTyeProcessing.szRequirementIssuer = requTypeProcess.szRequirementIssuer;
rTyeProcessing.szOrganization = requTypeProcess.szOrganization;
rTyeProcessing.dIssuedate = requTypeProcess.dIssuedate;
rTyeProcessing.dExpirydate = requTypeProcess.dExpirydate;
rTyeProcessing.szSignedBy = requTypeProcess.szSignedBy;
rTyeProcessing.szAttachedDocumentNo = requTypeProcess.szAttachedDocumentNo;
if (String.IsNullOrEmpty(rTyeProcessing.szAttachedDocumentNo))
{
}
else
{
UploadFile();
}
rTyeProcessing.szSubject = requTypeProcess.szSubject;
rTyeProcessing.iApplicationDetailsId = requTypeProcess.iApplicationDetailsId;
rTyeProcessing.iEmpId = requTypeProcess.iEmpId;
NPAEntities context = new NPAEntities();
Log.Debug("PostRequirementTypeProcessing Request traced");
var newRTP = context.NPAAddRequirementTypeProcessing(requTypeProcess.szDescription, requTypeProcess.iRequirementTypeId,
requTypeProcess.szRequirementNumber, requTypeProcess.szRequirementIssuer, requTypeProcess.szOrganization,
requTypeProcess.dIssuedate, requTypeProcess.dExpirydate, requTypeProcess.szSignedBy,
requTypeProcess.szAttachedDocumentNo, requTypeProcess.szSubject, requTypeProcess.iApplicationDetailsId,
requTypeProcess.iEmpId);
return newRTP.ToList();
}
There is a field called 'szAttachedDocumentNo' which is a document that's being saved in the database as well.
After saving all data, I want the physical file of the 'szAttachedDocumentNo' to be saved on the server. So i created a method called "UploadFile" as follows:
[HttpPost]
public void UploadFile()
{
if (HttpContext.Current.Request.Files.AllKeys.Any())
{
// Get the uploaded file from the Files collection
var httpPostedFile = HttpContext.Current.Request.Files["UploadedFile"];
if (httpPostedFile != null)
{
// Validate the uploaded image(optional)
string folderPath = HttpContext.Current.Server.MapPath("~/UploadedFiles");
//string folderPath1 = Convert.ToString(ConfigurationManager.AppSettings["DocPath"]);
//Directory not exists then create new directory
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
// Get the complete file path
var fileSavePath = Path.Combine(folderPath, httpPostedFile.FileName);
// Save the uploaded file to "UploadedFiles" folder
httpPostedFile.SaveAs(fileSavePath);
}
}
}
Before running the project, i debbugged the post method, so when it comes to "UploadFile" line, it takes me to its method.
From the file line, it skipped the remaining lines and went to the last line; what means it didn't see any file.
I am able to save everything to the database, just that i didn't see the physical file in the specified location.
Any help would be much appreciated.
Regards,
Somad
Makes sure the request "content-type": "multipart/form-data" is set
[HttpPost()]
public async Task<IHttpActionResult> UploadFile()
{
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
try
{
MultipartMemoryStreamProvider provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
if (provider.Contents != null && provider.Contents.Count == 0)
{
return BadRequest("No files provided.");
}
foreach (HttpContent file in provider.Contents)
{
string filename = file.Headers.ContentDisposition.FileName.Trim('\"');
byte[] buffer = await file.ReadAsByteArrayAsync();
using (MemoryStream stream = new MemoryStream(buffer))
{
// save the file whereever you want
}
}
return Ok("files Uploded");
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}

c# sync only new files to amazon s3

I'm uploading all my local files to s3 using this code:
static string bucketName = "s3bucket";
static string directoryPath = #"C:\data\";
private void btnUpload_Click(object sender, EventArgs e) {
try {
TransferUtility directoryTransferUtility =
new TransferUtility(new AmazonS3Client(Amazon.RegionEndpoint.USWest2));
TransferUtilityUploadDirectoryRequest request =
new TransferUtilityUploadDirectoryRequest {
BucketName = bucketName,
Directory = directoryPath,
SearchPattern = "*.xml"
};
directoryTransferUtility.UploadDirectory(request);
MessageBox.Show("Upload completed");
} catch (AmazonS3Exception ex) {
MessageBox.Show(ex.Message);
}
}
If I run the code again all files are re-uploaded to s3 and that's a bad idea if let's say we have 1000+ files in our local directory.
I know I can compare file by file because aws stores the md5 of each file. So my question is can I do this with a command that comes preinstalled? Do I have to recursively compare file by file? If the sync command exists on awscli bundle (aws s3 sync ./sourceDir s3://bucketname/) does it exists on c# as well?
All the files will be replaced. S3 docs , but if you still want to check files you can use some function like this
ListObjectsRequest request = new ListObjectsRequest()
{
BucketName = "Your Bucket name",
Delimiter = "/",
Prefix = "location"
};
public bool CheckFile(ListObjectsRequest request)
{
bool res = false;
try
{
ListObjectsResponse response = s3client.ListObjects(request);
if (response.S3Objects != null && response.S3Objects.Count > 0)
{
S3Object o = response.S3Objects.Where(x => x.Size != 0 && x.LastModified > DateTime.Now.AddHours(-24)).FirstOrDefault();
if (o != null)
{
//you can use thes fields
// o.Key; //o.Size, //o.LastModified
res = true;
}
}
else
{
res = false;
}
}
catch (Exception)
{
throw;
}
return res;
}

EntityTooSmall in CompleteMultipartUploadResponse

using .NET SDK v.1.5.21.0
I'm trying to upload a large file (63Mb) and I'm following the example at:
http://docs.aws.amazon.com/AmazonS3/latest/dev/LLuploadFileDotNet.html
But using a helper instead the hole code and using jQuery File Upload
https://github.com/blueimp/jQuery-File-Upload/blob/master/basic-plus.html
what I have is:
string bucket = "mybucket";
long totalSize = long.Parse(context.Request.Headers["X-File-Size"]),
maxChunkSize = long.Parse(context.Request.Headers["X-File-MaxChunkSize"]),
uploadedBytes = long.Parse(context.Request.Headers["X-File-UloadedBytes"]),
partNumber = uploadedBytes / maxChunkSize + 1,
fileSize = partNumber * inputStream.Length;
bool lastPart = inputStream.Length < maxChunkSize;
// http://docs.aws.amazon.com/AmazonS3/latest/dev/LLuploadFileDotNet.html
if (partNumber == 1) // initialize upload
{
iView.Utilities.Amazon_S3.S3MultipartUpload.InitializePartToCloud(fileName, bucket);
}
try
{
// upload part
iView.Utilities.Amazon_S3.S3MultipartUpload.UploadPartToCloud(fs, fileName, bucket, (int)partNumber, uploadedBytes, maxChunkSize);
if (lastPart)
// wrap it up and go home
iView.Utilities.Amazon_S3.S3MultipartUpload.CompletePartToCloud(fileName, bucket);
}
catch (System.Exception ex)
{
// Huston, we have a problem!
//Console.WriteLine("Exception occurred: {0}", exception.Message);
iView.Utilities.Amazon_S3.S3MultipartUpload.AbortPartToCloud(fileName, bucket);
}
and
public static class S3MultipartUpload
{
private static string accessKey = System.Configuration.ConfigurationManager.AppSettings["AWSAccessKey"];
private static string secretAccessKey = System.Configuration.ConfigurationManager.AppSettings["AWSSecretKey"];
private static AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretAccessKey);
public static InitiateMultipartUploadResponse initResponse;
public static List<UploadPartResponse> uploadResponses;
public static void InitializePartToCloud(string destinationFilename, string destinationBucket)
{
// 1. Initialize.
uploadResponses = new List<UploadPartResponse>();
InitiateMultipartUploadRequest initRequest =
new InitiateMultipartUploadRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'));
initResponse = client.InitiateMultipartUpload(initRequest);
}
public static void UploadPartToCloud(Stream fileStream, string destinationFilename, string destinationBucket, int partNumber, long uploadedBytes, long maxChunkedBytes)
{
// 2. Upload Parts.
UploadPartRequest request = new UploadPartRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'))
.WithUploadId(initResponse.UploadId)
.WithPartNumber(partNumber)
.WithPartSize(maxChunkedBytes)
.WithFilePosition(uploadedBytes)
.WithInputStream(fileStream) as UploadPartRequest;
uploadResponses.Add(client.UploadPart(request));
}
public static void CompletePartToCloud(string destinationFilename, string destinationBucket)
{
// Step 3: complete.
CompleteMultipartUploadRequest compRequest =
new CompleteMultipartUploadRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'))
.WithUploadId(initResponse.UploadId)
.WithPartETags(uploadResponses);
CompleteMultipartUploadResponse completeUploadResponse =
client.CompleteMultipartUpload(compRequest);
}
public static void AbortPartToCloud(string destinationFilename, string destinationBucket)
{
// abort.
client.AbortMultipartUpload(new AbortMultipartUploadRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'))
.WithUploadId(initResponse.UploadId));
}
}
my maxChunckedSize is 6Mb (6 * (1024*1024)) as I have read that the minimum is 5Mb...
why am I getting "Your proposed upload is smaller than the minimum allowed size" exception? What am I doing wrong?
The error is:
<Error>
<Code>EntityTooSmall</Code>
<Message>Your proposed upload is smaller than the minimum allowed size</Message>
<ETag>d41d8cd98f00b204e9800998ecf8427e</ETag>
<MinSizeAllowed>5242880</MinSizeAllowed>
<ProposedSize>0</ProposedSize>
<RequestId>C70E7A23C87CE5FC</RequestId>
<HostId>pmhuMXdRBSaCDxsQTHzucV5eUNcDORvKY0L4ZLMRBz7Ch1DeMh7BtQ6mmfBCLPM2</HostId>
<PartNumber>1</PartNumber>
</Error>
How can I get ProposedSize if I'm passing the stream and stream length?
Here is a working solution for the latest Amazon SDK (as today: v.1.5.37.0)
Amazon S3 Multipart Upload works like:
Initialize the request using client.InitiateMultipartUpload(initRequest)
Send chunks of the file (loop until the end) using client.UploadPart(request)
Complete the request using client.CompleteMultipartUpload(compRequest)
If anything goes wrong, remember to dispose the client and request, as well fire the abort command using client.AbortMultipartUpload(abortMultipartUploadRequest)
I keep the client in Session as we need this for each chunk upload as well, keep an hold of the ETags that are now used to complete the process.
You can see an example and simple way of doing this in Amazon Docs itself, I ended up having a class to do everything, plus, I have integrated with the lovely jQuery File Upload plugin (Handler code below as well).
The S3MultipartUpload is as follow
public class S3MultipartUpload : IDisposable
{
string accessKey = System.Configuration.ConfigurationManager.AppSettings.Get("AWSAccessKey");
string secretAccessKey = System.Configuration.ConfigurationManager.AppSettings.Get("AWSSecretKey");
AmazonS3 client;
public string OriginalFilename { get; set; }
public string DestinationFilename { get; set; }
public string DestinationBucket { get; set; }
public InitiateMultipartUploadResponse initResponse;
public List<PartETag> uploadPartETags;
public string UploadId { get; private set; }
public S3MultipartUpload(string destinationFilename, string destinationBucket)
{
if (client == null)
{
System.Net.WebRequest.DefaultWebProxy = null; // disable proxy to make upload quicker
client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretAccessKey, new AmazonS3Config()
{
RegionEndpoint = Amazon.RegionEndpoint.EUWest1,
CommunicationProtocol = Protocol.HTTP
});
this.OriginalFilename = destinationFilename.TrimStart('/');
this.DestinationFilename = string.Format("{0:yyyy}{0:MM}{0:dd}{0:HH}{0:mm}{0:ss}{0:fffff}_{1}", DateTime.UtcNow, this.OriginalFilename);
this.DestinationBucket = destinationBucket;
this.InitializePartToCloud();
}
}
private void InitializePartToCloud()
{
// 1. Initialize.
uploadPartETags = new List<PartETag>();
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest();
initRequest.BucketName = this.DestinationBucket;
initRequest.Key = this.DestinationFilename;
// make it public
initRequest.AddHeader("x-amz-acl", "public-read");
initResponse = client.InitiateMultipartUpload(initRequest);
}
public void UploadPartToCloud(Stream fileStream, long uploadedBytes, long maxChunkedBytes)
{
int partNumber = uploadPartETags.Count() + 1; // current part
// 2. Upload Parts.
UploadPartRequest request = new UploadPartRequest();
request.BucketName = this.DestinationBucket;
request.Key = this.DestinationFilename;
request.UploadId = initResponse.UploadId;
request.PartNumber = partNumber;
request.PartSize = fileStream.Length;
//request.FilePosition = uploadedBytes // remove this line?
request.InputStream = fileStream; // as UploadPartRequest;
var up = client.UploadPart(request);
uploadPartETags.Add(new PartETag() { ETag = up.ETag, PartNumber = partNumber });
}
public string CompletePartToCloud()
{
// Step 3: complete.
CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest();
compRequest.BucketName = this.DestinationBucket;
compRequest.Key = this.DestinationFilename;
compRequest.UploadId = initResponse.UploadId;
compRequest.PartETags = uploadPartETags;
string r = "Something went badly wrong";
using (CompleteMultipartUploadResponse completeUploadResponse = client.CompleteMultipartUpload(compRequest))
r = completeUploadResponse.ResponseXml;
return r;
}
public void AbortPartToCloud()
{
// abort.
client.AbortMultipartUpload(new AbortMultipartUploadRequest()
{
BucketName = this.DestinationBucket,
Key = this.DestinationFilename,
UploadId = initResponse.UploadId
});
}
public void Dispose()
{
if (client != null) client.Dispose();
if (initResponse != null) initResponse.Dispose();
}
}
I use DestinationFilename as the destination file so I can avoid the same name, but I keep the OriginalFilename as I needed later.
Using jQuery File Upload Plugin, all works inside a Generic Handler, and the process is something like this:
// Upload partial file
private void UploadPartialFile(string fileName, HttpContext context, List<FilesStatus> statuses)
{
if (context.Request.Files.Count != 1)
throw new HttpRequestValidationException("Attempt to upload chunked file containing more than one fragment per request");
var inputStream = context.Request.Files[0].InputStream;
string contentRange = context.Request.Headers["Content-Range"]; // "bytes 0-6291455/14130271"
int fileSize = int.Parse(contentRange.Split('/')[1]);,
maxChunkSize = int.Parse(context.Request.Headers["X-Max-Chunk-Size"]),
uploadedBytes = int.Parse(contentRange.Replace("bytes ", "").Split('-')[0]);
iView.Utilities.AWS.S3MultipartUpload s3Upload = null;
try
{
// ######################################################################################
// 1. Initialize Amazon S3 Client
if (uploadedBytes == 0)
{
HttpContext.Current.Session["s3-upload"] = new iView.Utilities.AWS.S3MultipartUpload(fileName, awsBucket);
s3Upload = (iView.Utilities.AWS.S3MultipartUpload)HttpContext.Current.Session["s3-upload"];
string msg = System.String.Format("Upload started: {0} ({1:N0}Mb)", s3Upload.DestinationFilename, (fileSize / 1024));
this.Log(msg);
}
// cast current session object
if (s3Upload == null)
s3Upload = (iView.Utilities.AWS.S3MultipartUpload)HttpContext.Current.Session["s3-upload"];
// ######################################################################################
// 2. Send Chunks
s3Upload.UploadPartToCloud(inputStream, uploadedBytes, maxChunkSize);
// ######################################################################################
// 3. Complete Upload
if (uploadedBytes + maxChunkSize > fileSize)
{
string completeRequest = s3Upload.CompletePartToCloud();
this.Log(completeRequest); // log S3 response
s3Upload.Dispose(); // dispose all objects
HttpContext.Current.Session["s3-upload"] = null; // we don't need this anymore
}
}
catch (System.Exception ex)
{
if (ex.InnerException != null)
while (ex.InnerException != null)
ex = ex.InnerException;
this.Log(string.Format("{0}\n\n{1}", ex.Message, ex.StackTrace)); // log error
s3Upload.AbortPartToCloud(); // abort current upload
s3Upload.Dispose(); // dispose all objects
statuses.Add(new FilesStatus(ex.Message));
return;
}
statuses.Add(new FilesStatus(s3Upload.DestinationFilename, fileSize, ""));
}
Keep in mind that to have a Session object inside a Generic Handler, you need to implement IRequiresSessionState so your handler will look like:
public class UploadHandlerSimple : IHttpHandler, IRequiresSessionState
Inside fileupload.js (under _initXHRData) I have added an extra header called X-Max-Chunk-Size so I can pass this to Amazon and calculate if it's the last part of the uploaded file.
Fell free to comment and make smart edits for everyone to use.
I guess you didn't set the content-length of the part inside the UploadPartToCloud() function.

Categories