Search code examples
c#sql-serverwinformsstored-proceduressql-server-2014-express

How to get return value from stored procedure in Windows form C#


This is my procedure:

DECLARE @ReturnValue int

SELECT @ReturnValue = idUser
FROM Users
WHERE Alias = @UserAlias AND Password = @UserPassword 

RETURN @ReturnValue

This is my C# code where I'd hope I could retrieve the value from the procedure:

TeamPWSecureBD.Open(); //Open SQL Connection

string alias = textBoxUsernameLogin.Text.Trim();
string pass = textBoxPasswordLogin.Text;

SqlCommand LoginVerify = new SqlCommand("_spUserVerify", TeamPWSecureBD);
LoginVerify.CommandType = CommandType.StoredProcedure;

LoginVerify.Parameters.AddWithValue("@UserAlias", alias);
LoginVerify.Parameters.AddWithValue("@UserPassword", pass);

SqlDataReader UserVerify = LoginVerify.ExecuteReader();

//Se o valor retornado pelo sp for 0 significa que o user não existe.
//O sp retorna o id do utilizador se o username e a password estiverem corretas.
//O id de utilizador menor é o 7.
if (Convert.ToInt32(UserVerify.GetSqlValue(0)) == 0)
    MessageBox.Show("Invalid username/password.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
else
{
    GlobalVariables.UserLoggedIn = Convert.ToInt32(UserVerify.GetSqlValue(0));
    PWLists MainForm = new PWLists();
    MainForm.ShowDialog();
    this.Close();
}

When I execute the procedure in SQL Server, the returned value is correct.

But once I try to read it in the form it crashes with error:

invalid attempt to read when no data is present


Solution

  • If you want to catch the value of the RETURN statement executed by your stored proceduere you need to add another parameter to your SqlCommand

     SqlParameter r = LoginVerify.Parameters.Add("@return", SqlDbType.Int);
     r.Direction = ParameterDirection.ReturnValue;
     r.Value = 0;
     SqlDataReader UserVerify = LoginVerify.ExecuteReader();
    
     // Now you need to complete the reading from the UserVerify reader and 
     // finally you can catch the return value 
     .....
    
     UserVerify.Close();
     int result = (int)r.Value;
    

    However, given the code of your StoredProcedure, I think you could simply avoid to declare another parameter and also the SqlDataReader because you seem to return just one row with one field. The exact scope for ExecuteScalar...

    SP is now just a select

    SELECT idUser FROM Users 
    WHERE Alias = @UserAlias AND Password = @UserPassword 
    

    and the code to retrieve the idUser is

    object result = LoginVerify.ExecuteScalar();
    
    if (result == null)
        MessageBox.Show("Invalid username/password.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
    else
    {
        GlobalVariables.UserLoggedIn = Convert.ToInt32(result);
        PWLists MainForm = new PWLists();
        MainForm.ShowDialog();
        this.Close();
    }