I am trying to look at the fields of a Multipart upload and based on the contents of the string fields decide if I want to extract the attached files or not.
So it seemed reasonable to create a Custom MultiPartFormDataStreamprovider and check in there but when I try to copy the data via CopyToAsync pointing at a filestream I get no data. It seems the stream has already been read. What am I doing wrong?
internal class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider { isValidFields _validateFields; internal CustomMultipartFormDataStreamProvider(string path, isValidFields validateFields) : base(path) { _validateFields = validateFields; } private readonly Collection _isFormData = new Collection(); // private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase); //public NameValueCollection FormData //{ //get { return _formData; } //} public override async Task ExecutePostProcessingAsync() { for (var index = 0; index < Contents.Count; index++) { if (IsStream(index)) continue;
var formContent = Contents[index];
var contentDisposition = formContent.Headers.ContentDisposition;
var formFieldName = UnquoteToken(contentDisposition.Name) ?? string.Empty;
var formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
if (_validateFields != null)
{
if (_validateFields(FormData) == false)
{
throw new Exception("Invalid data");
}
}
for (var index = 0; index < Contents.Count; index++)
{
if (!IsStream(index))
continue;
var formContent = Contents[index];
var contentDisposition = formContent.Headers.ContentDisposition;
var formFieldName = UnquoteToken(contentDisposition.Name) ?? string.Empty;
FileStream fileStream = null;
string pathname = Path.Combine(base.RootPath, Path.GetFileName(GetLocalFileName(formContent.Headers)));
using (fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None))
{
try
{
await formContent.CopyToAsync(fileStream).ContinueWith((copyTask) =>
{
fileStream.Close();
});
}
catch (Exception ex)
{
throw;
}
}
}
}
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 bool IsStream(int idx)
{
return !_isFormData[idx];
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null) throw new ArgumentNullException("parent");
if (headers == null) throw new ArgumentNullException("headers");
var contentDisposition = headers.ContentDisposition;
if (contentDisposition != null)
{
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
Stream result = base.GetStream(parent, headers);
return result;
}
throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
}
public override string GetLocalFileName(HttpContentHeaders headers)
{
return headers.ContentDisposition.FileName.Replace("\"", string.Empty);
}
}
this is called by
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string guid = Guid.NewGuid().ToString();
string fileSaveLocation = HttpContext.Current.Server.MapPath("~/App_Data");
if (subDir.Length > 0)
Path.Combine(fileSaveLocation, subDir);
fileSaveLocation = Path.Combine(fileSaveLocation, guid);
Directory.CreateDirectory(fileSaveLocation);
CustomMultipartFormDataStreamProvider provider = new CustomMultipartFormDataStreamProvider(fileSaveLocation, validateFields);
try
{
// Read all contents of multipart message into CustomMultipartFormDataStreamProvider and allow validation of fields
await Request.Content.ReadAsMultipartAsync(provider);