Asp.net web services fácilmente compatibles con cualquier tecnología
En anteriores entradas ya se ha comentado tanto sobre servicios web, arquitectura soap, wcf y wcf rest services. Por un lado se ha destacado por qué puede interesarnos una arquitectura orientada a servicios, como empezar a desarrollar servicios web en el entorno .net y el más generalizado modo de desarrollo empleando wcf.
Sin embargo una vez que entras en el desarrollo, más allá de los ejemplos académicos, los requisitos que demanda la aplicación son más exigentes. Se te puede plantear que el web service sea accesible desde varias tecnologías, aprovechar al máximo el entorno .net para descargar los recursos necesarios para correr los servicios, validación de datos y feedback para los diferentes clientes que hacen uso del web service. En esta entrada se comentan algunos de estos puntos siguiendo el caso desarrollado en el que se hacía necesario que el web service fuera compatible para múltiples entornos. Tres puntos que se van a tener en cuenta al desarrollar este Web Service: Compatibilidad, en concreto que el tipo de datos que intercambie no sean propietarios de .net, facilidanto de esta manera el desarrollo del lado del cliente que lo usa, aprovechar posibilidades de .net disminuyendo requisitos del lado de hardware, robustez no dejando únicamente del lado del cliente validación de datos y proporcionando suficiente información en caso de datos incorrectos.
Empezando con la compatibilidad, ya que el Web Service proporciona acceso a datos, en el entorno .net sería tentador usar un Dataset como tipo de retorno, pero tendría 2 inconvenientes, ya que se debe describir el tipo de dato por wsdl pero en este caso no podría saberse hasta tiempo de ejecución, por lo tanto deberíamos pasar al desarrollador cliente el xml schema que da la estructura del Dataset (podría optarse por convertir el Dataset a xml), lo segundo, la complejidad de describirlo haría necesario un gran número de intercambio de información y ralentización de la comunicación. Por ello utilizaremos un tipo orientado a objetos y compatible con cualquier plataforma tecnlógica, entities. Veamos el tipo que definimos para nuestro Web Service, tener en cuenta además que está desarrollado para el framework 2.0, por lo que no hace uso de la sintaxis abreviada.
public class licencie { private string _nombreemp; private string _direccion; private string _telefono; private string _personacont; private int _ident; public int Ident { get { return _ident; } set { _ident = value; } } public string NombreEmp { get { return _nombreemp; } set { _nombreemp = value; } } public string Direccion { get { return _direccion; } set { _direccion = value; } } public string Telefono { get { return _telefono; } set { _telefono = value; } } public string PersonaCont { get { return _personacont;} set { _personacont = value; } } }
En cuanto al método que devuelve datos, destacar que hace uso de genéricos, así como la opción de cache como una de las posibilidades que ofrece asp.net de manera que únicamente se hará una nueva consulta a la bb.dd pasado el tiempo que configuramos en el parámetro.
[WebMethod(Description = "Liste toutes épreuves ouvertes pour inscription",CacheDuration=300)] public List<licencie> ListEpreuves() { List<licencie> licencies = new List<licencie>(); using (SqlConnection con = new SqlConnection(@"Data Source=.\SQLEXPRESS;database=database;User ID=user;Password=pass")) { using (SqlCommand cmd = new SqlCommand("Select * from empresas", con)) { con.Open(); SqlDataReader dr = cmd.ExecuteReader(); while (dr.Read()) { licencie licencie1 = new licencie(); licencie1.NombreEmp = Convert.ToString(dr["nombreemp"]); licencie1.Direccion = Convert.ToString(dr["direccion"]); licencie1.Telefono = Convert.ToString(dr["telefono"]); licencie1.PersonaCont = Convert.ToString(dr["personacont"]); licencie1.Ident = int.Parse(dr["ident"].ToString()); licencies.Add(licencie1); } con.Close(); return licencies; } } } }
El último punto por comentar es diseñar web services robustos, no dejar únicamente del lado del cliente la validación de entrada. Para ello usaremos SoapException cómo atrapar y reenviar errores a la aplicación que hace uso del web services. Veamoslo en el método que hace uso de esta posibilidad:
[WebMethod(Description = "Inscrire un licencié à une épreuve")] public int InscripLicencie(licencie objlicencie) { int a; using (SqlConnection con = new SqlConnection(@"Data Source=.\SQLEXPRESS;database=database;User ID=user;Password=pass")) { using (SqlCommand cmd = new SqlCommand("Insert into epreuves(ident,nombreemp,direccion,telefono,personacont)Values(@Ident,@NombreEmp,@Direccion,@Telefono,@PersonaCont)", con)) { if ((string.IsNullOrEmpty(objlicencie.NombreEmp)) || (string.IsNullOrEmpty(objlicencie.Direccion)) || (string.IsNullOrEmpty(objlicencie.Telefono)) || (string.IsNullOrEmpty(objlicencie.PersonaCont)) || (objlicencie.Ident==0)) { SoapException se = new SoapException("Erreur, colonne de donnée nulle ou vide", SoapException.ClientFaultCode, Context.Request.Url.AbsoluteUri); throw se; } cmd.Parameters.AddWithValue("@Ident", objlicencie.Ident); cmd.Parameters.AddWithValue("@NombreEmp", objlicencie.NombreEmp); cmd.Parameters.AddWithValue("@PersonaCont", objlicencie.PersonaCont); cmd.Parameters.AddWithValue("@Direccion", objlicencie.Direccion); cmd.Parameters.AddWithValue("@Telefono", objlicencie.Telefono); con.Open(); try { a = cmd.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { con.Close(); } return a; } } }
Con esto se concluye la entrada con la intención de diseñar web services compatibles y más eficientes. La funcionalidad final del código aquí usado puede testearse en ffvoileclient donde se usa un cliente asp.net para usar el web services. En cuanto al diseño de clientes en otras plataformas la documentación puede encontrarse en java/Tomcat, php, asp 3.0.