使用SignalR,当hub方法返回特定值时,是否有可能调用.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
}
替代方法是抛出异常,但我想避免这种情况,因为错误实际上不是服务器故障,而是用户故障。
答案 0 :(得分:2)
假设您确信异常不是适合您的工具,您可以使用一些自定义属性来标记必须将false
返回值转换为错误的方法,然后拦截任何来自BuildIncoming
的{{1}}来电:
从里面你可以拦截对原始方法的调用,检查它是否标记了你的属性以及它是否返回HubPipelineModule
,如果是这种情况你可以从那里抛出异常。最重要的是,您仍然会抛出异常使其调用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
。
答案 1 :(得分:0)
正如Wasp指出的那样,使用SignalR JavaScript客户端,只有在设置hubResult.Error
时才会拒绝承诺,只有在处理请求时抛出异常才会发生这种情况。没有办法使用集线器管道修改它。
一般情况下,我可能会坚持使用例外情况,但如果您正在寻找其他替代方案,您还可以修改客户端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方法都会拒绝promise。 与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) { });
这样,您就可以完全控制如何解释返回值。