通过Web Api将文件上载到Azure Blob存储,而无需访问本地文件系统

时间:2013-06-03 13:48:02

标签: c# azure asp.net-web-api azure-storage-blobs

我正在尝试通过web-api将文件从本地命令行客户端上传到Azure存储。 我正在使用Azure Web站点。与客户合作不是问题。而且我的一切工作都很好。这是web-api代码:

    public async Task<HttpResponseMessage> PostUpload()
    {
        // need a local resource to store uploaded files temporarily
        LocalResource localResource = null;
        try
        {
            // Azure web-site fails here
            localResource = RoleEnvironment.GetLocalResource("TempStorage");
        }
        catch (Exception e)
        {
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Unable to get access to local resources");
        }

        var provider = new MultipartFormDataStreamProvider(localResource.RootPath);

        // Read the form data.
        await Request.Content.ReadAsMultipartAsync(provider);

        // snipped validation code
        var container = // code to get container

        foreach (var fileData in provider.FileData)
        {
            var filename = GetBlobName(fileData);
            var blob = container.GetBlockBlobReference(filename);
            using (var filestream = File.OpenRead(fileData.LocalFileName))
            {
                blob.UploadFromStream(filestream);
            }
            File.Delete(fileData.LocalFileName);
        }

        return Request.CreateResponse(HttpStatusCode.OK);
    }

当我在本地运行时,一切正常,但是当我在Azure中部署网站时,我无法上传,因为Azure网站无法访问LocalResource。我需要切换到Azure Web-Role。我可以切换,但访问本地文件系统一直困扰着我。

MultipartFormDataStreamProvider()的实例需要LocalResource。我还没有找到将文件上传到WebApi的替代方法。我的计划是channel through upload directly to Azure,而不是在本地硬盘上存储任何东西。

还有其他方法可以上传文件吗?

P.S。我看过usages of Shared Access Signatures,我可以在其中为客户端应用程序提供带签名的URL,并让客户端直接上传到Azure Blog。但是我不确定将签名传递给客户端会有多安全,而且不太舒服。目前我认为客户端将在非常恶劣的环境中运行,并且从客户端返回任何东西都不可信任。

UPD 我的最终解决方案涉及使用在服务器上发布的只写共享访问签名并传递给客户端。然后客户端将文件直接上传到Azure。这样我通过管理上传的文件节省了很多麻烦。这是我的解决方案more detailed description

3 个答案:

答案 0 :(得分:12)

这不是您正在寻找的答案,但您可以使用MultiPartFileStreamProvider和Path.GetTempPath()在Azure网站上使用本地存储。代码看起来像这样

public async Task<HttpResponseMessage> PostUpload()
{
    var provider = new MultipartFileStreamProvider(Path.GetTempPath());

    // Read the form data.
    await Request.Content.ReadAsMultipartAsync(provider);

    // do the rest the same     
}

答案 1 :(得分:2)

我发现这篇StackOverflow文章覆盖了MultipartFormDataStreamProvider,因此文件不是先存储在本地,而是直接写入AWSStream。看到: Is it possible to override MultipartFormDataStreamProvider so that is doesn't save uploads to the file system?

但我必须说我也喜欢trailmax的解决方案。

答案 2 :(得分:1)

使用LocalResource使代码工作的一种可能解决方案是在通过Owin自托管web api的工作进程内部托管它。

您可以在http://www.asp.net/web-api/overview/hosting-aspnet-web-api/host-aspnet-web-api-in-an-azure-worker-role

找到简单的演练

您只需要在RoleEntryPoint的OnStart()方法中启动Owin托管的api。请记住,您还可以从Web api响应中返回Html,这样您就可以将辅助角色作为一个非常灵活的基础项目。

这是一个快速摘录,展示了如何从上面的链接设置Owin主机:

private IDisposable _webApp = null;

public override bool OnStart() {
   ServicePointManager.DefaultConnectionLimit = 5;

   var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["DefaultEndpoint"];
   var baseUri = string.Format("{0}://{1}", endpoint.Protocol, endpoint.IPEndpoint);

   _webApp = WebApp.Start<Startup>(new StartOptions(baseUri));

   return base.OnStart();
}

public override void OnStop() {
    if (_webApp != null) {
        _webApp.Dispose();
    }
    base.OnStop();
}

...

using System.Web.Http;
using Owin;

class Startup {
    public void Configuration(IAppBuilder app) {
        var config = new HttpConfiguration();

        config.Routes.MapHttpRoutes("Default", "{controller}/{id}",
                                    new { id = RouteParameter.Optional });

        app.UseWebApi(config);

    }
}