c# - 带有额外参数的 Webapi 表单数据上传(到 DB)

标签 c# file-upload asp.net-web-api form-data

我需要上传发送额外参数的文件。

我在 stackoverflow 中找到了以下帖子:Webapi ajax formdata upload with extra parameters

它描述了如何使用 MultipartFormDataStreamProvider 并将数据保存到文件服务器来执行此操作。我不需要将文件保存到服务器,而是保存到数据库。 我已经有使用 MultipartMemoryStreamProvider 的工作代码,但它不使用额外的参数。

你能告诉我如何在 webapi 中处理额外的参数吗?

例如,如果我添加文件并测试参数:

data.append("myParameter", "test"); 

这是我的 webapi,它在没有额外参数的情况下处理文件上传:

if (Request.Content.IsMimeMultipartContent())
{               
    var streamProvider = new MultipartMemoryStreamProvider();
    var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<IEnumerable<FileModel>>(t =>
    {
        if (t.IsFaulted || t.IsCanceled)
        {
            throw new HttpResponseException(HttpStatusCode.InternalServerError);
        }

        _fleDataService = new FileDataBLL();
        FileData fle;

        var fleInfo = streamProvider.Contents.Select(i => {         
            fle = new FileData();
            fle.FileName = i.Headers.ContentDisposition.FileName;

            var contentTest = i.ReadAsByteArrayAsync();
            contentTest.Wait();
            if (contentTest.Result != null)
            {
                fle.FileContent = contentTest.Result;
            }                       

            // get extra parameters here ??????

            _fleDataService.Save(fle);

            return new FileModel(i.Headers.ContentDisposition.FileName, 1024); //todo
        });
        return fleInfo;
    });
    return task;
}

最佳答案

扩展 gooid 的答案,我将 FormData 提取封装到提供程序中,因为我在引用它时遇到问题。在我看来,这只是提供了更好的实现。

public class MultipartFormDataMemoryStreamProvider : MultipartMemoryStreamProvider
{
    private readonly Collection<bool> _isFormData = new Collection<bool>();
    private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
    private readonly Dictionary<string, Stream> _fileStreams = new Dictionary<string, Stream>();

    public NameValueCollection FormData
    {
        get { return _formData; }
    }

    public Dictionary<string, Stream> FileStreams
    {
        get { return _fileStreams; }
    }

    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)
        {
            throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
        }

        _isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
        return base.GetStream(parent, headers);
    }

    public override async Task ExecutePostProcessingAsync()
    {
        for (var index = 0; index < Contents.Count; index++)
        {
            HttpContent formContent = Contents[index];
            if (_isFormData[index])
            {
                // Field
                string formFieldName = UnquoteToken(formContent.Headers.ContentDisposition.Name) ?? string.Empty;
                string formFieldValue = await formContent.ReadAsStringAsync();
                FormData.Add(formFieldName, formFieldValue);
            } 
            else
            {
                // File
                string fileName = UnquoteToken(formContent.Headers.ContentDisposition.FileName);
                Stream stream = await formContent.ReadAsStreamAsync();
                FileStreams.Add(fileName, stream);
            }
        }
    }

    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;
    }
}

下面是我的使用方法。请注意,由于我们使用的是 .NET 4.5,所以我使用了 await。

    [HttpPost]
    public async Task<HttpResponseMessage> Upload()
    {
        if (!Request.Content.IsMimeMultipartContent())
        {
            return Request.CreateResponse(HttpStatusCode.UnsupportedMediaType, "Unsupported media type.");
        }

        // Read the file and form data.
        MultipartFormDataMemoryStreamProvider provider = new MultipartFormDataMemoryStreamProvider();
        await Request.Content.ReadAsMultipartAsync(provider);

        // Extract the fields from the form data.
        string description = provider.FormData["description"];
        int uploadType;
        if (!Int32.TryParse(provider.FormData["uploadType"], out uploadType))
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest, "Upload Type is invalid.");
        }

        // Check if files are on the request.
        if (!provider.FileStreams.Any())
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest, "No file uploaded.");
        }

        IList<string> uploadedFiles = new List<string>();
        foreach (KeyValuePair<string, Stream> file in provider.FileStreams)
        {
            string fileName = file.Key;
            Stream stream = file.Value;

            // Do something with the uploaded file
            UploadManager.Upload(stream, fileName, uploadType, description);

            // Keep track of the filename for the response
            uploadedFiles.Add(fileName);
        }

        return Request.CreateResponse(HttpStatusCode.OK, "Successfully Uploaded: " + string.Join(", ", uploadedFiles));
    }

关于c# - 带有额外参数的 Webapi 表单数据上传(到 DB),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19723064/

相关文章:

c# - 将文件写入连接到 Windows PC 的 PNP 设备

java - GWT 和异步文件上传 - 帮助

angularjs - Angular POST 到 Web API 不传递数据

c# - 在 C# 中扩展 DataTable

c# - 假设图像旋转准确地操纵高度和宽度是否安全?

c# - 不能在 'Binding' 类型的 'Source' 属性上设置 'Binding'

php - Fine Uploader 需要分块文件并重新加入

Angular 2/Express 上传文件到服务器

c# - 通过 Web API 将文件流上传到 StreamReader

asp.net-web-api - 是什么导致 OWIN 管道中的 OperationCanceledException?