Cre*_*esh 12 sql-server error-handling web-services
我们使用存储过程在数据库中实现大多数业务规则.
我永远无法决定如何最好地将数据约束违规错误从数据库传递回用户界面.我所谈论的约束更多地依赖于业务规则而不是数据完整性.
例如,诸如"无法插入重复键行"之类的db错误与业务规则"您不能具有多个具有相同名称的Foo"相同.但是我们已经在最常识的位置"实现"了它:作为一个唯一的约束,当规则被违反时抛出异常.
其他规则,例如"你每天只允许100个Foos"不会导致错误,因为它们由自定义代码优雅地处理,例如return empty dataset应用程序代码检查并传递回ui层.
这就是问题所在.我们的ui代码看起来像这样(这是AJAX.NET webservices代码,但任何ajax框架都可以):
WebService.AddFoo("foo", onComplete, onError); // ajax call to web service
function onComplete(newFooId) {
if(!newFooId) {
alert('You reached your max number of Foos for the day')
return
}
// update ui as normal here
}
function onError(e) {
if(e.get_message().indexOf('duplicate key')) {
alert('A Foo with that name already exists');
return;
}
// REAL error handling code here
}
Run Code Online (Sandbox Code Playgroud)
(作为旁注:我注意到这是stackoverflow在您提交评论过快时所执行的操作:服务器生成HTTP 500响应并且ui捕获它.)
所以你看,我们在这里处理两个地方的业务规则违规,其中一个(即唯一的constaint错误)作为特殊情况处理,应该处理真正的错误(而不是违反业务规则),因为.NET将Exceptions一直传播到onError()处理程序.
这感觉不对.我认为我的选择是:
"select name from Foo where name = @Name")并返回app服务器期望的"违反业务规则"标志,insert into Foo捕获任何异常并将其转换为应用服务器期望的"业务规则违反"标志insert into Foo(如3)并让Exception传播到ui,并让app服务器将业务规则违规提升为真实Exceptions(而不是1).这样,所有错误都在ui层onError()(或类似)代码中处理.我喜欢的2)和3)是业务规则违规被"抛出" 它们被实现的地方:在存储过程中.我不喜欢1)和3)我认为它们涉及愚蠢的检查"if error.IndexOf('duplicate key')",就像目前ui层中的内容一样.
编辑:我喜欢4),但大多数人都说Exception只在特殊情况下使用s .
那么,你们如何优雅地处理传播业务规则违规行为?
我们不在数据库中执行业务逻辑,但我们确实拥有所有验证服务器端,低级DB CRUD操作与更高级别的业务逻辑和控制器代码分开.
我们在内部尝试做的是传递具有类似函数的验证对象Validation.addError(message,[fieldname]).各种应用程序层将其验证结果附加到此对象上,然后我们调用Validation.toJson()以生成如下所示的结果:
{
success:false,
general_message:"You have reached your max number of Foos for the day",
errors:{
last_name:"This field is required",
mrn:"Either SSN or MRN must be entered",
zipcode:"996852 is not in Bernalillo county. Only Bernalillo residents are eligible"
}
}
Run Code Online (Sandbox Code Playgroud)
这可以很容易地在客户端处理,以显示与各个字段以及一般消息相关的消息.
关于约束违规,我们使用#2,即我们在插入/更新之前检查潜在的违规,并将错误附加到验证对象.
存储过程可以使用 RAISERROR 语句将错误信息返回给调用者。其使用方式可以允许用户界面决定错误的显示方式,同时允许存储过程提供错误的详细信息。
可以使用msg_id、严重性和状态以及一组错误参数来调用 RAISERROR 。以这种方式使用时,必须已使用 sp_addmessage 系统存储过程将具有给定msg_id的消息输入到数据库中。此msg_id可以作为 SqlException 中的 ErrorNumber 属性进行检索,该异常将在调用存储过程的 .NET 代码中引发。然后,用户界面可以决定显示哪种类型的消息或其他指示。
错误参数被替换到生成的错误消息中,类似于printf语句在 C 中的工作方式。但是,如果您只想将参数传递回 UI,以便 UI 可以决定如何使用它们,只需将错误消息设置为没有文本,只有参数的占位符。一条消息可能是 '"%s"|%d',用于传回字符串参数(用引号引起来)和数字参数。.NET 代码可以将它们分开,并按照您喜欢的方式在用户界面中使用它们。
RAISERROR 还可以用在存储过程的 TRY CATCH 块中。这将允许您捕获重复键错误,并将其替换为您自己的错误号,这意味着代码中“插入时出现重复键”,并且它可以包含实际的键值。您的 UI 可以使用它来显示“订单号已存在”,其中“x”是提供的键值。
| 归档时间: |
|
| 查看次数: |
10790 次 |
| 最近记录: |