.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来处理,通过跟踪异常信息的抛出,找到对应的源码,自定义一些处理逻辑来符合业务的需求. 网关都是给接口 ...
随机推荐
- C语言:整数保存 原码 反码 补码
#include <stdio.h> /* 本题结果为:-4 short类型占据2字节 ;赋值后实际占据了3个字节,所以有溢出警告提示,结果只保留0xfffc 保存二进制:1111 111 ...
- ti
一.选择题DCBCDCDACAACBBABACBDCBBDA二.简答题(每小题5分,共20分)1. 1)简洁紧凑,灵活方便2)运算符丰富3)数据类型丰富4)C语言是结构化语言5)语法限制较少,程序设计 ...
- C语言:虚拟地址 和编译模式
所谓虚拟地址空间,就是程序可以使用的虚拟地址的有效范围.虚拟地址和物理地址的映射关系由操作系统决定,相应地,虚拟地址空间的大小也由操作系统决定,但还会受到编译模式的影响.这节我们先讲解CPU,再讲解编 ...
- C控制台程序 GUI程序
控制台程序对应的工程类型为"Win32控制台程序(Win32 Console Application)",GUI 程序对应的工程类型为"Win32程序(Win32 App ...
- Java基础00-Lamda表达式30
1. Lambda表达式 Java8新特征之Lambda表达式 1.1 函数式编程思想概述 1.2 体验Lambda表达式 代码示例: 方式一就不演示了,可以去看Java基础24 方式2:匿名内部类的 ...
- MySQL主从复制的简单搭建
@ 目录 1.MySQL一主一从的简单搭建 1.1.主从复制简介 1.2.MySQL主从复制简介 1.3.主从复制的架构 1.4.前期准备 1.5.主要配置实现 1.5.1.测试环境 1.5.2.配置 ...
- go反射原理
go反射原理 本文基于go1.13.15 1.go汇编 1.1 基本语法 go采用plan9的汇编器完成汇编,有下面几个重要的伪寄存器 FP: Frame pointer: 局部变量访问 PC: Pr ...
- [考试总结]noip8
又是一个题的正解都没有打出来的一天 但是自己独创了 \(lca\) 的求法, 然而如果去掉求 \(lca\) 的过程,就不会 \(TLE\) 了. \(\huge{\text{囧}}\) 然后就是对性 ...
- Windows10公钥远程连接Linux服务器
目录 前言 一.环境准备 二.使用步骤 1.服务器安装并配置OpenSSH 2. 本地生成密钥 3. 服务器ssh添加密钥 三 总结 前言 使用公钥远程登陆Linux十分方便,无需输入密码,同时采用V ...
- 机器学习:单元线性回归(python简单实现)
文章简介 使用python简单实现机器学习中单元线性回归算法. 算法目的 该算法核心目的是为了求出假设函数h中多个theta的值,使得代入数据集合中的每个x,求得的h(x)与每个数据集合中的y的差值的 ...