jQuery MVC中的Ajax.BeginForm上传文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19042116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ajax.BeginForm in MVC to upload files
提问by Alexander C.
I was trying to use an example mentioned here How to do a ASP.NET MVC Ajax form post with multipart/form-data?
我试图使用这里提到的一个例子How to do a ASP.NET MVC Ajax form post with multipart/form-data?
But I keep getting "fail" error message box
但我不断收到“失败”错误消息框
Index.cshtml
索引.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 />
Controller
控制器
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);
}
}
Files.cshtml
文件.cshtml
@model IEnumerable<string>
@foreach (string f in Model)
{
<p>@f</p>
}
Global.asax
全球.asax
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
回答by Ashwini Verma
That is complicated better use jquery forms plugin.
这很复杂,最好使用jquery 表单插件。
Here is the sample:
这是示例:
Html.BeginForm
Html.BeginForm
@using (Html.BeginForm("YourAction", "YourController"))
{
@Html.AntiForgeryToken()
<input type="file" name="files"><br>
<input type="submit" value="Upload File to Server">
}
Action Method
动作方法
[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);
}
}
}
}
Progress Bar
进度条
<div class="progress progress-striped">
<div class="progress-bar progress-bar-success">0%</div>
</div>
Jquery & Form script
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>
Update...
更新...
People who are getting issue of calling action method twice is due to Ajax.BeginForm, just convert it to Html.BeginForm(). For more clarification and to download sample code please refer at this blog.
遇到两次调用 action 方法问题的人是由于 Ajax.BeginForm,只需将其转换为 Html.BeginForm()。有关更多说明和下载示例代码,请参阅此博客。
回答by ViRuSTriNiTy
The answer from Ashwini Verma
is almost correct but it has a drawback, the form is submitted twice.
来自的答案Ashwini Verma
几乎是正确的,但它有一个缺点,表单提交了两次。
This is caused by the use of Ajax.BeginForm()
. Using Html.BeginForm()
will fix it.
这是由于使用Ajax.BeginForm()
. 使用Html.BeginForm()
将修复它。
Here's an example:
下面是一个例子:
@* 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"}}))
{
回答by Pavel Nazarov
You need html5 file handling and read file contents on client to get base64 encoded data.
您需要 html5 文件处理并在客户端读取文件内容以获取 base64 编码数据。
On client you have to put:
在客户端你必须把:
<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>
So your code will fill hidden fields with file data (filename, type, size, base64 encoded contents). And on server side you put:
因此,您的代码将使用文件数据(文件名、类型、大小、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
}
The code needs to be modified with your models and logic but it worked for me
代码需要使用您的模型和逻辑进行修改,但它对我有用