0
votes

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);
1

1 Answers

0
votes

okay by using the MultipartMemoryStreamProvider the xtraction to file can be held off and the functionality of MultiPartFormDataStreamprovider replicated, but with more control.