Miałem ten problem i znalazłem rozwiązanie oparte na Jonathan's code here. Jest pewien problem z jego kodem, ale tutaj jest moje rozwiązanie. Jeśli chcesz przesłać duży plik, taki jak plik o wielkości 1 Gb/s, musisz wyrzucić plik i wysłać go przez kilka żądań (jedno żądanie daje czas). najpierw ustaw maksymalny limit dla klienta i serwera.
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483647" />
</requestFiltering>
</security>
<system.webServer>
i
<system.web>
<httpRuntime targetFramework="4.5" maxRequestLength="2147483647" />
</system.web>
następnie fragment pliku i wysłać każdy uchwyt, czekać na odpowiedź i wysłać następny kawałek. tutaj jest kod javascript i kontroler.
<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>
kod Javascript by Chuck kontroler połączeń i aktualizacji 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);
});
i tutaj jest kontrolerem przesyłać do przechowywania chucnk w ("App_Data/Filmy/Temp"), a następnie połączyć je i przechowywać w („App_Data/Filmy”):
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);
}
}
}
Jednakże, jeśli dwóch użytkowników w tym samym czasie przesyłania plików o tej samej nazwie, nie będzie jakiś problem, i trzeba obsługiwać ten problem. Czytając responseText, możesz złapać błąd i wyjątek i przyciąć go.
Dzięki Colin, jeszcze jedno pytanie, dlaczego preferowane jest używanie rozwiązania opartego na RIA, ponieważ lepsza wydajność przesyłania lub coś innego? – George2
Obsługa przeglądarki dla standardowego HTTP nie zezwala na takie rzeczy, jak określanie, które typy plików są dozwolone, podobnie rzeczy takie jak paski postępu są lepiej obsługiwane przez flash/java –
1. Czy za pomocą kontroli FileUpload nie można określić typu pliku? Jestem zdezorientowany. 2. Myślę, że używanie rozwiązania nie opartego na RIA może również zaimplementować pasek postępu, np. Jak przesyłać załącznik jest Gmail. Nie oznacza to, że używanie zwykłego Http nie może zaimplementować paska postępu. Wszelkie komentarze? – George2