6

我正在尝试通过 web-api 将文件从本地命令行客户端上传到 Azure 存储。为此,我正在使用 Azure 网站。与客户合作不是问题。而且我在本地一切正常。这是网络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 的替代方法。我的计划是通过直接上传到 Azure 进行引导,而不在本地硬盘上存储任何内容。

有没有其他上传文件的方法?

ps 我已经看到共享访问签名的用法,我可以为客户端应用程序提供一个带有签名的 url,并让客户端直接上传到 Azure 博客。但我不确定这将是多么安全,并且(还)不太舒服将签名传递给客户端。目前我认为客户端将在非常恶劣的环境中运行,并且从客户端返回的任何内容都不可信。

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

4

3 回答 3

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     
}
于 2013-06-03T16:22:43.170 回答
2

我发现这篇 StackOverflow 文章覆盖了 MultipartFormDataStreamProvider,这样文件就不会首先存储在本地,而是直接写入 AWSStream。请参阅: 是否可以覆盖 MultipartFormDataStreamProvider 以便不将上传内容保存到文件系统?

但我不得不说我也喜欢 trailmax 的解决方案。

于 2013-11-02T21:09:52.173 回答
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);

    }
}
于 2013-07-19T20:42:14.940 回答