Request.Content.ReadAsMultipartAsync Throws System.IO exception - azure

I am uploading an image to an ASP WebAPI service and then uploading it to windows azure. everything was working great but suddenly I started getting the following exception:
System.IO.IOException: The process cannot access the file
'C:\DWASFiles\Sites\Tasteat\Temp\BodyPart_a5c79910-6077-4c24-b814-10fdc0e0b3d4'
because it is being used by another process.
This is the code that throws the exception:
var provider = new BlobStorageProvider(container);
Trace.TraceInformation("Uploading raw image to blob");
await Request.Content.ReadAsMultipartAsync(provider);
Trace.TraceInformation("Uploading finished");
I know its this line await Request.Content.ReadAsMultipartAsync(provider); because I see the line before it in the log but not the line after it.
Any ideas?
Everything was working great up until a few days

So as it seems the code I posted above actually saves a local file and only then uploaded it to the server, which causes the error but also is slow.
after a lot of trying I finally change to the following solution and everything started working and it was even faster!
first create a streamprovider:
public class BlobStorageMultipartStreamProvider : MultipartStreamProvider
{
private readonly string _containerName;
private readonly string _fileName;
public BlobStorageMultipartStreamProvider(string containerName, string fileName)
{
_containerName = containerName;
_fileName = fileName;
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
Stream stream = null;
if (!String.IsNullOrWhiteSpace(_fileName))
{
string connectionString = ConfigurationManager.ConnectionStrings["BlobStorage"].ConnectionString;
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer blobContainer = blobClient.GetContainerReference(_containerName);
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(_fileName);
stream = blob.OpenWrite();
}
return stream;
}
}
The upload code:
string fileName = Guid.NewGuid()+".Png";
MultipartStreamProvider provider = new BlobStorageMultipartStreamProvider("container",fileName);
Trace.TraceInformation("Uploading raw image to blob");
await Request.Content.ReadAsMultipartAsync(provider);
Trace.TraceInformation("Uploading finished");

Related

reading content of blob from azure function

I'm trying to read the content of a blob inside an azure function.
Here's the code:
Note:
If I comment out the using block and return the blob i.e.
return new OkObjectResult(blob);
I get back the blob object.
However, if I use the using block, I get 500.
Any idea why I can't get the content?
string storageConnectionString = "myConnectionString";
CloudStorageAccount storageAccount;
CloudStorageAccount.TryParse(storageConnectionString, out storageAccount);
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = cloudBlobClient.GetContainerReference("drawcontainer");
var blob = drawingsContainer.GetBlockBlobReference("notes.txt");
using (StreamReader reader = new StreamReader(blob.OpenRead()))
{
content = reader.ReadToEnd();
}
return new OkObjectResult(content);
HTTP 500 indicates that the code has error. The most probable reason for error is the variable 'content'. Define the variable 'content' outside the using block as the scope of the content variable defined inside it is limited to the block only. Declare it outside the using block, something like below:
try
{
string content = string.Empty;
using (StreamReader reader = new StreamReader(blob.OpenRead()))
{
content = reader.ReadToEnd();
}
}
catch (Exception ex)
{
// Log exception to get the details.
}
Always make use of try catch to get more details about errors in the code.
The OpenRead method didn't exist so I used the async one and it solved it.
I got to this solution after creating an azure function in VS and publishing it and it works.
Here's the code I used:
public static class Function1
{
[FunctionName("Function1")]
public static async Task<ActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
string storageConnectionString = "DefaultEndpointsProtocol=https;AccountName=avitest19a1c;AccountKey=<AccessKey>";
CloudStorageAccount storageAccount = null;
CloudStorageAccount.TryParse(storageConnectionString, out storageAccount);
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer drawingsContainer = cloudBlobClient.GetContainerReference("drawcontainer");
var blob = drawingsContainer.GetBlockBlobReference("notes.txt");
string content = string.Empty;
**var contentStream = await blob.OpenReadAsync();**
using (StreamReader reader = new StreamReader(contentStream))
{
content = reader.ReadToEnd();
}
return new OkObjectResult(content);
}
}

Azure blob download to stream has errors

I am trying to download an Azure blob to MemoryStream, and I am getting error "'memoryStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'". But I am able to download to file.
The code snippet is below
private static void GetExcelBlobData(string filename, string connectionString, string containerName)
{
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
// Retrieve reference to a blob named "test.xlsx"
CloudBlockBlob blockBlobReference = container.GetBlockBlobReference(filename);
DataSet ds;
using (var memoryStream = new MemoryStream())
{
//downloads blob's content to a stream
blockBlobReference.DownloadToStream(memoryStream);
}
}
Debug console error on line "blockBlobReference.DownloadToStream(memoryStream)" is shown
Does anyone know what I'm doing wrong here?

C# Azure storage from one blob copy file to another blob

How can I read a file to stream from one blob and upload to another blob? My requirement is to copy a file from one blob to another blob with different file name? In C#
The easiest way to achieve it is using "Azure Storage Data Movement Library" (you can get it thru nuget package).
This is a simple-sample to make the transfer:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.DataMovement;
using System;
namespace BlobClient
{
class Program
{
static void Main(string[] args)
{
const string storageConnectionString = "DefaultEndpointsProtocol=https;AccountName=juanktest;AccountKey=loHQwke4lSEu1p2W3gg==";
const string container1 = "juankcontainer";
const string sourceBlobName = "test.txt";
const string destBlobName = "newTest.txt";
//Setup Account, blobclient and blobs
CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
CloudBlobClient blobClient = account.CreateCloudBlobClient();
CloudBlobContainer blobContainer = blobClient.GetContainerReference(container1);
blobContainer.CreateIfNotExists();
CloudBlockBlob sourceBlob = blobContainer.GetBlockBlobReference(sourceBlobName);
CloudBlockBlob destinationBlob = blobContainer.GetBlockBlobReference(destBlobName);
//Setup data transfer
TransferContext context = new TransferContext();
Progress<TransferProgress> progress = new Progress<TransferProgress>(
(transferProgress) => {
Console.WriteLine("Bytes uploaded: {0}", transferProgress.BytesTransferred);
});
context.ProgressHandler = progress;
// Start the transfer
try
{
TransferManager.CopyAsync(sourceBlob, destinationBlob,
false /* isServiceCopy */,
null /* options */, context);
}
catch (Exception e)
{
Console.WriteLine("The transfer is cancelled: {0}", e.Message);
}
Console.WriteLine("CloudBlob {0} is copied to {1} ====successfully====",
sourceBlob.Uri.ToString(),
destinationBlob.Uri.ToString());
Console.ReadLine();
}
}
}
Note that "Azure Storage Data Movement Library" is very robust so you can track the transfer progress, cancel the operation or even suspend it to resume it later ;)
One of the easiest ways to copy files is with the AzCopy utility.
I would like to recommend another method other than the above to get this done.
That is azure functions. (serverless compute service).
As a prerequisite, you should have some knowledge in azure functions, creating them, deploying them. 1. What is azure function 2. create an Azure function app
And the following code snippet is the simplest and basic way to perform this action. (In here, when a user uploading a new file to the "demo" blob, the function will be triggered and read that uploaded file from the demo blob and copy to the "output" blob.)
namespace Company.Function{
public static class NamalFirstBlobTrigger
{
[FunctionName("NamalFirstBlobTrigger")]
public static void Run([BlobTrigger("demo/{name}", Connection = "AzureWebJobsStorage")]Stream myBlob,
[Blob("output/testing.cs",FileAccess.Write, Connection = "AzureWebJobsStorage")]Stream outputBlob,
string name,
ILogger log)
{
myBlob.CopyTo(outputBlob);
}
}}

Upload and retrieve file from blob storage

I want to upload file in azure blob storage and retrieve that file in my own application.
My Code:
protected void btnUploadtoCloud_Click(object sender, EventArgs e)
{
UploadFile();
}
public string UploadFile()
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"));
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer blobContainer = blobClient.GetContainerReference("vest");
blobContainer.CreateIfNotExist();
BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
containerPermissions.PublicAccess = BlobContainerPublicAccessType.Container;
blobContainer.SetPermissions(containerPermissions);
CloudBlob blobText = blobContainer.GetBlobReference(fupPicture.FileName);
blobText.Properties.ContentType = fupPicture.PostedFile.ContentType;
string blobURL = blobText.Uri.ToString();
blobText.UploadFromStream(fupPicture.FileContent);
imgTest.ImageUrl = blobURL;
return blobURL;
}
But my problem is first line of UploadFile.I include image because I want to show my ref dll too.
.
Why error in RoleEnvironment. May i missing some thing to include.
Note : I have window azure account and I deploy other sites easily.
EDIT
After Gaurav suggestion I try :
string cnn = "<add name=\"testconnectionstring\" DefaultEndpointsProtocol=\"http;AccountName=mystorage;AccountKey=A9Jlajksdh69szut9zOfsxWMD/qLaP3Gy6ID9mIarNmCDasdhlyNlAR9wV0NGjqJUZeM4x6x5bTumLv+1nC51clHDl5GTYYPA==" + " />";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(cnn);
but unable to work I got error invalid combination.
The reason you're getting this error is because RoleEnvironment is only available when your code is running in context of a Cloud Service (Web Role) either in local compute emulator or in cloud.
Since it is a web application and I am guessing that you will be deploying it in an Azure Website, you can simply use AppSettingsReader to read from Web.Config file. Something like:
var rdr = new AppSettingsReader();
string connectionString = (string) rdr.GetValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", typeof(String));
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
If your application is connecting to a cloud storage account, your connection string would look something like:
DefaultEndpointsProtocol=https;AccountName=your-account-name;AccountKey=your-account-key
For connecting to local storage emulator, your connection string would look like:
UseDevelopmentStorage=true

How do I upload a file to Azure blob storage from a MVC view

I am coding a MVC5 internet application and would like some help to upload a file from my own filesystem to an Azure Blob.
Here is my Azure upload code function:
public void UploadFileToBlobStorage(string containerName, string blockBlogName, string fileName)
{
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
// Create the container if it doesn't already exist.
container.CreateIfNotExists();
container.SetPermissions(
new BlobContainerPermissions
{
PublicAccess =
BlobContainerPublicAccessType.Blob
});
// Retrieve reference to a blob named "myblob".
CloudBlockBlob blockBlob = container.GetBlockBlobReference(blockBlogName);
// Create or overwrite the "myblob" blob with contents from a local file.
using (var fileStream = System.IO.File.OpenRead(fileName))
{
blockBlob.UploadFromStream(fileStream);
}
}
Here is my function to upload a test file:
public void UploadTestFile(string localFileName)
{
string containerName = "TestContainer";
string blockBlogName = "Test.txt";
AzureService azureService = new AzureService();
azureService.UploadFileToBlobStorage(containerName, blockBlogName, localFileName);
}
I am not sure how to call the UploadTestFile() function from a MVC View where the user can browse to a file to upload.
Do I need to use Ajax, or can I simply upload a file by calling the method from a MVC view? Can I please have some help with this?
Thanks in advance
One way to call your UploadTestFile() function from an MVC View is by using the Html.BeginForm() method. I am including an example below:
#using (Html.BeginForm("UploadTestFile", "INSERT_YOUR_CONTROLLER_NAME_HERE", FormMethod.Post, new { enctype = "multipart/form-data" })) {
<span>
<input type="file" name="myFile" multiple /> <br>
<input type="submit" value="Upload" />
</span>
}
Also, a couple of suggestions on your code:
UploadFileToBlobStorage(): The code checks for container existence and setting permissions on every request. I would recommend separating the container.CreateIfNotExists() and container.SetPermissions(…) logic into a separate initialization function that needs to be executed only once on first deployment.
UploadFileToBlobStorage(): It looks like the code will try to upload the localFileName from the VM file system and not the multi-part form data. One approach would be to use the HttpFileCollectionBase class and the Controller.Request property. Example below:
public void UploadFileToBlobStorage(
string containerName,
string blockBlogName,
HttpFileCollectionBase files)
{
// .....
// Use this:
blockBlob.UploadFromStream(files[0].InputStream);
/* uploading the first file:
you can enumerate thru the files collection
if you are uploading multiple files */
/* Instead of this:
Create or overwrite the "myblob" blob with contents
from a local file. */
using (var fileStream = System.IO.File.OpenRead(fileName))
{
blockBlob.UploadFromStream(fileStream);
}
}
[HttpPost]
public void UploadTestFile()
{
string containerName = "TestContainer";
string blockBlogName = "Test.txt";
AzureService azureService = new AzureService();
// Notice the Request.Files instead of localFileName
azureService.UploadFileToBlobStorage(
containerName, blockBlogName, Request.Files);
}
Please let me know if that works on your end.

Resources