Clase ExcelLogica


using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.IO;
using System.Reflection;

namespace Logica.Excel
{
    public static class ExcelLogica
    {
        public static List<object> Leer(string archivo)
        {
            var lista = new List<object>();

            List<List<string>> samples = new List<List<string>>();
            try
            {
                int selCount = 0;
                var document = SpreadsheetDocument.Open(archivo, false);
                var workbookPart = document.WorkbookPart;
                var sheets = workbookPart.Workbook.Descendants<Sheet>();
                var fila = 1;               

                foreach (Sheet sheet in sheets)
                {
                    var workSheet = ((WorksheetPart)workbookPart.GetPartById(sheet.Id)).Worksheet;
                    var sheetData = workSheet.Elements<SheetData>().First();
                    List<Row> rows = sheetData.Elements<Row>().ToList();

                    var columnas = rows.ElementAt(0).Elements<Cell>().Count();
                    var b = new string[columnas];
                   
                    foreach (Row row in rows)
                    {
                        var indice = 0;

                        b = new string[columnas];

                        foreach (Cell c in row.Elements<Cell>())
                        {
                            var value = "";

                            if (c != null)
                            {
                                value = c.InnerText;

                                if (c.DataType != null)
                                {
                                    switch (c.DataType.Value)
                                    {
                                        case CellValues.SharedString:

                                            // For shared strings, look up the value in the
                                            // shared strings table.
                                            var stringTable =
                                                workbookPart.GetPartsOfType<SharedStringTablePart>()
                                                .FirstOrDefault();

                                            // If the shared string table is missing, something
                                            // is wrong. Return the index that is in
                                            // the cell. Otherwise, look up the correct text in
                                            // the table.
                                            if (stringTable != null)
                                            {
                                                value =
                                                    stringTable.SharedStringTable
                                                    .ElementAt(int.Parse(value)).InnerText;
                                            }
                                            break;

                                        case CellValues.Boolean:
                                            switch (value)
                                            {
                                                case "0":
                                                    value = "FALSE";
                                                    break;
                                                default:
                                                    value = "TRUE";
                                                    break;
                                            }
                                            break;
                                    }
                                }

                                b[indice] = value;
                                indice++;
                            }
                        }

                        fila++;
                        lista.Add(b);
                    }
                }
            } catch (Exception ex)
            {}

            return lista;
        }

        public static byte[] GenerarOpenXml(DataTable t, string autofiltro)
        {
            MemoryStream stream = new MemoryStream();

            using (SpreadsheetDocument myWorkbook =
                    SpreadsheetDocument.Create(stream,
                    SpreadsheetDocumentType.Workbook, true))
            {
                WorkbookPart workbookPart = myWorkbook.AddWorkbookPart();
                var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
                string relId = workbookPart.GetIdOfPart(worksheetPart);

                var fileVersion = new FileVersion { ApplicationName = "Microsoft Office Excel" };

                var sheets = new Sheets();
                var sheet = new Sheet { Name = t.TableName, SheetId = 1, Id = relId };
                sheets.Append(sheet);

                SheetData sheetData = new SheetData(CreateSheetData(t));

                var workbook = new Workbook();
                workbook.Append(fileVersion);
                workbook.Append(sheets);
                var worksheet = new Worksheet();
                worksheet.Append(sheetData);

                AutoFilter autoFilter1 = null;

                if (autofiltro != null)
                {
                    autoFilter1 = new AutoFilter() { Reference = autofiltro };
                    worksheet.Append(autoFilter1);
                }

                worksheetPart.Worksheet = worksheet;
                myWorkbook.WorkbookPart.Workbook = workbook;
                myWorkbook.WorkbookPart.Workbook.Save();
                myWorkbook.Close();

                return stream.ToArray();
            }
        }

        public static byte[] GenerarOpenXml<T>(this IEnumerable<T> collection, string autofiltro)
        {
            var t = ToDataTable(collection, "Subdiario");

            return GenerarOpenXml(t, autofiltro);
        }

        public static MemoryStream BuildExcel(DataTable dataTable, string autofiltro)
        {
            MemoryStream stream = new MemoryStream();

            using (SpreadsheetDocument myWorkbook =
                    SpreadsheetDocument.Create(stream,
                    SpreadsheetDocumentType.Workbook, true))
            {
                WorkbookPart workbookPart = myWorkbook.AddWorkbookPart();
                var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
                string relId = workbookPart.GetIdOfPart(worksheetPart);

                var fileVersion = new FileVersion { ApplicationName = "Microsoft Office Excel" };

                var sheets = new Sheets();
                var sheet = new Sheet { Name = dataTable.TableName, SheetId = 1, Id = relId };
                sheets.Append(sheet);

                SheetData sheetData = new SheetData(CreateSheetData(dataTable));

                var workbook = new Workbook();
                workbook.Append(fileVersion);
                workbook.Append(sheets);
                var worksheet = new Worksheet();
                worksheet.Append(sheetData);

                AutoFilter autoFilter1 = null;

                if (autofiltro != null)
                {
                    autoFilter1 = new AutoFilter() { Reference = autofiltro };
                    worksheet.Append(autoFilter1);
                }


                worksheetPart.Worksheet = worksheet;
                myWorkbook.WorkbookPart.Workbook = workbook;
                myWorkbook.WorkbookPart.Workbook.Save();
                myWorkbook.Close();

                return stream;
            }
        }

        private static List<OpenXmlElement> CreateSheetData(DataTable dataTable)
        {
            List<OpenXmlElement> elements = new List<OpenXmlElement>();

            var rowHeader = new Row();
            Cell[] cellsHeader = new Cell[dataTable.Columns.Count];
            for (int i = 0; i < dataTable.Columns.Count; i++)
            {
                cellsHeader[i] = new Cell();
                cellsHeader[i].DataType = CellValues.String;
                cellsHeader[i].CellValue = new CellValue(dataTable.Columns[i].ColumnName);
            }
            rowHeader.Append(cellsHeader);
            elements.Add(rowHeader);

            foreach (DataRow rowDataTable in dataTable.Rows)
            {
                var row = new Row();
                Cell[] cells = new Cell[dataTable.Columns.Count];

                for (int i = 0; i < dataTable.Columns.Count; i++)
                {
                    cells[i] = new Cell();

                    if (dataTable.Columns[i].DataType == System.Type.GetType("System.Decimal"))
                        cells[i].DataType = CellValues.Number;
                    else if (dataTable.Columns[i].DataType == System.Type.GetType("System.DateTime"))
                        cells[i].DataType = CellValues.Date;
                    else
                        cells[i].DataType = CellValues.String;

                    cells[i].CellValue = new CellValue(rowDataTable[i].ToString());
                }
                row.Append(cells);
                elements.Add(row);
            }
            return elements;
        }

        public static DataTable ToDataTable<T>(this IEnumerable<T> collection, string tableName)
        {
            DataTable tbl = ToDataTable(collection);
            tbl.TableName = tableName;
            return tbl;
        }

        public static DataTable ToDataTable<T>(this IEnumerable<T> collection)
        {
            DataTable dt = new DataTable();
            Type t = typeof(T);
            PropertyInfo[] pia = t.GetProperties();
            object temp;
            DataRow dr;

            for (int i = 0; i < pia.Length; i++)
            {
                dt.Columns.Add(pia[i].Name, Nullable.GetUnderlyingType(pia[i].PropertyType) ?? pia[i].PropertyType);
                dt.Columns[i].AllowDBNull = true;
            }

            //Populate the table
            foreach (T item in collection)
            {
                dr = dt.NewRow();
                dr.BeginEdit();

                for (int i = 0; i < pia.Length; i++)
                {
                    temp = pia[i].GetValue(item, null);
                    if (temp == null || (temp.GetType().Name == "Char" && ((char)temp).Equals('\0')))
                    {
                        dr[pia[i].Name] = (object)DBNull.Value;
                    }
                    else
                    {
                        dr[pia[i].Name] = temp;
                    }
                }

                dr.EndEdit();
                dt.Rows.Add(dr);
            }
            return dt;
        }
    }

}

Crear nuevo usuario de sql server

En el servidor de base de datos, en la carpeta Security / Logins, agregar el usuario:




En User Mapping, marcar la base de datos a la que se quiera acceder, y marcar db_datareader:


Agregar el usuario:


En Membership, darle el rol db_datareader


Input type file - subir archivos MVC

*** es importante poner el multipart/form-data !!!!! ***
*** el method tiene que ser Post ***

Vista

@using (Html.BeginForm("GuardarPlanilla""Avales"FormMethod.Post, new { id = "FormGestionPlanilla", enctype = "multipart/form-data" }))

{

      @Html.TextBoxFor(m => m.RutaPlanilla, new { type = "file", Class = "btn btn-success navbar-btn" })

}


Controller

[HttpPost]
public ActionResult GuardarPlanilla(AvalPlanillaVM modelo, AvalPlanillaDetalleVM modeloDet)
{
    var archivo = this.HttpContext.Request.Files.Get("RutaPlanilla");
    var file = (System.Web.HttpPostedFileWrapper)(archivo);
    var nombreArchivo = file.FileName.Substring(file.FileName.LastIndexOf("\\") + 1);
    var rutaArchivo = this.Server.MapPath("../XLS/" + nombreArchivo);

    file.SaveAs(rutaArchivo); 
}

Leer excel con OpenXml y retornarlo en una lista genérica

Uso:

var excel = ExcelLogica.Leer("c:\\temp\\excel1.xlsx");

foreach (var fila in excel)
{
var f = (string[])fila;

          //en el caso de que sea una fecha, hay que parsearla
      fecha = DateTime.FromOADate(int.Parse(f[2]));

Console.WriteLine(f[0] + "  " + f[1] + " " + fecha);
}

Código de ExcelLogica: http://desaX.blogspot.com.uy/2017/12/clase-excellogica.html

Invalidar ModelState manualmente

El primer campo es el key, es el nombre del atributo para el cual se desplegara el mensaje

ModelState.AddModelError("Usuario", "mensaje");



Acceder a otros campos dentro de un CustomAttribute

Ej, para acceder al valor del atributo FechaHasta:

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        var otherValue = validationContext.ObjectType.GetProperty("FechaHasta").GetValue(validationContext.ObjectInstance, null);

Refused to display 'site' in a frame because it set 'X-Frame-Options' to 'sameorigin'


En global.asax, agregar:

AntiForgeryConfig.SuppressXFrameOptionsHeader = true;

En web.config:

  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="X-Frame-Options" value="AllowAll" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>

Validaciones con DataAnnotations

1. Definir los DataAnnotations en el ViewModel para cada atributo que se quiera validar:

[Required(ErrorMessage = "Ingrese el nombre")]
public string Nombre { get; set; }

2. Agregar la verificación en el Action:

public ActionResult Guardar(PersonaViewModel persona)
{
   if (ModelState.IsValid)
   {
      ...
      return View();
   } else
   {
      ViewBag.Mensaje = "Error en los datos ingresados, debe completar los campos requeridos";
      return View("Error");
   }
}

*** El objeto ModelState contiene toda la información de los errores ocurridos, en ModelState.Values
*** Solo con esto, ya queda funcionando la validación del lado del servidor.
*** Para que la validación se haga también del lado del cliente, se debe agregar lo siguiente:

1. Agregar los siguientes scripts:

<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>

2. Agregar los ValidationMessages para cada atributo:

<div class="field-validation-error">@Html.ValidationMessageFor(m => m[i].Path)</div>
@Html.TextBoxFor(m => m[i].Path)

3. También se puede agregar el ValidationSummary, que sirve para mostrar un resumen de todos los campos con error. Esto en general se agrega al final de la página:

<div class="validation-summary-errors">
    @Html.ValidationSummary()
</div>

*** Tener en cuenta que el comportamiento de las validaciones en IE a veces es diferente a Chrome ***

Generar excel con OpenXML y retornarlo en el Response

public ActionResult DesplegarExcel(SubdiarioViewModel subdiario)
{
            //lista es una estructura generica (ej, un DTO), con cualquier complejidad

            var ret = ExcelLogica.GenerarOpenXml(lista, "A1:AB1");

            Response.Clear();
            Response.ContentType = "application/force-download";
            Response.AddHeader("content-disposition", "attachment; filename=" + nombre);
            Response.BinaryWrite(ret);         
            Response.Flush();
            Response.End();

            return new EmptyResult();