none
Llamar método dentro de otro método RRS feed

  • Pregunta

  • Buenas tardes,

    Estoy creando un WebService con C# el cual contiene un método llamado PAGO, dentro de éste, ejecuto otro método booleano llamado Autenticar para validar un usuario y una contraseña, de esta forma:

    public class ServicioMarquez : System.Web.Services.WebService
        {
            SqlConnection cnn;
            SqlCommand cmd;
            string mensaje;
    
            [WebMethod]
            public MetodoPago PAGO(string usu_ws, string pass_ws)
            {
                MetodoPago propiedades = new MetodoPago();
    
                if (Autentica(usu_ws, pass_ws) == true)
                {
                    propiedades.cod_error = "1";
                    propiedades.des_error = "AUTENTICACIÓN CORRECTA";
                }
                else
                {
                    propiedades.cod_error = "2";
                    propiedades.des_error = mensaje;
                }
    
                return propiedades;
            }
    
            private bool Autentica(string usu, string pass)
            {
                bool finalizado = true;
                string password = "";
    
                try
                {
                    using (cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["BD_DESARROLLOConnetionString"].ToString()))
                    {
                        cnn.Open();
                        string query = "SELECT USU,PASS FROM USUARIO WHERE USU=@USU";
                        cmd = new SqlCommand(query, cnn);
                        cmd.Parameters.AddWithValue("@USU", usu);
                        SqlDataReader reader = cmd.ExecuteReader();
                        if (reader.Read())
                        {
                            password = Convert.ToString(reader["PASS"]);
                        }
                        cnn.Close();
    
                        if (password == "" | password != pass)
                        {
                            finalizado = false;
                        }
                    }
                }
                catch (Exception ex)
                {
                    finalizado = false;
                    mensaje = Convert.ToString(ex.Message);
                }
    
                return finalizado;
            }
        }

    Mi pregunta es: ¿Es correcto invocar un método dentro de otro? es válido la forma en que lo estoy realizando o hay otra mejor práctica para realizarlo?


    Carlos Márquez


    domingo, 26 de enero de 2014 21:37

Respuestas

  • mas pasa por la cuestión del ámbito y que la funcionalidad está amarrada a la variable mensaje que es una variable global,

    exacto, la idea es definir las cosas con la menor ambito que sea necesario

    no pasa por u  tema de poder o no poder, sino por un tema de como diseñas de forma reutilizable y mantenible, lo global siempre es sinonimo de problemas, a veces es necesario la cuestion es que no sea todo global

    si vas a definir una funcionalidad que valida digamos temperatudas, no definas los alores de las temperaturas en una variable global y que el metodo lo tome de alli

    sino que la funciona reciba estos valores en concreto que debe usar, de esa forma si mas adelante alguine requiere de la misma funcionalidad puede llevarsela y reusarla si tener que estar revisando todo el codigo para ver donde sale cada variable

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    martes, 28 de enero de 2014 11:18

Todas las respuestas

  • Hola Carlos,

    Invocar un método dentro de otro es correcto, lo que no es correcto es cómo autentificas al usuario. Para ello los WebService tienen muchos mecanismos. Tienes lo básico aquí: http://msdn.microsoft.com/library/system.web.security(v=vs.110).aspx y aquí: http://msdn.microsoft.com/library/vstudio/system.web.services.webservice.user(v=vs.100).aspx

    Y aquí tienes un artículo sobre seguridad en web services: http://msdn.microsoft.com/en-us/library/ff648318.aspx

    Y lo primero de todo: no guardes nunca un password en texto plano en la bbdd, haz un hash+salt como mínimo, o encripta, tienes un montón de librerías en el framework para cifrar datos.

    Un saludo,

    Juanma

    domingo, 26 de enero de 2014 23:01
  • Hola, Juanma.

    Lo de la parte de la autenticación fue algo rápido que hice para tratar de ilustrar el ejemplo, siempre suelo realizar esa parte con una clase y mi propio método de encriptación, lo que quería asegurarme era si la parte del llamado del método dentro de otro era la correcta, de todas formas voy a revisar los mecanismos para autenticar que me envías.


    Carlos Márquez

    domingo, 26 de enero de 2014 23:37
  • hola

    algo que no se si has evaluado es el transporte de los datos que envias al invocar el web service

    o sea vas a usar este servicio en una red interna, o por internet, porque algo que aconsejaria es que evalues usar SSL para asegurar la invocacion por un medio seguro

    ya que si envias el usuario y password directo cualquiera que este escuchando la red podrias interceptar el mensaje soap

    ---

    lo que tambien veo mal es como asignas la variable mensaje, alli rompes con cualquier idea de encapsular funcionalidad

    si vas a enviar un mensaje porque no usas el Exception, osino haz que la clase MetodoPago  la cree y directamente el metodo Autenticar()

    eso de definir una variable publica "mensaje" no es correcto

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    lunes, 27 de enero de 2014 0:34
  • Hola, Tuttini.

    si vas a enviar un mensaje porque no usas el Exception, osino haz que la clase MetodoPago  la cree y directamente el metodo Autenticar()

    Puedo hacer una segunda instancia de mi clase MetodoPago dentro del método Auntentica y en el catch asignar la propiedad des_error el mensaje de error? de esta forma...

    private bool Autentica(string usu, string pass)
            {
                MetodoPago propiedades = new MetodoPago();
                bool finalizado = true;
                string password = "";
    
                try
                {
                    using (cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["BD_DESARROLLOConnetionString"].ToString()))
                    {
                     //CODIGO   
                    }
                catch (Exception ex)
                {
                    finalizado = false;
                    propiedades.des_error=convert.tostring(ex.message);
                }
    
                return finalizado;
            }


    Carlos Márquez

    lunes, 27 de enero de 2014 1:25
  • Puedo hacer una segunda instancia de mi clase MetodoPago dentro del método Auntentica y en el catch asignar la propiedad des_error el mensaje de error?

    no eso no funciona porque es otra instancia que defines de forma local, si asignaras el valor pero no lo recibiras en el webmethod para poder devolverlo como resultado

    private MetodoPago Autentica(string usu, string pass)
    {
    	string password = "";
    
    	try
    	{
    		using (cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["BD_DESARROLLOConnetionString"].ToString()))
    		{
    		 //CODIGO   
    		}
    		
    		return new MetodoPago()     
    		{
    			cod_error = "1",
    			des_error = "AUTENTICACIÓN CORRECTA"
    		};
    	}
    	catch (Exception ex)
    	{
    		return new MetodoPago()     
    		{
    			cod_error = "2",
    			des_error = ex.Message
    		};
    	}
    
    }

    la validacion que genere directamente la respuesta, asi no necesitas tener nada global para pasar datos

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    lunes, 27 de enero de 2014 2:31
  • Hola, Tuttini.

    Entonces usar variables de esta manera es incorrecto?

    public partial class Form1 : Form
        {
            string variable;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                variable = "Hola Mundo";
                MessageBox.Show(variable);
            }


    Carlos Márquez

    lunes, 27 de enero de 2014 4:00
  • Hola, Tuttini.

    Y que tal usando variables privadas? de esta forma si es permitido y no rompe el encapsulamiento?

    public partial class Form1 : Form
        {
            private string variable;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                variable = "hola";
                MessageBox.Show(variable);
            }
    }


    Carlos Márquez

    lunes, 27 de enero de 2014 4:26
  • Hola, Tuttini.

    Usando variables privadas es valido hacer esto, no? declarando la variable mensaje como privada

    public class ServicioMarquez : System.Web.Services.WebService
        {
            SqlConnection cnn;
            SqlCommand cmd;
            private string mensaje; //Declarando mensaje como privada
    
            [WebMethod]
            public MetodoPago PAGO(string usu_ws, string pass_ws)
            {
                MetodoPago propiedades = new MetodoPago();
    
                if (Autentica(usu_ws, pass_ws) == true)
                {
                    propiedades.cod_error = "1";
                    propiedades.des_error = "AUTENTICACIÓN CORRECTA";
                }
                else
                {
                    propiedades.cod_error = "2";
                    propiedades.des_error = mensaje;
                }
    
                return propiedades;
            }
    
            private bool Autentica(string usu, string pass)
            {
                bool finalizado = true;
                string password = "";
    
                try
                {
                    using (cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["BD_DESARROLLOConnetionString"].ToString()))
                    {
                        cnn.Open();
                        string query = "SELECT USU,PASS FROM USUARIO WHERE USU=@USU";
                        cmd = new SqlCommand(query, cnn);
                        cmd.Parameters.AddWithValue("@USU", usu);
                        SqlDataReader reader = cmd.ExecuteReader();
                        if (reader.Read())
                        {
                            password = Convert.ToString(reader["PASS"]);
                        }
                        cnn.Close();
    
                        if (password == "" | password != pass)
                        {
                            finalizado = false;
                        }
                    }
                }
                catch (Exception ex)
                {
                    finalizado = false;
                    mensaje = Convert.ToString(ex.Message);
                }
    
                return finalizado;
            }
        }


    Carlos Márquez

    lunes, 27 de enero de 2014 4:42
  • eso de definir una variable publica "mensaje" no es correcto

    Pero mensaje no es una variable publica, es privada


    Carlos Márquez

    lunes, 27 de enero de 2014 11:57
  • si eso lo se, pero que pasa si alguien se quiere llevar la funcionalida de autenticar par aimplementarla en otra funcionalidad?

    digo sin declarar variables por fuera de de este no podrias llevartelo, ahi es donde apunto, autenticar es una funcionalidad que deberia tener una responsabilidad simple, no necesita algo global para informar de algun problema

    podrias hacer que esta directamnte devuelva la clase con la descripcion del error, o podrias ahcer que devuelva un Exception lanzado por ti y sea captura por tu otra funcionalidad

    quizas algo como esto

    	[WebMethod]
    	public MetodoPago PAGO(string usu_ws, string pass_ws)
    	{
    		MetodoPago propiedades = new MetodoPago();
    		
    		try
    		{
    			if (Autentica(usu_ws, pass_ws))
    			{
    				propiedades.cod_error = "0";
    				propiedades.des_error = "AUTENTICACIÓN CORRECTA";
    			}
    			else
    			{
    				propiedades.cod_error = "1";
    				propiedades.des_error = "NO AUTENTICA";
    			}
    		}
    		catch(Exception ex)
    		{
    			propiedades.cod_error = "2";
    			propiedades.des_error = ex.Message;
    		}
    		
    		return propiedades;
    	}
    
    	private bool Autentica(string usu, string pass)
    	{
    	
    		using (SqlConnection cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["BD_DESARROLLOConnetionString"].ToString()))
    		{
    			cnn.Open();
    			string query = "SELECT COUNT(*) FROM USUARIO WHERE USU=@USU AND PASS = @pass";
    			SqlCommand cmd = new SqlCommand(query, cnn);
    			cmd.Parameters.AddWithValue("@USU", usu);
    			cmd.Parameters.AddWithValue("@pass", pass);
    			SqlDataReader reader = cmd.ExecuteReader();
    			
    			int result = Convert.ToInt32(cmd.ExecuteScalar());
    			
    			return result != 0
    		}
    
    	}

    no definas el connection y command de forma global, se puede definir localmente en el metodo

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    lunes, 27 de enero de 2014 12:13
  • Hola, Tuttini.

    Vos decís: Pero que pasa si alguien se quiere llevar la funcionalida de autenticar par aimplementarla en otra funcionalidad?

    digo sin declarar variables por fuera de de este no podrias llevartelo, ahi es donde apunto, autenticar es una funcionalidad que deberia tener una responsabilidad simple, no necesita algo global para informar de algun problema

    Si te fíjas el método autenticar es privado y de tal forma no se va a poder autoimplementar desde otra parte, tenes razón en que quizás no necesite otra variable para informar de algún problema, es cierto, pero todavía no se porque debería de caer en un error de encapsulamiento, si es cierto mensaje es una variable global pero solo para esta clase ya que se sigue manteniendo como privada y no es accesible desde otra clase,

    Me podes explicar por qué al usar la variable mensaje cae en error de encapsulación?


    Carlos Márquez

    lunes, 27 de enero de 2014 12:37
  • Hola, Tuttini.

    Para cerrar esta pregunta, entonces lo que vos queres decir es que no es una cuestión de variable publica porque la variable es privada, mas pasa por la cuestión del ámbito y que la funcionalidad está amarrada a la variable mensaje que es una variable global, entonces si alguien quisiera hacer uso de ella tendría que declarar siempre esa variable donde vaya a utilizar esa funcionalidad o en su defecto crear una variable como propiedad, todo esto pudiéndose evitar de la forma como propusiste. No pasa por ser una cuestión que No se pueda usar variables globales porque Si se puede, claro siempre recordando que se debe de usar el ámbito mas pequeño.

    Te entendí bien?


    Carlos Márquez

    martes, 28 de enero de 2014 1:11
  • mas pasa por la cuestión del ámbito y que la funcionalidad está amarrada a la variable mensaje que es una variable global,

    exacto, la idea es definir las cosas con la menor ambito que sea necesario

    no pasa por u  tema de poder o no poder, sino por un tema de como diseñas de forma reutilizable y mantenible, lo global siempre es sinonimo de problemas, a veces es necesario la cuestion es que no sea todo global

    si vas a definir una funcionalidad que valida digamos temperatudas, no definas los alores de las temperaturas en una variable global y que el metodo lo tome de alli

    sino que la funciona reciba estos valores en concreto que debe usar, de esa forma si mas adelante alguine requiere de la misma funcionalidad puede llevarsela y reusarla si tener que estar revisando todo el codigo para ver donde sale cada variable

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    martes, 28 de enero de 2014 11:18