Cuando estamos utilizando MVC .Net muchas veces es necesario guardar lo que el usuario está enviando en logs o en la base de datos para poder monitorear errores de usuario final (Ver log sencillo en c# .Net).
De la siguiente forma obtenemos todos los parámetros enviados y ordenados en una variable cadena:
string parametros="";
//recorremos todos los parametros
foreach (var parameter in Request.Params.AllKeys)
{
parametros += parameter + ": " + Request.Params[parameter]+"\n";
}
//se ira guardando de la siguiente forma
//parametro1: pato
//parametro2: pato2
Para cancelar una factura electrónica es necesario crear un tercer certificado llamado pfx, este certificado se debe crear por medio de Openssl en conjunto de nuestro archivo Cer y nuestro archivo Key los cuales debemos ya tener si es que estamos timbrando.
Para crear el archivo pfx utilizaremos la clase Processde .Net, esta clase sirve para mandar comandos como si estuviéramos en consola, de esta manera utilizaremos los comandos de Openssl.
Les recuerdo que antes deben instalar Openssl ycomo está en el siguiente ejemplo debe estar instalado en la unidad c:/openssl-win32.
En caso que se tenga Openssl instalado en otra ruta distinta, solo modifiquen esa parte del código. A continuación la clase mágica:
public class PFX
{
string cer = "";
string key = "";
string clavePrivada = "";
string ArchivoPFX = "";
string ArchivoKPEM = "";
string ArchivoCPEM = "";
public string error = "";
public string mensajeExito = "";
///
<summary>
///
/// </summary>
/// <param name="cer_">archivo cer a utilizar</param>
/// <param name="key_">archivo key a utilizar</param>
/// <param name="clavePrivada_">clave para el archivo pfx</param>
/// <param name="archivoPfx_">ruta del archivo pfx</param>
/// <param name="path">ruta para archivos temporales PEM</param>
public PFX(string cer_, string key_, string clavePrivada_, string archivoPfx_, string pathTemp)
{
cer = cer_;
key = key_;
clavePrivada = clavePrivada_;
ArchivoKPEM = pathTemp + "k.pem";
ArchivoCPEM = pathTemp + "c.pem";
ArchivoPFX = archivoPfx_;
}
public bool creaPFX()
{
bool exito = false;
//validaciones
if (!File.Exists(cer))
{
error = "No existe el archivo cer en el sistema";
return false;
}
if (!File.Exists(key))
{
error = "No existe el archivo key en el sistema";
return false;
}
if (clavePrivada.Trim().Equals(""))
{
error = "No existe una clave privada aun en el sistema";
return false;
}
//creamos objetos Process
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Diagnostics.Process proc2 = new System.Diagnostics.Process();
System.Diagnostics.Process proc3 = new System.Diagnostics.Process();
proc.EnableRaisingEvents = false;
proc2.EnableRaisingEvents = false;
proc3.EnableRaisingEvents = false;
//openssl x509 -inform DER -in certificado.cer -out certificado.pem
proc.StartInfo.FileName = "openssl";
proc.StartInfo.Arguments = "x509 -inform DER -in \"" + cer + "\" -out \"" + ArchivoCPEM + "\"";
proc.StartInfo.WorkingDirectory = @"C:\openssl-win32\bin\";
proc.Start();
proc.WaitForExit();
//openssl pkcs8 -inform DER -in llave.key -passin pass:a0123456789 -out llave.pem
proc2.StartInfo.FileName = "openssl";
proc2.StartInfo.Arguments = "pkcs8 -inform DER -in \"" + key + "\" -passin pass:" + clavePrivada + " -out \"" + ArchivoKPEM + "\"";
proc2.StartInfo.WorkingDirectory = @"C:\openssl-win32\bin\";
proc2.Start();
proc2.WaitForExit();
//openssl pkcs12 -export -out archivopfx.pfx -inkey llave.pem -in certificado.pem -passout pass:clavedesalida
proc3.StartInfo.FileName = "openssl";
proc3.StartInfo.Arguments = "pkcs12 -export -out \"" + ArchivoPFX + "\" -inkey \"" + ArchivoKPEM + "\" -in \"" + ArchivoCPEM + "\" -passout pass:" + clavePrivada;
proc3.StartInfo.WorkingDirectory = @"C:\openssl-win32\bin\";
proc3.Start();
proc3.WaitForExit();
proc.Dispose();
proc2.Dispose();
proc3.Dispose();
//enviamos mensaje exitoso
if (System.IO.File.Exists(ArchivoPFX))
mensajeExito = "Se ha creado el archivo PFX ";
else
{
error = "Error al crear el archivo PFX, puede ser que el cer o el key no sean archivos con formato correcto";
return false;
}
//eliminamos los archivos pem
if (System.IO.File.Exists(ArchivoCPEM)) System.IO.File.Delete(ArchivoCPEM);
if (System.IO.File.Exists(ArchivoKPEM)) System.IO.File.Delete(ArchivoKPEM);
exito = true;
return exito;
}
}
Para utilizarla de la siguiente manera:
//yo siempre utilizo la misma clave privada de mi timbrado para encriptar el pfx
//la ruta para archivos temporales solo se utiliza para archivos que serán eliminados al final
oPFX = new PFX("algunaruta/archivocer.cer", "algunaruta/archivokey.key", "algunpassword", "algunacarpeta/miarchivo.pfx", "rutaparacreararchivostemporalesPem/");
if (oPFX.creaPFX())
Console.WriteLine("Archivo creado con éxito");
else
Console.WriteLine(oPFX.error);
Para regresar un arreglo anónimo u objeto anónimo con formato JSON a través de un controller en MVC .Net, por ejemplo la lista de algún catalogo que no se necesite llenar con alguna tabla de base de datos, o una lista de años, meses o días, tenemos que hacerlo de la siguiente manera:
public JsonResult Metodo()
{
return Json(new[] { new { Id = 1, Nombre = "Dato 1"},new { Id=2, Nombre="Dato 2"}
}, JsonRequestBehavior.AllowGet);
//JsonRequestBehavior.AllowGet es opcional si nuestro método permitirá ser llamado por Get
}
Para eliminar un carácter que aparece al inicio o al final de una cadena en C# existen dos métodos en la clase string útiles, su nombre son TrimStart y TrimEnd, estos nos permiten eliminar en este caso el 0 de una cadena al inicio, es decir dejar 00012121 como 12121 o viceversa dejar 121210000 como 12121, y se hace de la siguiente forma:
//Eliminamos los ceros del inicio
string cadena="00012121";
cadena=cadena.TrimStart(new Char[] { '0' });
//resultado: 12121
//Eliminamos los ceros del final
string cadena="121210000";
cadena=cadena.TrimEnd(new Char[] { '0' });
//resultado: 12121
Si deseas eliminar otro carácter remplaza el 0 por el que necesites.
Cuando comenzamos a utilizar Entity Framework vemos la maravilla de LINQ al obtener los datos de manera relacional, organizarlos como si de Sql se tratara, pero nunca nos preguntamos que de distinto tiene cuando utilizamos IQueryable o IEnumerable, para explicarlo rápidamente nos basaremos en la siguiente tabla (suponiendo que su nombre es tabla, literal):
Cuando obtenemos los datos con IEnumerable de la siguiente forma:
IEnumerable<tabla> lst= from d in db.tabla
select d;
Si quisiéramos hacer un filtrado con una clausula where posterior a nuestra obtención de datos haríamos lo siguiente:
lst= lst.Where(d=>d.name=='Pedro');
Cuando utilizamos IEnumerable al llenar nuestro objeto con LINQlo que obtenemos son los datos de la tabla en nuestra colección es decir, que al aplicar el filtrado trabajamos directamente con un conjunto de datos en memoria al cual se le hace el where directamente. Esto ocasiona un mal performance cuando nuestra tabla tiene millones de datos ya que los tendríamos en memoria y posterior aplicaríamos el filtrado, esto es una mala practica que jamas se debe hacer.
Ahora veamos la diferencia con IQueryable:
IQueryable<tabla> lst= from d in db.tabla
select d;
//lo que obtiene IQueryable despues de la consulta es:
// select * from tabla
Ahora haremos el mismo filtro posterior a la consulta:
lst= lst.Where(d=>d.name=='Pedro');
//y aquí lo que hacemos es concatenarle:
select * from tabla where name='Pedro'
A diferencia de IEnumerable lo que tenemos en nuestro objeto IQueryablees la consulta SQL en sí, es decir tenemos algo como lo siguiente:
select * from tabla
where name='Pedro'
En conclusión si vamos a realizar filtrados dinámicos en un conjunto de datos se debe utilizar la interface IQueryable, es la forma correcta de aplicar manipulación a nuestra consulta antes de enviarla al servidor de base de datos. ¿Cuando se realizar el envió de la consulta al servidor por parte de IQueryable? Cuando hacemos uso de los datos es decir, cuando aplicamos un foreach o hacemos un ToList().
Para poder cachar excepciones dentro de una consulta LINQ y poder manipular el error para que no truene la consulta en si misma debemos hacer uso de Lambda, esto es útil cuando nuestra base de datos puede presentar inconsistencias las cuales pueden ocasionar una excepción en ciertos casos, y podemos evitarlo de la siguiente forma:
EntityDB db= new EntityDB();
var lst = from d in db.tabla.ToList() //es importante hacerlo lista
select new TablaViewModel
{
id = d.id,
//campo es string por lo cual
//nuestra función delegada regresara igual string
campo = (new Func<string>(() => {
try {
// suponiendo que exista una referencia
// a una tabla secundaria la cual no siempre exista
// lo cual puede ocasionar una excepción
// de esta manera lo podemos manipular
return d.tablaSecundaria.campo2;
}
catch { return "No existe"; }
}
)
)()
};
De esta manera nuestra consulta no tronara y podemos darle un resultado a la vista donde mostraremos nuestros datos.
En c# existe una manera fácil para recorrer dinámicamente los atributos de un objeto, de la siguiente manera podemos obtener el valor de un objeto dinámicamente y también el nombre de sus atributos en forma de cadena, para ello haremos uso de la clase PropertyInfo con la cual podemos obtener la estructura de nuestro objeto, abajo comento y pongo un ejemplo simple para entenderlo:
Clase para el ejemplo:
public class Auto
{
public string Nombre { get; set; }
public string Marca { get; set; }
public string Modelo { get; set; }
public int Año { get; set; }
}
Y para realizar el recorrido de los atributos lo hacemos de la siguiente manera:
Auto oAuto = new Auto() { Nombre = "Mi auto", Marca = "Honda", Modelo = "Civic", Año = 2018 };
PropertyInfo[] properties = typeof(Auto).GetProperties();
foreach (PropertyInfo property in properties)
{
//así obtenemos el nombre del atributo
string NombreAtributo=property.Name;
//así obtenemos el valor del atributo
string Valor=property.GetValue(oAuto);
Console.WriteLine("El atributo "+NombreAtributo+" tiene el valor: "+ Valor);
}
Y el resultado:
El atributo Nombre tiene el valor: Mi auto El atributo Marca tiene el valor: Honda El atributo Modelo tiene el valor: Civic El atributo Año tiene el valor: 2018
Si agregamos nuevos atributos a nuestra clase este algoritmo seguiría recorriendo dinámicamente todas la nuevas propiedades de nuestra clase.
Para poner un password a un pdf en C# podemos hacer uso de la librería iTextSharp(la cual pueden instalar con nuget, ¿Cómo utilizar nuget?) la cual tiene muchas funcionalidades para el manejo de archivos pdf. Partiendo de un archivo pdf ya existente con el siguiente código:
using (var input = new FileStream("C:/archivoOriginal.pdf", FileMode.Open, FileAccess.Read, FileShare.Read))
using (var output = new FileStream("C:/archivoConContrasena.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
var reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true,"tucontraseña", "tucontraseña", PdfWriter.ALLOW_PRINTING);
}