I have an application written with Xamarin.iOS that causes files to be corrupted after they are downloaded into the application.
I am comparing checksums by download the file within the application, and then uploading the downloaded file to dropbox. I am then comparing the checksum of the dropbox file to the original file on the server.
Normally, the checksums match. Occasionally, the checksums do not match. These files are really videos, and it causes the videos to not be playable.
The Question
How can downloads (using HttpWebRequest) occasionally cause corrupted files, but continue to download successfully?
The Code
public class DownloadService : IDownloadService
{
private const int BufferSize = 1024*1024;
/// <summary>
/// Download a remote file to a local location.
/// </summary>
/// <param name="url">The url of the file to download.</param>
/// <param name="localPath">The local path to save the file.</param>
/// <param name="progress">The progress off the download (percentage|bytesread|totalbytes).</param>
/// <param name="cancel">A reference to a boolean that can be set to true if you want to cancel the download.</param>
/// <returns>
/// Returns the local file that was downloaded.
/// Use this instead of the localPath parameter because you may have passed no extension asking for us to autodetermine the extension.
/// </returns>
public string DownloadFile(string url, string localPath, Action<int, long, long> progress, ref bool cancel)
{
cancel = false;
var didCancel = false;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.ReadWriteTimeout = 3000;
var buffer = new byte[BufferSize];
var realPath = localPath;
try
{
using (var response = webRequest.GetResponse())
{
// get the total size of this request
var totalSize = 0;
try { totalSize = int.Parse(response.Headers["MediaItemLength"]);
}catch(Exception ex) { throw new NotImplementedException("Get the total size some other way!"); }
// ensure there is a proper extension
if (string.IsNullOrEmpty(Path.GetExtension(localPath)))
{
// the localpath given didn't have an extension.
// we need to try to determine the exention through custom HTTP headers.
string httpHeaderExtension = null;
try
{
httpHeaderExtension = response.Headers["MediaExtension"];
if (string.IsNullOrEmpty(httpHeaderExtension))
throw new Exception("The header was present, but it was empty.");
}
catch (Exception ex)
{
throw new Exception("localPath didn't provide an extension and we couldn't infer would through custom HTTP headers.");
}
// add the correct extension to our local file path
realPath += httpHeaderExtension;
}
if(File.Exists(realPath))
File.Delete(realPath);
using (var responseStream = response.GetResponseStream())
{
using (var dest = new FileStream(realPath, FileMode.CreateNew, FileAccess.Write))
{
long totalBytes = 0;
int currentBlockSize;
while ((currentBlockSize = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytes += currentBlockSize;
var percentage = (int)(totalBytes * 100.0 / totalSize);
dest.Write(buffer, 0, currentBlockSize);
if (progress != null)
progress(percentage, totalBytes, totalSize);
if (cancel)
{
didCancel = true;
break;
}
}
}
}
}
}catch(Exception ex)
{
// delete the file
if (File.Exists(realPath))
File.Delete(realPath);
throw;
}
// delete the file
if (didCancel && File.Exists(realPath))
File.Delete(realPath);
return realPath;
}
}
The code is pretty straight forward. I do include some additional/custom headers for getting the total file size so that I can avoid a HEAD request to get the value. I need the total file size for download progress.
Related
Can someone tell me why I keep getting a read and write timeout on this function? I have this as a code behind function on click even from a button. Everything as far as the data looks good until I get to the stream section and it still steps through, but when I check the Stream object contents after stepping into that object it states Read Timeout/Write Timeout: System invalid Operation Exception.
protected void SubmitToDB_Click(object sender, EventArgs e)
{
if (FileUploader.HasFile)
{
try
{
if (SectionDropDownList.SelectedValue != null)
{
if (TemplateDropDownList.SelectedValue != null)
{
// This gets the full file path on the client's machine ie: c:\test\myfile.txt
string strFilePath = FileUploader.PostedFile.FileName;
//use the System.IO Path.GetFileName method to get specifics about the file without needing to parse the path as a string
string strFileName = Path.GetFileName(strFilePath);
Int32 intFileSize = FileUploader.PostedFile.ContentLength;
string strContentType = FileUploader.PostedFile.ContentType;
//Convert the uploaded file to a byte stream to save to your database. This could be a database table field of type Image in SQL Server
Stream strmStream = FileUploader.PostedFile.InputStream;
Int32 intFileLength = (Int32)strmStream.Length;
byte[] bytUpfile = new byte[intFileLength + 1];
strmStream.Read(bytUpfile, 0, intFileLength);
strmStream.Close();
saveFileToDb(strFileName, intFileSize, strContentType, bytUpfile); // or use FileUploader.SaveAs(Server.MapPath(".") + "filename") to save to the server's filesystem.
lblUploadResult.Text = "Upload Success. File was uploaded and saved to the database.";
}
}
}
catch (Exception err)
{
lblUploadResult.Text = "The file was not updloaded because the following error happened: " + err.ToString();
}
}
else
{
lblUploadResult.Text = "No File Uploaded because none was selected.";
}
}
Try something like this:
using (var fileStream = FileUploader.PostedFile.InputStream)
{
using (var reader = new BinaryReader(fileStream))
{
byte[] bytUpfile = reader.ReadBytes((Int32)fileStream.Length);
// SAVE TO DB...
}
}
I know that NAudio.UWP is a work in progress but the newest release (1.8) does seem to have the ability to write a .wav.
private IWavePlayer player;
private WaveStream reader;
private IWaveIn recorder;
private MemoryStream recordStream;
private IRandomAccessStream selectedStream;
private void Record()
{
if (recorder == null)
{
recorder = new WasapiCaptureRT();
recorder.RecordingStopped += RecorderOnRecordingStopped;
recorder.DataAvailable += RecorderOnDataAvailable;
}
if (reader != null)
{
reader.Dispose();
reader = null;
}
recorder.StartRecording();
}
private async void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
Debug.WriteLine(waveInEventArgs.BytesRecorded);
if (reader == null)
{
recordStream = new MemoryStream();
reader = new RawSourceWaveStream(recordStream, recorder.WaveFormat);
}
await recordStream.WriteAsync(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}
Where/How do you create the Storage file name, path etc? There is no destination param...This is the only code that came with the example.
**Mark if you see this Chrome is blocking the 1.8 code download.
Where/How do you create the Storage file name, path etc?
It actually depends on your requirements. For example, you could use fixed name and timestamp to named your audio file.
var file = KnownFolders.MusicLibrary.CreateFileAsync("song"+DateTime.Now.ToString("yyyy-MM-DD-hh-mm-ss")+".wav",CreationCollisionOption.GenerateUniqueName);
You could copy record stream to a new file stream. For example:
var file = await KnownFolders.MusicLibrary.CreateFileAsync("test.wav");
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
recordStream.CopyTo(stream.AsStream());
}
In one of my Azure Web App Web API application, I am creating temp files using this code in a Get method
string path = Path.GetTempFileName();
// do some writing on this file. then read
var fileStream = File.OpenRead(path);
// then returning this stream as a HttpResponseMessage response
My question is, in a managed environment like this (not in VM), do I need to clear those temporary files by myself?
Shouldn't Azure itself supposed to clear those temp files?
Those files only get cleaned when your site is restarted.
If your site is running in Free or Shared mode, it only gets 300MB for temp files, so you could run out if you don't clean up.
If your site is in Basic or Standard mode, then there is significantly more space (around 200GB!). So you could probably get away with not cleaning up without running into the limit. Eventually, your site will get restarted (e.g. during platform upgrade), so things will get cleaned up.
See this page for some additional detail on this topic.
Maybey if you extend FileStream you can override dispose and remove it when disposed is called? That is how i'm resolving it for now. If i'm wrong let me know.
/// <summary>
/// Create a temporary file and removes its when the stream is closed.
/// </summary>
internal class TemporaryFileStream : FileStream
{
public TemporaryFileStream() : base(Path.GetTempFileName(), FileMode.Open)
{
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
// After the stream is closed, remove the file.
File.Delete(Name);
}
}
Following sample demonstrate how to save temp file in azure, both Path and Bolb.
Doc is here:https://code.msdn.microsoft.com/How-to-store-temp-files-in-d33bbb10
Code click here:https://github.com/Azure-Samples/storage-blob-dotnet-store-temp-files/archive/master.zip
Under part is the core logic of bolb code:
private long TotalLimitSizeOfTempFiles = 100 * 1024 * 1024;
private async Task SaveTempFile(string fileName, long contentLenght, Stream inputStream)
{
try
{
await container.CreateIfNotExistsAsync();
CloudBlockBlob tempFileBlob = container.GetBlockBlobReference(fileName);
tempFileBlob.DeleteIfExists();
await CleanStorageIfReachLimit(contentLenght);
tempFileBlob.UploadFromStream(inputStream);
}
catch (Exception ex)
{
if (ex.InnerException != null)
{
throw ex.InnerException;
}
else
{
throw ex;
}
}
}
private async Task CleanStorageIfReachLimit(long newFileLength)
{
List<CloudBlob> blobs = container.ListBlobs()
.OfType<CloudBlob>()
.OrderBy(m => m.Properties.LastModified)
.ToList();
long totalSize = blobs.Sum(m => m.Properties.Length);
long realLimetSize = TotalLimitSizeOfTempFiles - newFileLength;
foreach (CloudBlob item in blobs)
{
if (totalSize <= realLimetSize)
{
break;
}
await item.DeleteIfExistsAsync();
totalSize -= item.Properties.Length;
}
}
I've added storage file to my codenameone application. In some event I wanna delete specific storage file and recreate it with some old filtered data and new data. It doesn't work well on deletion.
First I create method for clear storage file in StorageManager class:
public void clearData(String pStorageTable){
Storage.getInstance().deleteStorageFile(pStorageTable);
}
In other class I use this method like this:
// load all data of specific storage file
// ...
new DBManager().clearData(ThreeTrans.DB_NAME);
// write old data with filtering of specific ID and new data
// ...
here is method of write data:
public void write(ThreeTrans pTT){
if(store == null) {
store = Storage.getInstance();
}
DB_NAME = "TT";
if(!store.exists(DB_NAME)) {
Hashtable depHash = new Hashtable();
String k = "1" + pTT.getNumber();
depHash.put(k, pTT.toString());
store.writeObject(DB_NAME, depHash);
}
else {
Hashtable depHash = (Hashtable)store.readObject(DB_NAME);
if (!depHash.containsValue(pTT.getNumber())) {
String k = String.valueOf(getLastKeyNumber());
depHash.put(k, pTT.toString());
store.writeObject(DB_NAME, depHash);
}
}
}
at first I was using this method for delete storage file:
public void clearData(String pStorageTable){
if(store == null) {
store = Storage.getInstance();
}
for (String str : store.listEntries()) {
if(str.toLowerCase().startsWith(pStorageTable)) {
store.deleteStorageFile(str);
}
}
}
and after this problem this method changed to this;
public void clearData(String pStorageTable){
Storage.getInstance().deleteStorageFile(pStorageTable);
}
I'm assuming that you didn't invoke close() on the output stream or the input stream working with the file and there is still a lock on the file. This is usually the case for such issues.
I am looking for some suggestion or sample around retrieving images (actual file, not URL), from a picture library using REST API.
Thanks for any input.
Task 1: Getting a List of Image libs on a given site
public static XmlNode GetPicLibListingXML(string imagingServiceURL)
{
Imaging wsImaging = new Imaging();
wsImaging.UseDefaultCredentials = true;
wsImaging.Url = imagingServiceURL;
XmlNode xnPicLibs = wsImaging.ListPictureLibrary();
return xnPicLibs;
}
Sample return XML:
<Library name="{3C1D52F5-5387-490A-9A2D-A9C99A208C00}" title="Tech Images" guid="3c1d52f5-5387-490a-9a2d-a9c99a208c00" url="Tech Images" xmlns="http://schemas.microsoft.com/sharepoint/soap/ois/" />
Task 2: Listing Images in a given library
public static XmlNode GetImageFileListing(string imagingServiceURL, string imageFileLibraryName)
{
Imaging wsImaging = new Imaging();
ImageInfo curImageInfo = new ImageInfo();
wsImaging.UseDefaultCredentials = true;
wsImaging.Url = imagingServiceURL;
XmlNode xnListItems = wsImaging.GetListItems(imageFileLibraryName, "");
return xnListItems;
}
Task 3: Download Image(s)
private const string ATTR_FILENAME = "name";
private const string FILENAMESPACEURI = "http://schemas.microsoft.com/sharepoint/soap/ois/";
public static bool DownloadImageFiles(string imagingServiceURL, string imageFileLibraryName, string[] fileNames, string saveToFolder)
{
Imaging wsImaging = new Imaging();
wsImaging.UseDefaultCredentials = true;
wsImaging.Url = imagingServiceURL;
XmlElement parent = (XmlElement)wsImaging.Download(imageFileLibraryName, string.Empty, fileNames, 0, true);
XmlNodeList files = parent.GetElementsByTagName("File", FILENAMESPACEURI);
foreach (XmlNode file in files)
{
if (Directory.Exists(saveToFolder) == false)
{
Directory.CreateDirectory(saveToFolder);
}
byte[] fileBytes = Convert.FromBase64String(file.InnerText);
using (FileStream fs = File.OpenWrite(saveToFolder + file.Attributes[ATTR_FILENAME].Value))
{
BinaryWriter writer = new BinaryWriter(fs);
writer.Write(fileBytes);
writer.Close();
}
}
return true;
}
Note:
Imaging() class is a web reference to imagining.asmx
The Download call natively returns XML so yo uneed to run it through a conversion to byte
If you need to get a reference on the Imagine web service check this on out on MSDN:
http://msdn.microsoft.com/en-us/library/imaging.imaging.aspx
source:
http://gourangaland.wordpress.com/2008/05/30/using-the-moss-imaging-web-service-to-download-imagesimaging-asmx/