C# WinServiceBasic1 v1.1.0: Servicio con servidor HTTP

El servicio que he programado hasta ahora no ofrece ninguna funcionalidad, uno de los usos más habituales es ofrecer un puerto abierto a la escucha para comunicarse con otras aplicaciones en red que ejercen de clientes. En vez de inventar un nuevo protocolo vamos a usar uno reconocido, usando la clase HttpListener vamos a crear un servidor HTTP muy sencillo (espacio de nombres “using System.Net”);

Proyecto en GitHub (v1.1.0)

Clase WebServer

Vamos a crear una clase WebServer que agrupa todas las funcionalidades de nuestro servidor Web. Solo contiene dos atributos privados:

  • _listener: Una instancia de la clase HttpListener.
  • _responderMethod: El capturador de evento cuando un cliente se conecta.

Los métodos que ofrece son tres:

  • WebServer: El constructor de la clase, recibe la URL donde se pondrá a la escucha (por ejemplo “http://localhost:8080/test/” y la función externa a la clase que genera la respuesta al cliente (_responderMethod).  La parte más interesante del constructor es la llamada a _listener.Start().
  • Run: Este método no acepta parámetros. Emplea el método IsListening de HttpListener para determinar si se ha iniciado. La clase  HttpListenerContext proporciona acceso a los objetos de solicitud y respuesta utilizados por la clase HttpListener.  Llama al método interno que apunta a la función que captura la solicitud cliente “_responderMethod(ctx.Request);” y con la respuesta la redirecciona al cliente HTTP.
  • Stop: Este método es muy simple, llama a la Stop y Close de HttpListener.

Ejecución

Ejecutamos e introducimos la siguiente URL en nuestro navegador para ver el resultado: http://localhost:8080/test/.

Posts relacionados

Referencias Externas

 

 

Anuncios

C# WinServiceBasic1 v1.0.1: Añadimos algunas mejoras al servicio

Después de experimentar un poco con el servicio (C# WinServiceBasic1: Crear un servicio básico en Windows) he prescindido del control de VS que permite instalar el servicio y hacerlo yo mismo a mano con scripts PS (PowerShell), los he guardado en la carpeta Debug y permiten instalar / desinstalar / arrancar / parar / ver estado del servicio.

Proyecto WinServiceBasic1 en GitHub.

WinServiceBasic1_install.ps1

Utilizo el comando New-Service para instalar el servicio, el script previamente copia el ejecutable en C:\bin y borra el servicio si ya existiese previamente.

WinServiceBasic1_delete.ps1

WinServiceBasic1_start.ps1

Start-Service -Name "MyNewService"

WinServiceBasic1_stop.ps1

Stop-Service -Name "MyNewService"

WinServiceBasic1_view.ps1

Get-WmiObject win32_service -Filter "name='MyNewService'"

También he realizado modificaciones en las propiedades del objeto eventLog1 (clase EventLog para escribir logs que se visualizan en el visor de eventos de Windows), es necesario especificar la propiedad Source, normalmente se define como el nombre de la aplicación (“MyNewService” en este caso).

Ajusto algunos parámetros del objeto “MyNewService” (heredado de la clase ServiceBase) para modificar el comportamiento del servicio. La propiedad AutoLog a “False” para que la aplicación no genere eventos por su cuenta.

Además he sobrecargado el método WriteEntry para ilustrar como generar diferentes tipos de eventos (información, error,…):

Ahora los eventos del visor de eventos de Windows proporcionan más información:

Después de probar un rato con EventLog he instalado NLog para generar logs con más flexibilidad (ver “NLog: Sistema de logging gratuito y de código abierto para .Net“)

Referencias externas

 

NLog1 C#: Configuración versión de la aplicación con App.Config

Voy a continuar con  NLog: Sistema de logging gratuito y de código abierto para .Net.

Proyecto en GitHub NLog1.

He añadido algunas mejoras sin relación con el propio NLog,  Algo esencial para el control del proyecto es la gestión de versiones para controlar los cambios realizados (yo sigo este esquema de versionado siempre Semantic Versioning 2.0.0). El fichero App.config del proyecto en VS2012 con sintaxis XML es el candidato ideal para alojar la información de la versión del proyecto añadiendo a mano un nuevo bloque “<appSettings>” y dentro una etiqueta con clave valor :

Otra forma de definir la versión si queremos tratarla posteriormente en nuestra aplicación es definir 3 parámetros clave valor para X.Y.Z de la versión (MAJOR.MINOR.PATCH).

Poder acceder a la información de la versión desde el código de nuestra aplicación es esencial, sobre todo si queremos condicionar la ejecución de un bloque de código especial dependiendo de la versión por ejemplo. Para ello debemos añadir la referencia “System.Configuration” al proyecto y el espacio de nombres a nuestra aplicación:

using System.Configuration;

Para acceder a la variable desde nuestro programa es muy sencillo:

Como conclusión, podemos añadir la información que necesitemos, algunos usos muy comunes es incluir información de conexión a la base de datos o configuración del usuario.

Referencias externas:

 

 

 

C# WinServiceBasic1: Crear un servicio básico en Windows

Los servicios (o demonio en Linux) son normalmente aplicaciones que corren de fondo (sin interfaz) y ofrecen como su nombre lo dice un servicio a otras aplicaciones, es muy común por ejemplo para implementar  protocolos de comunicaciones en red con otras máquinas mediante sockets TCP/UDP actuando como un servidor.  Otro uso muy común es como servidor de acceso a datos alojados en una máquina central.

Código del ejercicio en GitHub

Crear un servicio en VS 2012

En Visual Studio ahora te facilita crear aplicaciones de este tipo ya que ofrece un tipo de proyecto especifico “Windows Service”:

Visual Studio añade automáticamente una clase nueva Service1.cs heredada de System.ServiceProcess.ServiceBase.

Cambiamos el nombre de “Service1” por “MyNewService” buscando y reemplazando en todo el proyecto,

Añadir eventos de Windows

En la vista de diseño de Service1.cs arrastramos y añadimos un control “EventLog

VS le asigna un nombre eventLog1 a la nueva clase, podemos cambiar el nombre de la clase en las propiedades.

Ahora ya podemos añadir eventos para notificar de arranque / parada del servicio.

Instalar el servicio

Para crear un instalador usamos el botón derecho del ratón en la vista diseño Service1.cs sobre el fondo y el menú contextual seleccionamos “Add Installer”, revisamos las propiedades de “serviceInstaller1”, ServiceName debe estar definido como “MyNewService”, es importante elegir el tipo de arranque (lo dejamos en manual por el momento).

Para instalar el servicio hay que hacerlo mediante el interprete de comandos “Developer Command Prompt” incluido en VS.

Ahora vamos a la carpeta de salida donde está WinServiceBasic1.exe y ejecutamos:

installutil.exe WinServiceBasic1.exe

 

MVVMBasicDemo1: Patrón de diseño MVVM con aplicaciones basadas en WPF Resultado de imagen de WPF (Windows Presentation Foundation)

WPF (Windows Presentation Foundation) es una tecnología de MS para diseñar interfaces de usuario tomando ideas de técnicas Web y aplicaciones Windows. WPF permite definir las ventanas en ficheros de texto plano que contienen un lenguaje de etiquetado llamado XAML (basado en XML).

El proyecto completo se puede descargar en GitHub: https://github.com/ikerlandajuela/MVVMBasicDemo1.

 

De está forma separa las capas con la lógica de la aplicación y la capa de presentación donde interactuamos con el usuario. Está separación tan nítida propicia adoptar patrones de diseño como MVVM (Model-View-ViewModel ) para desarrollar aplicaciones complejas.

WPF emplea data-binding para conectar  la UI (User Interface) con la lógica de la aplicación, gracias a ello cuando un origen de dato cambia su valor  el cambio se refleja de forma automática en la UI, también si a la inversa la presentación del dato cambia en la UI los cambios tienen reflejo en la lógica de negocio interna (el contenido de un TextBox modificado por el usuario por ejemplo) .

El modelo MVVM estructura la aplicación en 3 capas:

  • Model: Mantiene los orígenes de datos.
  • ViewModel: Actúa de conector entre las otras dos capas.
  • View: Mantiene la información de la UI.

MVVMBasicDemo1: Primera aplicación

Este es el ejemplo mas sencillo que he encontrado para entender los fundamentos básicos de MVVM con WPF.  La única ventana de la aplicación muestra el nombre y apellido (cada uno en su respectivo TextBox editable) de una lista de estudiantes, junto a los dos TexBox (FirstName y LastName) hay un TextBlock con el nombre y apellidos unidos (FullName), cuando el usuario modifica el nombre o apellido de un estudiante inmediatamente la modificación se actualiza de forma automática en el TexBox (de lectura). Los controles con la lista de usuarios se crean de forma dinámica dependiendo de la lista de estudiantes que proporcionemos en la capa ViewModel.

 

Creamos un nuevo proyecto de tipo “WPF Application” en VS (Visual Studio). Creamos 3 carpetas (Model, ViewModel, Views)

Model

Añadimos una nueva clase “StudentModel” a la carpeta “Model”.

Para poder usar las técnicas de programación que se describen a continuación debemos añadir al comienzo del fichero un nuevo espacio de nombres System.ComponentModel.

using System.ComponentModel;

La clase base ‘INotifyPropertyChanged‘ notifica que el valor de una propiedad ha cambiado, genera un evento PropertyChanged cuando cambia el valor de un miembro de la clase. Debemos definir un atributo de tipo PropertyChangedEventHandler como manejador del evento para notificar a las clases cuando cambia una propiedad en alguno de los atributos editables (firstName,lastName).

Los atributos privados de la clase son el nombre y apellido, controlamos el acceso a sus propiedades con los descriptores de acceso get/set (ver más sobre este tema en “C# class LibroCalificaciones: Acceso a propiedades con descriptores de acceso get / set“), de esta forma controlamos cuando cambia el valor y lanzamos la función RaisePropertyChanged que a su vez llama a al manejador PropertyChanged. El resto de código y comprobaciones que realiza con fáciles de comprender. Si por ejemplo cambia el nombre genera un evento adicional para que en coherencia cambie el FullName.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.ComponentModel;

namespace MVVMBasicDemo1.Model
{
public class StudentModel { }

public class Student : INotifyPropertyChanged
{
private string firstName;
private string lastName;

public string FirstName
{
get
{
return firstName;
}

set
{
if (firstName != value)
{
firstName = value;
RaisePropertyChanged("FirstName");
RaisePropertyChanged("FullName");
}
}
}

public string LastName
{
get { return lastName; }

set
{
if (lastName != value)
{
lastName = value;
RaisePropertyChanged("LastName");
RaisePropertyChanged("FullName");
}
}
}

public string FullName
{
get
{
return firstName + " " + lastName;
}
}

public event PropertyChangedEventHandler PropertyChanged;

private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}

 

ViewModel

En la capa intermedia ViewModel añadimos la clase StudentViewModel.cs. La clase representa el origen de datos de donde se nutre con la lista de alumnos.

La clase StudentViewModel contiene un solo atributo público de tipo Clase ObservableCollection<T>  esta clase representa una colección de datos dinámicos de la clase Student definida en el modelo de datos. El método público LoadStudents() carga la colección de datos con la información de los estudiantes.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using MVVMBasicDemo1.Model;
using System.Collections.ObjectModel;

namespace MVVMBasicDemo1.ViewModel
{
class StudentViewModel
{
public ObservableCollection<Student> Students
{
get;
set;
}

public void LoadStudents()
{
ObservableCollection<Student> students = new ObservableCollection<Student>();

students.Add(new Student { FirstName = "Mark", LastName = "Allain" });
students.Add(new Student { FirstName = "Allen", LastName = "Brown" });
students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" });
students.Add(new Student { FirstName = "Iker", LastName = "Landajuela" });

Students = students;
}
}
}

Views

Lo primero hemos movido el archivo MainWindow.xaml a la carpeta Views donde debería estar.

App.xaml es el punto de entrada cuando arranca la aplicación, VS lo genera de forma automática cuando creamos el proyecto de tipo WPF.

En este fichero debemos modificar el atributo StartupUri para que apunte a  MainWindow.xaml dentro de la carpeta Views. Si quisiéramos mostrar otra ventana en el inicio de la aplicación la definimos en este campo.

App.xaml incluye también por detrás código en el fichero App.xaml.cs (clase Application).

 

MainWindow.xaml

Este fichero contiene la definición de la ventana de nuestra aplicación usando XAML y la etiqueta Window. Definimos algunas propiedades básicas como el tamaño de ventana y el título.

Dentro de Window definimos un control Grid, este control define una rejilla donde alojamos controles en las casillas (Ver The Grid Control). En nuestro caso sólo contiene una vista con la etiqueta views que se encarga de cargar nuestra vista StudentView.xaml.

StudentView.xaml

He añadido un nuevo elemento de tipo “User Control (WPF)” al proyecto en la carpeta Views.  El archivo StudentView.xaml contiene los controles para visualizar la lista de estudiantes, la etiqueta principal UserControl contiene un Grid, dentro un control StackPanel (Ver “WPF StackPanel“).

El control ItemsControl es donde opera la magia del data-binding, se asocia a la propiedad Students (colección de clases Student) definida en la clase StudentViewModel. Dentro de ItemsControl se define ItemsControl.ItemTemplate que contiene el modelo de visualización de un estudiante.

Cada clase TextBox se asocia a un atributo de la clase student usando la propiedad Text.


<UserControl x:Class = "MVVMBasicDemo1.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:MVVMBasicDemo1.Views"
mc:Ignorable = "d"
d:DesignHeight = "300" d:DesignWidth = "300">

<Grid>
<StackPanel HorizontalAlignment = "Left">

<ItemsControl ItemsSource = "{Binding Path = Students}">

<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>

<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>

<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>

</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>

</ItemsControl>

</StackPanel>
</Grid>

</UserControl>

 

Enlaces externos

C# BasicLinkedList: Listas enlazadas

Vamos a seguir desarrollando el post anterior (“C# Clases autorreferenciadas“) para generar una lista enlazada, una lista enlazada es una colección lineal o una secuencia de nodos representados con clases autorreferenciadas. El acceso a la lista se realiza desde el primero nodo (raíz o head) y se recorre accediendo al miembro que apunta al siguiente nodo y así hasta el final (el miembro del último nodo que apunta al siguiente se define como null para evitar errores). Normalmente las listas tienen las operaciones comunes para trabajar con sus nodos, vamos a definir métodos para:

  • Construir una lista vacía y darle un nombre.
  • Insertar un nodo en la cabecera.
  • Insertar un nodo al final.
  • Eliminar el primer nodo de la lista.
  • Eliminar un nodo del final de la lista.
  • Comprobar si una lista está vacía.
  • Imprimir por pantalla el contenido.
  • Obtener el número de elementos o nodos de la lista.

Clase para definir un nodo

Similar al ejemplo anterior definimos una clase que represente un nodo. Definimos dos constructores, el segundo permite crear un nodo y definir el nodo al que apunta como siguiente elemento en la lista.

Lo más remarcable de la clase es la referencia object. Nos permite almacenar tipos de datos simples como si fueran objetos. El tipo object es un alias para Object en .NET. Todos los tipos de variables son herencia directa de este tipo. Podemos asignar valores de cualquier tipo a variables de tipo object. Cuando una variable se convierte a un tipo object a esta operación se le llama boxing o boxed. Cuando se realiza la operación inversa se denomina unboxing.

Clase lista

La clase lista tiene contiene como miembros head y tail. Son respectivamente referencias al primer y último nodo de la lista, también definimos una variable string para asignar un nombre a la lista.

 

Definimos un método que nos resultará de utilidad más adelante, el método IsListEmpty retorna true si la cabeza de lista apunta a null.

Ahora definimos un método para operar sobre la lista insertando un nuevo nodo al inicio de la misma.  Si la lista esta recién creada o vacía la cabeza y la cola apunta al nuevo y único la misma. En caso contrario la cabeza apunta al nuevo nodo y le pasamos el nodo de cabeza actual como miembro para que quede en segundo lugar.

Para añadir un nodo al final definimos el siguiente método:

Antes de continuar con un método para borrar un elemento del inicio de la lista vamos a definir una clase EmptyListException para lanzar una excepción cuando se producen operaciones ilegales sobra la lista, por ejemplo si la lista está vacía. Usamos System.ApplicationException para excepciones generadas por nuestra programa.

Ahora ya podemos crear un método para borrar un elemento de la cabecera de la lista. Si la lista está vacía lanza una excepción que podemos capturar y tratar desde el programa principal. Después obtenemos el miembro del nodo de cabecera y restablece las referencias del primer y último nodo (si solo hay un nodo en la lista head y last quedaran a null, si hay más de un elemento avanzamos al siguiente nodo la cabecera).

Visto el anterior ejemplo borrar el último nodo es similar. Pero en este caso el método que debemos seguir  nodo no es muy eficiente (esto se solucionaría con una lista doblemente enlazada). Recorremos desde el primero nodo uno de detrás de otro hasta que el nodo siguiente no sea el último, de esta manera hacemos que apunte a null quedando fuera el último nodo.

Ahora solo nos queda un método para imprimir los nodos de la lista.

Ahora veamos como se puede utilizar:

Referencias externas