Uploading to Azure File Share from a Razor Page - c#

I am trying to find an example of uploading a file to an Azure file share from a razor page. I would like to be able to select a file and then have that file saved to the share. I am using Visual Studio 2017, .Net Core 2.0. The only examples I am finding are for Blob storage. Any help would be much appreciated.

[HttpPost]
public IActionResult Index(Microsoft.AspNetCore.Http.IFormFile files)
{
string storageConnectionString = "connectionstring to your azure file share";
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(storageConnectionString);
CloudFileClient cloudFileClient = cloudStorageAccount.CreateCloudFileClient();
CloudFileShare cloudFileShare = cloudFileClient.GetShareReference("your file share name");
cloudFileShare.CreateIfNotExistsAsync();
CloudFileDirectory rootDirectory = cloudFileShare.GetRootDirectoryReference();
CloudFile file = rootDirectory.GetFileReference(files.FileName);
TransferManager.Configurations.ParallelOperations = 64;
// Setup the transfer context and track the upoload progress
SingleTransferContext context = new SingleTransferContext();
using (Stream s1 = files.OpenReadStream())
{
var task = TransferManager.UploadAsync(s1, file);
task.Wait();
}
return RedirectToPage("/Index");
}

Here is a simple method I'm using to upload a single file to an endpoint.
[HttpPost]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file != null)
{
using (var stream = new MemoryStream())
{
try
{
// assume a single file POST
await file.CopyToAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
// now send up to Azure
var filename = file.FileName;
var storageAccount = CloudStorageAccount.Parse(<YOUR CREDS HERE>);
var client = storageAccount.CreateCloudFileClient();
var shareref = client.GetShareReference("YOUR FILES SHARE");
var rootdir = shareref.GetRootDirectoryReference();
var fileref = rootdir.GetFileReference(filename);
await fileref.DeleteIfExistsAsync();
await fileref.UploadFromStreamAsync(stream);
return Ok(new { fileuploaded = true });
}
catch (Exception ex)
{
return BadRequest(ex);
}
}
}
else
{
return BadRequest(new { error = "there was no uploaded file" });
}
}

Related

Azure Storage upload Bug

I do not know if this is a bug or not, but I have made a Xamarin app, that will connect to Azure storage to upload a file.
It doesn't want to upload nd I get this error
Azure service, to upload the file
I made the same application, using a console app (for testing fester)
var path = Path.Combine(projectPath, "universal.txt");
var fullpath = Path.GetFullPath(path);
var FileName = Path.GetFileName(fullpath);
using (StreamWriter sw = new StreamWriter(fullpath)) {
sw.WriteLine("Hello I want to go to Universal tomorrow");
}
var AzureStorage = new BlobContainerClient(ConectionString, ContanerName);
var blob = AzureStorage.GetBlobClient(FileName);
await blob.UploadAsync(fullpath);
My file get uploaded to Azure
File in storage
Use these functions to upload a file from xamarin.
static CloudBlobContainer GetContainer(ContainerType containerType)
{
var account = CloudStorageAccount.Parse(Constants.StorageConnection);
var client = account.CreateCloudBlobClient();
return client.GetContainerReference(containerType.ToString().ToLower());
}
public static async Task<string> UploadFileAsync(ContainerType containerType, Stream stream)
{
var container = GetContainer(containerType);
await container.CreateIfNotExistsAsync();
var name = Guid.NewGuid().ToString();
var fileBlob = container.GetBlockBlobReference(name);
await fileBlob.UploadFromStreamAsync(stream);
return name;
}
OR
client = new BlobServiceClient(storageConnectionString);
containerClient = await client.CreateBlobContainerAsync(containerName);
blobClient = containerClient.GetBlobClient(fileName);
await containerClient.UploadBlobAsync(fileName, memoryStreamFile);

How can I post image from UWP to .NET core web api?

Now I have configured for UWP photo post to web api part which is using HttpClient.
Uri uri = new Uri("http://localhost:50040/api/Upload");
IInputStream inputStream = await photoFile.OpenAsync(FileAccessMode.Read);
HttpMultipartFormDataContent multipartContent = new HttpMultipartFormDataContent();
multipartContent.Add(new HttpStreamContent(inputStream), "myFile", photoFile.Name);
Windows.Web.Http.HttpClient newclient = new Windows.Web.Http.HttpClient();
Windows.Web.Http.HttpResponseMessage response = await client.PostAsync(uri, multipartContent);
But I don't know how to set for the server side which is my .NET core web api to get the image which post from my UWP application.Please Help me, thank you.
But I don't know how to set for the server side which is my .NET core web api
Please reference the File uploads official tutorial to create your server side. For example, add POST method as following sample code showed to receive the UWP client sent file with the client code you showed above.
// POST api/values
[HttpPost]
public async Task<IActionResult> Post(IFormFile myFile)
{
// full path to file in temp location, you could change this
var filePath = Path.GetTempFileName();
if (myFile.Length > 0)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await myFile.CopyToAsync(stream);
}
}
// process uploaded files
// Don't rely on or trust the FileName property without validation.
return Ok(new { filePath, myFile.Length });
}
More details you could also reference the official sample.
In Web API Controller
public IHostingEnvironment _environment;
public UploadFilesController(IHostingEnvironment environment) // Create Constructor
{
_environment = environment;
}
[HttpPost("UploadImages")]
public Task<ActionResult<string>> UploadImages([FromForm]List<IFormFile> allfiles)
{
string filepath = "";
foreach (var file in allfiles)
{
string extension = Path.GetExtension(file.FileName);
var upload = Path.Combine(_environment.ContentRootPath, "ImageFolderName");
if (!Directory.Exists(upload))
{
Directory.CreateDirectory(upload);
}
string FileName = Guid.NewGuid() + extension;
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(upload, FileName), FileMode.Create))
{
file.CopyTo(fileStream);
}
}
filepath = Path.Combine("ImageFolderName", FileName);
}
return Task.FromResult<ActionResult<string>>(filepath);
}
In yourpage.xaml.cs
using Windows.Storage;
using Windows.Storage.Pickers;
.....
StorageFile file;
......
private async void btnFileUpload_Click(object sender, RoutedEventArgs e) // Like Browse button
{
try
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".png");
file = await openPicker.PickSingleFileAsync();
if (file != null)
{
//fetch file details
}
}
catch (Exception ex)
{
}
}
//When upload file
var http = new HttpClient();
var formContent = new HttpMultipartFormDataContent();
var fileContent = new HttpStreamContent(await file.OpenReadAsync());
formContent.Add(fileContent, "allfiles", file.Name);
var response = await http.PostAsync(new Uri("Give API Path" + "UploadImages", formContent);
string filepath = Convert.ToString(response.Content); //Give path in which file is uploaded
Hope this code helps you...
But remember formContent.Add(fileContent, "allfiles", file.Name); line is important and allfiles is that name of parameter to fetch files in web api method "public Task<ActionResult<string>> UploadImages([FromForm]List<IFormFile> **allfiles**)"
Thanks!!!

Upload new file to onedrive using microsoft graph c# asp.net

Trying to upload a file to onedrive that does not already exist. I have managed to get it to update an existing file. But can't seem to figure out how to create a brand new file. I have done this useing the Microsoft.Graph library.
Here is the code that works to update an existing file:
public async Task<ActionResult> OneDriveUpload()
{
string token = await GetAccessToken();
if (string.IsNullOrEmpty(token))
{
// If there's no token in the session, redirect to Home
return Redirect("/");
}
GraphServiceClient client = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token);
return Task.FromResult(0);
}));
try
{
string path = #"C:/Users/user/Desktop/testUpload.xlsx";
byte[] data = System.IO.File.ReadAllBytes(path);
Stream stream = new MemoryStream(data);
// Line that updates the existing file
await client.Me.Drive.Items["55BBAC51A4E4017D!104"].Content.Request().PutAsync<DriveItem>(stream);
return View("Index");
}
catch (ServiceException ex)
{
return RedirectToAction("Error", "Home", new { message = "ERROR retrieving messages", debug = ex.Message });
}
}
I'd suggest using the ChunkedUploadProvider utility that is included in the SDK. Aside from being a little easier to work with, it will allow you to upload files of any side rather than being limited to files under 4MB.
You can find a sample of how to use ChunkedUploadProvider in the OneDriveUploadLargeFile unit test.
To answer your direct question, uploading works the same for both replacing and creating files. You do however need to specify the file name rather than just an existing Item number:
await graphClient.Me
.Drive
.Root
.ItemWithPath("fileName")
.Content
.Request()
.PutAsync<DriveItem>(stream);
This code will help you all to upload small and large files using Microsoft graph Api Sdk in ASP .NEt Core
Upload or replace the contents of a DriveItem
*Controller code : -*
[BindProperty]
public IFormFile UploadedFile { get; set; }
public IDriveItemChildrenCollectionPage Files { get; private set; }
public FilesController(ILogger<FilesModel> logger, GraphFilesClient graphFilesClient, GraphServiceClient graphServiceClient, ITokenAcquisition tokenAcquisition)
{
_graphFilesClient = graphFilesClient;
_logger = logger;
_graphServiceClient = graphServiceClient;
_tokenAcquisition = tokenAcquisition;
}
[EnableCors]
[HttpPost]
[Route("upload-file")]
[RequestFormLimits(MultipartBodyLengthLimit = 100000000)]
[RequestSizeLimit(100000000)]
public async Task<IActionResult> uploadFiles(string itemId, string folderName, [FromHeader] string accessToken)
{
_logger.LogInformation("into controller");
if (UploadedFile == null || UploadedFile.Length == 0)
{
return BadRequest();
}
_logger.LogInformation($"Uploading {UploadedFile.FileName}.");
var filePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), UploadedFile.FileName);
_logger.LogInformation($"Uploaded file {filePath}");
using (var stream = new MemoryStream())
{
UploadedFile.CopyTo(stream);
var bytes = stream.ToArray();
_logger.LogInformation($"Stream {stream}.");
stream.Flush();
await _graphFilesClient.UploadFile(
UploadedFile.FileName, new MemoryStream(bytes), itemId, folderName, accessToken);
}
return Ok("Upload Successful!");
}
*Service code :-*
[EnableCors]
public async Task UploadFile(string fileName, Stream stream,string itemId,string folderName,string accessToken)
{
GraphClients graphClients = new GraphClients(accessToken);
GraphServiceClient _graphServiceClient = graphClients.getGraphClient();
_logger.LogInformation("Into Service");
var filePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(),fileName);
_logger.LogInformation($"filepath : {filePath}");
Console.WriteLine("Uploading file: " + fileName);
var size = stream.Length / 1000;
_logger.LogInformation($"Stream size: {size} KB");
if (size/1000 > 4)
{
// Allows slices of a large file to be uploaded
// Optional but supports progress and resume capabilities if needed
await UploadLargeFile(filePath, stream,accessToken);
}
else
{
try
{
_logger.LogInformation("Try block");
String test = folderName + "/" + fileName;
// Uploads entire file all at once. No support for reporting progress.
// for getting your sharepoint site open graph explorer > sharepoint sites > get my organization's default sharepoint site.
var driveItem = await _graphServiceClient
.Sites["Your share point site"]
.Drive
.Root.ItemWithPath(test)
.Content
.Request()
.PutAsync<DriveItem>(stream);
_logger.LogInformation($"Upload complete: {driveItem.Name}");
}
catch (ServiceException ex)
{
_logger.LogError($"Error uploading: {ex.ToString()}");
throw;
}
}
}
private async Task UploadLargeFile(string itemPath, Stream stream,string accessToken)
{
GraphClients graphClients = new GraphClients(accessToken);
GraphServiceClient _graphServiceClient = graphClients.getGraphClient();
// Allows "slices" of a file to be uploaded.
// This technique provides a way to capture the progress of the upload
// and makes it possible to resume an upload using fileUploadTask.ResumeAsync(progress);
// Based on https://docs.microsoft.com/en-us/graph/sdks/large-file-upload
// Use uploadable properties to specify the conflict behavior (replace in this case).
var uploadProps = new DriveItemUploadableProperties
{
ODataType = null,
AdditionalData = new Dictionary<string, object>
{
{ "#microsoft.graph.conflictBehavior", "replace" }
}
};
// Create the upload session
var uploadSession = await _graphServiceClient.Me.Drive.Root
.ItemWithPath(itemPath)
.CreateUploadSession(uploadProps)
.Request()
.PostAsync();
// Max slice size must be a multiple of 320 KiB
int maxSliceSize = 320 * 1024;
var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, stream, maxSliceSize);
// Create a callback that is invoked after
// each slice is uploaded
IProgress<long> progress = new Progress<long>(prog =>
{
_logger.LogInformation($"Uploaded {prog} bytes of {stream.Length} bytes");
});
try
{
// Upload the file
var uploadResult = await fileUploadTask.UploadAsync(progress);
if (uploadResult.UploadSucceeded)
{
_logger.LogInformation($"Upload complete, item ID: {uploadResult.ItemResponse.Id}");
}
else
{
_logger.LogInformation("Upload failed");
}
}
catch (ServiceException ex)
{
_logger.LogError($"Error uploading: {ex.ToString()}");
throw;
}
}

C# downloading from Windows Azure Storage returns an empty file without any exceptions

I'm trying to use Windows Azure Storage for my Windows Store App with Mobile Services to store images. I made uploading work by following this guide:
http://www.windowsazure.com/en-us/develop/mobile/tutorials/upload-images-to-storage-dotnet/
However, I couldn't find any material on downloading the files. I couldn't even find classes reference for windows store version! If someone could guide me to the documentation I would be grateful.
Anyway, I wrote the code but it doesn't seem work:
public static async System.Threading.Tasks.Task DownloadUserImage(SQLUser userData)
{
var usersFolder = await GetUsersFolder();
var imageUri = new Uri(userData.ImageUri);
var accountName = "<SNIP>";
var key = "<SNIP>";
StorageCredentials cred = new StorageCredentials(accountName, key);
CloudBlobContainer container = new CloudBlobContainer(new Uri(string.Format("https://{0}/{1}", imageUri.Host, userData.ContainerName)), cred);
CloudBlockBlob blob = container.GetBlockBlobReference(userData.ResourceName);
var imageFile = await usersFolder.CreateFileAsync(userData.Id.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
using (var fileStream = await imageFile.OpenAsync(FileAccessMode.ReadWrite))
{
try
{
await blob.DownloadToStreamAsync(fileStream);
}
catch (Exception e)
{
Tools.HandleLiveException(e);
}
}
}
This code results in empty file creation, but it doesn't throw any exceptions whatsoever. If I paste the value of imageUri to my browser, it starts downloading the file and completes the download successfully. However, my program does not, for some reason.
Any help, please?
Apparently, I've been opening the stream in a wrong way. Here's a fix:
public static async System.Threading.Tasks.Task DownloadUserImage(SQLUser userData)
{
var usersFolder = await GetUsersFolder();
var imageUri = new Uri(userData.ImageUri);
var accountName = "<SNIP>";
var key = "<SNIP>";
StorageCredentials cred = new StorageCredentials(accountName, key);
CloudBlobClient client = new CloudBlobClient(new Uri(string.Format("https://{0}", imageUri.Host)), cred);
CloudBlobContainer container = client.GetContainerReference(userData.ContainerName);
var blob = await container.GetBlobReferenceFromServerAsync(userData.ResourceName);
var imageFile = await usersFolder.CreateFileAsync(userData.Id.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
using (var fileStream = await imageFile.OpenStreamForWriteAsync())
{
try
{
await blob.DownloadToStreamAsync(fileStream.AsOutputStream());
}
catch (Exception e)
{
Tools.HandleLiveException(e);
}
}
}
It works perfectly now.

Set Content-type of media files stored on Blob

We have a website hosted on Azure. It is media based, and we are using JWPlayer to playback media with HTTP pseudostreaming. The media files are stored on blob in 3 formats - mp4, ogg, webm.
The issue is the content type of media files is set as application/octet-stream for all types. Due to this there are some issues in media playback and progress bar.
How can I set the appropriate Content-type of files stored on blob (like - video/mp4, video/ogg, video/webm)?
I do not want to do it manually for each file by going in blob interface. There must be some other way to do it which I am not aware of. Perhaps a config file, settings file, etc sorts. Or perhaps a code block to set up the Content-type for all files stored in a folder.
Any suggestions?
Thanks
This should work:
var storageAccount = CloudStorageAccount.Parse("YOURCONNECTIONSTRING");
var blobClient = storageAccount.CreateCloudBlobClient();
var blobs = blobClient
.GetContainerReference("thecontainer")
.ListBlobs(useFlatBlobListing: true)
.OfType<CloudBlockBlob>();
foreach (var blob in blobs)
{
if (Path.GetExtension(blob.Uri.AbsoluteUri) == ".mp4")
{
blob.Properties.ContentType = "video/mp4";
}
// repeat ad nauseam
blob.SetProperties();
}
Or set up a dictionary so you don't have to write a bunch of if statements.
Unfortunately, the accepted answer here is not currently working for the latest SDK (12.x.+)
With the latest SDK, the content type should be set via BlobHttpHeaders.
var blobServiceClient = new BlobServiceClient("YOURCONNECTIONSTRING");
var containerClient = blobServiceClient.GetBlobContainerClient("YOURCONTAINERNAME");
var blob = containerClient.GetBlobClient("YOURFILE.jpg");
var blobHttpHeader = new BlobHttpHeaders { ContentType = "image/jpeg" };
var uploadedBlob = await blob.UploadAsync(YOURSTREAM, new BlobUploadOptions { HttpHeaders = blobHttpHeader });
YOURSTREAM could be a new BinaryData(byte[])
This is work example to upload video to Azure Blob Storage with right Content-Type:
public static String uploadFile(
CloudBlobContainer container,String blobname, String fpath) {
CloudBlockBlob blob;
try {
blob = container.getBlockBlobReference(blobname);
File source = new File(fpath);
if (blobname.endsWith(".mp4")) {
System.out.println("Set content-type: video/mp4");
blob.getProperties().setContentType("video/mp4");
}
blob.upload(new FileInputStream(source), source.length());
return blob.getUri().toString();
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (StorageException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
With Azure.Storage.Blogs (12.8.4),
We can set content type of file as below.
In Default, Azure Storage stores file in application/octet-stream, In case of *.svg file, doesn't properly render in html.
So we have to save *.svg file in azure blob storage with content type image/svg+xml while uploading into blob.
Below is the code sample I got working.
BlobServiceClient blobServiceClient = new BlobServiceClient("CONNECTIONSTRING");
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient("CONTAINERNAME");
BlobClient blobClient = containerClient.GetBlobClient("BLOBNAME");
try
{
Stream stream = file.OpenReadStream();
await blobClient.UploadAsync(stream, true);
blobClient.SetHttpHeaders(new BlobHttpHeaders() { ContentType = file.ContentType });
}
ContentType Set on header should place just below the blobClient.UploadAsync().
With Azure Storage v10 SDK, blobs can be uploaded using BlockBlobURL as instructed in the Node.js quickstart:
const {
Aborter,
BlockBlobURL,
ContainerURL,
ServiceURL,
SharedKeyCredential,
StorageURL,
uploadFileToBlockBlob
} = require("#azure/storage-blob");
const containerName = "demo";
const blobName = "quickstart.txt";
const content = "hello!";
const credentials = new SharedKeyCredential(
STORAGE_ACCOUNT_NAME,
ACCOUNT_ACCESS_KEY
);
const pipeline = StorageURL.newPipeline(credentials);
const serviceURL = new ServiceURL(
`https://${STORAGE_ACCOUNT_NAME}.blob.core.windows.net`,
pipeline
);
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
const aborter = Aborter.timeout(30 * ONE_MINUTE);
await blockBlobURL.upload(aborter, content, content.length);
Then content type can be set after the upload with the setHTTPHeaders method:
// Set content type to text/plain
await blockBlobURL.setHTTPHeaders(aborter, { blobContentType: "text/plain" });
Files can be uploaded with the uploadFileToBlockBlob method from #azure/storage-blob.
In python
azure_connection_str = libc.retrieve.get_any_secret('AZURE_STORAGE_CONNECTION')
blob_service_client = BlobServiceClient.from_connection_string(azure_connection_str)
blobs = blob_service_client.list_blobs()
my_content_settings = ContentSettings(content_type='video/mp4')
for blob in blobs:
blob_client = blob_service_client.container_client.get_blob_client(blob)
blob_client.set_http_headers(content_settings=my_content_settings)
Using php, one can upload the video by setting the content type as follows
$blobRestProxy = ServicesBuilder::getInstance()->createBlobService($connectionString);
//upload
$blob_name = "video.mp4";
$content = fopen("video.mp4", "r");
$options = new CreateBlobOptions();
$options->setBlobContentType("video/mp4");
try {
//Upload blob
$blobRestProxy->createBlockBlob("containername", $blob_name, $content, $options);
echo "success";
} catch(ServiceException $e){
$code = $e->getCode();
$error_message = $e->getMessage();
echo $code.": ".$error_message."<br />";
}
here is what i do
BlobHTTPHeaders h = new BlobHTTPHeaders();
String blobContentType = "image/jpeg";
h.withBlobContentType(blobContentType);
blobURL.upload(Flowable.just(ByteBuffer.wrap(Files.readAllBytes(img.toPath()))), img.length(), h, null, null, null)
.subscribe(resp-> {
System.out.println("Completed upload request.");
System.out.println(resp.statusCode());
});
You can use Azure Storage Explorer to do this manually. Right-click the file to change and select Properties. Go to ContentType and edit the value to the correct one i.e. "video\mp4"

Categories

Resources