====== C# Xtra (II) ====== ===== Sockets ===== * [[code:tools#sockets|Explicación de sockets]]. ==== Creación de un servidor RAW ==== System.Net.Sockets.TcpListener server = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 2005); server.Start(); Byte[] bytes = new Byte[256]; String data = null; while (true) { System.Net.Sockets.TcpClient client = server.AcceptTcpClient(); data = null; System.Net.Sockets.NetworkStream stream = client.GetStream(); int i; while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) { data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); Console.WriteLine("Received: {0}", data); data = data.ToUpper(); byte[] msg = System.Text.Encoding.ASCII.GetBytes(data); stream.Write(msg, 0, msg.Length); Console.WriteLine("Sent: {0}", data); } } Para enviar un "salto de línia" haremos: byte[] msg = System.Text.Encoding.ASCII.GetBytes(data + "\n\r"); stream.Write(msg, 0, msg.Length); ===== Expresiones Regulares ===== ==== In a nutshell ==== En ''System.Text.RegularExpressions'' existe la clase ''Regex'' que se encarga de localizar combinaciones (matches) de expresiones regulares en un texto. Por ejemplo, su método estático ''Matches'' recibe un texto y una expresión regular y devuelve objetos ''Match'' de las coincidencias. \\ Un objeto ''Match'' tiene las siguientes propiedades interesantes: * ''NextMatch()'': * ''Index'': Posición dentro del string original donde se encuentra el primer carácter de la coincidencial. * ''Lenght'': * ''Success'': * ''Value'': Recoge el substring de la coincidencia encontrada. string startBy = "src=\"|src = \"|src= \"|src =\""; var matches = System.Text.RegularExpressions.Regex.Matches(text, startBy, System.Text.RegularExpressions.RegexOptions.IgnoreCase); List lImgNames = new List(); for (int i = 0; i < matches.Count; i++) { var match = matches[i]; int start = match.Index + match.Value.Length; int end = text.IndexOf("\"", start); string file = text.Substring(start, end - start); lImgNames.Add(file); } ===== Comunicación entre procesos ===== ==== Canales IPC ==== Son utilizados para realizar una comunicación entre procesos que están corriendo en la misma máquina (IPC, //inter-process communication//). Y son más rápidos que utilizar rutinas sobre red, son algo parecidas a las //Named Pipes// existentes en el //kernel32.dll//. \\ Para poder usar dichos canales se necesitan los siguientes elementos: - Objeto cliente. - Objeto servidor. - Objetos compartidos, referenciados tanto por el cliente como por el server pero que a la vez no referencien a ninguno de ellos. También necesitaremos agregar una referencia a //System.Runtime.Remoting//. Y hacer ''using'' de unos cuantos namespaces: using System.Runtime.Remoting.Channels.Ipc; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting; === El dominio de la aplicación === Un dominio de aplicación es un proceso dentro del sistema operativo donde una o más aplicaciones residen. Los objetos que se encuentran en el mismo dominio de aplicación se comunican directamente, en cambio, los que están en distintos dominios se comunican a partir del transporte de copias de estos objetos. Existe una clase (**System.MarshalByRefObject**) que sirve como clase base para las clases que intervengan la comunicación e intercambio de mensajes entre dominios de aplicación (si no heredasen serían //marshal by value//). === Los objetos compartidos === Necesitaremos crear la clase de los objetos que se compartirán (ha de heredar de ''MarshalByRefObject''). namespace SharedObjects { public class Class1 : MarshalByRefObject { string v; public string Value { get { return this.v; } set { this.v = value; } } } } === El servidor === Creamos un canal de servidor a partir de un nombre de canal (en formato string) y lo registramos mediante el método estático de la clase ''ChannelServices'', a este se le pasan dos objetos, un objeto correspondiente al canal en sí y un boolean, que será //true// si el canal será manejado a partir de un protocolo seguro. \\ \\ Luego deberemos registrar los objetos compartidos a partir del método estático ''RegisterWellKnownServiceType'' dentro de ''RemotingConfiguration'', si lo hacemos mediante ''WellKnownObjectMode.Singleton'' se creará un único objeto objeto, para acceder a él la ruta será ''ipc://nombreDelCanal/NombreDelObjeto''. \\ \\ Para recoger un objeto utilizaremos el método ''GetObject'' de la clase ''Activator''. IpcServerChannel server = new IpcServerChannel("myChannel"); ChannelServices.RegisterChannel(server, false); RemotingConfiguration.RegisterWellKnownServiceType(typeof(SharedObjects.Class1), "sharedObjs", WellKnownObjectMode.Singleton); SharedObjects.Class1 c = (SharedObjects.Class1)Activator.GetObject(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); c.Value = "Servidor"; === El cliente === Únicamente es necesario acceder al objeto a partir de ''Activator.GetObject''. // IpcClientChannel icc = new IpcClientChannel(); // ChannelServices.RegisterChannel(icc, true); // RemotingConfiguration.RegisterWellKnownClientType(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); SharedObjects.Class1 c = (SharedObjects.Class1)Activator.GetObject(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); Console.WriteLine(c.Value); ===== Configuración ===== ==== Fichero app.config ==== El fichero que configura la aplicación es el ''app.config'' y se ha de encontrar en el directorio donde está el ensamblado ejecutable de la aplicación. === Leer un valor === Para leer el valor //logFile// de un fichero de configuración como el que sigue: Utilizaremos un objeto de la clase **AppSettingsReader** y su método ''GetValue'': (string)new System.Configuration.AppSettingsReader().GetValue("dbFile", typeof(String)); === Agregar secciones === Podemos agregar secciones personalizadas al fichero, por ejemplo una sola para el tema de ''log'', para ello deberemos declararla entro de la tag ''configSections'' indicando nombre y tipo como sigue:
Para leer estas secciones deberemos agregar la referencia al ensamblado ''System.Configuration'' y poder así utilizar la clase ''ConfigurationManager'': IDictionary confTable = (IDictionary)System.Configuration.ConfigurationManager.GetSection("log"); string logFile = (string)confTable["logFile"]; === Agregar grupos de secciones === Podemos agregar grupos de secciones, por ejemplo:
... Y luego acceder a ellas como si accediesemos a una sección personalizada: IDictionary confTable = (IDictionary)System.Configuration.ConfigurationManager.GetSection("atm.ws/dbInfo"); string dataSource = (string)confTable["DataSource"]; ===== Programación declarativa con C# ===== * [[code:best-practices#programacion_declarativa|Programación declarativa]] ==== Métodos ==== Podemos realizar un bucle ''foreach'' con el método ''List.ForEac'' y una expresión lambda. using System; using System.Collections.Generic; class Example { static void Main() { new List { 1, 2, 3 } .ForEach(i => Console.WriteLine(i)); } } De una forma parecida podemos sacar partido del delagado ''Action'', el cual permite una funcion ''Action'' el cual encaja con ''Console.WriteLine''. using System; using System.Collections.Generic; class Example { static void Main() { new List { 1, 2, 3 } .ForEach(Console.WriteLine); } } También el método ''Enumerable.Range'': using System; using System.Linq; class Example { static void Main() { Int32 sum = Enumerable.Range(0, 99) .Where(i => i % 2 == 0) .Sum(); Console.WriteLine(sum); } }