ASP.Net MVC 使用 jquery-form 插件上传文件并返回 Json 结果

Posted

技术标签:

【中文标题】ASP.Net MVC 使用 jquery-form 插件上传文件并返回 Json 结果【英文标题】:ASP.Net MVC Upload file using jquery-form plugin and returning a Json result 【发布时间】:2011-07-01 17:44:42 【问题描述】:

我正在尝试使用 JQuery 表单插件 (http://jquery.malsup.com/form/) 从我的视图中上传一个文件和几个额外的字段,并且我希望操作方法返回一个 Json javascript回调的结果。

目前,ActionMethod 被正确调用(我可以处理表单中的文件和字段)但是当我返回 Json 结果时,浏览器会尝试将其作为文件下载(如果我下载文件并查看其内容,则我返回的 JSON 内容。)。

这是我的表格:

<form id="FormNewFile" action="@Url.Content("~/Home/AddFile")" method="post" enctype="multipart/form-data">
    <input type="hidden" name="eventId" value="25" />
    <input type="text" name="description" />
    <input type="file" name="fileName" />
    <input type="submit" value="Send!" />
</form>

这是我的 javascript:

  <script type="text/javascript">
     $(function () 
        $("#FormNewFile").ajaxForm(
           dataType:'json',
           success:processJson
     );
     );

     function processJson(a,b) 
        alert('success');
     
  </script>

这是我的 ActionMethod:

   [HttpPost]
   public ActionResult AddFile(long? eventId, string description)
   
      int id = 5;
      return Json(new id);
   

浏览器尝试下载的文件名称类似于 AddFilee87ce48e,最后 8 个字符是随机的十六进制字符。

最后,下载的文件内容是:

"id":5

而且 javascript 中的 processJson 函数永远不会被调用。

我在 Google 上搜索了很多,唯一可行的是将 JSON 结果作为 action 方法的“内容”结果返回,我认为这就是我要采用的方法,但我仍然想知道为什么会这样不工作?

有什么想法吗?

【问题讨论】:

【参考方案1】:

我最终做的是手动序列化我想要返回为 JSON 的对象,如果我这样做,那么响应将没有标题,因此它将由 javascript 而不是浏览器处理。我使用了这个辅助方法:

  public static ActionResult JsonPlain(object x)
  
     var result = new ContentResult();
     result.Content = new JavaScriptSerializer().Serialize(x);
     return result;
  

希望这对其他人有帮助

【讨论】:

Thanx willvv,成功了。我只是在 IE9 中遇到这个问题 +1 @willw,谢谢。还解决了我在 IE9 想要下载 JSON 响应时遇到的问题。【参考方案2】:

这是正常行为。 Excerpt from the documentation:

由于无法上传 使用浏览器的文件 XMLHttpRequest 对象,表单插件 使用隐藏的 iframe 元素来帮助 与任务。这是一个常见的 技术,但它有内在的 限制。 iframe 元素是 用作表单的目标 提交操作,这意味着 服务器响应被写入 框架。这很好,如果响应 类型是 html 或 XML,但不起作用 以及如果响应类型是脚本 或 JSON,这两者通常都包含 需要reresented的字符 在找到时使用实体引用 HTML 标记。

为了应对挑战 脚本和 JSON 响应,表单 插件允许这些响应 嵌入在 textarea 元素中,它 建议您这样做 这些响应类型在使用时 与文件上传结合。请 但是请注意,如果没有 在表单中输入文件,然后 请求使用普通 XHR 提交 表单(不是 iframe)。这使 你的服务器代码负担要知道 何时使用 textarea 何时不使用 到。如果你喜欢,你可以使用 要强制的插件的 iframe 选项 它总是使用 iframe 模式和 那么你的服务器总是可以嵌入 文本区域中的响应。下列 响应显示脚本应该如何 从服务器返回:

这意味着如果你想返回 JSON,你需要将它包装在你服务器上的 &lt;textarea&gt; 标签中。为此,您可以编写一个源自JsonResult 的自定义操作结果,并将生成的 JSON 包装在这些标签中。

【讨论】:

是的,我看到了,但我只是不理解 【参考方案3】:

以下博客文章 jQuery File Upload in ASP.NET MVC without using Flash 解决了将响应包装在文本区域中的问题,如 Darin Dimitrov 的回答所述。

【讨论】:

【参考方案4】:

查看表单标签上的操作:

action="@Url.Content("~/Home/AddFile")"

我见过的唯一用法是在脚本标签中,例如:

<script language="javascript" src="<%=Url.Content("~/Scripts/jquery-1.3.2.js")%>

该操作的正确参考是:

action="/Home/Addfile"

虽然我不太确定为什么但 UrlHelper 的解释:

Url.Content("~/somepath")

将虚拟路径转换为绝对路径并需要一个物理文件,例如 javascript。

json 结果可能会作为文件下载返回,因为 mvc 框架需要一些描述的文件下载。就像:

<a href="<%= Url.Content("~/_docs/folder/folder/document.pdf") %>">
document.pdf</a>

将下载或显示物理 pdf 文件。

【讨论】:

你说得对,Url.Content 并不是要这样做,但最终它会生成 action="Home/Addfile",所以它没有任何区别。它实际上是在尝试下载文件,因为当您返回 JsonResult 时,它会添加一个 JSON 标头,并且浏览器会尝试处理带有标头的所有响应。【参考方案5】:

我的解决方案使用 json 并且没有特定的 javascript:

/// <summary>
/// A result to use in combination with jquery.ajax.form when we want to upload a file using ajax
/// </summary>
public class FileJsonResult : JsonResult

    public JsonResult Result  get; set; 

    public FileJsonResult(JsonResult result):base()
    
        this.Result = result;
    

    public override void ExecuteResult(ControllerContext context)
    
        context.HttpContext.Response.Write("<textarea>");
        this.Result.ExecuteResult(context);
        context.HttpContext.Response.Write("</textarea>");
        context.HttpContext.Response.ContentType = "text/html";
    

【讨论】:

以上是关于ASP.Net MVC 使用 jquery-form 插件上传文件并返回 Json 结果的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 和 Angularjs 与 ASP.NET MVC 和 Reactjs

Asp.net mvc和asp.net有啥区别?

ASP.NET MVC

ASP.NET中的MVC如何使用?

ASP.NET中的MVC如何使用?

七天学会ASP.NET MVC ——ASP.NET MVC 数据传递