如何解决Try...catch 在围绕存储过程执行时不起作用
在我的 web api 数据访问层中,Asp.net TRY CATCH 没有捕获存储过程的失败。注意:此代码模板用于丢弃我的 web api 数据访问层并且工作正常。只是在这种情况下不是。奇怪的!! (我在底部包含了一个类似且有效的示例)。
我希望存储过程失败,因为没有符合条件的行。因此,在这种情况下,我会引发错误 (RAISERROR) 并将一个条目写入我的错误日志表。
当我通过 SSMS 执行它或运行调用执行存储过程的 Web api 的 Web 应用程序时会发生这种情况。
包含 2 个条目的错误日志表。 1 来自通过 SSMS 运行存储过程,另一个来自运行我的网络应用程序。
问题是web api数据访问层代码执行没有捕捉到存储过程返回的错误。它不会进入 CATCH。
这是从我的 web api 控制器调用的 web api 数据访问层函数。它的 TRY CATCH 无法正常工作:
public List<BlogPublishedCategory>
GetBlogCategorysInBlogsPublishedList(string userName,string ipAddress)
{
string userFriendlyMessage = "Unable to get the blog categorys in the
blogs published list. We have been notified and are working to resolve
this. Please do not continue.";
List<BlogPublishedCategory> blogPublishedCategoryList = new
List<BlogPublishedCategory>();
sqlDataReader blogCategorysInBlogsDataReader = null;
try
{
dbFunc.OpenDB();
sqlCommand cmd = new sqlCommand("dbo.GetBlogCategorysInBlogsPublished",dbFunc.objConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@a_UserName",userName);
cmd.Parameters.AddWithValue("@a_IpAddress",ipAddress);
blogCategorysInBlogsDataReader = cmd.ExecuteReader();
while (blogCategorysInBlogsDataReader.Read())
{
// Add to the list of BlogPublishedCategory - creates a new row for the collection.
blogPublishedCategoryList.Add(new BlogPublishedCategory
{
BlogCategoryId = Convert.ToInt32(blogCategorysInBlogsDataReader["BlogCategoryId"]),BlogCategoryDescr = blogCategorysInBlogsDataReader["BlogCategoryDescr"].ToString(),});
}
// Return the blogPublishedCategoryList object.
return blogPublishedCategoryList;
}
catch (sqlException sqlex)
{
if (sqlex.Message.Contains("Critical"))
{
currentDateTime = DateTime.Now;
senDalertEmailResult = SenDalertEmailToStaff(currentDateTime,userName,ipAddress);
if (senDalertEmailResult == "")
{
throw new Exception(userFriendlyMessage);
}
else
{
throw new Exception("In DataAccessLayer/GetBlogCategorysInBlogsPublishedList(). Sending an alert email for the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + senDalertEmailResult);
}
}
else
{
errorMessage = "sql Exception Error in DataAccessLayer/GetBlogCategorysInBlogsPublishedList(). Using 'GetBlogCategorysInBlogsPublished' s/p. Error: " + sqlex.Message;
currentDateTime = DateTime.Now;
processErrorLogAndSenDalertEmailResult = ProcessErrorLogAndSenDalertEmail(currentDateTime,errorMessage,additionalInfoForLog,ipAddress);
if (processErrorLogAndSenDalertEmailResult != "")
{
throw new Exception("Error in DataAccessLayer/GetBlogCategorysInBlogsPublishedList(). Using 'GetBlogCategorysInBlogsPublished' s/p. Logging the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + processErrorLogAndSenDalertEmailResult);
}
else
{
throw new Exception(userFriendlyMessage);
}
}
}
catch (Exception ex)
{
errorMessage = "Error in DataAccessLayer/GetBlogCategorysInBlogsPublishedList(). Using 'GetBlogCategorysInBlogsPublished' s/p. Error: " + ex.Message;
currentDateTime = DateTime.Now;
processErrorLogAndSenDalertEmailResult = ProcessErrorLogAndSenDalertEmail(currentDateTime,ipAddress);
if (processErrorLogAndSenDalertEmailResult != "")
{
throw new Exception("Error in DataAccessLayer/GetBlogCategorysInBlogsPublishedList(). Using 'GetBlogCategorysInBlogsPublished' s/p. Logging the initial error: " + ex.Message + ". Now getting this error: " + processErrorLogAndSenDalertEmailResult);
}
else
{
throw new Exception(userFriendlyMessage);
}
}
finally
{
if (blogCategorysInBlogsDataReader != null)
{
blogCategorysInBlogsDataReader.Close();
}
dbFunc.CloseDB();
}
}
GetBlogCategorysInBlogsPublished 存储过程(由于行数为 0,因此失败):
USE [DBGbngDev]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].
[GetBlogCategorysInBlogsPublished]') AND type in (N'P',N'PC'))
BEGIN
DROP PROCEDURE [dbo].GetBlogCategorysInBlogsPublished
END
GO
CREATE procedure [dbo].[GetBlogCategorysInBlogsPublished]
@a_UserName varchar(250) = NULL,@a_IpAddress varchar(250) = NULL
AS
BEGIN
DECLARE @RowCount int,@ReturnCode int,@CurrentDateTime datetime,@Message varchar(max) = '',@ApiMessageOut varchar(max),@ApiAccessSwitchOut bit
DECLARE @ErrorLine AS INT;
DECLARE @ErrorMessage AS VARCHAR(2048);
DECLARE @ErrorNumber AS INT;
DECLARE @ErrorSeverity AS INT;
DECLARE @ErrorState AS INT;
DECLARE @DatabaseName AS VARCHAR(255);
DECLARE @ServerName AS VARCHAR(255);
DECLARE @ErrorDescription AS VARCHAR(MAX);
DECLARE @CRLF AS VARCHAR(2);
SELECT @CurrentDateTime = GETDATE()
BEGIN TRY
SET NOCOUNT ON;
IF ( ( @a_UserName = '' OR @a_UserName IS NULL )
OR ( @a_IpAddress = '' OR @a_IpAddress IS NULL ) )
BEGIN
SELECT @Message = 'Critical Error - procedure GetBlogCategorysInBlogsPublished - invalid
parameters. They cannot be null or empty.'
IF ( @a_UserName = '' OR @a_UserName IS NULL )
BEGIN
SET @a_UserName = 'No "user name" parameter provided.'
END
IF ( @a_IpAddress = '' OR @a_IpAddress IS NULL )
BEGIN
SET @a_IpAddress = 'No "ip address" parameter provided.'
END
RAISERROR (@Message,16,1)
END
ELSE
BEGIN
-- Do the API security check. If this user is valid,you can continue with further
processing.
SELECT @ReturnCode = -1
EXECUTE @ReturnCode = dbo.GetApiAccess
@CurrentDateTime,@a_UserName,@a_IpAddress,@a_ApiAccessSwitchFromGet = @ApiAccessSwitchOut OUTPUT,@a_ApiMessageFromGet = @ApiMessageOut OUTPUT
IF @ReturnCode = -1
BEGIN
RAISERROR ('Critical Error - procedure GetBlogCategorysInBlogsPublished Failed during execute of procedure GetApiAccess.',1 )
END
-- Web api access was granted.
IF @ApiAccessSwitchOut = 1
BEGIN
SELECT disTINCT (a.BlogCategoryId) as BlogCategoryId,a.BlogCategoryDescr as BlogCategoryDescr
FROM dbo.BlogCategory a
JOIN dbo.Blog b On ( a.BlogCategoryId = b.BlogCategoryId )
WHERE ( b.PublishSwitch = 1 AND b.CanBeSeenSwitch = 1 )
ORDER BY a.BlogCategoryId asc
SELECT @ReturnCode = @@ERROR,@RowCount = @@ROWCOUNT
IF @ReturnCode <> 0
BEGIN
SELECT @Message = 'Critical Error - procedure GetBlogCategorysInBlogsPublished Failed during the select.'
RAISERROR (@Message,1)
END
IF @RowCount = 0
BEGIN
SELECT @Message = 'Critical Error - procedure GetBlogCategorysInBlogsPublished Failed during the select. There are no BlogCategory entries.'
RAISERROR (@Message,1)
END
END
ELSE
BEGIN
-- Web api access was NOT granted. The user did not have permission to use the web api or there is an error in the GetApiAccess procedure.
RAISERROR (@ApiMessageOut,1 )
END
END
-- Returns success.
RETURN 0
END TRY
BEGIN CATCH
SELECT
@ErrorLine = ERROR_LINE()
-- ERROR_MESSAGE() contains the RAISERROR message raised above.,@ErrorMessage = ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@DatabaseName = CAST(DB_NAME() AS VARCHAR),@ServerName = CAST(SERVERPROPERTY ( 'ServerName' ) AS VARCHAR),@CRLF = CHAR(13) + CHAR(10)
SET @ErrorDescription = 'From stored procedure: ' + ERROR_PROCEDURE()
+ '. Error Line: ' + CAST(@ErrorLine AS VARCHAR)
+ '. Error Message: ' + @ErrorMessage
+ ' Error Number: ' + CAST(@ErrorNumber AS VARCHAR)
+ '. Error Severity: ' + CAST(@ErrorSeverity AS VARCHAR)
+ '. Error State: ' + CAST(@ErrorState AS VARCHAR)
+ '. Database Name: ' + @DatabaseName
+ '. Server Name: ' + @ServerName
IF (XACT_STATE() <> 0)
BEGIN
ROLLBACK TRANSACTION
END
IF (@ErrorSeverity = 16) AND (@ErrorState = 2)
BEGIN
RAISERROR(@ErrorMessage,@ErrorSeverity,@ErrorState)
END
ELSE
BEGIN
-- Log the critical error.
BEGIN TRY
EXEC dbo.InsertBlogErrorLog
@a_LogDateTime = @CurrentDateTime,@a_UserName = @a_UserName,@a_UserIpAddress = @a_IpAddress,@a_ObjectID = @@PROCID,@a_MessageType = 'S/P Critical Error',@a_LogMessage = @ErrorDescription
END TRY
BEGIN CATCH
-- Stack the messages.
SELECT @Message = 'Critical Error - procedure InsertBlogErrorLog Failed. A log entry cannot be made. Do not continue. Contact IT. Initial error message: ' + @ErrorMessage
RAISERROR(@Message,1)
END CATCH
SELECT @message = 'Critical Error - do not continue. Contact IT and provide this log date: ' + Convert(VARCHAR,@CurrentDateTime,21)
RAISERROR(@Message,1)
END
-- Returns failure.
RETURN 1
END CATCH
END
这是一个类似的例子,我在存储过程中强制出现错误,以表明类似(几乎相同)的 web api 数据访问层函数确实捕获了存储过程错误。
带有条目的错误日志表。从运行我的 web api。
DOES 捕获存储过程返回的错误的 web api 数据访问层代码执行。它确实进入 CATCH 并执行我期望的处理。
这是从我的 web api 控制器调用的 web api 数据访问层函数。它具有正常工作的 TRY CATCH:
public List<BlogCategory> GetBlogCategoryList(string userName,string ipAddress)
{
string userFriendlyMessage = "Unable to get blog categories. We have been notified and are working to resolve this. Please do not continue.";
List<BlogCategory> blogCategoryList = new List<BlogCategory>();
sqlDataReader blogCategoryDataReader = null;
try
{
dbFunc.OpenDB();
sqlCommand cmd = new sqlCommand("dbo.GetBlogCategory",dbFunc.objConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@a_UserName",userName);
cmd.Parameters.AddWithValue("@a_IpAddress",ipAddress);
blogCategoryDataReader = cmd.ExecuteReader();
while (blogCategoryDataReader.Read())
{
blogCategoryList.Add(new BlogCategory
{
BlogCategoryId = Convert.ToInt32(blogCategoryDataReader["BlogCategoryId"]),BlogCategoryDescr = blogCategoryDataReader["BlogCategoryDescr"].ToString(),});
}
return blogCategoryList;
}
catch (sqlException sqlex)
{
if (sqlex.Message.Contains("Critical"))
{
// A "critical" error coming from the stored procedure.
// So,send an alert email to a staff member (an Admin),but do NOT process the error log as it has been done already
// in the stored procedure.
currentDateTime = DateTime.Now;
senDalertEmailResult = SenDalertEmailToStaff(currentDateTime,ipAddress);
if (senDalertEmailResult == "")
{
throw new Exception(userFriendlyMessage);
}
else
{
throw new Exception("In DataAccessLayer/GetBlogCategoryList(). Sending an alert email for the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + senDalertEmailResult);
}
}
else
{
// Not coming from the stored procedure. Like if the stored procedure above was not named properly,does not exist,parameter missing,etc.
errorMessage = "sql Exception Error in DataAccessLayer/GetBlogCategoryList(). Using 'GetBlogCategory' s/p. Error: " + sqlex.Message;
// Log the error and send an alert email.
currentDateTime = DateTime.Now;
processErrorLogAndSenDalertEmailResult = ProcessErrorLogAndSenDalertEmail(currentDateTime,ipAddress);
if (processErrorLogAndSenDalertEmailResult != "")
{
throw new Exception("Error in DataAccessLayer/GetBlogCategoryList(). Using 'GetBlogCategory' s/p. Logging the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + processErrorLogAndSenDalertEmailResult);
}
else
{
throw new Exception(userFriendlyMessage);
}
}
}
catch (Exception ex)
{
errorMessage = "Error in DataAccessLayer/GetBlogCategoryList(). Using 'GetBlogCategory' s/p. Error: " + ex.Message;
currentDateTime = DateTime.Now;
processErrorLogAndSenDalertEmailResult = ProcessErrorLogAndSenDalertEmail(currentDateTime,ipAddress);
if (processErrorLogAndSenDalertEmailResult != "")
{
throw new Exception("Error in DataAccessLayer/GetBlogCategoryList(). Using 'GetBlogCategory' s/p. Logging the initial error: " + ex.Message + ". Now getting this error: " + processErrorLogAndSenDalertEmailResult);
}
else
{
throw new Exception(userFriendlyMessage);
}
}
finally
{
if (blogCategoryDataReader != null)
{
blogCategoryDataReader.Close();
}
dbFunc.CloseDB();
}
}
这是 GetBlogCategory 存储过程(它失败了,因为我强制设置了 rowcount = 0 ):
USE [DBGbngDev]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].
[GetBlogCategory]') AND type in (N'P',N'PC'))
BEGIN
DROP PROCEDURE [dbo].GetBlogCategory
END
GO
CREATE procedure [dbo].[GetBlogCategory]
@a_UserName varchar(250) = NULL,@a_IpAddress varchar(250) = NULL
AS
BEGIN
DECLARE @RowCount int,@ApiAccessSwitchOut bit
SELECT @CurrentDateTime = GETDATE()
DECLARE @ErrorLine AS INT;
DECLARE @ErrorMessage AS VARCHAR(2048);
DECLARE @ErrorNumber AS INT;
DECLARE @ErrorSeverity AS INT;
DECLARE @ErrorState AS INT;
DECLARE @DatabaseName AS VARCHAR(255);
DECLARE @ServerName AS VARCHAR(255);
DECLARE @ErrorDescription AS VARCHAR(MAX);
DECLARE @CRLF AS VARCHAR(2);
BEGIN TRY
SET NOCOUNT ON;
IF ( ( @a_UserName = '' OR @a_UserName IS NULL ) OR ( @a_IpAddress = '' OR @a_IpAddress IS NULL ) )
BEGIN
SELECT @Message = 'Critical Error - procedure GetBlogCategory - invalid parameters. They cannot be null or empty.'
IF ( @a_UserName = '' OR @a_UserName IS NULL )
BEGIN
SET @a_UserName = 'No "user name" parameter provided.'
END
IF ( @a_IpAddress = '' OR @a_IpAddress IS NULL )
BEGIN
SET @a_IpAddress = 'No "ip address" parameter provided.'
END
RAISERROR (@Message,you can continue with further processing.
SELECT @ReturnCode = -1
EXECUTE @ReturnCode = dbo.GetApiAccess
@CurrentDateTime,@a_ApiMessageFromGet = @ApiMessageOut OUTPUT
IF @ReturnCode = -1
BEGIN
RAISERROR ('Critical Error - procedure GetBlogCategory Failed during execute of procedure GetApiAccess.',1 )
END
-- Web api access was granted.
IF @ApiAccessSwitchOut = 1
BEGIN
--SELECT BlogCategoryId as BlogCategoryId
--,BlogCategoryDescr as BlogCategoryDescr
--FROM dbo.BlogCategory
--ORDER BY BlogCategoryDescr asc
--SELECT @ReturnCode = @@ERROR,-- @RowCount = @@ROWCOUNT
--IF @ReturnCode <> 0
-- BEGIN
-- SELECT @Message = 'Critical Error - procedure GetBlogCategory Failed during the select.'
-- RAISERROR (@Message,1)
-- END
SET @RowCount = 0
IF @RowCount = 0
BEGIN
SELECT @Message = 'Critical Error - procedure GetBlogCategory Failed during the select. There are no entries.'
RAISERROR (@Message,1)
END
END
ELSE
BEGIN
-- Web api access was NOT granted. The user did not have permission to use the web api or there is an error in the GetApiAccess procedure.
-- Pass the message returned from the GetApiAccess procedure.
RAISERROR (@ApiMessageOut,1 )
END
END
-- Returns success.
RETURN 0
END TRY
BEGIN CATCH
SELECT
@ErrorLine = ERROR_LINE()
-- ERROR_MESSAGE() contains the RAISERROR message raised above.,@CRLF = CHAR(13) + CHAR(10)
SET @ErrorDescription = 'From stored procedure: ' + ERROR_PROCEDURE()
+ '. Error Line: ' + CAST(@ErrorLine AS VARCHAR)
+ '. Error Message: ' + @ErrorMessage
+ ' Error Number: ' + CAST(@ErrorNumber AS VARCHAR)
+ '. Error Severity: ' + CAST(@ErrorSeverity AS VARCHAR)
+ '. Error State: ' + CAST(@ErrorState AS VARCHAR)
+ '. Database Name: ' + @DatabaseName
+ '. Server Name: ' + @ServerName
IF (XACT_STATE() <> 0)
BEGIN
ROLLBACK TRANSACTION
END
IF (@ErrorSeverity = 16) AND (@ErrorState = 2)
BEGIN
RAISERROR(@ErrorMessage,@ErrorState)
END
ELSE
BEGIN
-- Log the critical error.
BEGIN TRY
EXEC dbo.InsertBlogErrorLog
@a_LogDateTime = @CurrentDateTime,@a_LogMessage = @ErrorDescription
END TRY
BEGIN CATCH
-- Stack the messages.
SELECT @Message = 'Critical Error - procedure InsertBlogErrorLog Failed. A log entry cannot be made. Do not continue. Contact IT. Initial error message: ' + @ErrorMessage
RAISERROR(@Message,1)
END
-- Returns failure.
RETURN 1
END CATCH
END
Dan...我把我原来的 C# 循环代码放回去,我改变了失败的 s/p GetBlogCategorysInBlogsPublished,我完全删除了 SELECT disTINCT 子句,只是通过设置 @Rowcount = 0 来强制 RAISERROR。TRY CATCH 在web api 函数将其提取并正确处理。
然后我在 SSMS 中使用 SELECT disTINCT 并运行它。 在“结果”选项卡中,我看到了 2 个结果,即列标题和错误消息列。
这 2 个结果可能是问题所在吗?
在消息选项卡中,我得到:消息 50000,级别 16,状态 1,第 26 行 严重错误 - 过程 GetBlogCategorysInBlogsPublished 在选择过程中失败。没有博客类别条目。
然后我在 SSMS 中,在没有 SELECT 的情况下强制错误。 在“结果”选项卡中,我看到只有 1 列。
解决方法
确保使用数据访问层中的所有结果集以确保引发异常。使用 NextResult()
的示例模式:
do {
while (blogCategoryDataReader.Read())
{
blogCategoryList.Add(new BlogCategory
{
BlogCategoryId = Convert.ToInt32(blogCategoryDataReader["BlogCategoryId"]),BlogCategoryDescr = blogCategoryDataReader["BlogCategoryDescr"].ToString(),});
}
} while blogCategoryDataReader.NextResult();
原因是生成的异常消息RAISERROR
落后于底层表格数据流中SELECT查询生成的结果集。这实际上变成了客户端 API 必须使用的多个结果集,因此客户端应用程序将所有结果使用到 ensure exceptions are raised and can be detected 非常重要。
请注意,SSMS 使用 FireInfoMessagesOnUserErrors 连接属性而不是 try/catch 来显示用户错误以及其他上下文信息。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。