16 de diciembre de 2015

Multiples bindings WCF

Para empezar quiero mostrar la información del sitio de Microsoft sobre múltiples bindings(click sobre la imagen para leer mejor)


A continuación presento una combinación de endpoints validos en un servicio WCF

Binding(B1) + Address(A1) + Contract(C1)  —>  EndPoint valido
Binding(B1) + Address(A2) + Contract(C1)  —>  EndPoint valido
Binding(B1) + Address(A1) + Contract(C2)  —>  EndPoint valido
Binding(B1) + Address(A1) + Contract(C3)  —>  EndPoint valido

Binding(B2) + Address(A2) + Contract(C1)  —>  EndPoint valido
Binding(B3) + Address(A3) + Contract(C1)  —>  EndPoint valido

Con el ejemplo anterior dejamos claro dos cosas:

1) Múltiples Endpoints:
 Address compartida - Bindings iguales - Contracts diferentes

Es permitido que múltiples EndPoints utilicen el mismo tipo de binding e incluso tener la misma dirección pero pueden diferir en el contrato, esto es un beneficio ya que logra definir para diferentes clientes uno y solamente un binding, definir una única dirección para diferentes endpoints  y entregar a diferentes clientes la misma dirección de referencia al servicio WCF pero cada cliente tendrá diferentes operaciones disponibles esto se logra definiendo distintas operaciones en diferentes interfaces.

Como ejemplo para este caso se creara un proyecto WCF Service el cual tendrá tres interfaces y una clase que las implementa, el solution explorer del proyecto queda de esta manera


en la siguientes imágenes expongo el código de las interfaces, solamente definen un método string que devuelve un saludo al usuario indicando que interface se implementa, la interface IGeneral hereda de la interface IBinding01 y de la interface IBinding02 tal como se muestra en el código

interface IBinding01.cs

interface IBinding02.cs
interface IGeneral.cs

y el código de Binding.cs que es la clase que implementa la interface IGeneral es 


como ven en el código anterior, en la clase Binding solamente implemento la interface IGeneral pues esta contiene los métodos definidos en IBinding01, y IBinding02, pero si ustedes quieren especificar las interfaces por separado e implementar explícitamente los métodos de cada interface también es valido el procedimiento que se utiliza en esta entrada, de hecho el cambio solamente sería en la clase Binding al momento de especificar las interfaces después todo lo que se aplica a continuación es exactamente lo mismo asi que tu decides como codificas tu clase Binding, aquí muestro el ligero cambio en la clase Binding cuando se quiera especificar explícitamente cada interface a implementar


este es la configuración del Web.config para múltiples endpoints con el mismo tipo de binding, mismo servicio pero diferente contrato

  
    
      
        
          
        
      
    
    
      
        
        
        
        
        
          
            
          
        
      
    
    
  
  
    
  
    
        
    

El proyecto se aloja en IIS, ahora procedere a crear un proyecto de tipo Windows Forms que actuara como cliente del servicio WCF, muestro la imagen para agregar la referencia de servidor


el intellisense de Visual Studio ahora reconoce las tres interfaces definidas en el servico WCF


este es el formulario a utilizar


por ultimo el codigo del formulario que actúa como cliente y también la imagen del formulario con los mensajes provenientes desde cada contrato
private void button1_Click(object sender, EventArgs e)
 {
  cliente.GeneralClient cliente = new ClienteWCF.cliente.GeneralClient();
  label1.Text = cliente.saludo01(textBox1.Text.ToString());
  label2.Text = cliente.saludo02(textBox1.Text.ToString());
  label3.Text = cliente.saludoGeneral(textBox1.Text.ToString());
 }


2) Múltiples Endpoints:
 Address diferentes - Bindings diferentes - Contract igual

Si por el contrario cada endpoint utiliza un binding diferente entonces se hace necesario crear diferentes direcciones de acceso al servicio WCF, en este caso es valido utilizar el mismo contrato para todos los endpoints, no es necesario crear uno nuevo por cada binding.
El beneficio aquí es que el servicio WCF y las mismas operaciones definidas en este estarán disponibles para diferentes protocolos de acceso.

Como ejemplo se crearan tres endpoints con tres diferentes bindings, como se puede ver en el código cada endpoint especifica una dirección única que será el distintivo del binding utilizado

  
 
  

  
  
  
  
  
  
  





También se pueden especificar todas las direcciones a utilizar en el nodo

















  
    
      
      
    
  

10 de diciembre de 2015

Configuración Web.config netTcpBinding

esta configuración de Web.config me funciono para un proyecto WCF Service hospedado en IIS utilizando un endpoint netTcpBinding recordar también que la aplicación que se ha hospedado en IIS debe tener habilitados los protocolos http, net.tcp, esto se logra desde las configuraciones avanzadas en IIS configuration Manager y se debe hacer tanto para el proyecto recién creado de WCF como para Default Web Site tal como se muestra en la imagen



  
    
  

  
  
    
      
        
          
        
      

      
      
        
          
        
      
    
  
  
    
      
        
        
      
    
  
  
    
      
    
  


  
    
    
    
  

y en el cliente automáticamente se creara esta configuración en el App.config, tomar en cuenta el identity dns value tanto en la configuracion del servicio WCF como en la configuracion de la aplicación cliente

    
        
            
                
            
        
        
            
                
                    
                
            
        
    

9 de diciembre de 2015

Configuración de WCF Service Library con netTcpBinding y IIS Host

De forma predeterminada, IIS sólo admite HTTP o HTTPS. Con el fin de permitir que IIS netTcpBinding lo primero que tenemos que activar / activar WCF Non-HTTP Activation. Para hacer eso, ir al panel de control -> Programas y características -> Activar las características de Windows o desactivar y luego busque "Microsoft .NET Framework 3.5.1 '. Verá algo parecido a continuación:


Asegúrese de seleccionar las dos opciones. Esto permitirá que IIS pueda trabajar con los protocolos HTTP, HTTPS, net.tcp, net.pipe, net.msmq, msmq.formatname.

Paso 2:
Como esto desregistra el ASP.NET de la máquina, el siguiente paso es registrar de nuevo ASP.NET con IIS. Para ello, vaya al símbolo del sistema de Visual Studio y luego escriba 'aspnet_regiis -i'. Esto registra el ASP.NET con IIS y usted será capaz de alojar su aplicación web de nuevo.


Paso 3:
Debemos comprobar si los servicios Net.Pipe y Net.Tcp estan en ejecución. Estos tres servicios garantiza que IIS es capaz de escuchar a la petición TCP y también permitirá compartir puerto.Ir a Herramientas administrativas> Servicios y revise el siguiente servicio si se ejecuta, si no iniciarlos.


Paso 4:
A medida que la máquina está configurada para apoyar netTcp, el siguiente paso es configurar IIS para permitir a un sitio web para utilizar el puerto net.tcp por defecto que es 808. También puede cambiar cualquier otro puerto que desee. Asegúrese de que no configura net.tcp al puerto 80 porque está siendo utilizado por HTTP y no se puede tener dos protocolos que se ejecutan en el mismo puerto. Alternativa, o bien el cambio de puerto HTTP a otra cosa que no sea 80 (sólo si desea utilizar net.tcp en el puerto 80, pero no es un método recomendado).

Ahora para configurar IIS: Abrir IIS Configuration Manager, luego ir a "Sitio Web predeterminado" y haga clic derecho sobre él y luego ir a Edit bindings:




En el cuadro de texto 'información vinculante', es necesario especificar qué puerto que desea utilizar para la conexión netTCP. Como mencioné anteriormente, es 808 por defecto, pero se puede tener cualquier otro puerto también. El formato es 'puerto: IP address', así que entré en '808: *' y haga clic en Aceptar.

Ahora se debe habilitar el protocolo net.tcp para el Default Web Site, para ello se debe posicionar sobre el Default Web Site y luego seleccionar Advanced Settings



Ahora el sitio web está configurado para escuchar solicitud de conexión TCP en el puerto 808. Recuerde que si usted tiene página web múltiples donde necesita configuración TCP entonces usted tiene que hacer lo mismo para todos los sitios web.

Paso 5:
Lo siguiente es habilitar el protocolo net.tcp para su aplicación en el IIS. Para ello haga clic derecho en su aplicación en el IIS y luego haga clic en "Configuración avanzada" y busque la propiedad de los Protocolos habilitados 'y no entrar en' net.tcp '. Lista de protocolo habilitado es una lista separada por comas por lo que puede permitir que varios protocolos separándolas con una coma.



Ahora su sitio web está totalmente configurado para utilizar net.tcp vinculante. El siguiente paso es configurar el proyecto para tener servicio de WCF en el puerto TCP 808.

Paso 6:
Esta entrada continua en el supuesto que estamos utilizando un proyecto WCF Service Application tal como se muestra en la figura:


Luego dar clic derecho sobre el proyecto y luego ir a la pestaña 'Propiedades'. Usted debe tener algo como abajo. Seleccione la pestaña 'web' de los servidores de la izquierda y haga el cambio de IIS Express del Visual Development Studio Server a Local IIS Web Service servidor y luego se debe dar click sobre el botón Create Virtual Directory


La razón por la que hemos cambiado de servidor para ser local Servidor Web IIS en lugar de Visual Development Server estudio es que se puede configurar IIS Web Server para apoyar net.tcp pero no se puede configurar el mismo para Visual Studio Desarrollo Server. Esto se debe a que el Visual Studio Server sólo soporta HTTP.

Ahora el siguiente paso es configurar tu web.config del proyecto de apoyo a netTcpBinding para el Servicio WCF.

Paso 7:
Nuestro último paso es configurar web.config para utilizar netTcpBinding para el Servicio WCF, como podran darse cuenta desde el paso 5 estoy utilizando un proyecto de WCF Server Application con nombre WCFBorrar y el Solution Explorer para este proyecto queda de la siguiente manera


Tras la muestra del Solution Explorer del proyecto el Web.config del servicio WCF utilizando netTcpBinding queda así

     
    
  

    
    
      
        
        
          
            
          
        

        
        
        
          
            
          
        
      
    
    
     
      
        
          
          
        
      
    
    
    
      
        
      
    
  

    
    
    
  


En este Web.config hay algunos puntos a tener en cuenta:

- Atributo de la 'serviceMetadata' 'httpGetEnabled' debe establecerse en "falso". Esto permitirá descubrir WCF metadatos de servicio sobre protocolo no HTTP.

- Tenga en cuenta que estamos usando 'mexTcpBinding' para el punto final mex. También puede utilizar 'mexHttpBinding', pero luego tienes que configurar el atributo 'httpGetEnabled' a 'True' y usted debería ser capaz de localizar el uso de la dirección http Servicio WCF lugar de net.tcp.

- Es importante que especifique el baseAddress para su punto final. Esto ayudará a IIS para que encuentre su servicio WCF. A continuación, saber dónde buscar.

- es importante hacer notar que aunque en el atributo se especifique la direccion

        
          
        
      
al especificar la dirección del servidor al momento de agregar una service reference desde el cliente se debe utilizar esta direccion pero con /mex al final, es decir que la dirección en la cual el cliente creara una referencia al servicio WCF creado utilizando net.tcp y hospedado en IIS local es net.tcp://localhost:808/WCFBorrar/Service1.svc/mex


netTcpBinding con Windows Service Host

Lo primero a hacer es crear un proyecto de tipo WCF Service Library con nombre WCF4Windows


antes de continuar hacer la observación que elimine las clase Service1.cs y la interface IService1.cs que el proyecto de WCF Service Library creo por defecto y en cambio se agregó una nueva clase WCFService.cs y una nueva interface IWCFService.cs de tal manera que el Solution Explorer del proyecto queda de la siguiente manera
el objetivo de la entrada es hospedar y consumir un servicio WCF hospedado en Windows Service, bajo esa premisa el sencillísimo código para la interfaz IWCFService es
using System.ServiceModel;

namespace WCF4Windows
{
    [ServiceContract]
    interface IWCFService
    {
        [OperationContract]
        string saludo(string nombre);
    }
}
y la clase WCFService que implementa la interfaz anterior es
namespace WCF4Windows
{
    public class WCFService:IWCFService
    {
        public string saludo(string nombre)
        {
            return string.Format("Hola {0} has creado un enlace a un servicio hospedado en Windows", nombre);
        }
    }
}
aquí lo interesante viene en la configuración del App.config pues se creara un endpoint utilizando netTcpBinding en lugar del BasicHttpBinding que viene por defecto al crear cualquier proyecto WCF, también se debe definir un endpoint utilizando el mexTcpBinding pues es la manera en que se publica el metadata del servicio

   


  















  











Ahora bien, hay algunos puntos a tener en cuenta:
- Atributo del serviceMetadata 'httpGetEnabled' debe establecerse en "falso". Esto permitirá descubrir metadatos de servicio WCF sobre protocolo que no sea HTTP.

- Tenga en cuenta que estamos usando 'mexTcpBinding' para el endpoint mex. También puede utilizar 'mexHttpBinding', pero luego tienes que configurar el atributo 'httpGetEnabled' a 'True' y deberas localizar el Servicio WCF haciendo uso de la dirección http en lugar de net.tcp.

- Es importante que especifique el baseAddress para su punto final. Esto ayudará al Windows Service para que encuentre su servicio WCF.

con lo anterior se ha creado un sencillo...sencillísimo ejemplo de WCF Service Library Project utilizando netTcpBinding, ahora viene la parte de hospedarlo en un Windows Service, para ello agregamos un nuevo proyecto a la solución y esta vez sera del tipo Windows Service con nombre WService



y debemos agregar dos referencias al proyecto de Windows Service, una para el proyecto de WCF Service Library y otro para System.ServiceModel



a continuación vamos a copiar el App.config que se creo en el WCF Service Library y lo pegaremos en el Windows Service Project a fin de tener la misma configuración para ambos proyectos, el Service Explorer para nuestra aplicacion deberia de momento estar como muestro en la imagen, estan sombreadas las referencias agregadas y el App.config recién agregado:

Ahora se debe dar click derecho sobre la clase Service1.cs del proyecto de Windows Service y seleccionar View Designer


Luego en la venta de View Designer que acaba de abrirse damos click derecho y seleccionamos Add Installer tal como se muestra en la figura

La accion anterior agrego un nuevo elemento al proyecto de Windows Service, muestro el Solution Explorer resultane con el nuevo elemento resaltado

el ProjectInstaller utiliza para su configuracion un serviceProcessInstaller1 y serviceInstaller1, la vista diseño queda de la siguiente manera

damos click derecho sobre serviceProcessInstaller1 y seleccionamos propiedades, en propiedades cambiamos el accountattribute a NetworkServices



ahora damos click derecho sobre serviceInstaller1 que es el otro elemento de ProjectInstaller.cs y seleccionamos propiedades, en las propiedades seleccionamos el atributo Start Type y lo colocamos en Automatic

Ahora toca modificar el código del Windows Service a fin de que hospede el servicio WCF, el código de Service1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.ServiceModel;
using WCF4Windows;

namespace WService
{
    public partial class Service1 : ServiceBase
    {
        internal static ServiceHost myHost = null;
        BackgroundWorker worker;
        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {

            worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        }
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (myHost != null)
            {
                myHost.Close();
            }

            myHost = new ServiceHost(typeof(WCF4Windows.WCFService));
            myHost.Open();
        }

        protected override void OnStop()
        {
            if (myHost != null)
            {
                myHost.Close();
                myHost = null;
            }

        }
    }
}
listo, ahora tenemos que seleccionar Build Application y verificar que no se de ningún error, si todo va bien se tendrá un archivo ejecutable en el folder bin/debug dentro de la solución del Windows Service, para encontrarlo solo basta con dar click derecho sobre la solución y seleccionar Windows Explorer, el ejecutable se muestra en la imagen, ademas aprovecho en la imagen para mostrar como copiar la direcion en donde se encuentra el ejecutable pues sera util a continuación


ahora se debe abrir la consola de comando de Visual Studio y utilizar el installutil.exe junto con la ruta del WService que recién copiamos y la aplicación WService.exe


Procedemos a verificar que se ha agregado el servicio exitosamente, para ello desde la ventana de comandos de Windows escribimos services.msc y damos enter, con lo anterior se abrirá la ventana de servicios de Windows desde la cual podemos encontrar el servicio que recién agregamos


y para agregar una referencia desde otro proyecto al Windows Service recién creado agregar la dirección especificada en el App.config y agregar al final /mex tal como se muestra en la figura






Como punto final les advierto que la herramienta que utilizo para mostrar el código del Web.config siempre altera el codigo, me imagino debe ser por reglas de seguridad de Blogger, por tal razón dejo una imagen del contenido del archivo Web.config para que sirva de guia






3 de diciembre de 2015

Guardar - Mostrar imagenes en ASP.NET

Una imagen puede guardarse tanto en una base de datos como en una carpeta dedicada a guardar imágenes en el servidor, un punto importante es que a diferencia de las aplicaciones de escritorio en donde el componente OpenFileDialog permitía filtrar los tipos de archivos a seleccionar con el FileUpload esto no es posible, el usuario podrá seleccionar el tipo de archivo que desee, así que queda en manos del programador el definir los tipos de archivos permitidos.

Si se guarda en la base de datos debe especificarse el tipo de dato como Varbinary(MAX) y no como tipo IMAGE ya que según documentación de Microsoft este tipo de datos está próximo a desaparecer, igual se debe tener en cuenta el peso que supone a una base de datos el guardar imágenes, además la imagen a guardar se debe convertir en un array de bytes para almacenar el array en la base de datos.

A mi punto de vista, es mejor guardar las imágenes en una carpeta que subirlas a la base de datos. Sería más carga para el servidor de BD cargar ahí las imágenes, además de que se ocupa más procesamiento para descargarlas y nuevamente convertirlas a imagen. Unos datos antes de pasar a código:

*Es mejor guardar en el disco duro la imagen y en la base de datos, la ruta a dicha imagen.
*Nuestra imagen, contenida en el objeto HttpPostedFile dentro de un objeto de clase FileStream, deberá ser convertida a un conjunto de bytes para enviarlo a la base de datos. Dicho de otro modo, convertiremos el objeto de tipo Stream a un arreglo de bytes.
*Un stream es parámetro del constructor de binaryreader.
*En el Web.config se debe especificar el tamaño máximo permitido de las imágenes:

    

    
    

* Utilizar los siguientes espacios de nombre, útiles para tratar con archivos, datos, con la conexión y objetos de la base de datos SQL Server
using System.IO;
using System.Data;
using System.Data.SqlClient;

Ahora si, lo primero será agregar un control FileUpload a la página, este control permite al usuario examinar los directorios a fin de buscar la imagen que desea cargar en la base de datos, para este ejemplo también se agrega un control Button que al presionarlo guardara la imagen ya sea en un directorio especifico o en la base de datos y un control Label que presentara mensajes de guardado o error al usuario.



Ahora se va a validar que el archivo que se subió utilizando el control FileUpload sea en realidad una imagen, para eso se crea un array con los formatos que son permitidos y se compara con el formato del archivo que el cliente subió, este código va en el evento click del botón BDFile y al examinarlo notaran que hace una llamada al método GuardarArchivo(FileUpload.PostedFile) al que le enviamos el archivo que se ha cargado, este método guardar la imagen en una carpeta dentro del directorio raíz de nuestro proyecto
protected void BDFile_Click(object sender, EventArgs e) {
 string[] validFileTypes = { ".bmp", ".gif", ".png", ".jpg", ".jpeg" };
 
// Validar que exista un archivo cargado
if (fileUpload.HasFile) {
 string ext = System.IO.Path.GetExtension(fileUpload.PostedFile.FileName).ToLower();
 bool isValidFile = false;

// Validar extension de archivo cargado sea tipo imagen  
for (int i = 0; i < validFileTypes.Length; i++) {
 if (ext == validFileTypes[i]) {
  isValidFile = true;
 break;
 }
}

// En caso no tener una extension permitida 
 if (!isValidFile) {
   msg.Visible = true;
   msg.ForeColor = System.Drawing.Color.Red;
   msg.Text = "File format not recognised." +
              " Upload only Image formats";
               }

// metodo que guarda la imagen en una carpeta
   GuardarArchivo(fileUpload.PostedFile);
 }
 else {
    msg.Visible = true;
    msg.ForeColor = System.Drawing.Color.Red;
    msg.Text = "No se ha cargado ningun archivo !!!";
 }
}
Este código guarda la imagen en una carpeta dentro del directorio raíz del servidor, de momento lo trabajo en mi computadora personal pero al subir el proyecto al servidor recuerda que debes tener privilegios de lectura y escritura sobre esta carpeta
private void GuardarArchivo(HttpPostedFile file) {
  
// Se carga la ruta física de la carpeta temp del sitio
  string ruta = Server.MapPath("~/temp");

// Si el directorio no existe, crearlo
  if (!Directory.Exists(ruta))
       Directory.CreateDirectory(ruta);

//string archivo = String.Format("{0}\\{1}", ruta, file.FileName);
  string fullPath = Path.Combine(Server.MapPath("~/temp"), file.FileName);
          
// Verificar que el archivo no exista
 if (File.Exists(fullPath)){
  lblMessage.ForeColor = System.Drawing.Color.Red;
  lblMessage.Text = "ya existe el archivo " +file.FileName;
// en caso quisiera eliminar utilizaria esta linea de codigo
// if (File.Exists(archivo)) File.Delete(archivo);
  } 
  else
  {
  file.SaveAs(fullPath);
  lblMessage.ForeColor = System.Drawing.Color.Blue;
  lblMessage.Text = "se guardo el archivo " +file.FileName;
  }
}
Para esta entrada se guarda una imagen en la base de datos utilizando el código que muestro a continuación, agregue como definir un ContentType para los archivos de Word y Excel de Microsoft pues estos son diferentes a los archivos de imágenes o de PDF, esto es solo para explicar como tratar estos tipos de archivos ya que al estudiar el código se darán cuenta que el ContentType siempre se definirá del tipo imagen.


Recordar cambiar el nombre del método a utilizar en el evento click del botón BDFile, además presento la imagen de la tabla que se utiliza para guardar la imagen como un array de bytes(el id es autoincrement 1-1) y el código utilizado
private void GuardarBD(HttpPostedFile imagen) {

/* la cadena de conexión esta definida en Web.config, aunque recomiendo utilizar SQLconectionStingBuilder para evitar problemas de seguridad */           
 string conexion = WebApplication1.Properties.Settings.Default.cnn.ToString();
 Byte[] bytes = null;
// obtiene el nombre del archivo cargado por ej: pablo.docx - pablo.pdf - pablo.bmp
 string filename = imagen.FileName;
// obtiene la longitud del archivo cargado
 int img_len = imagen.ContentLength;
// obtiene a extension del archivo .png .jpg .bmp
 string ext = Path.GetExtension(filename).ToLower();
 string ext1 = Path.GetExtension(imagen.FileName).ToLower();
//obtiene el tipo de archivo cargado, es diferente a la extension, por ej: image/png - text/html - text/plain - application/pdf  
 string contenttype = String.Empty;

// definir el contentType basado en la extension del archivo
  switch (ext) {
   case ".doc":
    contenttype = "application/vnd.ms-word";
    break;
   case ".docx":
    contenttype = "application/vnd.ms-word";
    break;
   case ".xls":
    contenttype = "application/vnd.ms-excel";
    break;
   case ".xlsx":
    contenttype = "application/vnd.ms-excel";
    break;
   default:
    contenttype = imagen.ContentType.ToString();
    break;
   }
  if (contenttype != String.Empty)
   {
// Obtener el objeto stream a fin de leer su contenido
   Stream fs = imagen.InputStream;
// para guardar una imagen lo primero es tranformar esa imagen a binario para guardarlo en tipo BLOB
   BinaryReader br = new BinaryReader(fs);
   bytes = br.ReadBytes((Int32)fs.Length);
                
  SqlConnection cnx = new SqlConnection(conexion);
   try {
    cnx.Open();
    SqlCommand cmd = cnx.CreateCommand();
    cmd.CommandText =
    "INSERT INTO archivos (nombre, contentType, datos, lenght, ext) " +
    "VALUES (@nombre, @content, @datos, @lenght, @ext)";
    cmd.Parameters.AddWithValue("@nombre", filename);
    cmd.Parameters.AddWithValue("@content", contenttype);
    cmd.Parameters.Add("@datos", SqlDbType.VarBinary).Value = bytes;
    cmd.Parameters.AddWithValue("@lenght", img_len);
    cmd.Parameters.AddWithValue("@ext", ext);
    cmd.ExecuteNonQuery();
    lblMessage.ForeColor = System.Drawing.Color.Green;
    lblMessage.Text = "File Uploaded Successfully";
 }
   catch (Exception ex) { throw ex; }
  }
}
Ya guardamos ahora toca mostrar la imagen recuperando esta desde la carpeta temp dentro del directorio raíz de nuestro proyecto, para eso me creare un nuevo archivo WebForm(.aspx) al que llamare recuperarImagen.aspx Para mostrar el archivo de imagen agregare al proyecto un WebForm llamado MostrarImagen.aspx y sobre este agregare un control image referenciando a mi archivo recuperarImagen.aspx

Este es el código de recuperarImagen.aspx en el evento Load, como verán recupero una imagen especifica en la línea string filename = "logo_UCA.png"; pero en una aplicación real ustedes deben enviar el parámetro que sirva para distinguir y recuperar una imagen específica, explico el proceso al final del post.
protected void Page_Load(object sender, EventArgs e) {
 string filename = "logo_UCA.png";
 Response.Clear();
 Response.AddHeader("content-disposition", string.Format("inline;filename={0}", filename));
 //Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", filename));

 switch (Path.GetExtension(filename).ToLower()) {
   case ".jpg":
    Response.ContentType = "image/jpg";
    break;
   case ".gif":
    Response.ContentType = "image/gif";
    break;
   case ".png":
    Response.ContentType = "image/png";
    break;
  }
    
   Response.WriteFile(Server.MapPath(Path.Combine("~/temp", filename)));
   Response.End();
}

Utilizando Handler Generico .ashx Ahora vamos a recuperar la imagen guardada en la base de datos, lo primero será crear una entidad que represente la tabla que guarda la imagen, para eso creo un archivo llamado imágenes.cs
public class imagenes {
 public imagenes() { }
 public imagenes(int id, string nombre, int length, string content, string Ext) {
  this.Id = id;
  this.Nombre = nombre;
  this.Length = length;
  this.contentType = content;
  this.ext = Ext;
    }
    
  public int Id { get; set; }
  public string contentType { get; set; }
  public int Length { get; set; }
  public string Nombre { get; set; }
  public byte[] datos { get; set; }
  public string ext { get; set; }
}

Ahora toca agregar un Handler generico con nombre ImageHandler tal como se muestra

                               

Y el ImageHandler.ashx.cs debe quedar de la siguiente manera, especifico la imagen que quiero recuperar en la línea de código GetImagenById(1) que significa que recuperara la imagen con código id=1 pero en una aplicación real ustedes deben enviar el parámetro que sirva para distinguir y recuperar una imagen específica, explico el proceso al final del post...notar el uso de context antes del objeto Response al utilizar un Handler generico
public class ImageHandler : IHttpHandler {
 public void ProcessRequest(HttpContext context) {
 imagenes imagen = GetImagenById(1);

// la respuesta mostrara la imagen
 context.Response.Clear();
 context.Response.AddHeader("content-disposition", string.Format("inline;filename={0}", imagen.Nombre));

// especificando la extension al archivo que se va presentar
switch (Path.GetExtension(imagen.Nombre).ToLower()) {
  case ".jpg":
   context.Response.ContentType = "image/jpg";
   break;
  case ".gif":
   context.Response.ContentType = "image/gif";
   break;
  case ".png":
   context.Response.ContentType = "image/png";
   break;
}

// se envia la imagen
  context.Response.BinaryWrite(imagen.datos);
  context.Response.End();
      }

// busca una imagen especifica en la base de datos
private imagenes GetImagenById(int p) {
  imagenes img = null;
  string conexion = GuardarImagenes.Properties.Settings.Default.cnn.ToString();
  using (SqlConnection conn = new SqlConnection(conexion))
   {
  conn.Open();
  string query = @"SELECT id, nombre, contentType, datos, lenght, ext
                   FROM archivos
                   WHERE id = @id";
  SqlCommand cmd = new SqlCommand(query, conn);
  cmd.Parameters.AddWithValue("@id", p);
  SqlDataReader reader = cmd.ExecuteReader();

  if (reader.Read()) {
   img = new imagenes();
   img.Id = Convert.ToInt32(reader["id"]);
   img.Nombre = Convert.ToString(reader["nombre"]);
   img.Length = Convert.ToInt32(reader["lenght"]);
   img.contentType = Convert.ToString(reader["contentType"]);
   img.ext = Convert.ToString(reader["ext"]);
   img.datos = (byte[])reader["datos"];

  }
 }

 return img;
 }

public bool IsReusable {
 get
  {
  return false;
  }
}

Y desde el control image del WebForm MostrarImagen.aspx especificamos

Como vieron anteriormente, para recuperar una imagen se utiliza el control image y se especifica el archivo en el atributo src, este archivo se pasa como un link, entonces para enviar información sobre la imagen que se desea recuperar ya sea hacia el archivo .aspx o hacia el archivo .ashx se puede utilizar esta linea de código(si e que estas seguro que el id y por ende la imagen existe):
src="Image.ashx? Id=<%# Eval("Id")%>"

o esta linea de código que en caso de no existir un id para la imagen en la base de datos mostrara una imagen por defecto
src="<%# Eval("Id") == DbNull.Value ? "ImagenDisco.jpg" :  Eval("Id", "Image.ashx? Id={0}") %>"

como ven estamos utilizando el metodo GET para enviar la informacion asi que para recuperar el valor enviado -en este cado Id- desde un Handler generico se debe utilizar
int id = Convert.ToInt32(context.Request.Params["id"]);

y para recuperar el Id desde un archivo .aspx se puede utilizar
int id = Convert.ToInt32(Request.QueryString["id"]);

22 de septiembre de 2015

Expresiones regulares


martes, septiembre 22, 2015

31 de agosto de 2015

Test

Expresiones regulares
DataTable dt = dal.PoblarCBX_DPTO();
 DataRow dr = dt.NewRow();
 dr["Departmento"] = Convert.ToInt32("0");
 dr["Departmento"] = "-- Seleccione Departamento --";
 dt.Rows.InsertAt(dr,0);
 cbxDpto.DataSource = dt;
 cbxDpto.DisplayMember = "Departmento";
 cbxDpto.ValueMember = "Departmento";
 cbxDpto.SelectedIndex = 0;
Expresiones regulares
string DUI = @"\A[0-9]{8}(-)[0-9]{1}\Z";

string NOMBRE = @"\A((\w+)(\s?)(\w+))*\Z";

string MONEY = @"\A$?(\d{1,3},?(\d{3},?)*\d{3}(.\d{0,3})?|\d{1,3}(.\d{2})?)\Z";

string CORREO = @"\A(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@" + 
                            @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\." + 
                            @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|" +
                            @"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})\Z";

string telefono = @"\A[0-9]{8}\Z";

string telefonoGuion = @"\A[0-9]{4}(-)[0-9]{4}\Z";

string telefonoCodigo = @"\A(()[0-9]{3}())[0-9]{8}\Z";

string telefonoCodigoGuion = @"\A(()[0-9]{3}())[0-9]{4}(-)[0-9]{4}\Z";

Regex regAge = new Regex(@"^\d{2}$");

Regex regUrl = new Regex(@"^((https?|ftp)://|(www|ftp)\.)[a-z0-9-]+(\.[a-z0-9-]+)+([/?].*)?$");

Regex regCompany = new Regex(@"^[A-Z]([a-zA-Z0-9]|[- @\.#&!])*$");
Aceptar solo letras en un textbox
private void txtLetras_KeyPress(object sender, KeyPressEventArgs e){
 if (!(char.IsLetter(e.KeyChar)) && (e.KeyChar != (char)Keys.Back) && (e.KeyChar != (char)Keys.Space))
    {
    MessageBox.Show("Solo se permiten letras", "Advertencia", MessageBoxButtons.OK, MessageBoxIcon.Information);
    e.Handled = true;
    return;
    }
}
Aceptar solo numeros en textbox
private void txtNumeros_KeyPress(object sender, KeyPressEventArgs e){
 if (!(char.IsNumber(e.KeyChar)) && (e.KeyChar != (char)Keys.Back))
    {
    MessageBox.Show("Solo se permiten numeros", "Advertencia", MessageBoxButtons.OK, MessageBoxIcon.Information);
    e.Handled = true;
    return;
    }
}
Aceptar numeros double
private void textBox1_KeyPress(object sender, KeyPressEventArgs e){
 if (textBox1.Text.Contains(‘.’)) {
  if(!char.IsDigit(e.KeyChar)){
   e.Handled = true;
   }

  if (e.KeyChar == ‘\b’){
   e.Handled = false;
   }
  }
 else {
  if(!char.IsDigit(e.KeyChar)){
   e.Handled = true;
   }

  if(e.KeyChar==‘.’ || e.KeyChar==‘\b’)
   {
   e.Handled = false;
   }}}
Crear tabla SQL DDL con llave primaria
IF EXISTS(SELECT * FROM SYSOBJECTS WHERE TYPE ='U' AND NAME ='TIPO_USUARIO')
DROP TABLE TIPO_USUARIO
GO

CREATE TABLE TIPO_USUARIO(
idTipoUsuario int Identity(1,1),
descTipoUsuario varchar(20) NOT NULL,
CONSTRAINT PK_TIPO_USUARIO PRIMARY KEY(idTipoUsuario)
)
GO
o bien se puede especificar la llave primaria fuera de la definicion de tabla
ALTER TABLE employee ADD CONSTRAINT PK_TIPO_USUARIO PRIMARY KEY(idTipoUsuario)
Crear tabla SQL DDL con llave primaria y llave foranea
IF EXISTS(SELECT * FROM SYSOBJECTS WHERE TYPE ='U' AND NAME ='USUARIO')
DROP TABLE USUARIO
GO

CREATE TABLE USUARIO(
idUsuario char(8)NOT NULL,
idTipoUsuario int NOT NULL,
nomUsuario varchar(35) NOT NULL,
habilitado bit NOT NULL,
fechaExpCarnet smalldatetime NOT NULL,
fechaVencCarnet smalldatetime NOT NULL,

CONSTRAINT PK_USUARIO_idUsuario PRIMARY KEY(idUsuario),

CONSTRAINT FK_USUARIO_idTipoUsuario FOREIGN KEY (idTipoUsuario) REFERENCES TIPO_USUARIO(idTipoUsuario)

)
GO
de nuevo puede alterarse la tabla fuera de la definicion de esta
alter table libros
  add constraint FK_libros_codigoeditorial
  foreign key (codigoeditorial)
  references editoriales(codigo)
  on update cascade
  on delete cascade;
lunes, agosto 31, 2015

25 de agosto de 2015

Creando WCF Service Library con IIS Host

Antes de empezar les dejo esta respuesta de un foro que habla acerca de la diferencia entre WCF Service Application y WCF Service Library


En esta entrada vamos a crear un proyecto WCF Service Library que se va hospedar en IIS utilizando BasicHTTPBinding y MexHTTPBinding, recuerda que este tipo de proyectos te permite hospedar el servicio en diferentes host sin al parecer ningún tipo de limitaciones, por mi parte solo he tenido el gusto de utilizar WCF en IIS así que la entrada se va tratar de eso, si quieren ver el caso en que se utiliza WCF Service Application para crear un servicio WCF y hospedarlo en IIS les dejo esta entrada

Crearemos un nuevo proyecto de tipo WCF Service Library con las especificaciones que se muestran en la imagen


si vemos nuestro Solution Explorer tendremos los siguientes archivos de los cuales vamos a eliminar los dos archivos seleccionados


para luego agregar una clase(WCFAppcs) y una interface(IWCFApp) a nuestro proyecto, el Solution Explorer muestra como debería estar de momento el proyecto


este es el código de la interface IWCFApp


este es el código de la clase WPFAppcs que implementa la interface IWPFApp


Parecería que todo esta bien y muy alegres presionamos F5 para probar nuestro sencillisimo servicio WCF recién creado y... obtenemos un bonito y llamativo mensaje de error


Para solucionarlo se debe abrir el App.config y modificar las siguientes lineas con los valores indicados en la figura


Hecho lo anterior, debemos reconstruir la aplicación(rebuild solution) y luego presionar F5 con lo cual ahora se obtiene el WCF Test Client sin ningún problema


Se debe agregar un archivo de texto al proyecto, el nombre sera WCFAppcs.svc, tomar en cuenta la extension, debe ser .svc y al abrir este archivo colocar la siguiente linea de codigo que corresponde con el namespace.clase de nuestro proyecto  <%@ ServiceHost Service="WcfApp.WCFAppcs" %>


Hecho lo anterior, se debe construir la solución antes de continuar, nos dirigimos al IIS Manager(inetmgr) y desplegamos la carpeta Sites para luego sobre Default Web Site dar click derecho y seleccionar Add Application... tal como se muestra en la imagen 


a continuación especificar Alias y la dirección física de nuestro proyecto, para el ejemplo utilizo los datos que muestro en la imagen, el Physical path corresponderá con la dirección donde tu guardaste el proyecto


Damos click en el botón OK y vemos nuestro site disponible en el IIS Manager


El ultimo paso es dar click derecho sobre nuestro proyecto(desde Solution Exporer) y en el panel izquierdo seleccionamos Build para luego cambiar el Output path de bin\Debug a solamente bin\ tal como se muestra en la figura


Por ultimo debes agregar un Web.config a tu proyecto y copiar exactamente lo que tienes en el App.config, para hacerlo fácil copia el App.config que ya tienes en el proyecto y pegalo de nuevo solo que en vez de dejar el nombre App-copy.config cambiale a Web.config...ahora si ya podemos probar el servicio desde el navegador web con la siguiente dirección http://localhost/aliaz/WCFAppcs.svc


y listo, hay personas que crean un proyecto distinto solo para agregar el WCF Service, si te parece bien puedes hacerlo asi, a mi me parece que es llenar la solución con un proyecto de mas.