Tôi gặp sự cố này và tìm thấy giải pháp dựa trên Jonathan's code here. Có một số vấn đề với mã của anh ta, nhưng đây là giải pháp của tôi. Nếu bạn muốn tải lên một tập tin lớn, một cái gì đó giống như 1Gbyte tập tin, bạn phải chuck các tập tin và gửi nó thông qua một số yêu cầu (một yêu cầu cho thời gian ra). đầu tiên bạn đặt giới hạn tối đa cho phía máy khách và máy chủ.
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483647" />
</requestFiltering>
</security>
<system.webServer>
và
<system.web>
<httpRuntime targetFramework="4.5" maxRequestLength="2147483647" />
</system.web>
sau đó đoạn tập tin, và gửi mỗi chuck, chờ phản ứng và gửi đoạn tiếp theo. đây là mã javascript và bộ điều khiển.
<div id="VideoDiv">
<label>Filename:</label>
<input type="file" id="fileInput" /><br/><br/>
<input type="button" id="btnUpload" value="Upload a presentation"/><br/><br/>
<div id="progressbar_container" style="width: 100%; height: 30px; position: relative; background-color: grey; display: none">
<div id="progressbar" style="width: 0%; height: 100%; position: absolute; background-color: green"></div>
<span id="progressbar_label" style="position: absolute; left: 35%; top: 20%">Uploading...</span>
</div>
</div>
javascript mã để chuck, điều khiển cuộc gọi và cập nhật progressbar:
var progressBarStart = function() {
$("#progressbar_container").show();
}
var progressBarUpdate = function (percentage) {
$('#progressbar_label').html(percentage + "%");
$("#progressbar").width(percentage + "%");
}
var progressBarComplete = function() {
$("#progressbar_container").fadeOut(500);
}
var file;
$('#fileInput').change(function(e) {
file = e.target.files[0];
});
var uploadCompleted = function() {
var formData = new FormData();
formData.append('fileName', file.name);
formData.append('completed', true);
var xhr2 = new XMLHttpRequest();
xhr2.onload = function() {
progressBarUpdate(100);
progressBarComplete();
}
xhr2.open("POST", "/Upload/UploadComplete?fileName=" + file.name + "&complete=" + 1, true);
xhr2.send(formData);
}
var multiUpload = function(count, counter, blob, completed, start, end, bytesPerChunk) {
counter = counter + 1;
if (counter <= count) {
var chunk = blob.slice(start, end);
var xhr = new XMLHttpRequest();
xhr.onload = function() {
start = end;
end = start + bytesPerChunk;
if (count == counter) {
uploadCompleted();
} else {
var percentage = (counter/count) * 100;
progressBarUpdate(percentage);
multiUpload(count, counter, blob, completed, start, end, bytesPerChunk);
}
}
xhr.open("POST", "/Upload/MultiUpload?id=" + counter.toString() + "&fileName=" + file.name, true);
xhr.send(chunk);
}
}
$("#VideoDiv").on("click", "#btnUpload", function() {
var blob = file;
var bytesPerChunk = 3757000;
var size = blob.size;
var start = 0;
var end = bytesPerChunk;
var completed = 0;
var count = size % bytesPerChunk == 0 ? size/bytesPerChunk : Math.floor(size/bytesPerChunk) + 1;
var counter = 0;
progressBarStart();
multiUpload(count, counter, blob, completed, start, end, bytesPerChunk);
});
và đây là bộ điều khiển tải lên để lưu trữ các chucnk trong ("App_Data/Video/Temp") và sau đó kết hợp chúng và lưu trữ trong ("App_Data/Videos"):
public class UploadController : Controller
{
private string videoAddress = "~/App_Data/Videos";
[HttpPost]
public string MultiUpload(string id, string fileName)
{
var chunkNumber = id;
var chunks = Request.InputStream;
string path = Server.MapPath(videoAddress+"/Temp");
string newpath = Path.Combine(path, fileName+chunkNumber);
using (FileStream fs = System.IO.File.Create(newpath))
{
byte[] bytes = new byte[3757000];
int bytesRead;
while ((bytesRead=Request.InputStream.Read(bytes,0,bytes.Length))>0)
{
fs.Write(bytes,0,bytesRead);
}
}
return "done";
}
[HttpPost]
public string UploadComplete(string fileName, string complete)
{
string tempPath = Server.MapPath(videoAddress + "/Temp");
string videoPath = Server.MapPath(videoAddress);
string newPath = Path.Combine(tempPath, fileName);
if (complete=="1")
{
string[] filePaths = Directory.GetFiles(tempPath).Where(p=>p.Contains(fileName)).OrderBy(p => Int32.Parse(p.Replace(fileName, "$").Split('$')[1])).ToArray();
foreach (string filePath in filePaths)
{
MergeFiles(newPath, filePath);
}
}
System.IO.File.Move(Path.Combine(tempPath, fileName),Path.Combine(videoPath,fileName));
return "success";
}
private static void MergeFiles(string file1, string file2)
{
FileStream fs1 = null;
FileStream fs2 = null;
try
{
fs1 = System.IO.File.Open(file1, FileMode.Append);
fs2 = System.IO.File.Open(file2, FileMode.Open);
byte[] fs2Content = new byte[fs2.Length];
fs2.Read(fs2Content, 0, (int) fs2.Length);
fs1.Write(fs2Content, 0, (int) fs2.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + " : " + ex.StackTrace);
}
finally
{
if (fs1 != null) fs1.Close();
if (fs2 != null) fs2.Close();
System.IO.File.Delete(file2);
}
}
}
Tuy nhiên, nếu hai người dùng cùng một file upload thời gian với cùng một tên, sẽ có một số vấn đề, và bạn phải xử lý vấn đề này. Bằng cách đọc responseText, bạn có thể bắt được một số lỗi và ngoại lệ và cắt nó.
Cảm ơn Colin, một câu hỏi nữa, tại sao sử dụng giải pháp dựa trên RIA được ưu tiên hơn, vì hiệu suất tải lên tốt hơn hay một thứ gì đó khác? – George2
Hỗ trợ trình duyệt cho HTTP chuẩn không cho phép những thứ như chỉ định loại tệp nào được cho phép, các công cụ như thanh tiến trình được hỗ trợ tốt hơn bởi flash/java –
1. Sử dụng điều khiển FileUpload không thể chỉ định loại tệp? Tôi bị bối rối. 2. Tôi nghĩ rằng việc sử dụng giải pháp dựa trên không dựa trên RIA cũng có thể triển khai thanh tiến trình, như cách chúng tôi tải lên tệp đính kèm là Gmail. Vì vậy, nó không có nghĩa là sử dụng đồng bằng Http không thể thực hiện thanh tiến trình. Có ý kiến gì không? – George2