Avatar billede angelenglen Nybegynder
22. maj 2015 - 14:14 Der er 1 løsning

C# Download fil fra Azure Files Storage.

Jeg har startet et nyt MVC 6 WebAPI projekt, hvor jeg ønsker at streame en fil ud fra et Azure File Share.

Men dels får jeg ingen bytes ned fra Azure, dels kan jeg ikke finde ud af at sende dem ud af MVC controlleren.

Jeg havde det til at virke med nuGet pakken WindowsAzure.Storage 4.3.0, men efter jeg opgraderede til 4.4.1 forsvandt alle de synkrone metoder, og alting er nu async - og så virker intet af min kode længere :-/
Jeg har som det kan ses forsøgt at tilpasse mine metoder til at bruge DownloadToStreamAsync frem for den nu fjernede DownloadToStream, men det virker ikke :-/

Jeg er ved at være lidt frustreret over det hele :-\
Det er ikke let at ville være med på den nyeste teknologi bølge...

Her er min metode der kontakter Azure og henter filen:
public async Task<Stream> GetFileStream(string fileName)
    {
        var uri = new Uri(share.Uri + "/" + fileName);
        var file = new CloudFile(uri, credentials);

        using (var stream = new MemoryStream())
        {
            await file.DownloadToStreamAsync(stream);
            stream.Seek(0, SeekOrigin.Begin);
            return stream;
        }
    }


Her er min Controller metode:
[HttpGet]
    [Route("GetFile")]
    public HttpResponseMessage GetFile(string Username, string Password, string FullName)
    {

        var client = new AzureFilesClient.AzureFilesClient(Username, Password);
        Stream azureFileStream =  client.GetFileStream(FullName).Result;
        var fileName = Path.GetFileName(FullName);

        using (HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK))
        {
            response.Content = new StreamContent(azureFileStream);
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileName };
            return response;
        }
    }


Her er et eksempel på det JSON output jeg får fra Controlleren:
Det ser ud til at den blot serializer response-objektet, frem for at sende det til browseren som det er, som den burde (eller i hvert fald: som jeg ønsker).
{
    "Version": {
        "Major": 1,
        "Minor": 1,
        "Build": -1,
        "Revision": -1,
        "MajorRevision": -1,
        "MinorRevision": -1
    },
    "Content": {
        "Headers": [
            {
                "Key": "Content-Type",
                "Value": [
                    "application/octet-stream"
                ]
            },
            {
                "Key": "Content-Disposition",
                "Value": [
                    "attachmentx; filename=\"samplefile.docx\""
                ]
            }
        ]
    },
    "StatusCode": 200,
    "ReasonPhrase": "OK",
    "Headers": [],
    "RequestMessage": null,
    "IsSuccessStatusCode": true
}
Avatar billede angelenglen Nybegynder
06. juni 2015 - 11:19 #1
Efter en kombination af at læse lidt op på den sparsomme dokumentation der er til rådighed, samt lidt trial and error, er problemerne løst.

Azure delen brugte NuGet pakken "WindowsAzure.Storage" (4.4.1-preview).

Først problemet med at retur-objektet blev serialized til JSON. Det krævede at et custom ActionResult blev returneret i stedet for.

using Microsoft.AspNet.Mvc;
using System.IO;
using System.Threading.Tasks;

public class FileResultFromStream : ActionResult
{
    public FileResultFromStream(string fileDownloadName, Stream fileStream, string contentType)
    {
        FileDownloadName = fileDownloadName;
        FileStream = fileStream;
        ContentType = contentType;
    }

    public string ContentType { get; private set; }
    public string FileDownloadName { get; private set; }
    public Stream FileStream { get; private set; }

    public async override Task ExecuteResultAsync(ActionContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        context.HttpContext.Response.Headers.Add("Content-Disposition", new[] { "attachment; filename=" + FileDownloadName });
        await FileStream.CopyToAsync(context.HttpContext.Response.Body);
    }
}


Derefter problemet med at få binær data streamet fra Azure Files storage (eller enhver anden async stream kilde).

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.File;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;

    public async Task<Stream> GetFileStreamAsync(string fileName)
    {
        var uri = new Uri(share.Uri + "/" + fileName);
        var file = new CloudFile(uri, credentials);

        // Note: Do not wrap the stream variable in a Using, since it will close the stream too soon.
        var stream = new MemoryStream();
        await file.DownloadToStreamAsync(stream);
        stream.Seek(0, SeekOrigin.Begin);
        return stream;
    }


Og til sidst controller koden. Bemærk brugen af iActionResult interfacet.

[HttpGet]
    [Route("GetFile")]
    public async Task<IActionResult> GetFile(string username, string password, string fullName)
    {
        var client = new AzureFilesClient.AzureFilesClient(username, password);
        Stream stream = await client.GetFileStreamAsync(fullName);
        string fileName = Path.GetFileName(fullName);
        return new CustomActionResults.FileResultFromStream(fileName, stream, "application/msword");
    }


Bemærk at ovenstående eksempel er lavet til brug med Microsoft Word filer.
ContentType skal nok gøres mere dynamisk hvis dette skal bruges med anden type data.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester