的WebAPI FORMDATA上传(到DB)与额外的参数 [英] Webapi formdata upload (to DB) with extra parameters

查看:1487
本文介绍了的WebAPI FORMDATA上传(到DB)与额外的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我已经找到计算器以下职位:<一href=\"http://stackoverflow.com/questions/17177237/webapi-ajax-formdata-upload-with-extra-parameters\">Webapi阿贾克斯FORMDATA额外参数上传

它描述了如何利用这个MultipartFormDataStreamProvider和保存数据做文件服务器。我并不需要的文件保存到服务器,而是到DB。
我已经工作code。使用MultipartMemoryStreamProvider,但它不使用额外的参数。

您可以给我的线索如何处理中的WebAPI额外PARAMATERS?

例如,如果我添加的文件,也测试paramater:

  data.append(myParameter,测试);

下面是我的WebAPI的处理文件上传,无需额外paramater:

 如果(Request.Content.IsMimeMultipartContent())
{
    VAR streamProvider =新MultipartMemoryStreamProvider();
    VAR任务= Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<IEnumerable<FileModel>>(t = GT;
    {
        如果(t.IsFaulted || t.IsCanceled)
        {
            抛出新的Htt presponseException(的HTTPStatus code.InternalServerError);
        }        _fleDataService =新FileDataBLL();
        FLE的FileData;        变种fleInfo = streamProvider.Contents.Select(ⅰ= GT; {
            FLE =新的FileData();
            fle.FileName = i.Headers.ContentDisposition.FileName;            变种contentTest = i.ReadAsByteArrayAsync();
            contentTest.Wait();
            如果(contentTest.Result!= NULL)
            {
                fle.FileContent = contentTest.Result;
            }            //这里得到额外的参数??????            _fleDataService.Save(FLE);            返回新FileModel(i.Headers.ContentDisposition.FileName,1024); //去做
        });
        返回fleInfo;
    });
    返回任务;
}


解决方案

您可以通过实现自定义 DataStreamProvider ,一个不那么很干净的方式做到这一点复制从 MultipartFormDataStreamProvider 由多部分内容解析FORMDATA的逻辑。

我不明白为什么在作出决定的子类 MultipartFormDataStreamProvider MultiPartFileStreamProvider 没有至少提取code标识和公开FORMDATA集合,因为它涉及的只是文件保存到磁盘之外的多部分数据的许多任务非常有用。

不管怎样,下面的提供者应该帮助解决您的问题。您仍然需要确保当你遍历你忽略了什么,没有一个文件名的内容提供商(特别声明 streamProvider.Contents.Select()否则你的风险尝试上传的FORMDATA到DB)。因此,code,要求的供应商是一个HttpContent IsStream(),这是一个黑客位,但在最简单的是我能想到这样做。

请注意,它基本上是从 MultipartFormDataStreamProvider 源剪切和粘贴之能事 - 它并没有经过严格的测试(由<一个启发href=\"http://stackoverflow.com/questions/15842496/is-it-possible-to-override-multipartformdatastreamprovider-so-that-is-doesnt-sa\">this回答)。

 公共类MultipartFormDataMemoryStreamProvider:MultipartMemoryStreamProvider
{
    私人只读集合&LT;布尔&GT; _isFormData =新的收集和LT;布尔&GT;();
    私人只读NameValueCollection中_formData =新的NameValueCollection(StringComparer.OrdinalIgnoreCase);    公众的NameValueCollection FORMDATA
    {
        {返回_formData; }
    }    公共覆盖流GetStream(HttpContent父母,HttpContentHeaders头)
    {
        如果(家长== NULL)抛出新的ArgumentNullException(母公司);
        如果(头== NULL)抛出新的ArgumentNullException(头);        VAR contentDisposition = headers.ContentDisposition;        如果(contentDisposition!= NULL)
        {
            _isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
            返回base.GetStream(母头);
        }        抛出新的InvalidOperationException异常(没有发现需要MIME多主体部分内容处置头字段。);
    }    公共覆盖异步任务ExecutePostProcessingAsync()
    {
        对于(VAR指数= 0;指数 - LT; Contents.Count;指数++)
        {
            如果(IsStream(指数))
                继续;            VAR formContent =目录[指数]
            VAR contentDisposition = formContent.Headers.ContentDisposition;
            VAR formFieldName = UnquoteToken(contentDisposition.Name)?的String.Empty;
            VAR formFieldValue =等待formContent.ReadAsStringAsync();
            FormData.Add(formFieldName,formFieldValue);
        }
    }    私人静态字符串UnquoteToken(字符串标记)
    {
        如果(string.IsNullOrWhiteSpace(标记))
            返回记号。        如果(token.StartsWith(\\,StringComparison.Ordinal)及&放大器; token.EndsWith(\\,StringComparison.Ordinal)及&放大器; token.Length→1)
            返回token.Substring(1,token.Length - 2);        返回记号。
    }    公共BOOL IsStream(INT IDX)
    {
        返回_isFormData [IDX]!;
    }
}

它可以用来如下(TPL使用语法来匹配你的问题):

  [HttpPost]
公共任务&LT;串GT;邮政()
{
    如果(!Request.Content.IsMimeMultipartContent())
        抛出新的Htt presponseException(Request.CreateResponse(的HTTPStatus code.NotAcceptable,无效的请求!));    VAR提供商=新MultipartFormDataMemoryStreamProvider();    返回Request.Content.ReadAsMultipartAsync(供应商).ContinueWith(P =&GT;
    {
        VAR的结果= p.Result;
        VAR myParameter = result.FormData.GetValues​​(myParameter)FirstOrDefault()。        的foreach(在result.Contents.Where变种流((内容,IDX)=&GT; result.IsStream(IDX)))
        {
            var文件=新的FileData(stream.Headers.ContentDisposition.FileName);
            变种contentTest = stream.ReadAsByteArrayAsync();
            // ...等等,按你原来的code。        }
        返回myParameter;
    });
}

我用下面的HTML表单进行了测试:

 &LT;形式的行动=/ API /值方法=POSTENCTYPE =的multipart / form-data的&GT;
    &LT;输入名称=myParameter类型=隐藏值=我不做什么有趣的东西/&GT;
    &LT;输入类型=文件名称=文件1/&GT;
    &LT;输入类型=文件名称=文件2/&GT;
    &LT;输入类型=提交VALUE =OK/&GT;
&LT; /表及GT;

I need to upload file sending extra paramaters.

I have found the following post in stackoverflow: Webapi ajax formdata upload with extra parameters

It describes how to do this using MultipartFormDataStreamProvider and saving data to fileserver. I do not need to save file to server, but to DB instead. And I have already working code using MultipartMemoryStreamProvider, but it doesn't use extra parameter.

Can you give me clues how to process extra paramaters in webapi?

For example, if I add file and also test paramater:

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

Here is my webapi that processes fileupload without extra paramater:

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

解决方案

You can achieve this in a not-so-very-clean manner by implementing a custom DataStreamProvider that duplicates the logic for parsing FormData from multi-part content from MultipartFormDataStreamProvider.

I'm not quite sure why the decision was made to subclass MultipartFormDataStreamProvider from MultiPartFileStreamProvider without at least extracting the code that identifies and exposes the FormData collection since it is useful for many tasks involving multi-part data outside of simply saving a file to disk.

Anyway, the following provider should help solve your issue. You will still need to ensure that when you iterate the provider content you are ignoring anything that does not have a filename (specifically the statement streamProvider.Contents.Select() else you risk trying to upload the formdata to the DB). Hence the code that asks the provider is a HttpContent IsStream(), this is a bit of a hack but was the simplest was I could think to do it.

Note that it is basically a cut and paste hatchet job from the source of MultipartFormDataStreamProvider - it has not been rigorously tested (inspired by this answer).

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

    public NameValueCollection FormData
    {
        get { return _formData; }
    }

    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));
            return base.GetStream(parent, headers);
        }

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

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

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

It can be used as follows (using TPL syntax to match your question):

[HttpPost]
public Task<string> Post()
{
    if (!Request.Content.IsMimeMultipartContent())
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!"));

    var provider = new MultipartFormDataMemoryStreamProvider();

    return Request.Content.ReadAsMultipartAsync(provider).ContinueWith(p =>
    {
        var result = p.Result;
        var myParameter = result.FormData.GetValues("myParameter").FirstOrDefault();

        foreach (var stream in result.Contents.Where((content, idx) => result.IsStream(idx)))
        {
            var file = new FileData(stream.Headers.ContentDisposition.FileName);
            var contentTest = stream.ReadAsByteArrayAsync();
            // ... and so on, as per your original code.

        }
        return myParameter;
    });
}

I tested it with the following HTML form:

<form action="/api/values" method="post" enctype="multipart/form-data">
    <input name="myParameter" type="hidden" value="i dont do anything interesting"/>
    <input type="file" name="file1" />
    <input type="file" name="file2" />
    <input type="submit" value="OK" />
</form>

这篇关于的WebAPI FORMDATA上传(到DB)与额外的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆