XmlException only during high usage DataContractSerializer - serialization

I have a working windows 8 caching solution using DataContractSerializer that raises a XmlException "Unexpected end of file" only when the UI is being used 'quickly'.
public static class CachingData<T>
{
public static async void Save(T data, string filename, StorageFolder folder = null)
{
folder = folder ?? ApplicationData.Current.LocalFolder;
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream raStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outStream = raStream.GetOutputStreamAt(0))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(outStream.AsStreamForWrite(), data);
await outStream.FlushAsync();
}
}
}
catch (Exception exc)
{
throw exc;
}
}
public static async System.Threading.Tasks.Task<T> Load(string filename, StorageFolder folder = null)
{
folder = folder ?? ApplicationData.Current.LocalFolder;
T data = default(T);
StorageFile file = await folder.GetFileAsync(filename);
using (IInputStream inStream = await file.OpenSequentialReadAsync())
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
data = (T)serializer.ReadObject(inStream.AsStreamForRead());
}
return data;
}
}
e.g. user clicks on item in list CachingData.Load is called async via await, checks for FileNotEoundException and either loads the data from disk or from the network, serialising on completion.
After first loaded user selects another item in the list and cycle repeats.
The problem occurs when "After first loaded" becomes "does not wait for load" and the item selected is not available cached.
Not quite sure how to proceed or even how to debug, hoping that just ignoring will allow the app to continue(just withough the nice speed increase of caching)

Related

How do you upload 260kb PDF file to Azure Blob Storage using ASP.NET and .NET based Controller?

I currently am trying to upload a pdf file of size 260kb with Swagger UI and it doesnt work. If I try to do the same thing with a small 50kb Word file it works.
My controller code is:
[HttpPost()]
public async Task<IActionResult> Upload(IFormFile file)
{
var name = SanitizeFilename(file.FileName);
if (String.IsNullOrWhiteSpace(name))
{
throw new ArgumentException();
}
using (Stream stream = file.OpenReadStream())
{
await storage.Save(stream, name);
}
return Accepted();
}
My AzureBlobStorage class's save method is:
public async Task<Task> Save(Stream fileStream, string name)
{
var blobContainer = await GetBlobContainerAsync();
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(name);
var task = blockBlob.UploadFromStreamAsync(fileStream);
var success = task.IsCompletedSuccessfully;
return task;
//return blockBlob.UploadFromStreamAsync(fileStream);
}
Here is some of the debug windows:
This is from the controller of the word document:
This is from the controller of the PDF document:
Notice the red/pink lettering which is different.
This is from the AzureBlobStorage save method - word document:
This is from the AzureBlobStorage save method - pdf document:
I have read the IFormFile might not do continuous streaming but how do I know if that is the issue? And if it is, what is the preferred approach?
I am not following your logic here:
public async Task<Task> Save(Stream fileStream, string name)
{
var blobContainer = await GetBlobContainerAsync();
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(name);
var task = blockBlob.UploadFromStreamAsync(fileStream);
var success = task.IsCompletedSuccessfully;
return task;
//return blockBlob.UploadFromStreamAsync(fileStream);
}
This is the way it should be written:
public async Task Save(Stream fileStream, string name)
{
var blobContainer = await GetBlobContainerAsync();
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(name);
await blockBlob.UploadFromStreamAsync(fileStream);
}
You want to await for the task to finish here before you return.
Returning Task<Task> is slightly unorthodox and doesn't make sense for what you want to do here.
Also, keep in mind, if your file is really large, Kestrel server could give up on the request. There is a timeout in the range of around 90 seconds to complete the request. So, if uploading the file takes longer than 90 seconds, the caller could receive an error (but the upload will still finish).
Typically you will dump the file to the disk, then return an Accepted to the caller. Then post the file to a background queue to upload the file. More information about that here.

How to save zip compressed folder to disk asp.net core 3.0

I want to upload and save a zipped folder to a path on my disk drive using .net core 3.0 but the zipped folder is saving as 0bytes
[HttpPost]
[ValidateAntiForgeryToken()]
[RequestFormLimits(MultipartBodyLengthLimit = 20971520)]//max size should be 20MB
public IActionResult AddFile(List<IFormFile> files)
{
IActionResult ar = null;
try
{
if (id != 0)
{
foreach(var singlefile in files)
{
var ext = Path.GetExtension(singlefile.FileName).ToLowerInvariant();
//begin saving procedure
if(singlefile.Length > 0 && singlefile.Length <= Convert.ToInt32(_config.Value.FileSizeLimit))
{
var filepath = Path.Combine(_config.Value.StoredFilesPath, Path.GetRandomFileName().Split('.')[0] + ext);
using(var stream = System.IO.File.Create(filepath))
{
singlefile.CopyToAsync(stream);
}
}
}
}
catch (Exception e)
{
_log.Error(e);
}
return ar;
}
Please What am i missing out? I can save files with other extensions using this same piece of code, it saves and i can view properly but only .zip files saves as 0bytes
You didn't wait for the copy task to complete. Try change the method to an async action:
public async Task<IActionResult> AddFile(List<IFormFile> files)
{
...
using(var stream = System.IO.File.Create(filepath))
{
await singlefile.CopyToAsync(stream); // await here, otherwise the stream is disposed quickly
}
...
}

Files uploaded but not appearing on server

I use the code stated here to upload files through a webapi http://bartwullems.blogspot.pe/2013/03/web-api-file-upload-set-filename.html. I also made the following api to list all the files I have :
[HttpPost]
[Route("sharepoint/imageBrowser/listFiles")]
[SharePointContextFilter]
public async Task<HttpResponseMessage> Read()
{
string pathImages = HttpContext.Current.Server.MapPath("~/Content/images");
DirectoryInfo d = new DirectoryInfo(pathImages);//Assuming Test is your Folder
FileInfo[] Files = d.GetFiles(); //Getting Text files
List<object> lst = new List<object>();
foreach (FileInfo f in Files)
{
lst.Add(new
{
name = f.Name,
type = "f",
size = f.Length
});
}
return Request.CreateResponse(HttpStatusCode.OK, lst);
}
When calling this api, all the files uploaded are listed. But when I go to azure I dont see any of them (Content.png is a file I manually uploaded to azure)
Why are the files listed if they dont appear on azure.
According to your description, I suggest you could firstly use azure kudu console to locate the right folder in the azure web portal to see the image file.
Open kudu console:
In the kudu click the debug console and locate the site\wwwroot\yourfilefolder
If you find your file is still doesn't upload successfully, I guess there maybe something wrong with your upload codes. I suggest you could try below codes.
Notice: You need add image folder in the wwwort folder.
{
public class UploadingController : ApiController
{
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = Environment.GetEnvironmentVariable("HOME").ToString() + "\\site\\wwwroot\\images";
//string root = HttpContext.Current.Server.MapPath("~/images");
var provider = new FilenameMultipartFormDataStreamProvider(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
public class FilenameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public FilenameMultipartFormDataStreamProvider(string path) : base(path)
{
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : Guid.NewGuid().ToString();
return name.Replace("\"", string.Empty);
}
}
}
Result:

Save InkManager images to byte array

I'm new to win8 app programming but has been assigned to write a windows store app to capture customers' signature and save it to SQL Server. After some research I found a great tutorial
http://www.codeproject.com/Articles/416878/Metro-Paint which shows how to draw and save the image locally. My question is how do I use the InkManager class in the tutorial to save the image to byte arrays so that I can save the image to SQLServer? Thanks!
private async void btnSaveWritingAsImage_Click(object sender, RoutedEventArgs e)
{
if (MyInkManager.GetStrokes().Count > 0)
{
try
{
Windows.Storage.Pickers.FileSavePicker SavePicker = new Windows.Storage.Pickers.FileSavePicker();
SavePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Desktop;
SavePicker.DefaultFileExtension = ".png";
SavePicker.FileTypeChoices.Add("PNG", new string[] { ".png" });
SavePicker.FileTypeChoices.Add("JPG", new string[] { ".jpg" });
StorageFile filesave = await SavePicker.PickSaveFileAsync();
IOutputStream ab = await filesave.OpenAsync(FileAccessMode.ReadWrite);
if (ab != null)
await MyInkManager.SaveAsync(ab);
}
catch (Exception)
{
var MsgDlg = new MessageDialog("Only handwriting can be saved as image.", "Error while saving");
MsgDlg.ShowAsync();
}
}
else
{
var MsgDlg = new MessageDialog("Only handwriting can be saved as image.", "Error while saving");
await MsgDlg.ShowAsync();
}
}
add: (IBuffer.ToArray() is defined in WindowsRuntimeBufferExtensions)
using System.Runtime.InteropServices.WindowsRuntime;
then just do:
var buffer = await FileIO.ReadBufferAsync(image);//replace ab instead of image
var bytes = buffer.ToArray();

Cannot Open Files in WinRT Unit Testing

I am writing a unit test to validate the serialization of objects and I am able to successfully save the file without any issue. I can even browse the file and validate the contents are correct. However, when I attempt to open the file for reading I always receive an UnauthorizedAccess exception.
Here is the code used to save the item:
public static async Task SaveItem<T>(string folderName, T item)
where T : BaseBusinessItem
{
if (string.IsNullOrEmpty(folderName))
{
throw new ArgumentNullException("folderName");
}
if (item == null)
{
throw new ArgumentNullException("item");
}
try
{
var folder = await ApplicationData.Current.LocalFolder
.CreateFolderAsync(folderName, CreationCollisionOption.OpenIfExists);
var file =
await
folder.CreateFileAsync(item.UniqueID.GetHashCode().ToString(), CreationCollisionOption.ReplaceExisting);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
using (var outStream = stream.GetOutputStreamAt(0))
{
var serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(outStream.AsStreamForWrite(), item);
await outStream.FlushAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
Here is the code used to restore the item:
public static async Task<T> RestoreItem<T>(string folderName, string hashCode)
where T : BaseBusinessItem, new()
{
if (string.IsNullOrEmpty(folderName))
{
throw new ArgumentNullException("folderName");
}
if (string.IsNullOrEmpty(hashCode))
{
throw new ArgumentNullException("hashCode");
}
var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync(folderName);
var file = await folder.GetFileAsync(hashCode);
var inStream = await file.OpenSequentialReadAsync();
var serializer = new DataContractJsonSerializer(typeof(T));
var retVal = (T)serializer.ReadObject(inStream.AsStreamForRead());
return retVal;
}
And the unit test:
[TestMethod]
public async Task TestFileSaveLoad()
{
await _ds.SaveItem("TestFolder");
Guid ID = _item.UniqueID;
_ds = await ItemDataSource.LoadItem("TestFolder", ID.GetHashCode().ToString());
}
Any ideas or troubleshooting steps I might be missing. The unit test app manifest includes the following capabilities: Document Library, Internet (Client). The following declarations are in place: File Open Picker, File Save Picker and File Type Associations.
Thanks!
This code snippet helped me accomplish my goal. Hope this is helpful for someone else:
http://codepaste.net/gtu5mq