我有一个ASP.Net Web API应用程序,允许客户端(html页面和iPhone应用程序)上传图像。我正在使用此article中描述的异步上传任务。
当我想要保存到文件系统时,一切都很有效,因为这就是这个代码在幕后看起来自动执行的操作。但是,我不想将上传的文件保存到文件系统中。相反,我想使用AWS SDK for .Net将上传的流传递到Amazon S3存储桶。
我已将代码设置为将流发送到AWS。我无法弄清楚的问题是如何从Web API方法获取上传的内容流,而不是让它自动保存到磁盘。
我希望在 MultipartFormDataStreamProvider 中可以覆盖一个虚拟方法,它允许我对上传的内容做其他事情,而不是保存到磁盘,但似乎没有
有什么建议吗?
答案 0 :(得分:42)
您可以覆盖MultipartFormDataStreamProvider的GetStream方法以返回不是文件流但是您的AWS流的流,但是有一些问题这样做(我在此不再赘述)。相反,您可以创建一个派生自抽象基类MultipartStreamProvider的提供程序。以下示例主要基于MultipartFormDataStreamProvider和MultipartFileStreamProvider的实际源代码。您可以查看 here 和 here 了解详情。以下示例:
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; }
}
答案 1 :(得分:2)
由于@KiranChalla发布了他们的答案,因此在MultipartFormDataRemoteStreamProvider
中引入了一个新的抽象类Fix 1760: Make MultipartFormDataStreamProvider easier to work with non-FileStreams.,以简化这一过程。
该课程摘要在解释如何使用它方面做得很好:
适用于HTML文件上传的
MultipartStreamProvider
实现,用于将文件内容写入远程存储Stream
。流提供程序查看Content-Disposition头字段,并根据filename参数的存在确定输出远程Stream
。如果Content-Disposition标头字段中存在filename参数,则正文部分将写入Stream
提供的远程GetRemoteStream
。否则会写入MemoryStream
。