调用.fail(error)而不抛出异常
本文关键字:抛出异常 error fail 调用 | 更新日期: 2023-09-27 18:06:15
使用SignalR,当集线器方法返回特定值时,是否有可能调用.fail
而不是.done
?
也许使用SignalR管道?
public bool Delete(int addressId)
{
// User should not be able to delete default address
if(AddressService.IsDefaultAddressOfCustomer(addressId))
return false; // Should call .fail() on client
AddressService.Delete(addressId);
return true; // Should call .done() on client
}
另一种选择是抛出异常,但我希望避免这种情况,因为错误不是真正的服务器故障,而是用户故障。
假设您真的确信异常不是适合您的工具,您可以使用您将定义的一些自定义属性来标记方法,其中false
返回值必须转换为错误,然后拦截来自HubPipelineModule
的BuildIncoming
传入呼叫:
http://msdn.microsoft.com/en-us/library/microsoft.aspnet.signalr.hubs.hubpipelinemodule.buildincoming (v = vs.118) . aspx
从里面,你可以拦截调用你的原始方法,检查如果它被标记与你的属性,如果它返回false
,如果是这种情况下,你可以抛出一个异常从那里。底线是,您仍然会抛出异常以使其调用客户端.fail()
,但该异常不会使您的业务逻辑膨胀。像这样:
public class FailPipelineModule : HubPipelineModule
{
public override Func<IHubIncomingInvokerContext, Task<object>> BuildIncoming(Func<IHubIncomingInvokerContext, Task<object>> invoke)
{
return base.BuildIncoming(context =>
{
var r = (bool)(invoke(context)).Result;
if (context.MethodDescriptor.Attributes.Any(a => typeof(FailAttribute) == a.GetType()) && !r)
throw new ApplicationException("false");
return Task.FromResult((object)r);
});
}
}
你需要定义FailAttribute
,用它来标记集线器的方法,并在启动时注册FailPipelineModule
。
正如Wasp所指出的那样,使用SignalR JavaScript客户端,只有在设置了hubResult.Error
时才会拒绝承诺,这只有在处理请求时抛出异常时才会发生。没有办法使用hub管道来修改它。
一般来说,我可能会坚持使用异常在这种情况下,但如果你正在寻找另一种选择,你也可以修改客户端jquery.signalr-*.js
代码,特别是hubProxy原型invoke
方法。它有一个决定是解决还是拒绝承诺的条件:
if (result.Error) {
// code to reject ...
} else {
connection.log("Invoked " + that.hubName + "." + methodName);
d.resolveWith(that, [result.Result]);
}
你可以修改else代码块:
if (result.Error) {
// code to reject ...
} else {
connection.log("Invoked " + that.hubName + "." + methodName);
if (typeof result.Result === "boolean" && !result.Result) {
d.rejectWith(that, [result.Result]);
} else {
d.resolveWith(that, [result.Result]);
}
}
那么所有返回false的hub方法将拒绝承诺。与Wasp的解决方案相比,它的优势在于不必创建属性,而且总体上代码更少。缺点是,由于您手动编辑SignalR代码,因此它可能不太容易维护(因此,如果您这样做,它肯定应该在某处记录,并且您必须自己最小化脚本,而不是使用打包的脚本)。
一个更易于维护的客户端替代方案是包装集线器API,并返回你自己的延迟,例如:
var myHub = {
server: $.connection.myHub.server,
init: function() {
for (var methodName in this.server) {
if (this.server.hasOwnProperty(methodName)) {
this[methodName] = function() {
var deferred = $.Deferred();
this.server[methodName].apply(this.server, arguments)
.done(function(result) {
// reject if server hub method returned false
if (result === false) deferred.reject(result);
deferred.resolve(result);
});
return deferred.promise();
};
}
}
}
};
myHub.init();
然后不调用
$.connection.myHub.server.someMethod("hello", "world")
.done(function(result) { })
.fail(function(result) { });
你会调用
myHub.someMethod("hello", "world")
.done(function(result) { })
.fail(function(result) { });
这样,您就可以完全控制如何解释返回值。