Autor: irobles

Listary

Cómo Listary me facilita el trabajo diario

En mi día a día como desarrollador y administrador de sistemas, siempre estoy buscando herramientas que me ayuden a ahorrar tiempo y simplificar tareas repetitivas. Una de esas joyas que descubrí hace un tiempo es Listary

A primera vista, Listary parece solo un buscador rápido de archivos o un launcher, pero en realidad es mucho más que eso. Lo que más me gusta de esta aplicación es su capacidad para crear comandos personalizados y ejecutarlos de forma instantánea, sin tener que abrir terminales o menús innecesarios.

Por ejemplo, en mi caso utilizo Listary para conectarme a la VPN de mi trabajo. Normalmente, esto implicaría abrir un archivo .bat que contiene las reglas necesarias para que mi tráfico personal no pase por la VPN. Gracias a Listary, simplemente escribo un comando en su launcher —por ejemplo, vpn— y en segundos la conexión está activa.

Este pequeño detalle me ha ahorrado muchísimo tiempo y clics a lo largo del día. Además, la ejecución es fluida y puedo mantener mi flujo de trabajo sin interrupciones.

Integración con otras herramientas

Otra ventaja es que Listary se complementa muy bien con otras utilidades. En mi caso, lo uso junto con Remote Desktop Plus, una aplicación que me permite administrar mis credenciales y conexiones a servidores de forma más cómoda. No voy a profundizar mucho en esta herramienta (ya escribí una entrada dedicada a ella), pero basta decir que ambas hacen un excelente equipo para quienes trabajamos conectándonos constantemente a distintos entornos remotos.

Componentes para Blazor

Recientemente, en mi trabajo tomamos la decisión de rehacer un sistema desarrollado con ASP.NET MVC 5 debido a su alta acumulación de deuda técnica. Aunque gran parte de esa deuda se debía a que el desarrollo inicial estuvo orientado a resolver necesidades operativas inmediatas (lo cual fue una buena decisión en su momento), con el tiempo quedó claro que MVC no era la mejor opción para un sistema de ese tamaño.

Como parte del proyecto, se me encomendó buscar alternativas para la nueva versión del sistema. Inicialmente, pensé en usar WebForms para organizar mejor las vistas, pero descubrí que ya no es soportado por las versiones más recientes de .NET. Sin embargo, en mi investigación me topé con Blazor, una tecnología que no solo es moderna, sino que también permite construir componentes reutilizables y organizados, algo similar a lo que buscaba.

El reto con los Grids y Componentes

El sistema original utilizaba componentes de DevExpress y SyncFusion. Aunque DevExpress nos facilitaba un desarrollo ágil, no cumplía con un requerimiento clave: los grids no eran responsivos, algo crítico dado que el sistema debía ser accesible desde dispositivos móviles. Por ello, complementamos con los grids de SyncFusion, que sí ofrecían este soporte.

Con Blazor seleccionado como base para el desarrollo, la siguiente tarea fue buscar una librería de componentes que permitiera construir una aplicación web moderna y responsiva, sin sacrificar funcionalidad ni estética. Este artículo detalla las opciones que evalué y la elección final.

Librerías de componentes para Blazor

Durante mi análisis, encontré varias opciones interesantes. Aquí presento una lista de las principales librerías disponibles, junto con algunas notas relevantes:

DevExpress (De pago): Conocido por su robustez y herramientas avanzadas, aunque con un costo elevado.

Telerik (De pago): Amplia colección de componentes con soporte profesional.

SyncFusion (De pago / Community): Excelente soporte para grids responsivos, además de una licencia gratuita para pequeñas empresas y desarrolladores individuales.

SemanticUI (Gratuita): Diseño limpio y moderno, aunque requiere integración adicional para ciertos casos.

FomaticUI (Gratuita): Un fork de SemanticUI con mejoras, como un componente DatePicker.

jQWidgets (De pago): Basado en jQuery, ideal para quienes ya estén familiarizados con esa tecnología.

Radzen (De pago / Community): Compatible con Blazor Server y WASM, con licencia gratuita limitada.

MudBlazor (Gratuita): Ofrece componentes modernos y responsivos, con una curva de aprendizaje accesible.

Blazorise (De pago / Community): Soporte para múltiples frameworks CSS, ideal para proyectos personalizados.

FluentUI (Gratuita): Basado en los principios de diseño de Microsoft, ideal para aplicaciones con estilo Office.

MudBlazor – La Elección Final

Después de evaluar varias opciones, nos decidimos por MudBlazor. Esta librería destacó por su facilidad para replicar el layout del sistema anterior y por las características responsivas de su grid. Por defecto, el grid de MudBlazor ajusta su comportamiento en pantallas pequeñas, permitiendo un desplazamiento vertical en lugar de horizontal, justo lo que necesitábamos para mejorar la experiencia en dispositivos móviles.

Remote Desktop Plus

Remote Desktop Plus

Algo que posiblemente es muy común para la mayoría de la gente que trabajamos en el área de TI, es conectarnos por escritorio remoto a distintos servidores. Existen herramientas como TeamViewer o AnyDesk entre muchas otras, pero tal ves la más común sea el Escritorio Remoto de Windows que es lo que en mi caso uso con mayor frecuencia.

Al utilizar frecuentemente el escritorio remoto, me surgió el siguiente problema. Necesitaba algún cliente RDP para guardar los datos de acceso (ip, usuario y contraseña) para conectarme de forma fácil, esta característica ya la soporta la aplicación que ya viene por defecto en Windows, pero a su vez necesitaba poder recuperar o editar esos datos, ya que si no los escribo frecuentemente lo más seguro es que termine olvidandolos, ya que mi memoria no es muy buena.

Buscando por internet llegue a encontrarme con Remote Desktop Manager, y aunque me permitía guardar, y exportar las credenciales de acceso, la verdad es que no me gustaba que siempre aparecía un splash screen que aunque no duraba mucho, tener que esperar cada vez que necesitaba usarlo me parecía tedioso, así que empecé a buscar alguna otra alternativa y así encontré Remote Desktop Plus.

¿Porque me gusta RD+?

Remote Desktop Plus cubre las 2 necesidades que tenia que eran, poder conectarme de forma rápida a los servidores que utilizo pero a su vez me permite exportar las credenciales.

Pero algo que me soprendió y que es de bastante utilidad es que soporta linea de comandos, de esta manera puedo crear algún comando para conectarme a cualquier servidor.

Librería para CFDI 4.0

En 2015 haciendo mis prácticas profesionales en un despacho contable, conocí lo que era CFDI 3.2 y en mi afán de aprender, desarrollé una librería que generaba el XML sellado para su timbrado.

Pero justo al terminar mis prácticas, me contrató una empresa local dedicada a la facturación electrónica, donde laboré por más de 3 años dando soporte técnico al SDK para CFDI que comercializaban.

Con esa experiencia decidí volver a crear una librería para facturación electrónica, que coincidió con la llegada del Cfdi 3.3 y pude venderla cuando entró en vigor (ver aquí).

Además, al mismo tiempo en la empresa que trabajaba desarrollé una nueva versión del SDK, que también soportaba Cfdi 3.3, que entre sus características más resaltables eran:

  • Retro compatibilidad con los proyectos que ya usaban el SDK anterior (prácticamente era quitar el viejo e incorporar el nuevo)
  • Su nueva estructura le permitía darle soporte de forma mucho más facil
  • Implementé un sistema de plugins que le permitía al SDK realizar operaciones antes, durante y después de generar y timbrar el Cfdi.

Con esos casi 4 años de experiencia y los casi 7 años de experiencia profesional, decidí crear una librería para CFDI 4.0.

Actualmente estoy desarrollando una librería que soporta las versiones 3.3 (aún vigente) y 4.0 de CFDI. Esta librería podrá incluir cualquier complemento que necesites por medio de librerías extra que iré desarrollando y liberando tan pronto como me sea posible.

¿Cómo consigo la librería?

La librería la puedes conseguir desde la NuGet Gallery o puedes buscarla en Visual Studio, desde nuget package manager, igual que los complementos.

¿De verdad es gratis?

Si, la librería para CFDI junto con las librerías para complementos son totalmente gratuitas. Este es un proyecto personal y deseó poder implementar la mayor cantidad de complementos posibles (a ser posible, todos).

Soporte Técnico

Actualmente no dispongo del tiempo que me gustaría para darle soporte a un proyecto como este y no puedo ofrecer soporte 24/7.

Como dije anteriormente, mi idea es implementar la mayoría de los complementos, por lo que si necesitas alguno en concreto házmelo saber.

Importante

  • Actualmente estoy utilizando el ambiente de pruebas de Solución Factible para timbrar los CFDI y validar que las librerías estén trabajando correctamente.
  • Pronto publicaré un repositorio de GitHub con los ejemplos que timbré para validar las librerías, está atento a este sitio para que puedas descargarlo.

Ejemplos

CFDI 4.0 de Ingreso
C#
// Archivo XSLT necesario para la Cadena Original
string xsltFile = @"cadenaoriginal_4_0.xslt";
 
// Certificados
string cerFile = @"EKU9003173C9.cer";
string keyFile = @"EKU9003173C9.key";
string password = "12345678a";
 
// Se lee el Certificado
var cerInfo = CsdUtils.LeerCertificado(cerFile);
 
// Se crea el Comprobante
IsaRoGaMX.Cfdi.v40.Comprobante cfdi = new IsaRoGaMX.Cfdi.v40.Comprobante();
 
// Datos de la Factura
cfdi["Serie"] = "F";
cfdi["Folio"] = "1234";
cfdi["Fecha"] = DateTime.Now.ToString("s");
cfdi["CondicionesDePago"] = "CondicionesDePago";
cfdi["SubTotal"] = "200";
cfdi["Descuento"] = "1";
cfdi["Moneda"] = "MXN";
cfdi["TipoCambio"] = "1";
cfdi["Total"] = "198.95";
cfdi["TipoDeComprobante"] = "I";
cfdi["Exportacion"] = "01";
cfdi["MetodoPago"] = "PPD";
cfdi["FormaPago"] = "99";
cfdi["LugarExpedicion"] = "20000";
cfdi["Certificado"] = cerInfo.Certificado;
cfdi["NoCertificado"] = cerInfo.NoCertificado;
 
// Emisor
cfdi.Emisor["Rfc"] = "EKU9003173C9";
cfdi.Emisor["Nombre"] = "ESCUELA KEMPER URGATE";
cfdi.Emisor["RegimenFiscal"] = "601";
 
// Receptor
cfdi.Receptor["Rfc"] = "URE180429TM6";
cfdi.Receptor["Nombre"] = "UNIVERSIDAD ROBOTICA ESPAÑOLA";
cfdi.Receptor["DomicilioFiscalReceptor"] = "65000";
cfdi.Receptor["RegimenFiscalReceptor"] = "601";
cfdi.Receptor["UsoCFDI"] = "G01";
 
// Concepto
cfdi.Conceptos[0]["ClaveProdServ"] = "50211503";
cfdi.Conceptos[0]["Cantidad"] = "1";
cfdi.Conceptos[0]["ClaveUnidad"] = "H87";
cfdi.Conceptos[0]["Unidad"] = "Pieza";
cfdi.Conceptos[0]["Descripcion"] = "Cigarros";
cfdi.Conceptos[0]["ValorUnitario"] = "200.00";
cfdi.Conceptos[0]["Descuento"] = "1";
cfdi.Conceptos[0]["Importe"] = "200.00";
cfdi.Conceptos[0]["ObjetoImp"] = "02";
 
cfdi.Conceptos[0].Impuestos.Traslados[0]["Base"] = "1";
cfdi.Conceptos[0].Impuestos.Traslados[0]["Importe"] = "0.16";
cfdi.Conceptos[0].Impuestos.Traslados[0]["Impuesto"] = "002";
cfdi.Conceptos[0].Impuestos.Traslados[0]["TasaOCuota"] = "0.160000";
cfdi.Conceptos[0].Impuestos.Traslados[0]["TipoFactor"] = "Tasa";
 
cfdi.Conceptos[0].Impuestos.Retenciones[0]["Base"] = "1";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["Impuesto"] = "001";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["TipoFactor"] = "Tasa";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["TasaOCuota"] = "0.100000";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["Importe"] = "0.10";
 
cfdi.Conceptos[0].Impuestos.Retenciones[1]["Base"] = "1";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["Impuesto"] = "002";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["TipoFactor"] = "Tasa";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["TasaOCuota"] = "0.106666";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["Importe"] = "0.11";
 
cfdi.Impuestos["TotalImpuestosRetenidos"] = "0.21";
cfdi.Impuestos["TotalImpuestosTrasladados"] = "0.16";
 
cfdi.Impuestos.Retenciones[0]["Impuesto"] = "001";
cfdi.Impuestos.Retenciones[0]["Importe"] = "0.10";
 
cfdi.Impuestos.Retenciones[1]["Impuesto"] = "002";
cfdi.Impuestos.Retenciones[1]["Importe"] = "0.11";
 
cfdi.Impuestos.Traslados[0]["Base"] = "1";
cfdi.Impuestos.Traslados[0]["Importe"] = "0.16";
cfdi.Impuestos.Traslados[0]["Impuesto"] = "002";
cfdi.Impuestos.Traslados[0]["TasaOCuota"] = "0.160000";
cfdi.Impuestos.Traslados[0]["TipoFactor"] = "Tasa";
 
// Genera cadena original
string cadenaOriginal = XsltTransform.GeneraCadenaOriginal(cfdi.Documento, xsltFile);
 
// Genera sello
cfdi["Sello"] = CsdUtils.GeneraSelloFiscalDigital(cadenaOriginal, keyFile, password);
 
// Se guarda el Xml
cfdi.Documento.Save("F1234.xml");

Cfdi 4.0 de Nómina

C#
// Archivo XSLT necesario para la Cadena Original
string xsltFile = @"E:\Descargas\cadenaoriginal_4_0.xslt";
 
// Certificados
string cerFile = @"EKU9003173C9.cer";
string keyFile = @"EKU9003173C9.key";
string password = "12345678a";
 
// Se lee el Certificado
var cerInfo = CsdUtils.LeerCertificado(cerFile);
 
// Se crea el comprobante
IsaRoGaMX.Cfdi.v40.Comprobante cfdi = new IsaRoGaMX.Cfdi.v40.Comprobante();
 
// Datos del Comprobante
cfdi["Serie"] = "NOM";
cfdi["Folio"] = "789";
cfdi["Fecha"] = DateTime.Now.ToString("s");
cfdi["SubTotal"] = "5000.00";
cfdi["Descuento"] = "200";
cfdi["Moneda"] = "MXN";
cfdi["Total"] = "4800";
cfdi["TipoDeComprobante"] = "N";
cfdi["Exportacion"] = "01";
cfdi["MetodoPago"] = "PUE";
cfdi["LugarExpedicion"] = "20000";
cfdi["Certificado"] = cerInfo.Certificado;
cfdi["NoCertificado"] = cerInfo.NoCertificado;
 
// Emisor
cfdi.Emisor["Rfc"] = "URE180429TM6";
cfdi.Emisor["Nombre"] = "UNIVERSIDAD ROBOTICA ESPAÑOLA";
cfdi.Emisor["RegimenFiscal"] = "601";
 
// Receptor
cfdi.Receptor["Rfc"] = "XOJI740919U48";
cfdi.Receptor["Nombre"] = "INGRID XODAR JIMENEZ";
cfdi.Receptor["DomicilioFiscalReceptor"] = "88965";
cfdi.Receptor["RegimenFiscalReceptor"] = "605";
cfdi.Receptor["UsoCFDI"] = "CN01";
 
// Conceptos
cfdi.Conceptos[0]["ClaveProdServ"] = "84111505";
cfdi.Conceptos[0]["Cantidad"] = "1";
cfdi.Conceptos[0]["ClaveUnidad"] = "ACT";
cfdi.Conceptos[0]["Descripcion"] = "Pago de nómina";
cfdi.Conceptos[0]["ValorUnitario"] = "5000.00";
cfdi.Conceptos[0]["Descuento"] = "200";
cfdi.Conceptos[0]["Importe"] = "5000.00";
cfdi.Conceptos[0]["ObjetoImp"] = "01";
 
// Complemento Nomina
var nomina = new IsaRoGaMX.Cfdi.Nomina.v12.Nomina();
nomina["TipoNomina"] = "O";
nomina["FechaPago"] = "2021-12-24";
nomina["FechaInicialPago"] = "2021-12-09";
nomina["FechaFinalPago"] = "2021-12-24";
nomina["NumDiasPagados"] = "15";
nomina["TotalPercepciones"] = "5000.0";
nomina["TotalDeducciones"] = "200";
 
// Emisor
nomina.Emisor["RegistroPatronal"] = "B5510768108";
nomina.Emisor["RfcPatronOrigen"] = "URE180429TM6";
 
// Receptor
nomina.Receptor["Curp"] = "XEXX010101HNEXXXA4";
nomina.Receptor["NumSeguridadSocial"] = "000000";
nomina.Receptor["FechaInicioRelLaboral"] = "2015-01-01";
nomina.Receptor["Antigüedad"] = "P364W";
nomina.Receptor["TipoContrato"] = "01";
nomina.Receptor["TipoJornada"] = "01";
nomina.Receptor["TipoRegimen"] = "03";
nomina.Receptor["NumEmpleado"] = "120";
nomina.Receptor["Departamento"] = "Desarrollo";
nomina.Receptor["Puesto"] = "Ingeniero de Software";
nomina.Receptor["RiesgoPuesto"] = "1";
nomina.Receptor["PeriodicidadPago"] = "04";
nomina.Receptor["CuentaBancaria"] = "1111111111";
nomina.Receptor["Banco"] = "002";
nomina.Receptor["SalarioBaseCotApor"] = "490.22";
nomina.Receptor["SalarioDiarioIntegrado"] = "146.47";
nomina.Receptor["ClaveEntFed"] = "JAL";
 
// Percepciones
nomina.Percepciones["TotalSueldos"] = "5000.0";
nomina.Percepciones["TotalGravado"] = "2808.8";
nomina.Percepciones["TotalExento"] = "2191.2";
 
nomina.Percepciones[0]["TipoPercepcion"] = "001";
nomina.Percepciones[0]["Clave"] = "00500";
nomina.Percepciones[0]["Concepto"] = "Sueldos; Salarios Rayas y Jornales";
nomina.Percepciones[0]["ImporteGravado"] = "2808.8";
nomina.Percepciones[0]["ImporteExento"] = "2191.2";
 
// Deducciones
nomina.Deducciones["TotalOtrasDeducciones"] = "200";
 
nomina.Deducciones[0]["TipoDeduccion"] = "001";
nomina.Deducciones[0]["Clave"] = "00301";
nomina.Deducciones[0]["Concepto"] = "Seguridad Social";
nomina.Deducciones[0]["Importe"] = "200";
 
// Se agrega el complemento
cfdi.AgregaComplemento(nomina);
 
// Genera cadena original
string cadenaOriginal = XsltTransform.GeneraCadenaOriginal(cfdi.Documento, xsltFile);
 
// Genera sello
cfdi["Sello"] = CsdUtils.GeneraSelloFiscalDigital(cadenaOriginal, keyFile, password);
 
cfdi.Documento.Save("NUM789.xml");
Cfdi 4.0 Instituciones Educativas Privadas
C#
// Archivo XSLT necesario para la Cadena Original
string xsltFile = @"cadenaoriginal_4_0.xslt";
 
// Certificados
string cerFile = @"EKU9003173C9.cer";
string keyFile = @"EKU9003173C9.key";
string password = "12345678a";
 
// Se lee el Certificado
var cerInfo = CsdUtils.LeerCertificado(cerFile);
 
// Se crea el Comprobante
IsaRoGaMX.Cfdi.v40.Comprobante cfdi = new IsaRoGaMX.Cfdi.v40.Comprobante();
 
// Datos de la Factura
cfdi["Serie"] = "F";
cfdi["Folio"] = "1234";
cfdi["Fecha"] = DateTime.Now.ToString("s");
cfdi["CondicionesDePago"] = "CondicionesDePago";
cfdi["SubTotal"] = "200";
cfdi["Descuento"] = "1";
cfdi["Moneda"] = "MXN";
cfdi["TipoCambio"] = "1";
cfdi["Total"] = "198.95";
cfdi["TipoDeComprobante"] = "I";
cfdi["Exportacion"] = "01";
cfdi["MetodoPago"] = "PPD";
cfdi["FormaPago"] = "99";
cfdi["LugarExpedicion"] = "20000";
cfdi["Certificado"] = cerInfo.Certificado;
cfdi["NoCertificado"] = cerInfo.NoCertificado;
 
// Emisor
cfdi.Emisor["Rfc"] = "EKU9003173C9";
cfdi.Emisor["Nombre"] = "ESCUELA KEMPER URGATE";
cfdi.Emisor["RegimenFiscal"] = "601";
 
// Receptor
cfdi.Receptor["Rfc"] = "URE180429TM6";
cfdi.Receptor["Nombre"] = "UNIVERSIDAD ROBOTICA ESPAÑOLA";
cfdi.Receptor["DomicilioFiscalReceptor"] = "65000";
cfdi.Receptor["RegimenFiscalReceptor"] = "601";
cfdi.Receptor["UsoCFDI"] = "G01";
 
// Concepto
cfdi.Conceptos[0]["ClaveProdServ"] = "50211503";
cfdi.Conceptos[0]["Cantidad"] = "1";
cfdi.Conceptos[0]["ClaveUnidad"] = "H87";
cfdi.Conceptos[0]["Unidad"] = "Pieza";
cfdi.Conceptos[0]["Descripcion"] = "Cigarros";
cfdi.Conceptos[0]["ValorUnitario"] = "200.00";
cfdi.Conceptos[0]["Descuento"] = "1";
cfdi.Conceptos[0]["Importe"] = "200.00";
cfdi.Conceptos[0]["ObjetoImp"] = "02";
 
cfdi.Conceptos[0].Impuestos.Traslados[0]["Base"] = "1";
cfdi.Conceptos[0].Impuestos.Traslados[0]["Importe"] = "0.16";
cfdi.Conceptos[0].Impuestos.Traslados[0]["Impuesto"] = "002";
cfdi.Conceptos[0].Impuestos.Traslados[0]["TasaOCuota"] = "0.160000";
cfdi.Conceptos[0].Impuestos.Traslados[0]["TipoFactor"] = "Tasa";
 
cfdi.Conceptos[0].Impuestos.Retenciones[0]["Base"] = "1";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["Impuesto"] = "001";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["TipoFactor"] = "Tasa";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["TasaOCuota"] = "0.100000";
cfdi.Conceptos[0].Impuestos.Retenciones[0]["Importe"] = "0.10";
 
cfdi.Conceptos[0].Impuestos.Retenciones[1]["Base"] = "1";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["Impuesto"] = "002";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["TipoFactor"] = "Tasa";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["TasaOCuota"] = "0.106666";
cfdi.Conceptos[0].Impuestos.Retenciones[1]["Importe"] = "0.11";
 
// Complemento de Instituciones Educativas
var iedu = new IsaRoGaMX.Cfdi.Iedu.v10.InstEducativas();
iedu["CURP"] = "AAAA010101HNLRNL09";
iedu["autRVOE"] = "PEFHS821923KSDJ823";
iedu["nivelEducativo"] = "Secundaria";
iedu["nombreAlumno"] = "Nombre Alumno";
iedu["rfcPago"] = "BBB010101AAA";
 
// Se agrega al concepto
cfdi.Conceptos[0].AgregaComplemento(iedu);
 
// Impuestos
cfdi.Impuestos["TotalImpuestosRetenidos"] = "0.21";
cfdi.Impuestos["TotalImpuestosTrasladados"] = "0.16";
 
cfdi.Impuestos.Retenciones[0]["Impuesto"] = "001";
cfdi.Impuestos.Retenciones[0]["Importe"] = "0.10";
 
cfdi.Impuestos.Retenciones[1]["Impuesto"] = "002";
cfdi.Impuestos.Retenciones[1]["Importe"] = "0.11";
 
cfdi.Impuestos.Traslados[0]["Base"] = "1";
cfdi.Impuestos.Traslados[0]["Importe"] = "0.16";
cfdi.Impuestos.Traslados[0]["Impuesto"] = "002";
cfdi.Impuestos.Traslados[0]["TasaOCuota"] = "0.160000";
cfdi.Impuestos.Traslados[0]["TipoFactor"] = "Tasa";
 
// Genera cadena original
string cadenaOriginal = XsltTransform.GeneraCadenaOriginal(cfdi.Documento, xsltFile);
 
// Genera sello
cfdi["Sello"] = CsdUtils.GeneraSelloFiscalDigital(cadenaOriginal, keyFile, password);
 
// Se guarda el XML
cfdi.Documento.Save("F1234.xml");

.NET Fiddle – C# sin Visual Studio

En algunas ocasiones se necesita probar algún concepto o ver si es posible hacer algo de forma rápida.

Actualmente trabajo bastante con C# y dado que es molesto tener que crear un proyecto solo para probar algo sencillo y ejecutar el mastodonte que es Visual Studio solo para algo tan pequeño, encontré una solucion que se adapta este caso en especifico.

Se trata de dotnetfiddle.net, es un compilador online de C#, permite crear proyectos sencillos de Consola, MVC, Script y Nancy; entre sus opciones también permite seleccionar la versión de C# que queremos usar.

Esta herramienta me gusta bastante porque es bastante sencilla, permite crear snippets de código y probarlos desde el navegador, también puedes generar un enlace para compartirlo o incluso puedes trabajar al mismo tiempo sobre el mismo código con alguien más(esto último no lo he probado aún).

Para muestra un botón, sabia que existian los Extension Methods pero jamás los habia usado y me puse a revisar, ya que necesito formatear objetos DateTime a string pero quiero evitar el tener que escribir ToString(@”yyyy-MM-dd\THH:mm:ss”) cada vez que lo necesito, así que se me ocurrió intentar crear un Extension Method , así aprendia a usarlas y ademas me servia, ya que si en algun momento el formato de fecha que debo usar cambia, solo cambio el formato es la Extension Method.

Así que este fue el resultado: