MVC中的Ajax.BeginForm上传文件

Posted

技术标签:

【中文标题】MVC中的Ajax.BeginForm上传文件【英文标题】:Ajax.BeginForm in MVC to upload files 【发布时间】:2013-10-03 05:46:39 【问题描述】:

我试图使用这里提到的示例How to do a ASP.NET MVC Ajax form post with multipart/form-data?

但我不断收到“失败”错误消息框

索引.cshtml

<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<h2>Files Upload</h2>
<script type="text/javascript">
$(function() 
    $("#form0").submit(function(event) 
        var dataString;
        event.preventDefault();
        var action = $("#form0").attr("action");
        if ($("#form0").attr("enctype") == "multipart/form-data") 
            //this only works in some browsers.
            //purpose? to submit files over ajax. because screw iframes.
            //also, we need to call .get(0) on the jQuery element to turn it into a regular DOM element so that FormData can use it.
            dataString = new FormData($("#form0").get(0));
            contentType = false;
            processData = false;
         else 
            // regular form, do your own thing if you need it
        
        $.ajax(
            type: "POST",
            url: action,
            data: dataString,
            dataType: "json", //change to your own, else read my note above on enabling the JsonValueProviderFactory in MVC
            contentType: contentType,
            processData: processData,
            success: function(data) 
                //BTW, data is one of the worst names you can make for a variable

            ,
            error: function(jqXHR, textStatus, errorThrown) 
                //do your own thing
                alert("fail");
            
        );
    ); //end .submit()
);
</script>
<div id="uploadDiv">
@Html.Action("Files", "Home")
</div>

@using (Ajax.BeginForm("Files", "Home", new AjaxOptions  UpdateTargetId = "uploadDiv", HttpMethod = "Post" , new  enctype = "multipart/form-data", @id="form0"))

<div>
    <div>Upload new file:
        <input type="file" name="file" /></div>
    <input type="submit" value="Save" />
</div>

<br />

控制器

public PartialViewResult Files(HttpPostedFileBase file)
    
        IEnumerable<string> files;
        if ((file != null) && (file.ContentLength > 0))
        
            string fileName = file.FileName;
            string saveLocation = @"D:\Files";
            string fullFilePath = Path.Combine(saveLocation, fileName);               


            try
            
                file.SaveAs(fullFilePath);
                FileInfo fileInfo = new FileInfo(fullFilePath);
                file.InputStream.Read(new byte[fileInfo.Length], 0, file.ContentLength);                    
            
            catch (Exception e)
            
                TempData["FileUpload"] = e.Message;
                return PartialView();
            
            files = Directory.GetFiles(@"D:\Files\");
            return PartialView(files);
        
        else
        
            files = Directory.GetFiles(@"D:\Files\");
            return PartialView(files);
        
    

文件.cshtml

@model IEnumerable<string>

@foreach (string f in Model)

<p>@f</p>

全球.asax

ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

【问题讨论】:

我不久前写了一篇关于此的博客文章 - 可能会对您有所帮助:blog.shadowmoses.co.uk/2013/06/… 您在 Ajax.BeginForm 方法上缺少路由值。 【参考方案1】:

那比较复杂最好用jquery forms plugin。

示例如下:

Html.BeginForm

 @using (Html.BeginForm("YourAction", "YourController"))

    @Html.AntiForgeryToken()
    <input type="file" name="files"><br>
    <input type="submit" value="Upload File to Server">

动作方法

    [HttpPost]
    [ValidateAntiForgeryToken]
    public void YourAction(IEnumerable<HttpPostedFileBase> files)
    
        if (files != null)
        
            foreach (var file in files)
            
                // Verify that the user selected a file
                if (file != null && file.ContentLength > 0)
                
                    // extract only the fielname
                    var fileName = Path.GetFileName(file.FileName);
                    // TODO: need to define destination
                    var path = Path.Combine(Server.MapPath("~/Upload"), fileName);
                    file.SaveAs(path);
                
            
        
    

进度条

<div class="progress progress-striped">
   <div class="progress-bar progress-bar-success">0%</div>
</div>

Jquery 和表单脚本

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>

<script>
(function() 

var bar = $('.progress-bar');
var percent = $('.progress-bar');
var status = $('#status');

$('form').ajaxForm(
    beforeSend: function() 
        status.empty();
        var percentVal = '0%';
        bar.width(percentVal)
        percent.html(percentVal);
    ,
    uploadProgress: function(event, position, total, percentComplete) 
        var percentVal = percentComplete + '%';
        bar.width(percentVal)
        percent.html(percentVal);
    ,
    success: function() 
        var percentVal = '100%';
        bar.width(percentVal)
        percent.html(percentVal);
    ,
    complete: function(xhr) 
        status.html(xhr.responseText);
    
); 

)();       
</script>

更新...

遇到两次调用action方法问题的人是由于Ajax.BeginForm,只需将其转换为Html.BeginForm()。 更多说明和下载示例代码,请参阅this blog

【讨论】:

尝试在 $('form').ajaxForm() 中添加 dataType: 'json', type: "POST", contentType: "application/json"; 在IE文件uploder中添加此代码后禁用 @AshwiniVerma - 有了这个我没有在方法的参数中选择文件 - 文件,它是空的。你能告诉我这个。另外我还没有添加 Jquery 和表单脚本因为我不想要进度条。 @Saroj:确保文件输入的名称属性与操作方法的参数匹配。在我的示例中,它是 name="files" . 这是一个无效的方法。提交后,我想返回表单。【参考方案2】:

Ashwini Verma 的回答几乎是正确的,但有一个缺点,表单提交了两次。

这是由使用Ajax.BeginForm() 引起的。使用Html.BeginForm() 将修复它。

这是一个例子:

@* do not use Ajax.BeginForm() as it would cause the form to submit twice in connection with jQuery.Form *@
@using (var lForm = Html.BeginForm( 
  <ActionName>, <ControllerName>, FormMethod.Post, 
  new Dictionary<string, object> "name", <YourFormName>, "enctype", "multipart/form-data"))

【讨论】:

你是对的。它发送表单两次,但是如何使用 Html.BeginForm() 并放置一个 UpdateTargetId? @kavain 查看 Ajax.BeginForm() 生成的 HTML 代码并将其应用于 Html.BeginForm() 调用。它基本上是由 jQuery Ajax Unobtrusive 插件解析的所有 HTML 标记属性。因此,如果您确保正确生成更新目标的属性,那么目标更新也应该起作用。【参考方案3】:

您需要在客户端处理 html5 文件并读取文件内容以获取 base64 编码数据。

在客户端你必须放:

<div>
        @Html.HiddenFor(m => m.AttachmentFileName)
        @Html.HiddenFor(m => m.AttachmentFileSize)
        @Html.HiddenFor(m => m.AttachmentFileType)
        @Html.HiddenFor(m => m.AttachmentFileContentsBase64)

    <input type="file" name="AttachmentFile" id="AttachmentFile" onchange="handleAttachmentFileChange(this.files)" />
    @Html.ValidationMessageFor(m => m.AttachmentFile)
</div>

<script>
    function handleAttachmentFileChange(files) 
        var file = files[0];
        $("#AttachmentFileName").val(file.name);
        $("#AttachmentFileSize").val(file.size);
        $("#AttachmentFileType").val(file.type || "application/octet-stream");

        var fileReader = new FileReader();
        fileReader.onload = function () 
            fileReader.result;

            $("#AttachmentFileContentsBase64").val(fileReader.result);
        ;
        fileReader.readAsDataURL(file);
    ;
</script>

因此,您的代码将使用文件数据(文件名、类型、大小、base64 编码内容)填充隐藏字段。 在服务器端你放:

            if (AttachmentFileSize > 0)
            
                string fileName = AttachmentFileName.Contains("\\") ? AttachmentFileName.Substring(AttachmentFileName.LastIndexOf("\\") + 1) : AttachmentFileName;

                byte[] fileBytes = Convert.FromBase64String(AttachmentFileContentsBase64.Substring(AttachmentFileContentsBase64.IndexOf(',') + 1));

//save file to file system or db

                ModelState.Remove("CurrentAttachmentFileId");
                ModelState.Remove("CurrentAttachmentFileName");

            
            else if (AttachmentFileSize == -1)
            
//remove existing file from fs or db
            

代码需要使用您的模型和逻辑进行修改,但它对我有用

【讨论】:

以上是关于MVC中的Ajax.BeginForm上传文件的主要内容,如果未能解决你的问题,请参考以下文章

asp.net mvc  Ajax.BeginForm 异步上传图片的问题

MVC Ajax.BeginForm 提交上传图片

[Asp.net mvc]jquery.form.js无刷新上传

在 MVC3 中的 Ajax.Beginform 中调用自定义确认对话框

MVC小系列Html.BeginForm与Ajax.BeginForm

MVC4 剑道项目 Ajax.BeginForm UpdateTargetId 问题