Subir un archivo de Excel en ASP.Net MVC a la base de datos con Entity Framework

Posted on Posted in Entity Framework, MVC, SQL Server

Cuando en un proyecto tienes que subir un archivo de Excel en ASP.Net MVC a la base de datos existen diferentes formas, yo ya llevo tiempo usando una librería para extraer los datos del Excel y después trabajar con ellos ya sea para realizar cálculos o simplemente para almacenarlos en la DB para su uso posterior.

Subiendo el archivo

Lo primero es saber como subir un archivo de Excel en ASP.Net MVC para que este disponible en el controlador, si por ejemplo, ya tenemos una acción Create, podríamos copiar la vista y llamarla UploadFile por ejemplo, de cualquier forma, lo importante para subir un archivo son dos cosas :

  1. enctype = “multipart/form-data”
    Tenemos que definir la propiedad enctype  con el valor multipart/form-data en el elemento <form>,  para que el request pueda hacer llegar el archivo hasta el controlador, solamente hay que cambiar esto:

    @using (Html.BeginForm())
    

    Por esto:

    @using (Html.BeginForm("UploadFile", "Users", FormMethod.Post, new { enctype = "multipart/form-data" }))
    

     

  2. <input type=”File” />
    Hay que agregar un elemento <input> de tipo File, para que el usuario pueda seleccionar el archivo a subir, solo hay que agregar el elemento dentro del form de arriba, quedando algo asi:

    @using (Html.BeginForm("UploadFile", "Users", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
    
        @Html.AntiForgeryToken() // si tienes el decorador [ValidateAntiForgeryToken] en tu accion del controlador
        
        <input type="File" name="file" id="file" value="Selecciona el archivo" />
    
        <input type="submit" value="Subir archivo" />
    }
    

Guardando el archivo

Una vez que ya sabemos como subir un archivo de Excel en ASP.Net MVC, hay que guardar el archivo en el servidor, por lo general yo creo una carpeta llamada Files en la carpeta Content para este propósito, el código para guardar el archivo quedaría de la siguiente manera, claro, mas o menos, tu tendrás que adecuarlo a tus necesidades, pero puedes ver un ejemplo y el flujo del código:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadFile(HttpPostedFileBase file)
{
	if (file != null) 
	{
		if (!file.FileName.EndsWith(".xls") && !file.FileName.EndsWith(".xlsx"))
			return View();
		
		var fileName = DateTime.Now.ToString("yyyyMMddHHmm.") + file.FileName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries).Last();
		SaveFile(file, fileName);
		UploadRecordsToDataBase(fileName);
		return RedirectToAction("Index");
	}
	
	// Tu podras decidir que hacer aqui
	// si el archivo es nulo
	return View();
	
}

private void SaveFile(HttpPostedFileBase file, string fileName)
{
	var path = System.IO.Path.Combine(Server.MapPath("~/Content/Files/"), fileName);
	var data = new byte[file.ContentLength];
	file.InputStream.Read(data, 0, file.ContentLength);

	using (var sw = new System.IO.FileStream(path, System.IO.FileMode.Create))
	{
		sw.Write(data, 0, data.Length);
	}
}

Extraer los datos del archivo y subirlos a la base de datos

Ya que tenemos el archivo guardado es hora de usar una librería super amigable y rápida llamada ExcelDataReader.

Podemos instalarla en nuestro proyecto directamente de Nuget.

Y el código que usaríamos para extraer los datos, y después subir los registros guardados en una lista por medio de EntityFramework es el siguiente:

private void UploadRecordsToDataBase(string fileName)
{
	var records = new List<User>();
	using (var stream = System.IO.File.Open(Path.Combine(Server.MapPath("~/Content/Files/"), fileName), FileMode.Open, FileAccess.Read))
	{
		using (var reader = ExcelReaderFactory.CreateReader(stream))
		{                    
			while (reader.Read())
			{
				records.Add(new User {
					Email = reader.GetString(0),
					Credits = int.Parse(reader.GetValue(1).ToString()),
					RecordDate = DateTime.Now,
					IsActive = true,
				});
			}
		}
	}

	if (records.Any())
	{
		db.Users.AddRange(records);
		db.SaveChanges();
	}
}

 

También puedes compilar todos los registros en un DataSet y subir su(s) DataTable a las tablas que quieras usando SQLBulkCopy; el código para poner todos los registros en el DataSet lo encuentras en la documentación de la librería.