Tuve este problema y encontré la solución basada en Jonathan's code here. Hay algún problema con su código, pero esta es mi solución. Si desea cargar un archivo grande, algo así como un archivo de 1 Gb, debe tirar el archivo y enviarlo a través de varias solicitudes (una solicitud da tiempo de espera). primero establece el límite máximo para el lado del cliente y del servidor.
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483647" />
</requestFiltering>
</security>
<system.webServer>
y
<system.web>
<httpRuntime targetFramework="4.5" maxRequestLength="2147483647" />
</system.web>
continuación trozo del archivo, y enviar cada tirada, esperar la respuesta y enviar el siguiente fragmento. aquí está el javascript y el código del controlador.
<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>
código Javascript a Chuck, controlador de llamada y actualización 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);
});
y aquí está el controlador de carga para almacenar el chucnk en ("App_Data/Videos/Temp") y luego fusionarlos y almacenar en ("App_Data/Vídeos"):
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);
}
}
}
Sin embargo, si dos usuarios en el mismo tiempo subir archivos con el mismo nombre, habrá algún problema, y hay que tratar esta cuestión. Al leer responseText, puede detectar algunos errores y excepciones y recortarlo.
Gracias Colin, una pregunta más, ¿por qué es preferible utilizar la solución basada en RIA, ya que es mejor el rendimiento de carga o algo más? – George2
El soporte del navegador para HTTP estándar no permite cosas como especificar qué tipos de archivos están permitidos, también cosas como barras de progreso son mejor compatibles con flash/java –
1. ¿Usando el control FileUpload no se puede especificar el tipo de archivo? Estoy confundido. 2. Creo que el uso de una solución no basada en RIA también podría implementar una barra de progreso, como la forma en que cargamos los archivos adjuntos es Gmail. Por lo tanto, no significa que usar Http simple no puede implementar barra de progreso. ¿Algún comentario? – George2