使用xmlhttprequest从c#服务器端的formData获取带有查询字符串的文件

时间:2015-03-29 18:50:20

标签: c# xmlhttprequest asp.net-core asp.net-core-mvc

我已经被困在这几个小时了,甚至谷歌都不能帮助了。我正在尝试使用xmlhttprequest将文件从客户端发送到后端。我无法获得C#端的文件名,类型或内容。我很感激这方面的帮助。我遇到的很多代码都有我在ASP.Net 5和MVC 6中不支持的方法(例如HttpContext.Current和HttpPostedFile)

这是我的客户端JavaScript请求。这会发送绑定到我的模型的查询字符串没有问题,因此很容易访问,但是获取文件是我遇到的问题。

var form = new FormData();
form.append("file", file);

var queryParams = "id=" + (id == null ? -1 : id);
queryParams += "&name=" + name;
queryParams += "&value=" + val;

xhrAttach(REST_DATA + "/attach?" + queryParams, form, function (item) {

    console.log('attached: ', item);
    alert(item.responseText);
    row.setAttribute('data-id', item.id);
    removeProgressIndicator(row);
    setRowContent(item, row);
}, function (err) {
    console.log(err);
    //stop showing loading message
    stopLoadingMessage();
    document.getElementById('errorDiv').innerHTML = err;
});

function xhrAttach(url, data, callback, errback)
{
    var xhr = new createXHR();
    xhr.open("POST", url, true);
    //xhr.setRequestHeader("Content-type", "multipart/form-data");
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                callback(parseJson(xhr.responseText));
            }else{
                errback("Error: "+xhr.responseText);
            }
        }
    };
    xhr.timeout = 1000000;
    xhr.ontimeout = errback;
    xhr.send(data);
}

这是我的Controller处理请求。附件是一个模型,查询字符串绑定到它没有问题。我无法找到如何将File参数添加到模型中,或者这甚至是否重要。我尝试的东西都在这个代码下。

    // POST: /api/db/attach
    [Route("/api/[controller]/attach")]
    [HttpPost]
    public async Task<dynamic> attach(Attachment attachment)
    {
        //get the file somehow

    }

我已经尝试了很多东西,但是不记得究竟是什么,这是我尝试过的一件事,但是没有用。

var file = Request.Form["file"];

这是附件模型以防万一

namespace MyModel.Models
{
    public class Attachment
    {
        public long id { get; set; }
        public string name { get; set; }
        public string value { get; set; }
    }
}

3 个答案:

答案 0 :(得分:0)

我建议尝试以下方法:

public async Task<dynamic> attach([FromURI]Attachment attachment, [FromBody] FormDataCollection formData)

然后FormDataCollection应该有用于检索的表单数据。

答案 1 :(得分:0)

将一个名为File的公共get / set属性添加到Attachment模型中,并将上传的文件绑定到此属性。

与您类似的模型: https://github.com/aspnet/Mvc/blob/9f9dcbe6ec2e34d8a0dfae283cb5e40d8b94fdb7/test/WebSites/ModelBindingWebSite/Models/Book.cs#L8

public class Book
{
   public string Name { get; set; }

   public IFormFile File { get; set; }
}

以下控制器提供了模型绑定上传文件的不同方式的示例。 https://github.com/aspnet/Mvc/blob/9f9dcbe6ec2e34d8a0dfae283cb5e40d8b94fdb7/test/WebSites/ModelBindingWebSite/Controllers/FileUploadController.cs#L81

public KeyValuePair<string, FileDetails> UploadModelWithFile(Book book)
        {
           var file = book.File;
            var reader = new StreamReader(file.OpenReadStream());
            var fileContent = reader.ReadToEnd();
            var parsedContentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);
            var fileDetails = new FileDetails
            {
                Filename = parsedContentDisposition.FileName,
                Content = fileContent
            };

            return new KeyValuePair<string, FileDetails>(book.Name, fileDetails);
        }

如果这不起作用,那么我怀疑你的请求格式不正确。

答案 2 :(得分:0)

如果要在MVC端使用模型,请不要使用查询参数或FormData。只是不要。对我来说,最好先将文件放入base64字符串,而不是尝试发送File对象本身。我发布了有关如何执行此操作的信息:Convert input=file to byte array

然后,声明并格式化JSON对象:

var dataObj = {
    file = fileByteArray[0],
    id = (id == null ? -1 : id),
    name = name,
    value = val
};

fileByteArray[0]正在引用我链接中的对象。我在那里的答案假设您只是将文件base64字符串加载到该全局数组对象中。您可以将它保存为数组,就像我一样,然后逐个循环遍历它们,将[0]替换为[i],例如,作为for循环中的索引器,或者只使用var fileByteArray = ""与其他代码一起使用,使其不会推送其他文件,但总是只覆盖该变量,&amp;只是使用它。

关于最后一个参数的注意事项 - 如果使用jQuery,请不要使用val - 这是一个关键字。我上面只有它,因为它是你传递给URL参数值的。

摆脱这一行中的queryParams

xhrAttach(REST_DATA + "/attach?" + queryParams, form, function (item) {

将其更改为:

xhrAttach(REST_DATA + "/attach", form, function (item) {

将内容类型设置为:

,将注释掉的位置设置为

xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");

更改您发送的内容 - 它不再是FormData,它是JSON对象,需要进行字符串化处理:

xhr.send(JSON.stringify(dataObj));

修复您的模型,现在包括文件base64 string:

public class Attachment
{
    public string file { get; set; }
    public long id { get; set; }
    public string name { get; set; }
    public string value { get; set; }
}

修复你的POST方法。 2个问题:

  1. 如果您的班级继承了[HttpPost],则无法使用ApiController,您可能应该这样做。它必须是[System.Web.Http.HttpPost],是的,它必须完全拼写出来,或者它会假设它是[System.Web.Mvc.HttpPost]而不是分配路线 - 当你尝试时会出现404 - Not Found错误做你的POST。如果您继承自Controller,请忽略此。
  2. 如果您继承自[FromBody],则需要在模型上添加ApiController代码:

    public async Task<dynamic> attach([FromBody]Attachment attachment) { ... }

  3. 然后你得到这样的文件:

    string base64FileString = attachment.file;
    

    如果要将其存储在数据库的byte[]中,可以将其转换为:

    byte[] bytes = System.Convert.FromBase64String(base64FileString);
    

    顺便说一句,我认为您的回复处理是错误的。我不会这样做:

    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                callback(parseJson(xhr.responseText));
            }else{
                errback("Error: "+xhr.responseText);
            }
        }
    };
    

    我就是这样做的:

    xhr.onreadystatechange = function(response){
        if(xhr.readyState == 4 && xhr.status == 200){
                callback(parseJson(response.target.responseText));
        } else {
                alert("Error: " + response.target.responseText);
        }
    };
    

    假设response.target.responseText以可以显示的方式从服务器端发回错误。如果没有,将它发送到可以解析它的功能将是正确的选择。我不认为xhr.responseText是正确的。