【发布时间】:2009-02-22 00:37:50
【问题描述】:
我们使用存储过程在数据库中实现大部分业务规则。
我永远无法决定如何最好地将数据约束违规错误从数据库传递回用户界面。我所说的约束更多地与业务规则相关,而不是数据完整性。
例如,“无法插入重复的键行”之类的 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
}
(附带说明:我注意到当您提交 cmets 过快时,stackoverflow 会执行此操作:服务器生成 HTTP 500 响应并且 ui 会捕获它。)
所以你看,我们在这里在两个地方处理违反业务规则的行为,其中一个(即唯一约束错误)作为应该处理真实的代码的特殊情况处理> 错误(不是违反业务规则),因为 .NET 将异常一直传播到 onError() 处理程序。
这感觉不对。我认为我的选择是:
- 在应用服务器级别捕获“重复密钥违规”异常,并将其转换为用户界面期望的任何“违反业务规则”标志,
-
抢占错误(例如,使用
"select name from Foo where name = @Name")并返回应用服务器期望的任何内容作为“违反业务规则”标志, - 与 2) 相同:利用 db 层内置的唯一约束并盲目地
insert into Foo,捕获任何异常并将其转换为应用服务器期望的任何内容,作为“违反业务规则”标志李> - 盲目地
insert into Foo(如 3)并让该异常传播到 ui,加上让应用服务器将业务规则违规作为真正的Exceptions(而不是 1)提出。这样,所有错误都在 ui 层的onError()(或类似)代码中处理。
我喜欢 2) 和 3) 的地方在于,违反业务规则的行为被“抛出”在哪里实施:在存储过程中。我不喜欢 1) 和 3) 是我认为它们涉及像 "if error.IndexOf('duplicate key')" 这样的愚蠢检查,就像当前 ui 层中的内容一样。
编辑:我喜欢 4),但大多数人说只在例外情况下使用Exceptions。
那么,你们如何优雅地处理将违反业务规则的行为传播到用户界面?
【问题讨论】:
标签: sql-server web-services error-handling