.net core signalR 全局异常处理
Hub的异常拦截
{ }
{ }
*:first-child { }
*:last-child { }
{ }
{ }
{ }
{ }
{ }
{ }
{ }
{ }
{ }
h6:first-child { }
{ }
{ }
{ }
{ }
{ }
{ }
{ }
{ }
{ }
{ }
:first-child { }
:last-child { }
{ }
:first-child { }
:last-child { }
{ }
{ }
code { }
{ }
{ }
{ }
{ }
:first-child { }
:last-child { }
{ }
{ }
{ }
{ }
{ }
{ }
{ color: rgba(255, 255, 255, 1); padding: 5px; background-color: rgba(43, 102, 149, 1); border: 1px solid rgba(255, 255, 255, 1); border-radius: 5px; font-size: 24px; margin-top: 15px; margin-bottom: 15px }
environment
.net core 5.0
主题
对于hub中的方法执行 实现一个全局的异常处理
食用方法
1.实现自定义拦截类:
Microsoft.AspNetCore.SignalR.IHubFilter
public class HubMethodFilter : IHubFilter
{
public async ValueTask<object?> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object?>> next)
{
try
{
return await next(invocationContext);
}
catch(Exception e)
{
do something
// write log,send notice....
}
}
}
2.注册拦截器
services.AddSignalR(hubOptions =>
{
hubOptions.AddFilter<HubMethodFilter>();
})
扩展
在自定义拦截类中可使用 .net core 的依赖注入
文档
可忽略的源码
扩展
首先从注册的地方查找:Microsoft.Extensions.DependencyInjection.SignalRDependencyInjectionExtensions:
public static ISignalRServerBuilder AddSignalR(this IServiceCollection services, Action<HubOptions> configure)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
if (services == null)
{
throw new ArgumentNullException("services");
}
ISignalRServerBuilder result = services.AddSignalR();
services.Configure<HubOptions>(configure);
return result;
} public static ISignalRServerBuilder AddSignalR(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
services.AddConnections();
services.Configure(delegate(WebSocketOptions o)
{
o.KeepAliveInterval = TimeSpan.Zero;
});
services.TryAddSingleton<SignalRMarkerService>();
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<HubOptions>, HubOptionsSetup>());
return services.AddSignalRCore();
}public static ISignalRServerBuilder AddSignalRCore(this IServiceCollection services)
{
services.TryAddSingleton<SignalRCoreMarkerService>();
services.TryAddSingleton(typeof(HubLifetimeManager<>), typeof(DefaultHubLifetimeManager<>));
services.TryAddSingleton(typeof(IHubProtocolResolver), typeof(DefaultHubProtocolResolver));
services.TryAddSingleton(typeof(IHubContext<>), typeof(HubContext<>));
services.TryAddSingleton(typeof(IHubContext<, >), typeof(HubContext<, >));
services.TryAddSingleton(typeof(HubConnectionHandler<>), typeof(HubConnectionHandler<>));
services.TryAddSingleton(typeof(IUserIdProvider), typeof(DefaultUserIdProvider));
services.TryAddSingleton(typeof(HubDispatcher<>), typeof(DefaultHubDispatcher<>));
services.TryAddScoped(typeof(IHubActivator<>), typeof(DefaultHubActivator<>));
services.AddAuthorization();
SignalRServerBuilder signalRServerBuilder = new SignalRServerBuilder(services);
signalRServerBuilder.AddJsonProtocol();
return signalRServerBuilder;
}
看完后你就能发现,在默认注册的类中,没有一个是符合需要的其中HubDispatcher<>最为迷惑,里面有提供异常处理,但类是internal的,只好当场离去
既然默认配置都没有,只好从参数上上手还好就一个参数,找到其对应的扩展类Microsoft.AspNetCore.SignalR.HubOptionsExtensions:
ps:你可能会问为啥直接找扩展类,->HubOptions类的公开属性你看一下就能明白了
/// <summary>
/// Methods to add <see cref="IHubFilter"/>'s to Hubs.
/// </summary>
public static class HubOptionsExtensions
{
/// <summary>
/// Adds an instance of an <see cref="IHubFilter"/> to the <see cref="HubOptions"/>.
/// </summary>
/// <param name="options">The options to add a filter to.</param>
/// <param name="hubFilter">The filter instance to add to the options.</param>
public static void AddFilter(this HubOptions options, IHubFilter hubFilter)
{
_ = options ?? throw new ArgumentNullException(nameof(options));
_ = hubFilter ?? throw new ArgumentNullException(nameof(hubFilter));if (options.HubFilters == null)
{
options.HubFilters = new List<IHubFilter>();
} options.HubFilters.Add(hubFilter);
} /// <summary>
/// Adds an <see cref="IHubFilter"/> type to the <see cref="HubOptions"/> that will be resolved via DI or type activated.
/// </summary>
/// <typeparam name="TFilter">The <see cref="IHubFilter"/> type that will be added to the options.</typeparam>
/// <param name="options">The options to add a filter to.</param>
public static void AddFilter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]TFilter>(this HubOptions options) where TFilter : IHubFilter
{
_ = options ?? throw new ArgumentNullException(nameof(options)); options.AddFilter(typeof(TFilter));
} /// <summary>
/// Adds an <see cref="IHubFilter"/> type to the <see cref="HubOptions"/> that will be resolved via DI or type activated.
/// </summary>
/// <param name="options">The options to add a filter to.</param>
/// <param name="filterType">The <see cref="IHubFilter"/> type that will be added to the options.</param>
public static void AddFilter(this HubOptions options, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type filterType)
{
_ = options ?? throw new ArgumentNullException(nameof(options));
_ = filterType ?? throw new ArgumentNullException(nameof(filterType)); options.AddFilter(new HubFilterFactory(filterType));
}
}
/// <summary>
/// The filter abstraction for hub method invocations.
/// </summary>
public interface IHubFilter
{
/// <summary>
/// Allows handling of all Hub method invocations.
/// </summary>
/// <param name="invocationContext">The context for the method invocation that holds all the important information about the invoke.</param>
/// <param name="next">The next filter to run, and for the final one, the Hub invocation.</param>
/// <returns>Returns the result of the Hub method invoke.</returns>
ValueTask<object?> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object?>> next) => next(invocationContext);/// <summary>
/// Allows handling of the <see cref="Hub.OnConnectedAsync"/> method.
/// </summary>
/// <param name="context">The context for OnConnectedAsync.</param>
/// <param name="next">The next filter to run, and for the final one, the Hub invocation.</param>
/// <returns></returns>
Task OnConnectedAsync(HubLifetimeContext context, Func<HubLifetimeContext, Task> next) => next(context); /// <summary>
/// Allows handling of the <see cref="Hub.OnDisconnectedAsync(Exception)"/> method.
/// </summary>
/// <param name="context">The context for OnDisconnectedAsync.</param>
/// <param name="exception">The exception, if any, for the connection closing.</param>
/// <param name="next">The next filter to run, and for the final one, the Hub invocation.</param>
/// <returns></returns>
Task OnDisconnectedAsync(HubLifetimeContext context, Exception? exception, Func<HubLifetimeContext, Exception?, Task> next) => next(context, exception);
}
看到这里,瞬间就明白了,就这个了
不过将HubOptions设为**internal,又弄个扩展类来维护此属性也是绝了为了防止使用者乱来真是费尽了心思...直呼一流,有需要的可以学习一下~
到此也差不多结束了,最后贴一下IHubFilter的使用位置:Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher 好巧不巧就是HubDispatcher<>,据说是HubDispatcher<>中的信息太多了,不想直接公开...
private readonly Func<HubInvocationContext, ValueTask<object>> _invokeMiddleware;
private readonly Func<HubLifetimeContext, Task> _onConnectedMiddleware;
private readonly Func<HubLifetimeContext, Exception, Task> _onDisconnectedMiddleware; public DefaultHubDispatcher(IServiceScopeFactory serviceScopeFactory, IHubContext<THub> hubContext, bool enableDetailedErrors,
ILogger<DefaultHubDispatcher<THub>> logger, List<IHubFilter> hubFilters)
{
_serviceScopeFactory = serviceScopeFactory;
_hubContext = hubContext;
_enableDetailedErrors = enableDetailedErrors;
_logger = logger;
DiscoverHubMethods();var count = hubFilters?.Count ?? 0;
if (count != 0)
{
_invokeMiddleware = (invocationContext) =>
{
var arguments = invocationContext.HubMethodArguments as object[] ?? invocationContext.HubMethodArguments.ToArray();
if (invocationContext.ObjectMethodExecutor != null)
{
return ExecuteMethod(invocationContext.ObjectMethodExecutor, invocationContext.Hub, arguments);
}
return ExecuteMethod(invocationContext.HubMethod.Name, invocationContext.Hub, arguments);
}; _onConnectedMiddleware = (context) => context.Hub.OnConnectedAsync();
_onDisconnectedMiddleware = (context, exception) => context.Hub.OnDisconnectedAsync(exception); for (var i = count - 1; i > -1; i--)
{
var resolvedFilter = hubFilters[i];
var nextFilter = _invokeMiddleware;
_invokeMiddleware = (context) => resolvedFilter.InvokeMethodAsync(context, nextFilter); var connectedFilter = _onConnectedMiddleware;
_onConnectedMiddleware = (context) => resolvedFilter.OnConnectedAsync(context, connectedFilter); var disconnectedFilter = _onDisconnectedMiddleware;
_onDisconnectedMiddleware = (context, exception) => resolvedFilter.OnDisconnectedAsync(context, exception, disconnectedFilter);
}
}
}
说明:在构造函数中将filter注册到委托中,委托的调用就不看了,有兴趣的自己去翻翻吧
.net core signalR 全局异常处理的更多相关文章
- asp.net core添加全局异常处理及log4net、Nlog应用
0.目录 整体架构目录:ASP.NET Core分布式项目实战-目录 一.介绍 此篇文章将会介绍项目的全局异常收集以及采用log4net或者NLog记录. 众所周知,一旦自己的项目报错,如果没有进行处 ...
- ASP.NET Core 中间件自定义全局异常处理
目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...
- 在.NET Core程序中设置全局异常处理
以前我们想设置全局异常处理只需要这样的代码: AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledExc ...
- ASP.NET Core 中间件的使用(三):全局异常处理机制
前言 我们经常听到"秒修复秒上线",觉得很厉害的样子. 其实不然,这只是一个调侃而已,出现问题的方式很多(逻辑漏洞.代码异常.操作方式不正确等). 我们今天来说代码异常问题怎么快速 ...
- NET MVC全局异常处理(一) 【转载】网站遭遇DDoS攻击怎么办 使用 HttpRequester 更方便的发起 HTTP 请求 C#文件流。 Url的Base64编码以及解码 C#计算字符串长度,汉字算两个字符 2019周笔记(2.18-2.23) Mysql语句中当前时间不能直接使用C#中的Date.Now传输 Mysql中Count函数的正确使用
NET MVC全局异常处理(一) 目录 .NET MVC全局异常处理 IIS配置 静态错误页配置 .NET错误页配置 程序设置 全局异常配置 .NET MVC全局异常处理 一直知道有.NET有相关 ...
- Net Core SignalR 测试,可以用于unity、Layair、白鹭引擎、大数据分析平台等高可用消息实时通信器。
SignalR介绍 SignalR介绍来源于微软文档,不过多解释.https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?v ...
- aspnetcore配置log4net并添加全局异常处理
第一步:在NuGet中引用log4net 第二步:创建log4net.config <?xml version="1.0" encoding="utf-8" ...
- 全栈项目|小书架|服务器开发-Koa2 全局异常处理
什么是异常 做开发的基本都知道异常,像Android开发中常见的ANR异常.空指针异常,服务器开发中经常遇到的异常404,500异常,还有一些其他常见的异常,具体可见HTTP状态码. 基本上这些异常可 ...
- Spring Cloud Gateway的全局异常处理
Spring Cloud Gateway中的全局异常处理不能直接用@ControllerAdvice来处理,通过跟踪异常信息的抛出,找到对应的源码,自定义一些处理逻辑来符合业务的需求. 网关都是给接口 ...
随机推荐
- flutter实战demo,仿luckin coffee。
flutter_luckin_coffee flutter luckin coffee application(仿瑞幸咖啡) 目录 前言 安卓扫码体验 flutter版本信息 安装 相关插件 维护者 ...
- Redis主从复制那点事
我们在 Redis持久化机制你学会了吗?学习了AOF和RDB,如果Redis宕机,他们分别通过回放日志和重新读入RDB文件的方式恢复数据,从而提高可靠性.我们今天来想这么一个问题,假如我们 ...
- jquery 对HTML标签的克隆、删除
<table width="100%" class="table_form"> <tr> <td>奖励深度(<a hr ...
- jquery 判断单/复选框是否被选中
1 <div> 2 <span>高亮:</span><input type="checkbox" name="light&quo ...
- Samba 远程命令执行漏洞(CVE-2017-7494)
该漏洞影响Samba 3.5.0之后的所有版本,在4.6.4/4.5.10/4.4.14修复了这个漏洞 use exploit/linux/samba/is_known_pipename set rh ...
- Mac使用Charles抓取ios手机APP中的https请求
1.配置Http代理 Port为监听端口号,默认为8888,勾选Enable transparent HTTP proxying,接着勾选SOCKS proxy,可以监听Socks请求 2.安装Cha ...
- 云服务器是什么?ECS、BCC、CVM...
什么是云服务器?云服务器有哪些优势?能用来干什么? 很多人不太了解云服务器的定义和用途. 云服务器是一种简单高效.处理能力可弹性伸缩的计算服务,帮助用户快速构建更稳定.安全的应用,提升运维效率,降低 ...
- OceanBase三节点部署&&扩容
OceanBase三节点部署&&扩容 环境信息搭建三节点(1-1-1)创建资源池和租户查看数据分布 环境信息 IP OB目录 端口 192.168.43.89 /data/observ ...
- flink clickhouse-jdbc和flink-connector 写入数据到clickhouse因为jar包冲突导致的60 seconds.Please check if the requested resources are available in the YARN cluster和Could not resolve ResourceManager address akka报错血案
一.问题现象,使用flink on yarn 模式,写入数据到clickhouse,但是在yarn 集群充足的情况下一直报:Deployment took more than 60 seconds. ...
- 代码中如何优化过多的if..else
针对代码中,过多的 if ... else ..,如何优化减少if else呢?(非常重要的优化技巧) 缺点:过多的if else 导致阅读不方便,逻辑过于复杂,代码多长. 解决方法:可以采用多个方 ...