C# System.Data.SqlClient.SqlException:“将nvarchar值“STORES”转换为数据类型int时,转换失败。”

C# System.Data.SqlClient.SqlException:“将nvarchar值“STORES”转换为数据类型int时,转换失败。”,c#,sql-server,exception,stored-procedures,asmx,C#,Sql Server,Exception,Stored Procedures,Asmx,我正在C asmx Web服务中执行一个存储过程。 存储过程如下所示: @userName NVARCHAR(50), @password NVARCHAR(50), @defaultTabApp NVARCHAR(20) OUT AS Declare @defaultTabApptemp NVARCHAR(20) set @defaultTabApptemp ='NoAccess' BEGIN TRANSACTION if EXISTS(SELECT Top 1 [userId],[

我正在C asmx Web服务中执行一个存储过程。 存储过程如下所示:

@userName NVARCHAR(50),
@password NVARCHAR(50),
@defaultTabApp NVARCHAR(20) OUT
AS
Declare @defaultTabApptemp NVARCHAR(20)
set @defaultTabApptemp ='NoAccess'
BEGIN TRANSACTION
    if EXISTS(SELECT Top 1  [userId],[userName] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes') 
    Begin
       set @defaultTabApptemp = (select Top 1 [dbo].[users].[defaultTabApp] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes')
    end
 select @defaultTabApp =  @defaultTabApptemp 

COMMIT TRANSACTION
return @defaultTabApp

我的c代码是:

[WebMethod]
        public string Login(string userName, string userPass)
        {
            string result;
            SqlConnection conn = new SqlConnection(new DBConnection().ConnectionString);
           
            try
            {

                SqlCommand cmd = new SqlCommand("_getSpecificUserLogin", conn);
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                
                if (conn.State == System.Data.ConnectionState.Closed)
                {
                    conn.Open();
                }
                
                cmd.Parameters.AddWithValue("@userName", userName);
                cmd.Parameters.AddWithValue("@password", userPass);
               

                cmd.Parameters.Add("@defaultTabApp", SqlDbType.NVarChar,20);
                cmd.Parameters["@defaultTabApp"].Direction = ParameterDirection.Output;
                int i = cmd.ExecuteNonQuery();
                result = Convert.ToString(cmd.Parameters["@defaultTabApp"].Value);

            }


            finally
            {
                conn.Close();
            }
            return result;
}
我得到了这一行标题中的异常:int i=cmd.ExecuteNonQuery;我试图将其更改为executescalar,但遇到了相同的问题。我的存储过程中没有int类型。到底是什么问题?提前感谢。

RETURN只能返回int。您已经使用了OUT参数,应该删除存储过程末尾的RETURN@defaultTabApp语句。

替换

Declare @defaultTabApptemp NVARCHAR(20)
set @defaultTabApptemp ='NoAccess'
BEGIN TRANSACTION
    if EXISTS(SELECT Top 1  [userId],[userName] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes') 
    Begin
       set @defaultTabApptemp = (select Top 1 [dbo].[users].[defaultTabApp] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes')
    end
 select @defaultTabApp =  @defaultTabApptemp 

COMMIT TRANSACTION
return @defaultTabApp


您的登录过程的基本框架应该如下所示

请注意,您不需要事务,也不需要首先检查是否存在任何内容,这是由它为输出变量赋值这一事实所暗示的

如果密码不正确,或者没有为用户启用的应用程序,则您的代码无法处理这种情况

实际上,您将首先验证用户,并为他们分配某种票证,以表明他们已成功登录,并且不会重复检查他们的密码;当需要获取他们的默认应用程序时,他们已经通过了身份验证

如果一个用户可以拥有多个appAccess='Yes',则只需要使用top 1,在这种情况下,您缺少排序标准,用户将根据这些标准选择正确的用户-如果没有特定的order子句,则该值基本上是随机的

输出参数的正确语法为output

我还希望,如果这是一个面向公众的应用程序,那么密码不是纯文本,而是作为用户密码的散列存储在数据库中

create procedure UserLogin
@userName nvarchar(50),
@password nvarchar(50), -- This should be a HASH of the user's password, performed by the application
@defaultTabApp nvarchar(20) output
as
set nocount on
set @defaultTabApp='Default failure message'

select top 1 @defaultTabApp=defaultTabApp
from dbo.Users
where AppAccess=N'Yes'
    and Username=@userName and [Password]=@password 
order by <<criteria if there are more than 1 matching rows>>
Go

你的程序似乎有点混乱。您是否使用SSMS运行该过程并检查其输出是否正确?我认为您的语法不正确,或者无法将RETURN语句用于您想要的目的。请提供表架构和示例数据。如果存在,则不需要…选择。。。您可以在一行中完成所有操作,然后您也不需要事务处理我希望您没有存储明文密码…实际上,我的同事编写了存储过程,我应该编写Web服务的c代码。所以最好不要使用返回声明?谢谢,先生。我按照你的建议删除了return语句,它成功了。只需了解一件事,如果使用out参数,则不应返回。因此,如果我想从存储过程中得到一个值,return语句不是实现这一点的方法。不完全是这样,您可以有输出参数和一个返回值;它们由调用的app/function/proc进行不同的处理。返回值只能返回整数,通常用于表示成功或失败,输出参数可以是任何值。非常感谢,先生。问题是webservice将用于具有选项卡布局的android应用程序。每个选项卡对应一个部门。每个用户也是如此。我们想要的是,当用户输入他的凭证时,用户名和密码将成为调用存储过程的webservice方法的输入。如果用户名和密码正确,并且用户可以访问应用程序,那么程序应该返回他相应的部门,这样在我的应用程序中,我会在登录后将他引导到相应的选项卡。抱歉,评论太长,我想澄清Web服务和存储过程的用途,这样我就可以从您的建议中获益。您还没有澄清,但我只想强调不在应用程序、Web服务和数据库之间发送密码的重要性;数据库不应存储加密或未加密的密码。在发送或在任何地方使用密码之前,应用程序应始终对密码进行哈希处理,并且只应存储哈希值,最好是盐渍值。如果密码的哈希值与存储的哈希值匹配,则密码是正确的。这样,当你的数据库遭到黑客攻击,你所有的密码都被盗时,你就不会在下一次全球媒体发布会上出演主角-非常感谢,先生,我会试试的
create procedure UserLogin
@userName nvarchar(50),
@password nvarchar(50), -- This should be a HASH of the user's password, performed by the application
@defaultTabApp nvarchar(20) output
as
set nocount on
set @defaultTabApp='Default failure message'

select top 1 @defaultTabApp=defaultTabApp
from dbo.Users
where AppAccess=N'Yes'
    and Username=@userName and [Password]=@password 
order by <<criteria if there are more than 1 matching rows>>
Go