viernes, 6 de febrero de 2015

Crear un WebService con .NET

Si trabajamos con .NET, una tarea con la casi seguro que nos encontraremos habitualmente es con la de construir un servicio web que exponga una serie de datos. Esto es muy sencillo de hacer en .NET, y vamos a ver como se hace.

Antecedentes
Supongamos que vamos a realizar un webservice que se conecte a una base de datos SQL Server para lanzarle consultas y devolver los resultados. Esto será válido para la mayoría de casos con que nos encontramos, independientemente de que después debamos ampliar el servicio con otros métodos (como por ejemplo incluir seguridad, encriptación, etc).

Lo primero que se nos puede ocurrir, es crear una serie de métodos en el WebService de forma que cada uno reciba sus parámetros, monte las consultas, y las lance contra la base de datos para terminar devolviendo los resultados. Esto es correcto, pero vamos a crear una técnica más potente.

En vez de hacer un método por cada consulta a lanzar, vamos a tener un sólo método. Este, recibirá un nombre de opción a ejecutar, y según esa opción, lanzará una u otra consulta. Es más, no tendremos que tener las consultas dentro del propio WebService, sino que nos basaremos para configurarlas en un fichero XML. Esto nos va a permitir disponer de un código muy limpio y claro, con muy poco mantenimiento posterior, y configuraremos las posibles opciones y sus consultas relacionadas en un fichero XML, de forma que para crear, modificar, o eliminar nuevos métodos, no modificaremos el servicio web, sino únicamente el XML. Veamos cómo.

Fichero de configuración
Vamos a crear un fichero XML de configuración que contendrá los métodos de que dispondrá el servicio web. Posteriormente, dicho servicio recibirá el método a ejecutar, su lista de parámetros, y devolverá los resultados.

El fichero podría ser el siguiente:
<?xml version="1.0" encoding="utf-8" ?>
<OpcionesDisponibles>
  <opcion>
    <nombre>GetPaises</nombre>
    <SQL>SELECT cod_pais,pais FROM paises order by pais</SQL>
  </opcion>
  <opcion>
    <nombre>GetPais</nombre>
    <SQL>SELECT cod_pais,pais FROM paises WHERE cod_pais='#PARAMETRO_1#'</SQL>
  </opcion>
</OpcionesDisponibles>
Como se puede ver, es extremadamente simple, y nos permitirá ampliar, modificar, o reducir el servicio web sin tener que modificarlo.

El WebService: La clase mágica
Una vez que sabemos lo que queremos, y que tenemos nuestro fichero de configuración de métodos definido, sólo nos queda crear el servicio web.

Nuestro servicio recibirá tres parámetros: la opción a ejecutar, la lista de parámetros relativas a esa función, y el formato de resultado que deseamos. Así pues, manos a la obra:
using System;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;

public class WS_Clase
{
  static string ficheroOpciones = HttpContext.Current.Server.MapPath("~/") + "\\opciones.xml";

  /// <summary>
  /// Ejecutar y devolver un XML resultado de ejecutar una sentencia SQL configurada en un fichero XML.
  /// </summary>
  /// <param name="nombre"></param>
  /// <param name="listaParametros"></param>
  /// <returns></returns>
  public static XmlDocument GetOpcion(string nombre, string listaParametros)
  {
    try
    {
      // Buscar opcion en el fichero de parametros para obtener la SQL a ejecutar
      DataSet ds = new DataSet();
      ds.ReadXml(ficheroOpciones);
      DataTable dt = new DataTable();
      dt = ds.Tables[0];
      string SQL = string.Empty;

      for (int i = 0; i < dt.Rows.Count; i++)
      {
        if (Convert.ToString(dt.Rows[i]["nombre"]).ToUpper() == nombre.ToUpper())
        {
          SQL = Convert.ToString(dt.Rows[i]["SQL"]);
          break;
        }
      }
      if (SQL == string.Empty)
        throw new Exception("Opción no disponible: " + nombre);

      // Asignar parametros
      string[] parametros;
      parametros = listaParametros.Split('|');
      for (int i = 0; i < parametros.Length; i++)
      {
        SQL = SQL.Replace("#PARAMETRO_" + Convert.ToString(i + 1) + "#", parametros[i]);
      }

      // Ejecutar SQL
      dt = AccesoDatos.GetDataTable(SQL);

      System.Xml.XmlDocument x = DataTableToXmlDocument(dt);
      dt.Dispose();
      ds.Dispose();
      return x;

    }
    catch (Exception ex)
    {
      throw new Exception(ex.Message);
    }
  }

  public static int SetOpcion(string nombre, string listaParametros)
  {
    try
    {
      // Buscar opcion en el fichero de parametros para obtener la SQL a ejecutar
      DataSet ds = new DataSet();
      ds.ReadXml(ficheroOpciones);
      DataTable dt = new DataTable();
      dt = ds.Tables[0];
      string SQL = string.Empty;

      for (int i = 0; i < dt.Rows.Count; i++)
      {
        if (Convert.ToString(dt.Rows[i]["nombre"]).ToUpper() == nombre.ToUpper())
        {
          SQL = Convert.ToString(dt.Rows[i]["SQL"]);
          break;
        }
      }
      if (SQL == string.Empty)
        throw new Exception("Opción no disponible: " + nombre);

      // Asignar parametros
      string[] parametros;
      parametros = listaParametros.Split('|');
      for (int i = 0; i < parametros.Length; i++)
      {
        SQL = SQL.Replace("#PARAMETRO_" + Convert.ToString(i + 1) + "#", parametros[i]);
      }

      // Ejecutar SQL
      int resul = AccesoDatos.ExecuteSQL(SQL);

      // Devolver resultado
      dt.Dispose();
      ds.Dispose();
      return resul;
    }
    catch (Exception ex)
    {
      throw new Exception(ex.Message);
    }
  }

  /// <summary>
  /// GetOpcion en formato JSON
  /// </summary>
  /// <param name="nombre"></param>
  /// <param name="listaParametros"></param>
  /// <returns></returns>
  public static String GetOpcionJSON(string nombre, string listaParametros)
  {
    try
    {
      // Buscar opcion en el fichero de parametros para obtener la SQL a ejecutar
      DataSet ds = new DataSet();
      ds.ReadXml(ficheroOpciones);
      DataTable dt = new DataTable();
      dt = ds.Tables[0];
      string SQL = string.Empty;

      for (int i = 0; i < dt.Rows.Count; i++)
      {
        if (Convert.ToString(dt.Rows[i]["nombre"]).ToUpper() == nombre.ToUpper())
        {
          SQL = Convert.ToString(dt.Rows[i]["SQL"]);
          break;
        }
      }
      if (SQL == string.Empty)
        throw new Exception("Opción no disponible: " + nombre);

      // Asignar parametros
      string[] parametros;
      parametros = listaParametros.Split('|');
      for (int i = 0; i < parametros.Length; i++)
      {
        SQL = SQL.Replace("#PARAMETRO_" + Convert.ToString(i + 1) + "#", parametros[i]);
      }

      // Ejecutar SQL
      dt = AccesoDatos.GetDataTable(SQL);

      string x = DataTableToJSONDocument(dt);
      dt.Dispose();
      ds.Dispose();
      return x;

    }
    catch (Exception ex)
    {
      throw new Exception(ex.Message);
    }
  }

  #region " Métodos privados "

  /// <summary>
  /// Configurar DataTable con nomenclatura estandar para hacer mas fácil la lectura desde aplicaciones cliente (siempre mismos campos).
  /// </summary>
  /// <param name="dt"></param>
  /// <returns></returns>
  private static DataTable DataTableToStandard(DataTable dt)
  {
    try
    {
      DataTable dtResultado = new DataTable(dt.TableName);
      dtResultado.Columns.Add("campo", typeof(System.String));
      dtResultado.Columns.Add("valor", typeof(System.String));

      DataRow dr;
      for (int i = 0; i < dt.Rows.Count; i++)
      {
        dr = dtResultado.NewRow();
        dr["campo"] = dt.Rows[i][0];
        dr["valor"] = dt.Rows[i][1];
        dtResultado.Rows.Add(dr);
      }

      return dtResultado;
    }
    catch (Exception ex)
    {
      throw ex;
    }
  }

  private static String DataTableToJSONDocument(DataTable dt)
  {

    string[] StrDc = new string[dt.Columns.Count];
    string HeadStr = string.Empty;
    for (int i = 0; i < dt.Columns.Count; i++)
    {
      StrDc[i] = dt.Columns[i].Caption;
      HeadStr += "\"" + StrDc[i] + "\":\"" + StrDc[i] + i.ToString() + "¾" + "\",";
    }

    HeadStr = HeadStr.Substring(0, HeadStr.Length - 1);

    StringBuilder Sb = new StringBuilder();

    Sb.Append("[");

    for (int i = 0; i < dt.Rows.Count; i++)
    {
      string TempStr = HeadStr;
      for (int j = 0; j < dt.Columns.Count; j++)
      {
        TempStr = TempStr.Replace(dt.Columns[j] + j.ToString() + "¾", dt.Rows[i][j].ToString().Trim());
      }
      //Sb.AppendFormat("{{{0}}},",TempStr);

      Sb.Append("{" + TempStr + "},");
    }

    Sb = new StringBuilder(Sb.ToString().Substring(0, Sb.ToString().Length - 1));

    if (Sb.ToString().Length > 0)
      Sb.Append("]");

    return StripControlChars(Sb.ToString());

  }

  public static string StripControlChars(string s)
  {
    return Regex.Replace(s, @"[^\x20-\x7F]", "");
  }

  /// <summary>
  /// Pasar DataTable a XML estandarizado para su devolución por el WebService.
  /// </summary>
  /// <param name="dt"></param>
  /// <returns></returns>
  private static XmlDocument DataTableToXmlDocument(DataTable dt)
  {
    XmlDocument xml = new XmlDocument();
    System.Text.StringBuilder sb = new System.Text.StringBuilder();

    sb.Append("<?xml version='1.0' encoding='utf-8' ?>");
    sb.Append("<DocumentElement>");

    foreach (DataRow dr in dt.Rows)
    {
      sb.Append("<Dato>");

      foreach (DataColumn dc in dt.Columns)
      {
        sb.Append("<" + dc.ColumnName + ">" + dr[dc].ToString() + "</" + dc.ColumnName + ">");
      }

      //foreach (DataColumn dc in dt.Columns)
      //  sb.Append("<" + dc.ColumnName + ">" + dr[dc].ToString() + "</" + dc.ColumnName + ">");

      sb.Append("</Dato>");
    }

    sb.Append("</DocumentElement>");
    xml.LoadXml(sb.ToString());

    return xml;
  }

  #endregion

}

El WebService: La interfaz
Una vez hemos definido la clase que hace lo que deseamos, simplemente exponemos el webservice:
using WS_Clase; // Nuestra clase creada antes
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Xml;

namespace eCliente_WebService
{
  /// <summary>
  /// Servicio web para el acceso a datos de la web de eCliente
  /// </summary>
  [WebService(Namespace = "http://nuestra_url")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  [System.ComponentModel.ToolboxItem(false)]
  // Para permitir que se llame a este servicio web desde un script, usando ASP.NET AJAX, quite la marca de comentario de la línea siguiente. 
  // [System.Web.Script.Services.ScriptService]
  public class eCliente_WebService : System.Web.Services.WebService
  {
    [WebMethod]
    public string Test()
    {
      return "Hola desde el WebService de eCliente.";
    }

    [WebMethod]
    public XmlDocument GetOpcion(string nombre, string listaParametros)
    {
      return WS_Clases.GetOpcion(nombre, listaParametros);
    }

    [WebMethod]
    public int SetOpcion(string nombre, string listaParametros)
    {
      return WS_Clases.SetOpcion(nombre, listaParametros);
    }

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public void GetOpcionJSON(string nombre, string listaParametros)
    {
      HttpContext.Current.Response.Write(WS_Clases.GetOpcionJSON(nombre, listaParametros));
    }


    [WebMethod]
    [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
    public void GetOpcionJSONAjax(string nombre, string listaParametros, string callback = "")
    {
      System.Text.StringBuilder sb = new System.Text.StringBuilder();
      if (callback != "")
      {
        sb.Append(callback + "(");
        sb.Append(WS_Clases.GetOpcionJSON(nombre, listaParametros));
        sb.Append(");");
      }
      else
        sb.Append(WS_Clases.GetOpcionJSON(nombre, listaParametros));

      Context.Response.Clear();
      Context.Response.ContentType = "application/json";
      Context.Response.Write(sb.ToString());
      Context.Response.End();
    }

  }
}

Y eso es todo. Potente, ¿verdad?. Ahora sólo debemos modificar el fichero XML a nuestro gusto para adaptarlo a nuestras necesidades (ojo, recordar introducir algún sistema de seguridad, y a ser posible, excluir el fichero XML en el fichero robots.txt de nuestro servidor para que no sea indexado).

En otra entrada veremos como consumir un webservice.

Enlazando a Crystal Reports con .NET

En esta entrada vamos a crear una clase genérica que nos permita interactuar con informes realizados en Crystal Reports. La clase se logará en la base de datos, ejecutará los informes y nos los devolverá en el formato que nos interese. Si examinamos el código de la clase, realizado en C#, no son necesarias muchas explicaciones. Veámoslo pues:
// *************************************************************************
// CLASE PARA CREAR INFORMES UTILIZANDO CRYSTAL REPORTS (BUSINESS OBJECT)
//
// Referencias a importar (C:\Archivos de Programa\Business Objects\Common\3.5\managed\dotnet2)
//    CrystalDecisions.CrystalRports.Engine
//    CrystalDecisions.Shared
//
// Manuel Toscano Blancas
// *************************************************************************

using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
using System;
using System.Collections;

namespace GestorInformes
{
  class InformesCrystalReports
  {

    #region " Variables miembro "

    // Informacion de conexion a la BD
    private static string _bbdd_servidor;
    private static string _bbdd_nombre;
    private static string _bbdd_usuario;
    private static string _bbdd_clave;
    private static bool _bbdd_seguridadIntegrada;

    #endregion

    #region " Métodos públicos "

    /// <summary>
    /// Establecer las propiedades de conexión a la base de datos para los informes.
    /// </summary>
    /// <param name="servidor"></param>
    /// <param name="nombreBBDD"></param>
    /// <param name="usuario"></param>
    /// <param name="clave"></param>
    /// <param name="seguridadIntegrada"></param>
    public static void SetInfoConexion(string servidor, string nombreBBDD, string usuario, string clave, bool seguridadIntegrada)
    {
      _bbdd_servidor = servidor;
      _bbdd_nombre = nombreBBDD;
      _bbdd_usuario = usuario;
      _bbdd_clave = clave;
      _bbdd_seguridadIntegrada = seguridadIntegrada;
    }

    /// <summary>
    /// Generar informe y devolver resultado en forma de fichero en PDF.
    /// </summary>
    /// <param name="ficheroRPT"></param>
    /// <param name="hashTableFormulas"></param>
    /// <param name="ficheroPDF"></param>
    public static void ReportToPDF(string ficheroRPT, Hashtable hashTableFormulas, string ficheroPDF)
    {
      try
      {
        ReportDocument rpt;
        rpt = GetResultadoRPT(ficheroRPT, hashTableFormulas);
        rpt.ExportToDisk(ExportFormatType.PortableDocFormat, ficheroPDF);
        rpt.Close();
        rpt.Dispose();
      }
      catch (Exception ex)
      {
        throw new Exception(ex.InnerException.ToString());
      }
    }

    /// <summary>
    /// Generar informe y devolver resultado por impresora.
    /// </summary>
    /// <param name="ficheroRPT"></param>
    /// <param name="hashTableFormulas"></param>
    /// <param name="nombreImpresora"></param>
    /// <param name="numeroCopias"></param>
    /// <param name="dobleCara"></param>
    public static void ReportToPrinter(string ficheroRPT, Hashtable hashTableFormulas, string nombreImpresora = "", int numeroCopias = 1, bool dobleCara = false)
    {
      try
      {
        ReportDocument rpt;
        rpt = GetResultadoRPT(ficheroRPT, hashTableFormulas);
        // Se podrian configurar otras opciones de impresion con rpt.PrintOptions 
        rpt.PrintOptions.PrinterName = nombreImpresora;
        rpt.PrintOptions.PaperOrientation = CrystalDecisions.Shared.PaperOrientation.DefaultPaperOrientation;
        rpt.PrintOptions.PaperSize = CrystalDecisions.Shared.PaperSize.DefaultPaperSize;
        rpt.PrintOptions.PrinterDuplex = CrystalDecisions.Shared.PrinterDuplex.Default;
        rpt.PrintOptions.PaperSource = CrystalDecisions.Shared.PaperSource.Auto;
        if (dobleCara)
        {
          if (rpt.PrintOptions.PaperOrientation == PaperOrientation.Portrait)
            rpt.PrintOptions.PrinterDuplex = CrystalDecisions.Shared.PrinterDuplex.Vertical;
          else if (rpt.PrintOptions.PaperOrientation == PaperOrientation.Landscape)
            rpt.PrintOptions.PrinterDuplex = CrystalDecisions.Shared.PrinterDuplex.Horizontal;
          else
            rpt.PrintOptions.PrinterDuplex = CrystalDecisions.Shared.PrinterDuplex.Default;
        }
        // Imprimir
        rpt.PrintToPrinter(numeroCopias, true, 0, 0);
        rpt.Close();
        rpt.Dispose();
      }
      catch (Exception ex)
      {
        throw new Exception(ex.InnerException.ToString());
      }
    }

    #endregion

    #region " Métodos privados para la generación del informe "

    private static ReportDocument GetResultadoRPT(string ficheroRPT, Hashtable hashTableFormulas = null)
    {
      try
      {
        // Validaciones
        if (!System.IO.File.Exists(ficheroRPT)) throw new ApplicationException("No se encontró el fichero de reporte " + ficheroRPT);

        // Informe
        CrystalDecisions.CrystalReports.Engine.ReportDocument rpt = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
        rpt.Load(ficheroRPT);
        // Pasar fórmulas
        if (hashTableFormulas != null && hashTableFormulas.Count > 0)
        {
          foreach (string key in hashTableFormulas.Keys)
            SetFormula(rpt, key, hashTableFormulas[key].ToString());
        }
        // Logarse en todas las tablas
        LoginEnTablas(rpt);

        return rpt;
      }
      catch (Exception ex)
      {
        throw new Exception(ex.InnerException.ToString());
      }
    }

    private static void SetFormula(ReportDocument rpt, string nombre, string valor)
    {
      try
      {
        rpt.DataDefinition.FormulaFields[nombre].Text = "\"" + valor.ToString() + "\"";
      }
      catch (Exception ex)
      {
        throw new Exception("Fórmula no válida. " + ex.Message);
      }
    }

    private static void LoginEnTablas(ReportDocument rpt)
    {
      try
      {
        CrystalDecisions.Shared.TableLogOnInfo tableLogonInfo = new CrystalDecisions.Shared.TableLogOnInfo();
        CrystalDecisions.Shared.ConnectionInfo connectionInfo = new CrystalDecisions.Shared.ConnectionInfo();

        connectionInfo.ServerName = _bbdd_servidor;
        connectionInfo.DatabaseName = _bbdd_nombre;
        connectionInfo.UserID = _bbdd_usuario;
        connectionInfo.Password = _bbdd_clave;
        connectionInfo.IntegratedSecurity = _bbdd_seguridadIntegrada;

        // Tablas del informe
        foreach (CrystalDecisions.CrystalReports.Engine.Table table in rpt.Database.Tables)
        {
          if (table.LogOnInfo.ConnectionInfo.DatabaseName == connectionInfo.DatabaseName)    // Esto permite cambiar el login solo en tablas de la misma BBDD, no interfiere si son otras como por ejemplo XML
          {
            tableLogonInfo = table.LogOnInfo;
            tableLogonInfo.ConnectionInfo = connectionInfo;
            table.ApplyLogOnInfo(tableLogonInfo);
            if (table.Location.Contains("."))
              table.Location = _bbdd_nombre + ".dbo.[" + table.Location + "]";
          }
        }

        // Tablas de los SubInformes
        for (int i = 0; i < rpt.Subreports.Count; i++)
        {
          foreach (CrystalDecisions.CrystalReports.Engine.Table table in rpt.Subreports[i].Database.Tables)
          {
            if (table.LogOnInfo.ConnectionInfo.DatabaseName == connectionInfo.DatabaseName)    // Esto permite cambiar el login solo en tablas de la misma BBDD, no interfiere si son otras como por ejemplo XML
            {
              tableLogonInfo = table.LogOnInfo;
              tableLogonInfo.ConnectionInfo = connectionInfo;
              table.ApplyLogOnInfo(tableLogonInfo);
              if (table.Location.Contains("."))
                table.Location = _bbdd_nombre + ".dbo.[" + table.Location + "]";
            }
          }
        }

        tableLogonInfo = null;
        connectionInfo = null;
      }
      catch (Exception ex)
      {
        throw new Exception(ex.InnerException.ToString());
      }

    }

    #endregion

  }
}
La utilización de la clase genérica anterior, podría resumirse en el código siguiente, que sería el que utilizaríamos en nuestra aplicación:
System.Collections.Hashtable htFormulas = new System.Collections.Hashtable();
htFormulas.Clear();
htFormulas.Add("Codigo",dt.Rows[i]["ParametrosGeneracion"].ToString());
InformesCrystalReports.ReportToPDF(dt.Rows[i]["FicheroOrigen"].ToString(), htFormulas, ficheroDestinoPDF);
Eso crea un PDF con el resultado de ejecutar el informe, pero como hemos incluido otros métodos, podríamos haber hecho que directamente saliera por impresora, o bien recoger el objeto resultante para mostrarlo por pantalla en un contenedor de report.

Ficheros INI en .NET

Actualmente suelen utilizarse para almacenar configuraciones archivos XML o incluso JSON, pero existen ciertos escenarios en los que nos encontramos que debemos trabajar con ficheros .ini. Un fichero ini es un fichero de texto en el que almacenar configuraciones, que pueden ir incluidas dentro de grupo. Mejor verlo con un ejemplo:
[BaseDatos]
; Base de datos
BD_Servidor=TuServidorSQL
BD_Nombre=NombreDeTuBBDD
BD_SegIntegrada=Si
BD_Usu=
BD_Clave=
El fichero anterior crear un grupo, BaseDatos, para incluir dentro configuraciones relativas a la misma. Un fichero ini puede contener tantos grupos como sean necesarios.

Para trabajar con ficheros ini desde .NET, basta con definir en nuestro proyecto una clase como la siguiente:
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Ini
{
  /// <summary>
  /// Create a New INI file to store or load data
  /// </summary>
  public class IniFile
  {
    public string path;

    [DllImport("kernel32")]
    private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
    [DllImport("kernel32")]
    private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

    /// <summary>
    /// INIFile Constructor.
    /// </summary>
    /// <PARAM name="INIPath"></PARAM>
    public IniFile(string INIPath)
    {
      path = INIPath;
    }

    /// <summary>
    /// Write Data to the INI File
    /// </summary>
    /// <PARAM name="Section"></PARAM>
    /// Section name
    /// <PARAM name="Key"></PARAM>
    /// Key Name
    /// <PARAM name="Value"></PARAM>
    /// Value Name
    public void IniWriteValue(string Section, string Key, string Value)
    {
      WritePrivateProfileString(Section, Key, Value, this.path);
    }

    /// <summary>
    /// Read Data Value From the Ini File
    /// </summary>
    /// <PARAM name="Section"></PARAM>
    /// <PARAM name="Key"></PARAM>
    /// <PARAM name="Path"></PARAM>
    /// <returns></returns>
    public string IniReadValue(string Section, string Key)
    {
      StringBuilder temp = new StringBuilder(255);
      int i = GetPrivateProfileString(Section, Key, "", temp, 255, this.path);
      return temp.ToString();
    }

  }
}
Su uso podría ser como sigue:
IniFile ini = new IniFile(Application.StartupPath + @"\config.ini");

Globales.bbdd_servidor = ini.IniReadValue("BaseDatos", "Servidor");
Globales.bbdd_nombre = ini.IniReadValue("BaseDatos", "Nombre");
Globales.bbdd_seguridadIntegrada = (ini.IniReadValue("BaseDatos", "SeguridadIntegrada").ToUpper()=="SI")?true:false;
Globales.bbdd_usuario = ini.IniReadValue("BaseDatos", "Usuario");
Globales.bbdd_clave = ini.IniReadValue("BaseDatos", "Clave");
Es todo.

Sencilla clase de acceso a datos (SQL Server) con .NET

Una de las cosas más básicas que necesitaremos hacer con nuestros proyectos .NET, es sin duda conectarnos a una fuente de datos. .NET dispone de una serie de clases que nos facilitan esta tarea. Habitualmente suelo utilizar SQL Server (aunque cualquier fuente de datos es aceptada), y a continuación vamos a crear una pequeña clase, muy simple, para obtener acceso a datos en este gestor.
El ejemplo crea un clase muy simple, que puede ser compilada como una DLL y que nos puede ayudar a ralizar aplicaciones en 3 capas. La clase que aquí vamos a crear, es simple pero genérica, de forma que podrá ser utilizada desde cualquier aplicación sin modificación alguna (salvo las funcionalidades extra que queramos añadirle).
public class AccesoDatos
{
public static string cadenaConexion = string.Empty;
private SqlConnection conexion;
private SqlDataAdapter da;

public static void SetCadenaConexion(string connString)
{
  if (connString != string.Empty)
    cadenaConexion = connString;
  else
    cadenaConexion = String.Empty;
}

public AccesoDatos()
{
  conexion = new SqlConnection(cadenaConexion);
}

~AccesoDatos()
{
  da.Dispose();
  conexion.Close();
  conexion.Dispose();
}


public DataSet GetDataSet(string SQL)
{
  try
  {
    da = new SqlDataAdapter(SQL, conexion);
    DataSet ds = new DataSet();
    da.Fill(ds);
    return ds;
  }
  catch (Exception ex)
  {
    throw ex;
  }
}

public void UpdateDataSet(DataSet ds)
{
  try
  {
    SqlCommandBuilder cb = new SqlCommandBuilder(da);
    da.InsertCommand = cb.GetInsertCommand();
    da.DeleteCommand = cb.GetDeleteCommand();
    da.UpdateCommand = cb.GetUpdateCommand();
    da.InsertCommand.Connection = conexion;
    da.DeleteCommand.Connection = conexion;
    da.UpdateCommand.Connection = conexion;
    da.Update(ds);
    cb.Dispose();
  }
  catch (Exception ex)
  {
    throw ex;
  }
}

public DataTable GetDataTable(string SQL)
{
  try
  {
    SqlDataAdapter comando = new SqlDataAdapter(SQL, conexion);
    DataSet ds = new DataSet();
    comando.Fill(ds);
    comando.Dispose();
    return ds.Tables[0];
  }
  catch (Exception ex)
  {
    throw ex;
  }
}

public SqlDataReader GetDataReader(string SQL)
{
  try
  {
    conexion.Open();
    SqlCommand comando = new SqlCommand(SQL, conexion);
    SqlDataReader dr = comando.ExecuteReader();
    //conexion.Close();
    comando.Dispose();
    return dr;
  }
  catch (Exception ex)
  {
    throw ex;
  }
}

public string GetScalarValue(string SQL)
{
  try
  {
    conexion.Open();
    SqlCommand comando = new SqlCommand(SQL, conexion);
    string sv = (string)comando.ExecuteScalar();
    conexion.Close();
    comando.Dispose();
    return sv;
  }
  catch (Exception ex)
  {
    throw ex;
  }
}

public int ExecuteSQL(string SQL)
{
  try
  {
    SqlCommand comando = new SqlCommand();
    int resul = 0;
    comando.CommandText = SQL;
    comando.CommandType = CommandType.Text;
    comando.Connection = conexion;
    conexion.Open();
    resul = comando.ExecuteNonQuery();
    conexion.Close();
    return resul;
  }
  catch (Exception ex)
  {
    throw ex;
  }
}

public string GetField(string tabla, string clavePrimaria, string valorBuscado, string campoDevuelto)
{
  DataTable dt = new DataTable();
  string SQL = "";

  try
  {
    SQL = "SELECT " + campoDevuelto + " FROM " + tabla + " WHERE " + clavePrimaria + "='" + valorBuscado + "'";
    dt = this.GetDataTable(SQL);
    if (dt.Rows.Count > 0)
      return dt.Rows[0][campoDevuelto].ToString();

    return "";
  }
  catch (Exception ex)
  {
    return "Error en la búsqueda " + ex.Message;
  }
}


#region " Metodos de obtención de nueva clave primaria "

public string GetPrimaryKey(string tabla, string campo, short longitud)
{
  try
  {
    // SQL para obtener ultimo codigo
    string SQL = "SELECT TOP 1 " + campo + " FROM " + tabla + " ORDER BY " + campo + " DESC";
    SqlDataReader dr = this.GetDataReader(SQL);
    string codigo;

    // Obtener codigo
    if (dr.HasRows)
    {
      dr.Read();
      codigo = Convert.ToString(dr[campo]);
    }
    else
      codigo = "0";

    codigo = Convert.ToString(int.Parse(codigo) + 1);

    // Rellenar de ceros y devolver
    codigo = this.Ceros(codigo, longitud);   // dtTabla.Columns(cCampo).MaxLength)

    dr.Close();
    dr.Dispose();
    return codigo;
  }
  catch (Exception e)
  {
    return e.Message;
  }
}

private string Ceros(string texto, short ceros)
{
  string cadena = texto;
  string _ceros;
  if (ceros > texto.Length)
    _ceros = new string('0', ceros - cadena.Length) + cadena;
  else
    _ceros = cadena.Substring(0, ceros);
  return _ceros;
}

public int GetLastId(string tabla)
{
  return Convert.ToInt32(GetScalarValue("SELECT ident_current('" + tabla + "')"));
}

#endregion
Espero que os sirva.

Lectura de XML con PHP

Con PHP es sumamente sencillo leer y parsear ficheros XML. Para ver como se hace, lo mejor es hacerlo con un ejemplo.

Supongamos el siguiente fichero XML, que puede ser utilizado por un WebService, y que contiene nombres de método para el WebService y la sentencia SQL que debe ejecutar en cada uno de ellos:
<?xml version="1.0" encoding="utf-8" ?>
<OpcionesDisponibles>
  <opcion>
    <nombre>GetPaises</nombre>
    <SQL>SELECT cod_pais,pais FROM paises order by pais</SQL>
  </opcion>
  <opcion>
    <nombre>GetPais</nombre>
    <SQL>SELECT cod_pais,pais FROM paises WHERE cod_pais='#PARAMETRO_1#'</SQL>
  </opcion>
</OpcionesDisponibles>
Ahora, supongamos que desde PHP deseamos tener una función que dado el nombre del método, nos devuelva la SQL a ejecutar. La solución es tan simple como la siguiente:
// Dado un nombre de opción, buscar en el xml su SQL correspondiente
function getSQL($nombreOpcion)
{
  $xmlOpciones = simplexml_load_file('opciones.xml');
  $sql = ""; 
  foreach ($xmlOpciones->opcion as $opcion)
  {
    $nombre = $opcion->nombre;
    if ($nombre == $nombreOpcion)
    {
      $sql = $opcion->SQL;
      break;
    }
  }
  return $sql;
}
Así de sencillo.

Enviar email con PHP

En esta entrada se muestra una sencilla forma para enviar un email desde PHP. Para ello, se recibirán por parámetro (normalmente desde la llamada de un formulario html) el nombre del usuario, su dirección de email y el mensaje. Con estos datos, nuestro archivo php para enviar correo podría ser el siguiente:
<?php
  // Validar parametros
  if ($_REQUEST['nombre'] == '' || $_REQUEST['email'] == '' || $_REQUEST['mensaje'] == '')
    die ('Parámetros incorrectos');
    
  // Email
  $to = 'tu_direccion_de_email_de_destino';
  $subject = '[tu_asunto_por_defecto]';   
  $header = 'From:tu_email_de_origen';
  // Mensaje   
  $message = 'Mensaje de '.$_REQUEST['nombre'].'('.$_REQUEST['email'].')';
  $message .= $_REQUEST['mensaje'];
  // Enviar
  $retval = mail ($to,$subject,$message,$header);
  if( $retval == true )  
  {
     echo "Mensaje enviado correctamente...";
  }
  else
  {
     echo "El mensaje no se pudo enviar...";
  }
?>
Este método es muy simple, y nos puede servir para empezar, pero a partir de el pueden hacerse cosas más complejas (copias ocultas, ficheros adjuntos, etc). Eso ya queda a las necesidades de cada situación.

Envio de email con .NET

Esta entrada muestra un método genérico realizado en C# que se puede utilizar para el envío de emails desde nuestra aplicación. No necesita mayor explicación, así que, manos a la obra.
public static void EnviarMail(string cuentaDe, string cuentaSMTP, string cuentaUsuario, string cuentaClave, string para, string asunto, string texto, string paraCopia = "", string paraOculto = "", string ficheroAdjunto = "", string tituloMail = "[TituloPorDefecto] ")
{
  try
  {
    System.Net.Mail.MailMessage correo = new System.Net.Mail.MailMessage();
    System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient();

    // SMTP
    smtp.Host = cuentaSMTP;
    smtp.Port = 25;
    //smtp.EnableSsl = True
    if (cuentaUsuario != "")
      smtp.Credentials = new System.Net.NetworkCredential(cuentaUsuario, cuentaClave);

    // De
    correo.From = new System.Net.Mail.MailAddress(cuentaDe);
    // Para
    if (para.Contains(";"))
    {
      string[] mails = para.Split(';');
      for (int i = 0; i < mails.Length; i++)
        correo.To.Add(mails[i]);
    }
    else
      correo.To.Add(para);

    // Para copia
    if (paraCopia.Contains(";"))
    {
      string[] mails = paraCopia.Split(';');
      for (int i = 0; i < mails.Length; i++)
        correo.CC.Add(mails[i]);
    }
    else if (paraCopia != "")
      correo.CC.Add(paraCopia);

    // Para oculto
    if (paraOculto.Contains(";"))
    {
      string[] mails = paraOculto.Split(';');
      for (int i = 0; i < mails.Length; i++)
        correo.Bcc.Add(mails[i]);
    }
    else if (paraOculto != "")
      correo.Bcc.Add(paraOculto);

    // Correo
    correo.Subject = tituloMail + asunto;
    correo.Body = texto;
    correo.IsBodyHtml = true;
    correo.Priority = System.Net.Mail.MailPriority.Normal;
    
    // Adjunto
    if (ficheroAdjunto != "")
    {
      if (System.IO.File.Exists(ficheroAdjunto))
      {
        System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ficheroAdjunto);
        correo.Attachments.Add(attach);
      }
    }
    // Enviar
    smtp.Send(correo);

  }
  catch (Exception ex)
  {
    Log(ex.Message);
  }
}
Y ya está.

 

Copyright @ 2015 Tosblama