Te muestro como convertir un archivo PDF a un archivo Docx con dos librerías que tienen precio pero hacen su trabajo.
Código del ejemplo:
class Program
{
//ORIGEN PDF
static string pathPDF = @"C:\AlgunaRuta\archivo.pdf";
//DESTINOS ARCHIVO DOCX
static string pathDoc1 = @"C:\AlgunaRuta\archivo-spire.docx";
static string pathDoc2 = @"C:\AlgunaRuta\archivo-sautin.docx";
static void Main(string[] args)
{
//llamamos para convertir el pdf con spire
UsandoSpirePdf();
//llamamos para convertir el pdf con sautinsoft
UsandoSautin();
}
public static void UsandoSpirePdf()
{
PdfDocument pdf = new PdfDocument();
//cargamos el pdf
pdf.LoadFromFile(pathPDF);
//guardamos el docx
pdf.SaveToFile(pathDoc1, FileFormat.DOCX);
//abrimos el archivo
System.Diagnostics.Process.Start(pathDoc1);
}
public static void UsandoSautin()
{
SautinSoft.PdfFocus oPdfFocus = new SautinSoft.PdfFocus();
//cargamos el pdf
oPdfFocus.OpenPdf(pathPDF);
//si se tiene mas de 1 pagina
if (oPdfFocus.PageCount > 0)
{
//asignamos el tipo de documento al que convertiremos
oPdfFocus.WordOptions.Format = SautinSoft.PdfFocus.CWordOptions.eWordDocument.Docx;
//guardamos el dox
int resultado = oPdfFocus.ToWord(pathDoc2);
if (resultado == 0)
{
//abrimos el documento
System.Diagnostics.Process.Start(pathDoc2);
}
}
}
}
Te muestro cómo es posible recorrer una tabla por medio de una instrucción while en sql.
En el caso demysql u otro motor solo remplazar top por su equivalente, por ejemplo en mysql: limit 0,1.
Tabla people
Código utilizado:
insert into @tabla(id,name) select id,name from people
declare @count int = (select count(*) from @tabla)
while @count > 0
begin
declare @name varchar(max) = (select top(1) name from @tabla order by id)
declare @id int = (select top(1) id from @tabla order by id)
print 'Hola '+@name
delete @tabla where id=@id
set @count = (select count(*) from @tabla)
end
El archivo .ldf de toda base de datos en sql server sirve para llevar un log de toda consulta hecha en la base dedatos (todos los insert, update, select, etc etc).
Esto es útil para regresar en un punto en el tiempo y ver la base de datos como se encontraba en ese punto en su estructura y en sus datos.
Pero qué pasa cuando nuestra base de datos pesa ya un tamaño exagerado y queremos liberar el espacio de nuestro servidor. Optamos por realizar una liberación de este archivo (obviamente después de hacer los backups correspondientes).
A continuación te muestro como se debería hacer para una base de datos llamada PATODB:
ALTER DATABASE PATODB SET RECOVERY SIMPLE
GO
/* el 5 es 5 MB, se dejara el log con un tamaño de 5MB*/
DBCC SHRINKFILE (PATODB_Log, 5)
GO
ALTER DATABASE PATODB SET RECOVERY FULL
GO
Y así de simple liberamos el espacio de nuestro archivo .ldf.
Cuando hacemos un módulo para actualizar una imagen, ya sea el logotipo o una galería, muchas veces tenemos el problema de que sigue saliendo en el navegador la imagen vieja hasta que borramos el cache del navegador.
Lamentablemente los usuarios no saben que es el cache y esperan ver su imagen nueva, al seguir viendo la imagen vieja, el usuario piensa que no se ha subido con éxito la nueva imagen.
En el caso de Mvc .Net esto re se resuelve con un truco, e igual puede resolverse con su equivalencia en cualquier otro lenguaje de programación.
Para esto vamos a hacer uso de la funcionalidad Random, funcionalidad que existe en todo lenguaje de programación y basta con hacerlo de la siguiente manera, en el caso de MVC .Net lo haremos en razor (en la vista):
@{
//creamos el objeto random y asignamos a una variable string
Random r = new Random();
string a = r.Next().ToString();
}
<img src='http://unsitio.com/unaimagen.jpg?a=@a'>
Al poner una variable con un valor nuevo al final de nuestra url de la imagen, obligamos al navegador a volver a cargarla y no utilizar la que tiene en cache.
Ahora que estamos en la era de los webservice todos tenemos la necesidad de saber la forma de enviar datos por medio de Get o Post. En C# la forma de hacer una solicitud a un servicio o a un api es muy sencilla y en el siguiente ejemplo te muestro como hacerlo por medio de una clase que yo hice.
La clase siguiente está preparada para enviar cualquier tipo de objeto ya que recibe el tipo de objeto que se enviara y lo serializa en json.
Recuerda que si el objeto tiene referencias circulares, la siguiente clase no funcionara.
Clase:
public class RequestHdeleon
//esta clase nos sirve para tener control del resultado regresado por la solicitud
public class Reply
{
public Reply()
{
this.success = 0;
message = "";
}
public int success { get; set; }
public object data { get; set; }
public String menssage { get; set; }
}
public Reply Send<T>(string url,T objectRequest, string method="POST"){
try {
Reply oReply= new Reply();
JavaScriptSerializer js = new JavaScriptSerializer();
//serializamos el objeto
string json = Newtonsoft.Json.JsonConvert.SerializeObject(objectRequest);
//peticion
WebRequest request = WebRequest.Create(url_callback);
//headers
request.Method = method;
request.PreAuthenticate = true;
request.ContentType = "application/json;charset=utf-8'";
request.Timeout = 10000; //esto es opcional
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
oReply.success = 1;
//y aquí va nuestra respuesta, la cual es lo que nos regrese el sitio solicitado
oReply.data = result;
}catch(Exception e){
oReply.result = 0;
//en caso de error lo manejamos en el mensaje
oReply.menssage = e.Message;
}
return oReply;
}
}
Ejemplo de como utilizarla:
public class UnaClase(){
public string algo{get;set;}
}
//creamos la clase para enviar los parametros
UnaClase oUnObjeto= new UnaClase();
oUnObjeto.algo="pato feliz";
//Creamos el objeto para solicitud
RequestHdeleon oRequest= new RequestHdeleon();
//primer parametro url
//segundo parametro el objeto
//tercer parametro el metodo: POST, GET, PUT, DELETE
RequestHdeleon.Reply oReply=oRequest.Send<UnaClase>("http://somesite.com/api/somecontroller/",oUnObjeto,"POST");
Algunas veces tenemos la necesidad de llamar un método por medio de otro, y para ello hacemos uso de RedirectToAction.
RedirectToAction nos sirve para redirigir al usuario a otro controlador o a otro método dependiendo de la lógica de negocio, pero aparte, a veces necesitamos recibir en nuestro elemento destino algún valor para mostrarle al usuario o para realizar alguna validación. Para ello lo primero que se nos viene a la mente es por medio de ViewBag.
Lamentablemente ViewBag no tiene un tiempo de vida más allá del dominio del método, pero podemos apoyarnos de otro diccionario llamado TempData el cual se mantiene en toda la vida de la solicitud HTTP.
A continuación muestro un ejemplo sencillo de cómo quedaría:
public ActionResult Accion1 {
TempData["mensaje"] = "Un mensaje feliz :)";
//redirigimos a la Accion2 del mismo controlador
return RedirectToAction("Action2");
}
public ActionResult Accion2 {
if(TempData["mensaje"])
ViewBag.mensaje = TempData["mensaje"].ToString();
//de esta manera nuestra vista recibiria el ViewBag.mensaje solo cuando TempData no sea null
return View();
}
En c# es muy fácil obtener una cadena del contenido de un archivo, esto es algo muy útil ya que podemos almacenar información en texto plano en archivos y esta misma obtenerla en cadenas para darle alguna funcionalidad. Por ejemplo un archivo que contenga el cuerpo de un e-mail en .html y así leerlo como string, manipularlo y después enviarlo.
Anexo una clase que tiene un método estático el cual regresa un string a partir de la ruta de un archivo:
public class Archivo
{
public static string GetStringOfFile(string pathFile)
{
try
{
var contenido = File.ReadAllText(pathFile);
return contenido;
}
catch (Exception ex)
{
return string.Empty;
}
}
}
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);