是否可以覆盖MultipartFormDataStreamProvider,这样就不会将上传保存到文件系统中?

Sto*_*oop 31 c# asp.net-web-api

我有一个ASP.Net Web API应用程序,允许客户端(HTML页面和iPhone应用程序)上传图像.我正在使用本文中描述的异步上载任务.

当我想要保存到文件系统时,一切都很好,因为这就是这个代码在幕后看起来自动执行的操作.但是,我不想将上传的文件保存到文件系统中.相反,我想使用AWS SDK for .Net获取上传的流并将其传递到Amazon S3存储桶.

我已将代码设置为将流发送到AWS.我无法弄清楚的问题是如何从Web API方法获取上传的内容流,而不是让它自动保存到磁盘.

我希望我可以在MultipartFormDataStreamProvider中覆盖一个虚拟方法,它允许我对上传的内容做其他事情,而不是保存到磁盘,但似乎没有.

有什么建议?

Kir*_*lla 45

您可以覆盖MultipartFormDataStreamProvider的GetStream方法以返回不是文件流但是您的AWS流的流,但是有一些问题这样做(我在此不再赘述).相反,您可以创建一个派生自抽象基类MultipartStreamProvider的提供程序.以下示例主要基于MultipartFormDataStreamProvider和MultipartFileStreamProvider的实际源代码.您可以检查在这里这里了解更多详情.以下示例:

public class CustomMultipartFormDataStreamProvider : MultipartStreamProvider
{
    private NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);

    private Collection<bool> _isFormData = new Collection<bool>();

    private Collection<MyMultipartFileData> _fileData = new Collection<MyMultipartFileData>();

    public NameValueCollection FormData
    {
        get { return _formData; }
    }

    public Collection<MultipartFileData> FileData
    {
        get { return _fileData; }
    }

    public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
    {
        // For form data, Content-Disposition header is a requirement
        ContentDispositionHeaderValue contentDisposition = headers.ContentDisposition;
        if (contentDisposition != null)
        {
            // If we have a file name then write contents out to AWS stream. Otherwise just write to MemoryStream
            if (!String.IsNullOrEmpty(contentDisposition.FileName))
            {
                // We won't post process files as form data
                _isFormData.Add(false);

                 MyMultipartFileData fileData = new MyMultipartFileData(headers, your-aws-filelocation-url-maybe);
                 _fileData.Add(fileData);

                return myAWSStream;//**return you AWS stream here**
            }

            // We will post process this as form data
            _isFormData.Add(true);

            // If no filename parameter was found in the Content-Disposition header then return a memory stream.
            return new MemoryStream();
        }

        throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part..");
    }

    /// <summary>
    /// Read the non-file contents as form data.
    /// </summary>
    /// <returns></returns>
    public override async Task ExecutePostProcessingAsync()
    {
        // Find instances of HttpContent for which we created a memory stream and read them asynchronously
        // to get the string content and then add that as form data
        for (int index = 0; index < Contents.Count; index++)
        {
            if (_isFormData[index])
            {
                HttpContent formContent = Contents[index];
                // Extract name from Content-Disposition header. We know from earlier that the header is present.
                ContentDispositionHeaderValue contentDisposition = formContent.Headers.ContentDisposition;
                string formFieldName = UnquoteToken(contentDisposition.Name) ?? String.Empty;

                // Read the contents as string data and add to form data
                string formFieldValue = await formContent.ReadAsStringAsync();
                FormData.Add(formFieldName, formFieldValue);
            }
        }
    }

    /// <summary>
    /// Remove bounding quotes on a token if present
    /// </summary>
    /// <param name="token">Token to unquote.</param>
    /// <returns>Unquoted token.</returns>
    private static string UnquoteToken(string token)
    {
        if (String.IsNullOrWhiteSpace(token))
        {
            return token;
        }

        if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
        {
            return token.Substring(1, token.Length - 2);
        }

        return token;
    }
}

public class MyMultipartFileData
{
    public MultipartFileData(HttpContentHeaders headers, string awsFileUrl)
    {
        Headers = headers;
        AwsFileUrl = awsFileUrl;
    }

    public HttpContentHeaders Headers { get; private set; }

    public string AwsFileUrl { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 我真的希望看到该部分澄清了流被写入myAWSStream的位置.我想写一些Azure Blob存储而不是AWS.但我不知道(在方法GetStream中)如何访问流.在这个方法中我想做:BlobService.StoreImageToBlobFromStream(stream) (5认同)
  • 是的,无法解释的是MS会发送一个**需要*访问文件系统来处理这种基本场景的API.他们认为人们可能不会想要访问文件写入并执行磁盘IO来处理表单POST.格儿. (5认同)
  • 解决方案似乎是"让我们通过从这个类复制一大堆代码创建我们自己的类,其余来自这个类"几乎让我哭了. (3认同)

use*_*702 5

MultipartFormDataRemoteStreamProvider自从 @KiranChalla 发布了他们的答案后,Fix 1760中引入了一个新的抽象类:使 MultipartFormDataStreamProvider 更容易与非 FileStream 一起使用。让这变得更容易。

课程摘要很好地解释了如何使用它:

适合与 HTML 文件上传一起使用的实现MultipartStreamProvider,用于将文件内容写入远程存储Stream。流提供者查看 Content-Disposition 标头字段,并Stream根据文件名参数的存在确定输出远程。如果 Content-Disposition 标头字段中存在文件名参数,则正文部分将写入StreamGetRemoteStream. 否则它会被写入 a MemoryStream