Lanzamiento Oficial Driver Oracle para Entity Framework

Anteriormente en el blog ya os había hablado de las Betas publicas que iba liberando Oracle (I,II y III).

Bueno, creo que después de que le hayan pitado los oidos, ayer 29 de diciembre Oracle ha hecho el lanzamiento de la (primera) versión final de su driver para trabajar con Entity Framework para Oracle.

Lista de Descargas:

32-bit ODAC with Oracle Developer Tools for Visual Studio (Necesario para 32 y 64 bits)

32-bit ODAC xcopy

x64 ODAC installer and xcopy

 

Para ver la documentación, la podeis ver y descargar desde aquí.

 

Algunas novedades a destacar:

– Mejora en Mapeo de Datos

– Uso de WCF y OData

– Mejoras en los Binding a Cursores

 

Para el año nuevo prometo hacer una serie de post en el que hable más en profundidad de esta nueva versión.

Un saludo!!!

[HowTo]Agregar Código al Código desde un Addin

Introducción

Antes de comenzar a hablar del propio titulo, vamos a hacer un índice de los artículos publicados en la serie de extensibilidad:

Parte 1: Agregar elementos a un menú de VS

Parte 2: Obtener los tipos de Proyecto de VS

Parte 3: Agregar Un Proyecto Nuevo

Parte 4: Agregar Ficheros a un Proyecto

Parte 5: Agregar Referencias

Parte 6: Eliminando Datos

 

En este artículo vamos a ver como agregar código o modificar el texto existente en el documento activo.

Código

   1: string addingText = GetText();

   2: int position = GetPosition();

   3: var fichero = (EnvDTE.Document)_applicationObject.Solution.DTE.ActiveDocument;

   4: var sel = (fichero.Selection as EnvDTE.TextSelection);

   5: sel.GotoLine(position);

   6: sel.Text = addingText ;

   7: sel.NewLine(1);

En el ejemplo utilizo un objeto de tipo TextSelection para agregar el texto en la posición que yo indique a través del conjunto de métodos disponibles.

 

Espero que os sea de utilidad Saludos

[HowTo]Eliminando Proyectos, ficheros y referencias…

Introducción

Continuando con la serie de extensibilidad de Visual Studio, en este artículo vamos a ver como eliminar algunas de las cosas que ya hemos visto como añadir a un proyecto / solución desde un addin en VS.

Código

Eliminar un Proyecto Existente

   1: var solution = (Solution2)_applicationObject.Solution;

   2: var project = GetProject(solution);

   3: solution.Remove(project);

   4:  

 

Eliminar un Fichero Existente

   1: var solution = (Solution2)_applicationObject.Solution;

   2: var project = GetProject(solution);

   3: var file = GetFile(project);

   4: file.Remove();

Eliminar una Referencia Existente

   1: var solution = (Solution2)_applicationObject.Solution;

   2: var project = GetProject(solution);

   3: var reference = GetReference(project);

   4: reference.Remove();

 

Un saludo y espero que os sea de utilidad!!

[HowTo] Agregar Referencias a un proyecto

Introducción

Continuando con la serie de extensibilidad de Visual Studio, en este artículo vamos a ver como agregar una referencia a un proyecto existente.

Código

Partiendo de los código utilizados en ejemplos anteriores, vamos a agregar una nueva opción de menú y dentro del evento clic agregaremos el siguiente fragmento de código:

   1: string file = string.Empty;

   2:            using (OpenFileDialog opd = new OpenFileDialog())

   3:            {

   4:                opd.Filter = "DLL | (*.dll)";

   5:                if (opd.ShowDialog() == DialogResult.OK)

   6:                {

   7:                    file = opd.FileName;

   8:                    try

   9:                    {

  10:                        var solution = (Solution2)_applicationObject.Solution;

  11:                        var project = GetProject(solution);

  12:                        (project.Object as VSLangProj.VSProject).References.Add(file);

  13:                    }

  14:                    catch (Exception ex )

  15:                    {

  16:                        

  17:                        MessageBox.Show(String.Format("Sucedio un problema intentando agregar la DLL: {0}",ex.Message));

  18:                    }

  19:                    

  20:                }

  21:            }

En el método estamos haciendo una conversión del tipo Project(ENVDTE) a VSPRoject, y a continuación a través de la Colección References, agregamos la DLL indicada.

 

Un saludo y espero que os sea de utilidad.

[WINFORMS]Uso de DataAnnotations y Validación de Atributos en Winfoms

Introducción

Es algo muy común en aplicaciones WEB, ver que cuando el usuario introduce valores en un formulario y pulsa aceptar, si ha introducido algún valor erróneo, le aparezcan los errores y los mensajes de error.

Normalmente, esto se realiza a través de decorar con atributos las propiedades de nuestras entidades de negocio, por ejemplo:

   1: public class Empleado

   2: {

   3:     [Required(ErrorMessage = "El nombre es un campo obligatorio.")]

   4:     [StringLength(100,ErrorMessage="La longitud máxima permitida es de 100 caracteres.")]

   5:     public string Nombre { get; set; }

   6: }

 

En el ejemplo, si en el formulario no se mete, valor en el campo nombre o se introduce un nombre superior a 100 letras, al pulsar sobre el botón “Enviar” (Por ejemplo), se volvería a cargar el formulario con el errores por el Parámetro ErrorMessage del atributo.

El conjunto de atributos de validación se encuentra en el espacio de nombres “System.ComponentModel.DataAnnotations”, que para poder utilizarlo en una aplicación WINFORMS, es necesario, agregarlo como referencia al proyecto.

Ejemplo

Para comenzar voy a definir 2 interfaces en las que voy a basar el ejemplo.

La primera la interfaz IValidable, la cual va a ser implementada por todas mis entidades:

   1: public interface IValidable

   2: {

   3:     bool IsValid { get; set; }

   4:     List<ValidationResult> ValidationErrors { get; set; }

   5: }

La segunda la interfaz IValidator, que va a definir el contrato de los posibles validadores de objetos:

   1: interface IValidator

   2:    {

   3:         Tuple<bool, List<ValidationResult>> ValidateObject(IValidable objToValidate);

   4:    }

Esta interfaz presenta un método estático que va a recibir un objeto que implemente la Interfaz IValidable y va a devolver un Tuple con valor booleano y una lista de ValidationResult.

A continuación vamos a ver un ejemplo de implementación de la interfaz IValidator (Utilizando un patrón Singleton):

   1: public sealed class Validator : IValidator

   2:     {

   3:         private Validator()

   4:         {

   5:  

   6:         }

   7:         private static Validator validator = new Validator();

   8:  

   9:         public static Tuple<bool, List<ValidationResult>> Validate(IValidable objToValidate)

  10:         {

  11:             if (validator==null)

  12:                 validator = new Validator();

  13:             return validator.ValidateObject(objToValidate);

  14:         }

  15:        

  16:         private Tuple<bool,List<ValidationResult>> ValidateObject(IValidable  objToValidate)

  17:         {

  18:            var results = new List<ValidationResult>();

  19:            var context = new ValidationContext(objToValidate,null,null);

  20:             var obj = System.ComponentModel.DataAnnotations.Validator.TryValidateObject(objToValidate, context, results, true);

  21:   

  22:             return new Tuple<bool,List<ValidationResult>>(obj,results);

  23:         }

  24:        

  25:     }

En el método ValidateObject, vamos a utilizar un objeto de tipo ValidationContext, para definir el contexto de validación de nuestro objeto IValidable, y a través del método TryValidateObject, vamos a obtener si existen o no errores y el listado de errores (si existen) que se han producido, para devolverlos al objeto que realiza la llamada.

Ahora vamos a ver una implementación de la interfaz IValidable:

   1: public class Empleado : IValidable 

   2:     {

   3:         [Required(ErrorMessage = "El nombre es un campo obligatorio.")]

   4:         [StringLength(100,ErrorMessage="La longitud máxima permitida es de 100 caracteres.")]

   5:         public string Nombre { get; set; }

   6:         #region Miembros de IValidable

   7:  

   8:         public bool IsValid

   9:         {

  10:             get {

  11:                 var validator = Validator.Validate(this);

  12:                 _ValidationErrors = validator.Item2;

  13:                 return validator.Item1;

  14:             }

  15:         }

  16:         private List<ValidationResult> _ValidationErrors;

  17:         public List<ValidationResult> ValidationErrors

  18:         {

  19:             get

  20:             {

  21:                 return _ValidationErrors;

  22:             }

  23:             private set

  24:             {

  25:                 _ValidationErrors = value;

  26:             }

  27:         }

  28:  

  29:         #endregion

  30:     }

Dentro de la propiedad IsValid, he introducido la invocación al objeto Validator para hacer las pertinentes validaciones y obtener el conjunto de errores en el caso de existir alguno.

Para ver un ejemplo de utilización:

   1: Empleado empleado = new Empleado();//Fallará

   2: if (!empleado.IsValid)

   3: {

   4:     foreach (var error in empleado.ValidationErrors)

   5:     {

   6:         MessageBox.Show(error.ErrorMessage);

   7:     }

   8: }

   9: Empleado empleadoOK = new Empleado { Nombre = "Javier" };//No falllará

  10: if (!empleadoOK.IsValid)

  11: {

  12:     foreach (var error in empleadoOK.ValidationErrors)

  13:     {

  14:         MessageBox.Show(error.ErrorMessage);

  15:     }

  16: }

  17: else

  18: {

  19:     MessageBox.Show("El empleado es válido.");

  20: }

NOTA: Existe una interfaz IValidatableObject que presenta un método Validate que realiza una función similar, pero he decido crear mi propia interfaz para establecer la propiedad IsValid.

Espero que os sea interesante y/o de utilidad.

 

Saludos

[HowTo] Convertir un objeto Table de HTML a Datatable con C#

Introducción

El otro día navegando por los foros de MSDN me encontré una pregunta curiosa: Pasar de un ListView en modo Details a un HTML y viceversa. El viernes respondí a como pasar a HTML, y hoy al paso contrario. El tema está en VB, pero me ha parecido interesante y he decidido crear este artículo en C#.

Código

En primer lugar, me he creado un método extensor de la clase HtmlElement para que me devuelva un IEnumerable para buscar por un determinado Tag (ej: div, table…)

   1: public static class HtmlExtensions

   2:     {

   3:         public static IEnumerable<HtmlElement> GetByTagName(this HtmlElement element, string TagName)

   4:         {

   5:             return element.All.Cast<HtmlElement>().

   6:                                 Where(el=>el.TagName.ToUpper().Equals(TagName.ToUpper())).ToList();

   7:         }

   8:     }

Bien, por otro lado me he creado una clase para realizar toda la lógica del proceso de conversión:

   1: public class HtmlToDatatable

   2:     {

   3:         public static DataTable GetHtmlDataTable(string url, string tablename)

   4:         {

   5:          

   6:             return GetDataTable(url,tablename);

   7:         }

   8:         private static string ReadHtml(string url)

   9:         {

  10:             System.Net.WebClient client = new System.Net.WebClient();

  11:             return client.DownloadString(url);

  12:         }

  13:         private static HtmlDocument GetHtmlDocument(string url)

  14:         {

  15:             string htmlText = ReadHtml(url);

  16:             if (string.IsNullOrWhiteSpace(htmlText)) throw new Exception("No se ha leido texto html.");

  17:             using (WebBrowser browser = new WebBrowser())

  18:             {

  19:                 browser.DocumentText = htmlText;

  20:                 do

  21:                 {

  22:                     Application.DoEvents();

  23:                 } while (browser.ReadyState != WebBrowserReadyState.Complete);

  24:                 return browser.Document;

  25:             }

  26:         }

  27:         private static HtmlElement GetHtmlTable(HtmlDocument doc, string tablename)

  28:         {

  29:             return doc.GetElementById(tablename);

  30:         }

  31:         private static DataTable GetDataTable(string url, string tablename)

  32:         {

  33:             DataTable dt = new DataTable();

  34:             HtmlDocument doc = GetHtmlDocument(url);

  35:             if (doc == null) throw new Exception("No se ha obtenido el documento HTML.");

  36:             HtmlElement table = GetHtmlTable(doc, tablename);

  37:             if (table == null) throw new Exception("No se ha obtenido la tabla indicada.");

  38:             CreateColumns(table, dt);

  39:             CreateRows(table, dt);

  40:             return dt;

  41:         }

  42:  

  43:         private static void CreateRows(HtmlElement table, DataTable dt)

  44:         {

  45:             List<HtmlElement> rowCol = table.GetByTagName("TR").ToList();

  46:             DataRow row;

  47:             foreach (HtmlElement fila in rowCol)

  48:             {

  49:                 if  (fila.Parent.TagName != "THEAD")

  50:                 {

  51:                     row = dt.NewRow();

  52:                     List<HtmlElement> tdCol  = fila.GetByTagName("TD").ToList();

  53:  

  54:                     for(int counter  = 0 ; counter<=dt.Columns.Count - 1;counter++)

  55:                         row[counter] = tdCol[counter].InnerText;

  56:                     

  57:                     dt.Rows.Add(row);

  58:                 }

  59:             

  60:             }

  61:             

  62:  

  63:  

  64:         }

  65:         private static  void CreateColumns(HtmlElement table, DataTable dt)

  66:         {

  67:             HtmlElement header = table.GetByTagName("THEAD").FirstOrDefault();

  68:             HtmlElement firstRow = table.GetByTagName("TR").FirstOrDefault();

  69:             if (header == null)

  70:             {

  71:                 CreateHeaders(dt, firstRow);

  72:             }

  73:             else

  74:             {

  75:                 CreateHeaders(dt, header);

  76:                

  77:             }

  78:            

  79:             

  80:         }

  81:         private static void CreateHeaders(DataTable dt, HtmlElement headerElement)

  82:         {

  83:             foreach (HtmlElement element in headerElement.All)

  84:             {

  85:                 dt.Columns.Add(element.InnerText);

  86:             }

  87:         }

  88:     }

El proceso consistiría:

Dada una ruta URL a leer, y un elemento Table del mismo:

Leeremos el texto HTML.

Obtendremos el HtmlDocument a través de un WebBrowser.

Obtendremos el HtmlElement relativo a la tabla indicada.

Obtendremos filas y columnas para rellenar el DataTable.

Para utilizar el código:

   1: this.dataGridView1.DataSource = HtmlToDatatable.GetHtmlDataTable(String.Format(@"{0}test.html", Application.StartupPath), "datos");

 

Espero que os sea de utilidad.

 

Saludos!

OffTopic: Resumen 2011 y Felices Fiestas

Desde este post, me gustaría hacer un resumen personal de lo que me ha dado 2011:

– En lo personal nació mi segundo Hijo, Izan, y he visto como, en general, mi vida familiar ha sido genial.

– He conocido a gente realmente interesante de nuestro mundillo, no os voy a nombrar para no olvidarme de ninguno, pero tengo que daros las gracias.

– En lo “geek” ha sido un año realmente interesante, desde que fui nombrado como MCC hasta que en octubre fui nombrado MVP, hasta la asistencia a las Community Days organizados por Microsoft en Málaga.

– También en lo geek, he aprendido muchas cosas, y he asistido a grandes charlas técnicas que me han abierto los ojos en muchos aspectos.

Por ello considero, que en lo personal y geek el año ha sido realmente bueno.

 

Por otro lado, me gustaría felicitar a todo el mundo estas Fiestas de Navidad y el próximo año 2012 que esperamos que sea todavía mejor que 2011, y que nos traiga cosas buenas.

 

Saludos

PD: Y se me olvidaba espero que de salud sea mejor que este 2011, que me ha tratado bastante mal …. 🙁

[HowTo] Agregar Ficheros a un Proyecto Existente

Introducción

Siguiendo con la serie de post de extensibilidad que he estado escribiendo, vamos a ver en este artículo como agregar ficheros a un proyecto existente.

Agregar Ficheros

En este apartado vamos a ver como agregar ficheros nuevos o ficheros ya existentes.

Ficheros Nuevos

Al igual que existen plantillas predefinidas para proyectos, podemos encontrar plantillas de tipos de elementos agregables a un proyecto.

Para poder explorar el conjunto de plantillas existentes, dentro del directorio de instalación de Visual Studio, encontraremos la carpeta ItemTemplates, con los distintos lenguajes, instalados para poder consultar sus elementos.

 

   1: var solution = (Solution2)_applicationObject.Solution;

   2: var project = (Project)solution.Projects.Item(GetProject());

   3: var template = solution.GetProjectItemTemplate("Class.zip", "CSharp");

   4: var temp = project.ProjectItems.AddFromTemplate(template, "MyNewClass.cs");

El fragmento de código anterior está incluido en el evento click de una opción de menú de nuestro Addin.

El objeto Solution2 dispone del método GetProjectItemTemplate, que a través del nombre de la plantilla y el lenguaje a utilizar, nos va a permitir obtener el nombre de la plantilla para su importación.

A través del método AddFromTemplate de la colección ProjectItems del proyecto seleccionado, vamos a definir la plantilla obtenida y asignaremos el nombre de nuestro nuevo fichero.

Ficheros existentes

Existen dos formas de agregar un fichero existente a un proyecto:

– Como una copia

– De forma vinculada

1) Como una copia:

Se creará una copia del fichero deseado en la carpeta del proyecto y se agregará al mismo.

Para realizar este proceso bastaría con ejecutar el siguiente fragmento de código:

   1: string file = string.Empty;

   2: using (OpenFileDialog opd = new OpenFileDialog())

   3: {

   4:     if (opd.ShowDialog() == DialogResult.OK)

   5:     {

   6:         file = opd.FileName;

   7:         var solution = (Solution2)_applicationObject.Solution;

   8:         var project = (Project)solution.Projects.Item(GetProject());

   9:         project.ProjectItems.AddFromFileCopy(file);

  10:     }

  11: }

A través del cuadro de Abrir Fichero (OpenFileDialog) vamos a elegir un fichero existente, y lo agregaremos como una copia al proyecto seleccionado a través del método AddFromFileCopy.

2) De forma vinculada:

La segunda forma de agregar un fichero existente a un proyecto es a través de un Vinculo. Visual Studio establecerá un vinculo al fichero existente sin copiarlo en el directorio del proyecto. Esto puede generar problemas si el fichero se mueve o se elimina, provocando que el enlace se pierda.

El código va a ser muy similar al anterior, con la salvedad que en lugar de utilizar el método AddFromFileCopy se va a utilizar el método AddFromFile.

 

   1: string file = string.Empty;

   2: using (OpenFileDialog opd = new OpenFileDialog())

   3: {

   4:     if (opd.ShowDialog() == DialogResult.OK)

   5:     {

   6:         file = opd.FileName;

   7:         var solution = (Solution2)_applicationObject.Solution;

   8:         var project = (Project)solution.Projects.Item(GetProject());

   9:         project.ProjectItems.AddFromFile(file);

  10:     }

  11: }

 

Espero que os sea de utilidad.

 

Saludos

[HowTo] Agregar un Proyecto Nuevo a Visual Studio desde Código

Introducción

En un post anterior vimos como definir un nuevo elemento en el Menú contextual de la Solución dentro de Visual Studio, y en este otro Post, hemos visto como obtener las distintas plantillas de proyectos de Visual Studio según una determinada versión.

El objetivo del presente artículo, es indicar como agregar a una solución existente un Tipo de Proyecto dado, para ello partiendo del código de los dos artículos anteriores vamos a plantear una solución.

Agregando un nuevo Proyecto

Dentro del evento Click de nuestro elemento de Menú, vamos a agregar el siguiente bloque de código:

   1: var solution = (Solution2)_applicationObject.Solution;

   2:  

   3: var newProjectName = String.Format("DLL{0}", solution.Projects.Count + 1);

   4: var newProjectPath = String.Format(@"{0}{1}",solution.FullName.Substring(0,solution.FullName.LastIndexOf(@"")),newProjectName );

   5: var templateName = "ClassLibrary.zip";

   6: var template = solution.GetProjectTemplate(templateName , "CSharp");

   7: solution.AddFromTemplate(template, newProjectPath , newProjectName );

En el ejemplo, construyo de manera genérica el nombre del nuevo Proyecto llamandolo DLL + un contador que será el número de proyectos existentes en mi solución más 1.

Vamos a definir la ruta donde se va a almacenar el nuevo proyecto, el cual estará almacenado dentro del directorio de nuestra solución incluyendo el nombre de nuestro proyecto.

A continuación, obtendremos el nombre de la plantilla a partir del método GetProjectTemplate del objeto Solution2 que hemos definido.

Y por último a través del método AddFromTemplate definiremos el nuevo proyecto y se agregará a nuestra solución.

 

Espero que os sea de utilidad.

 

Saludos

[HowTo]Obtener los Tipos de Proyecto de Visual Studio

Introducción

En mi anterior artículo explicaba la forma de agregar una nueva opción de menú a uno ya existente, dentro de un Addin para Visual Studio.

Siguiendo un poco con el tema de “extender” Visual Studio, vamos a ver como podemos obtener los distintos tipos de proyecto de una determinada versión de Visual Studio. (En el siguiente artículo, veremos como agregar un proyecto a una solución existente).

Código

Aunque he publicado el código en Code MSDN, me gustaría exponerlo aquí y explicarlo brevemente:

En primer lugar, será necesario que obtengamos el directorio donde se encuentra instalada la versión de Visual Studio que vamos a comprobar:

   1: private  void GetVSFolder()

   2: {

   3:     string VSVersion = VSVersions.GetVSVersion(Version);

   4:     string folder = String.Format("{0}{1}",RegistryPath,VSVersion);

   5:     InstallationFolder = Registry.GetValue(folder, "InstallDir", "").ToString();

   6: }

Dada una versión de Visual Studio, y la ruta de Registro de Windows “HKEY_LOCAL_MACHINESOFTWAREMicrosoftVisualStudio”, vamos a obtener el valor de la clave “Install Dir”, y la asignaremos a una propiedad de nuestra clase.

Dentro del código vamos a tener un enumerador de las distintas versiones de VS y un diccionario (Dictionary<string,string>) con la pareja versión y Nombre largo. La versión es el valor que vamos a utilizar para poder obtener el directorio de Instalación.

La clase va a contener una Propiedad de tipo Lista de cadenas (List<string>) que va a contener las distintas agrupaciones para los proyectos (WEB, CSharp, VisualBasic…). Para obtener dichos valores:

   1: private  void  GetProjectTypes()

   2:         {

   3:             if (String.IsNullOrWhiteSpace(InstallationFolder)) throw new Exception("El Directorio de Visual Studio no puede estar vacio.");

   4:             ProjectType = new List<string>();

   5:             foreach(var folder in System.IO.Directory.EnumerateDirectories(String.Format(@"{0}ProjectTemplates",InstallationFolder)))

   6:             {

   7:                 if (!ProjectType.Contains(folder)) ProjectType.Add(folder);

   8:             }

   9:  

  10:         }

Para tratar las distintas plantillas, he definido una clase “ProjectTemplate”:

   1: public class ProjectTemplate

   2:    {

   3:        public string TemplateName { get; set; }

   4:        public string TemplatePath { get; set; }

   5:        public string ProjectType { get; set; }

   6:        public override string ToString()

   7:        {

   8:            return String.Format("{0} - {1}", ProjectType, TemplateName);

   9:        }

  10:    }

Y dentro de la clase una propiedad de tipo Lista (List<ProjectTemplate>), que rellenaremos de la siguiente manera:

   1: private void GetProjectTemplates()

   2:         {

   3:             if (String.IsNullOrWhiteSpace(InstallationFolder)) throw new Exception("El Directorio de Visual Studio no puede estar vacio.");

   4:             ProjectTemplates = new List<ProjectTemplate>();

   5:             

   6:             foreach (var file in System.IO.Directory.EnumerateFiles(String.Format(@"{0}ProjectTemplates", InstallationFolder),"*"

   7:                                                                         ,System.IO.SearchOption.AllDirectories))

   8:             {

   9:                 var possition = file.IndexOf("ProjectTemplates")+17;

  10:                ProjectTemplates.Add( new ProjectTemplate { 

  11:                                             TemplatePath = file,

  12:                                             TemplateName = file.Substring(file.LastIndexOf(@"")+1),

  13:                                             ProjectType = file.Substring(possition,file.IndexOf(@"",possition)) 

  14:                                         }

  15:                                         ) ;

  16:  

  17:             }

  18:         }

 

Para utilizar este proyecto, bastaría con agregar la referencia a un nuevo proyecto, y para poder probarlo:

   1: VSInfo.VSInfo vs = new VSInfo.VSInfo(VSInfo.eVSVersions.VS2010);

   2:            foreach (var template in vs.ProjectTemplates)

   3:            {

   4:               Console.WriteLine(template.ToString());

   5:            }

 

Espero que os sea de utilidad.

 

Saludos