Como posso capturar um erro de procedimento armazenado SQL acionado pelo raiseError () no arquivo .asmx?
-
12-09-2019 - |
Pergunta
Eu estou muito novo para .net. Tudo o que fiz até agora é implementar algumas chamadas de procedimento armazenadas do SQL como serviços da web, copiando e colando o código existente (conforme instruído pelo meu superior).
Estou chamando alguns comandos via Database.ExecuteNonQuery()
. No procedimento armazenado do SQL, estou realizando algumas verificações de segurança com base no loginid (um usuário pode editar apenas itens dos quais eles são o proprietário). Se a verificação de segurança falhar, estou chamando RaiseError () para acionar um erro, mas meu arquivo .asmx não está vendo isso como uma exceção e simplesmente sai do procedimento armazenado.
Meu arquivo ASMX:
[WebMethod]
public XmlDocument UpdateSomeItem(Int32 ItemIdNmb, String Foo)
{
try
{
// Create the Database object, using the default database service. The
// default database service is determined through configuration.
Database db = DatabaseFactory.CreateDatabase();
DbParameter param;
string sqlCommand = "updateSomeItem";
DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
db.AddInParameter(dbCommand, "ItemIdNmb", DbType.Int32, ItemIdNmb);
db.AddInParameter(dbCommand, "Foo", DbType.String, Foo);
db.AddInParameter(dbCommand, "UpdateLoginIdNmb", DbType.Int32, SessionLoginIdNmb);
#region Return Parameter
param = dbCommand.CreateParameter();
param.ParameterName = "Return";
param.Direction = ParameterDirection.ReturnValue;
param.DbType = DbType.Int32;
dbCommand.Parameters.Add(param);
#endregion
// Execute the Command
db.ExecuteNonQuery(dbCommand);
myDataSet = new DataSet();
myDataSet.DataSetName = "DataSet";
myDataSet.Tables.Add(errorDataTable);
statusDataRow["Status"] = "Success";
statusDataTable.Rows.Add(statusDataRow);
myDataSet.Tables.Add(statusDataTable);
returncodeDataRow["ReturnCode"] = dbCommand.Parameters["Return"].Value;
returncodeDataTable.Rows.Add(returncodeDataRow);
myDataSet.Tables.Add(returncodeDataTable);
xmlReturnDoc.LoadXml(myDataSet.GetXml());
return xmlReturnDoc;
}
// THIS IS WHERE I WANT MY RAISE ERROR TO GO
catch (Exception e)
{
return ReturnClientError(e, "someerror");
}
}
Meu procedimento armazenado SQL:
CREATE PROCEDURE updateSomeItem
(
@ItemIdNmb INT,
@Foo VARCHAR(100),
@UpdateLoginIdNmb INT
)
AS
SET NOCOUNT ON
/* If the user performing the action did not create the Item in question,
raise an error. */
IF NOT EXISTS
(
SELECT 1
FROM Items
WHERE IdNmb = @ItemIdNmb
AND LoginIdNmb = @UpdateLoginIdNmb
)
RAISERROR (
'User action not allowed - User is not the owner of the specified Item',
10,
1)
UPDATE Items
SET Foo = @Foo
WHERE IdNmb = @ItemIdNmb
RETURN 0
SET NOCOUNT OFF
GO
Solução 2
Atualizei meu procedimento armazenado com o seguinte:
/* If the user performing the action did not create the Item in question,
return a code other than 0. */
IF NOT EXISTS
(
SELECT 1
FROM Items
WHERE IdNmb = @ItemIdNmb
AND LoginIdNmb = @UpdateLoginIdNmb
)
RETURN 1
E eu lido com meu arquivo .asmx como este:
int returnValue = (int)dbCommand.Parameters["Return"].Value;
if (returnValue == 0)
statusDataRow["Status"] = "Success";
/* Stored Procedure will return a value of "1" if the user is
attempting to update an Item that they do not own. */
else
statusDataRow["Status"] = "Error";
statusDataTable.Rows.Add(statusDataRow);
myDataSet.Tables.Add(statusDataTable);
returncodeDataRow["ReturnCode"] = dbCommand.Parameters["Return"].Value;
returncodeDataTable.Rows.Add(returncodeDataRow);
myDataSet.Tables.Add(returncodeDataTable);
Outras dicas
O problema é que a gravidade do erro é muito baixa. As severidades 1 - 10 são tratadas como mensagens de informação e não quebram o fluxo de um aplicativo C#.
Uma explicação mais completa pode ser encontrada em um responda a partir de Remus Rusanu.