ABP标准模型来处理异常
作者:互联网
ABP
随笔分类 - ABP
Abp 业务异常源码解读
Abp 业务异常源码解读
最近一直在读代码整洁之道,我在读到第三章函数的3.9 使用异常替代返回错误码,其实在我的开发经历中都是使用返回错误码给到前端,之前在阅读ABP官网文档中就有看到过使用异常替代异常的做法,当时自己还是比较抵触,在读完本章之后我们就马上阅读了Abp的异常处理源码。
ABP 提供了一个内置的基础设施,并提供了一个标准模型来处理异常。
- 自动处理所有异常并向客户端发送标准格式的错误消息以获取 API/AJAX 请求。
- 自动隐藏内部基础架构错误并返回标准错误消息。
- 提供一种简单且可配置的方式来本地化异常消息,可以实现多语言返回。
- 自动将标准异常映射到HTTP 状态代码,并提供一个可配置的选项来映射自定义异常。
业务异常
您自己的大多数异常将是业务异常。该IBusinessException接口用于将异常标记为业务异常。
BusinessExceptionIBusinessException除了IHasErrorCode,IHasErrorDetails和接口之外,还实现了IHasLogLevel接口。
默认日志级别是Warning.
特定业务异常相关的错误代码。例如:
throw new BusinessException(QaErrorCodes.CanNotVoteYourOwnAnswer);
QaErrorCodes.CanNotVoteYourOwnAnswer只是一个const string。建议使用以下错误代码格式:
code-namespace是特定于您的模块/应用程序的唯一值。例子:
Volo.Qa:010002
Volo.Qa是这里的代码命名空间。然后将在本地化异常消息时使用代码命名空间。
- 您可以在需要时直接抛出BusinessException或派生您自己的异常类型。
- 该类的所有属性都是可选的BusinessException。但是您通常设置ErrorCodeor Message属性。
BusinessException(自定义的业务异常)
下面是我们实现一个自定义异常的代码逻辑
[Serializable]
// 继承异常Exception类(实现自定义异常)
// IBusinessException (标识业务异常)
// IHasErrorCode(实现Code字段)
// IHasErrorDetails(实现Details字段)
// IHasLogLevel(当前异常实现自定义日志等级)
public class BusinessException : Exception,
IBusinessException,
IHasErrorCode,
IHasErrorDetails,
IHasLogLevel
{
public string Code { get; set; }
public string Details { get; set; }
public LogLevel LogLevel { get; set; }
public BusinessException(
string code = null,
string message = null,
string details = null,
Exception innerException = null,
LogLevel logLevel = LogLevel.Warning)
: base(message, innerException)
{
Code = code;
Details = details;
LogLevel = logLevel;
}
/// <summary>
/// Constructor for serializing.
/// </summary>
public BusinessException(SerializationInfo serializationInfo, StreamingContext context)
: base(serializationInfo, context)
{
}
public BusinessException WithData(string name, object value)
{
Data[name] = value;
return this;
}
}
本地化资源(实现多语言)
不知道大家没有接触过Abp的多语言设计,Abp通过读取不同国家的语言包Json实现多语言设计
这个是Abp源码中使用多语言的案例,可以看到我们会统一定义一个文件夹保存不同国家的多语言Json
多语言Json结构案例:
culture是语言
texts是Key-Value
{
"culture": "zh-Hans",
"texts": {
"Volo.Abp.Http.DynamicProxying:10001": "业务异常"
}
}
然后在模块中将语言包文件夹中的Json,添加到本地化中
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<HttpClientTestResource>("en")
.AddVirtualJson("/Volo/Abp/Http/Localization");
});
设置异常本地化配置(不同的解决方案一定要进行注册,如果没注册就找不到对应的错误码Key)
Configure<AbpExceptionLocalizationOptions>(options =>
{
// 设置映射解决方案名称,因为考虑到不同的语言包,需要区分模块设计
options.MapCodeNamespace("Volo.Abp.Http.DynamicProxying", typeof(HttpClientTestResource));
});
结构如下:
我们的Key可以通过解决方案加Code的方式(Volo.Abp.Http.DynamicProxying
为解决方案:10001是返回给前端的错误Code)
{
"culture": "sl",
"texts": {
"Volo.Abp.Http.DynamicProxying:10001": "Poslovna izjema s podatki",
"Volo.Abp.Http.TestProxying:10002": "Poslovna izjema s podatki"
}
}
然后可以使用错误代码抛出业务异常:
// QaDomainErrorCodes.CanNotVoteYourOwnAnswer="Volo.Abp.Http.DynamicProxying:10001"
// 这样通过一个常量管理异常就简洁明了。
throw new BusinessException(QaDomainErrorCodes.CanNotVoteYourOwnAnswer);
HTTP 状态码映射
ABP 尝试按照以下规则自动确定最适合常见异常类型的 HTTP 状态代码:
- 对于AbpAuthorizationException:
- 401如果用户尚未登录,则返回(未经授权)。
- 如果用户已登录,则返回403(禁止)。
- 的返回400(错误请求)AbpValidationException。
- 返回404(未找到)EntityNotFoundException。
- (并且因为它扩展了)返回403(禁止)。IBusinessExceptionIUserFriendlyExceptionIBusinessException
- 的返回501(未实现)NotImplementedException。
- 500其他异常(假定为基础设施异常)的返回(内部服务器错误)。
IHttpExceptionStatusCodeFinder用于自动确定 HTTP 状态码。默认实现是DefaultHttpExceptionStatusCodeFinder类。它可以根据需要更换或扩展。
自定义映射
自定义映射可以覆盖自动 HTTP 状态代码确定。例如:
services.Configure<AbpExceptionHttpStatusCodeOptions>(options =>
{
options.Map("Volo.Qa:010002", HttpStatusCode.Conflict);
});
异常事件订阅(ExceptionSubscriber)
下面我们会涉及到处理异常,Abp框架的处理异常给我们提供通知入口ExceptionSubscriber
[ExposeServices(typeof(IExceptionSubscriber))]
// 继承IExceptionSubscriber接口,注入周期Transient(瞬态)
public abstract class ExceptionSubscriber : IExceptionSubscriber, ITransientDependency
{
public abstract Task HandleAsync(ExceptionNotificationContext context);
}
我们只需要继承ExceptionSubscriber
抽象类,然后Abp将自动注入,一对多
的形式进行注入。
触发通知的代码在ExceptionNotifier
源码
ExceptionNotifier(异常通知)
下面的代码就是实现异常通知发生事件的代码,我们只需要在异常过滤器中获取
ExceptionNotifier
然后调用NotifyAsync方法就可以啦
// 异常通知
public class ExceptionNotifier : IExceptionNotifier, ITransientDependency
{
public ILogger<ExceptionNotifier> Logger { get; set; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
public ExceptionNotifier(IServiceScopeFactory serviceScopeFactory)
{
ServiceScopeFactory = serviceScopeFactory;
Logger = NullLogger<ExceptionNotifier>.Instance;
}
// 通知入口
public virtual async Task NotifyAsync([NotNull] ExceptionNotificationContext context)
{
Check.NotNull(context, nameof(context));
using (var scope = ServiceScopeFactory.CreateScope())
{
// 1.获取所有实现IExceptionSubscriber接口的实现了类
var exceptionSubscribers = scope.ServiceProvider
.GetServices<IExceptionSubscriber>();
// 2.批量调用实现类的HandleAsync方法
foreach (var exceptionSubscriber in exceptionSubscribers)
{
try
{
await exceptionSubscriber.HandleAsync(context);
}
catch (Exception e)
{
Logger.LogWarning($"Exception subscriber of type {exceptionSubscriber.GetType().AssemblyQualifiedName} has thrown an exception!");
Logger.LogException(e, LogLevel.Warning);
}
}
}
}
}
AbpExceptionFilter异常拦截器源码
我们首先可以看到AbpExceptionFilter继承我们的异常拦截器,依赖注入的生命周期是瞬态的
// 我们首先可以看到AbpExceptionFilter继承我们的异常拦截器,依赖注入的生命周期是瞬态的
public class AbpExceptionFilter : IAsyncExceptionFilter, ITransientDependency
{
·····省略代码
}
AbpExceptionFilter如果满足以下任何条件,则处理异常:
- 异常由返回对象结果(不是视图结果)的控制器操作引发。
- 该请求是一个 AJAX 请求(X-Requested-WithHTTP 标头值为XMLHttpRequest)。
- 客户端明确接受application/json内容类型(通过acceptHTTP 标头)。
如果异常得到处理,它会自动记录下来,并将格式化的JSON 消息返回给客户端。
// 判断当前请求的异常是否需要自动处理
protected virtual bool ShouldHandleException(ExceptionContext context)
{
// 1.判断当前请求是否是控制器方法
// 2.并且有返回结果
if (context.ActionDescriptor.IsControllerAction() &&
context.ActionDescriptor.HasObjectResult())
{
return true;
}
// 1.当前请求中头accept是否是application/json内容类型
if (context.HttpContext.Request.CanAccept(MimeTypes.Application.Json))
{
return true;
}
// 1.当前请求是否是AJAX 请求
if (context.HttpContext.Request.IsAjax())
{
return true;
}
return false;
}
如果ShouldHandleException()
方法返回 true
就会进入HandleAndWrapException()
自动格式化处理异常方法
// 自动格式化处理异常
protected virtual async Task HandleAndWrapException(ExceptionContext context)
{
//TODO: Trigger an AbpExceptionHandled event or something like that.
// 1.首先还是老样子读取当前模块的配置信息
var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
// 2.获取异常格式转换器,因为需要将我们的异常格式化,多语言实现也是在这个格式化转换器中实现的
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>();
// 3.通过格式化转换器,将异常信息转换成为前端展示数据(这里就会使用到我们的配置信息)
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options =>
{
// 是否向客户端发送异常详细信息(默认是false)
options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients;
// 发送堆栈跟踪到客户端(默认是true)
options.SendStackTraceToClients = exceptionHandlingOptions.SendStackTraceToClients;
});
// 4.获取我们业务异常日志等级
var logLevel = context.Exception.GetLogLevel();
// 5.创建一个StringBuilder对象拼接异常信息
var remoteServiceErrorInfoBuilder = new StringBuilder();
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------");
remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true));
// 6.获取日志信息
var logger = context.GetService<ILogger<AbpExceptionFilter>>(NullLogger<AbpExceptionFilter>.Instance);
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
logger.LogException(context.Exception, logLevel);
// 7.获取注入IExceptionNotifier接口的实现类,给IExceptionSubscriber实现类接口批量发送事件
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception));
// 8.判断当前异常是不是身份认证异常
if (context.Exception is AbpAuthorizationException)
{
await context.HttpContext.RequestServices.GetRequiredService<IAbpAuthorizationExceptionHandler>()
.HandleAsync(context.Exception.As<AbpAuthorizationException>(), context.HttpContext);
}
else
{
// 9.添加请求头标识_AbpErrorFormat(给告诉调用者,这次的异常已经是被我们格式化的)
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
// 10.设置返回状态码
context.HttpContext.Response.StatusCode = (int)context
.GetRequiredService<IHttpExceptionStatusCodeFinder>()
.GetStatusCode(context.HttpContext, context.Exception);
// 11.将我们序列化好的错误信息放入请求返回结果中
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
}
// 12.清空当前请求的异常
context.Exception = null; //Handled!
}
参考资料
我曾七次鄙视自己的灵魂:第一次,当它本可进取时,却故作谦卑;
第二次,当它空虚时,用爱欲来填充;
第三次,在困难和容易之间,它选择了容易;
第四次,它犯了错,却借由别人也会犯错来宽慰自己;
第五次,它自由软弱,却把它认为是生命的坚韧;
第六次,当它鄙夷一张丑恶的嘴脸时,却不知那正是自己面具中的一副;
第七次,它侧身于生活的污泥中虽不甘心,却又畏首畏尾。 .net Core 使用IHttpClientFactory请求 摘要:导读:本文已添加在晨曦微服务之旅,现在自己在尝试微服务架构,一边学边做项目快速的进入状态。当然在学习的过程中会将自己学到的知识进行分享。 一、为什么不用HttpClient 1.HttPClient使用完之后不会立即关闭开启网络连接时会占用底层socket资源,但在HttpClient调用其本身的D 阅读全文 posted @ 2020-01-16 23:17 是你晨曦哥呀 阅读(6120) 评论(16) 推荐(12) 编辑 .Net Core组件化视图(部分视图) 摘要:.Net Core组件化视图(部分视图) 1.背景 1.以前我们使用.Net的时候使用部分视图的方式在,.Net Core 中能在单独处理逻辑的部分视图没有了,但是我们还是想使用现在的.Net Core换了一种方式,将视图组件化了。 2.视图组件介绍 1.可以将我们的视图重复的部分分离出来,达到可复 阅读全文 posted @ 2019-12-03 20:52 是你晨曦哥呀 阅读(1227) 评论(3) 推荐(0) 编辑 .net core 反射的介绍与使用 摘要:1. 概述反射 通过反射可以提供类型信息,从而使得我们开发人员在运行时能够利用这些信息构造和使用对象。 反射机制允许程序在执行过程中动态地添加各种功能。 2. Type类的介绍 是BCL(基底类别库)声明的一个抽象类,所有它不能被实例化 对于程序中用到的每一个类型,CLR(公共语言运行时)都会创建一 阅读全文 posted @ 2019-11-20 20:32 是你晨曦哥呀 阅读(4632) 评论(3) 推荐(1) 编辑 .net Core 使用AutoMapper 摘要:在我们的项目中慢慢的要把数据库的实体模型和视图模型进行分离,防止被人拿到我们表字段。在学校的时候自己只是有将很多数据库模型,写成一个视图模型返回到前台。 首先我们把这两个包引入项目中去。 然后我们创建一个转换配置类,这个类要继承 Profile 将我们需要转换的类写到我们构造函数里面去,这里要注意我 阅读全文 posted @ 2019-11-05 19:24 是你晨曦哥呀 阅读(6553) 评论(2) 推荐(4) 编辑 .net Core数据的幕等性 摘要:一、背景 代码实例:https://gitee.com/D_C_L/CurtainEtcAOP.git我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。 例如: 1. 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果。 2. 我们发起一笔付款请求,应该只 阅读全文 posted @ 2019-10-13 21:43 是你晨曦哥呀 阅读(820) 评论(3) 推荐(0) 编辑 .net core 拦截器的使用 摘要:.net core 拦截器的使用 阅读全文 posted @ 2019-10-13 19:37 是你晨曦哥呀 阅读(7516) 评论(1) 推荐(4) 编辑 使用ABP SignalR重构消息服务(二) 摘要:使用ABP SignalR重构消息服务(二) 上篇使用ABP SignalR重构消息服务(一)主要讲的是SignalR的基础知识和前端如何使用SignalR,这段时间也是落实方案设计。这篇我主要讲解SignalR源码(最近我手头工作比较忙@蟹老板)。 SignalR源码分析(原地址,原地址已经停止维 阅读全文 posted @ 2022-04-08 09:13 是你晨曦哥呀 阅读(551) 评论(4) 推荐(4) 编辑 使用ABP SignalR重构消息服务(一) 摘要:使用ABP SignalR重构消息服务 最近协助蟹老板升级新框架,维护基础设施服务,目前已经稳了。 早上蟹老板看到我进入公司,马上就叫停我,说我为什么左脚先进公司,你这样会让我很难做耶,这样把我给你一次机会把现在的消息服务重构了,我就放过你这一次。(当时我都没有反应过来,蟹老板就准备和我讲需求了,我 阅读全文 posted @ 2022-03-21 09:21 是你晨曦哥呀 阅读(970) 评论(0) 推荐(4) 编辑 ABP 使用ElasticSearch、Kibana、Docker 进行日志收集 摘要:ABP 使用ElasticSearch、Kibana、Docker 进行日志收集 后续会根据公司使用的技术,进行技术整理分享,都是干货哦别忘了关注我!!! 最近领导想要我把项目日志进行一个统一收集,因为现在环境有什么报错信息都是看Logs文件夹的日志数据,如果只有一个项目那到无所谓,但是我们现在的服 阅读全文 posted @ 2022-03-07 09:40 是你晨曦哥呀 阅读(2284) 评论(16) 推荐(20) 编辑 Abp 业务异常源码解读 摘要:Abp 业务异常源码解读 最近一直在读代码整洁之道,我在读到第三章函数的3.9 使用异常替代返回错误码,其实在我的开发经历中都是使用返回错误码给到前端,之前在阅读ABP官网文档中就有看到过使用异常替代异常的做法,当时自己还是比较抵触,在读完本章之后我们就马上阅读了Abp的异常处理源码。 ABP 提供 阅读全文 posted @ 2022-02-27 17:07 是你晨曦哥呀 阅读(554) 评论(0) 推荐(3) 编辑 Abp 审计模块源码解读 摘要:Abp 审计模块源码解读 Abp 框架为我们自带了审计日志功能,审计日志可以方便地查看每次请求接口所耗的时间,能够帮助我们快速定位到某些性能有问题的接口。除此之外,审计日志信息还包含有每次调用接口时客户端请求的参数信息,客户端的 IP 与客户端使用的浏览器。有了这些数据之后,我们就可以很方便地复现接 阅读全文 posted @ 2022-02-03 13:15 是你晨曦哥呀 阅读(433) 评论(0) 推荐(1) 编辑
使用ABP SignalR重构消息服务(二) 摘要:使用ABP SignalR重构消息服务(二) 上篇使用ABP SignalR重构消息服务(一)主要讲的是SignalR的基础知识和前端如何使用SignalR,这段时间也是落实方案设计。这篇我主要讲解SignalR源码(最近我手头工作比较忙@蟹老板)。 SignalR源码分析(原地址,原地址已经停止维 阅读全文 posted @ 2022-04-08 09:13 是你晨曦哥呀 阅读(551) 评论(4) 推荐(4) 编辑 使用ABP SignalR重构消息服务(一) 摘要:使用ABP SignalR重构消息服务 最近协助蟹老板升级新框架,维护基础设施服务,目前已经稳了。 早上蟹老板看到我进入公司,马上就叫停我,说我为什么左脚先进公司,你这样会让我很难做耶,这样把我给你一次机会把现在的消息服务重构了,我就放过你这一次。(当时我都没有反应过来,蟹老板就准备和我讲需求了,我 阅读全文 posted @ 2022-03-21 09:21 是你晨曦哥呀 阅读(970) 评论(0) 推荐(4) 编辑 ABP 使用ElasticSearch、Kibana、Docker 进行日志收集 摘要:ABP 使用ElasticSearch、Kibana、Docker 进行日志收集 后续会根据公司使用的技术,进行技术整理分享,都是干货哦别忘了关注我!!! 最近领导想要我把项目日志进行一个统一收集,因为现在环境有什么报错信息都是看Logs文件夹的日志数据,如果只有一个项目那到无所谓,但是我们现在的服 阅读全文 posted @ 2022-03-07 09:40 是你晨曦哥呀 阅读(2284) 评论(16) 推荐(20) 编辑 Abp 业务异常源码解读 摘要:Abp 业务异常源码解读 最近一直在读代码整洁之道,我在读到第三章函数的3.9 使用异常替代返回错误码,其实在我的开发经历中都是使用返回错误码给到前端,之前在阅读ABP官网文档中就有看到过使用异常替代异常的做法,当时自己还是比较抵触,在读完本章之后我们就马上阅读了Abp的异常处理源码。 ABP 提供 阅读全文 posted @ 2022-02-27 17:07 是你晨曦哥呀 阅读(555) 评论(0) 推荐(3) 编辑 Abp 审计模块源码解读 摘要:Abp 审计模块源码解读 Abp 框架为我们自带了审计日志功能,审计日志可以方便地查看每次请求接口所耗的时间,能够帮助我们快速定位到某些性能有问题的接口。除此之外,审计日志信息还包含有每次调用接口时客户端请求的参数信息,客户端的 IP 与客户端使用的浏览器。有了这些数据之后,我们就可以很方便地复现接 阅读全文 posted @ 2022-02-03 13:15 是你晨曦哥呀 阅读(433) 评论(0) 推荐(1) 编辑 全局获取HttpContext 摘要:全局获取HttpContext 在我们平常开发中会有这样的需求,我们的Service业务层需要获取请求上下文中的用户信息,一般我们从控制器参数传递过来。如果你觉得这样就可以了,请您关闭文章。 场景 但是我们也会遇到控制器传递困难的场景,我自己最近使用单库实现多租户的PAAS平台,发现EF Core上 阅读全文 posted @ 2021-07-11 16:30 是你晨曦哥呀 阅读(1036) 评论(5) 推荐(2) 编辑 Redis高可用调试 摘要:Redis高可用调试 背景:因为要让redis高可用,我们使用了redis双机热备(一台主机一台备机) 架构:虚拟IP=>nginx=>redis(双机) 测试 当我们使用nginx的双机热备模式,主节点挂掉之后,所有的请求会转发到从节点,这个时候我们的主节点故障恢复了,所有新的请求都会跑到主节点上 阅读全文 posted @ 2021-03-30 21:53 是你晨曦哥呀 阅读(93) 评论(0) 推荐(0) 编辑 .Net Core 使用EF Core codefirst模式 摘要:.Net Core 使用EF Core codefirst模式 什么是codefirst模式 EF Core有两种数据库设计模式,DBfirst 数据库优先、Codefirst 代码优先。 1、我们一般设计是先添加数据库表信息,然后将数据库的信息更新到项目实体中。这种做法就是我们的DBfirst模式 阅读全文 posted @ 2021-02-05 14:48 是你晨曦哥呀 阅读(999) 评论(0) 推荐(2) 编辑 BackgroundService 大佬教的好 摘要:BackgroundService 源码分析 因为换了工作也有两个多月没有写博客啦,因为跟着红超哥(大佬)一直在学习和做项目(反正就是在潜心修炼,大佬每天也是在我十万个为什么中度过的。) 最近在做一个接收服务端信息的项目,使用TCP建立连接,双方进行信息通信。后面我会陆陆续续的把自己学习的东西进行一 阅读全文 posted @ 2020-11-29 19:23 是你晨曦哥呀 阅读(942) 评论(3) 推荐(2) 编辑 .Net core 守护进程配置(supervisor) 摘要:1、介绍supervisor Supervisor是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,super 阅读全文 posted @ 2020-09-04 17:12 是你晨曦哥呀 阅读(1616) 评论(0) 推荐(1) 编辑 .Net Core缓存组件(MemoryCache)【缓存篇(二)】 摘要:一、前言 .Net Core缓存源码 1、上篇.NET Core ResponseCache【缓存篇(一)】中我们提到了使用客户端缓存、和服务端缓存。本文我们介绍MemoryCache缓存组件,说到服务端缓存我们一般都会想到MemoryCache、Redis等等优秀的缓存组件,各自有各自使用的场景。 阅读全文 posted @ 2020-07-22 23:21 是你晨曦哥呀 阅读(1625) 评论(3) 推荐(4) 编辑 .NET Core ResponseCache【缓存篇(一)】 摘要:一、前言 源码 1、最近一直在看项目性能优化方式,俗话说的好项目优化第一步那当然是添加缓存,我们的项目之所以卡的和鬼一样,要么就是你的代码循环查询数据库(这个之前在我们的项目中经常出现,现在慢慢在修正)或者代码做了很多不该做的事情。这个时候就可以引入我们的缓存了。(只要你的代码不是写的特别差,比如之 阅读全文 posted @ 2020-07-16 21:31 是你晨曦哥呀 阅读(2027) 评论(7) 推荐(9) 编辑 泛型知多少 摘要:一、什么是泛型 源码 1.泛型类和泛型方法兼复用性、类型安全和高效率于一身,是与之对应的非泛型的类和方法所不及。泛型广泛用于容器(collections)和对容器操作的方法中。.NET框架2.0的类库提供一个新的命名空间System.Collections.Generic,其中包含了一些新的基于泛型 阅读全文 posted @ 2020-05-18 00:31 是你晨曦哥呀 阅读(449) 评论(0) 推荐(0) 编辑 多线程之旅(Task 任务) 摘要:一、Task(任务)和ThreadPool(线程池)不同 源码 1、线程(Thread)是创建并发工具的底层类,但是在前几篇文章中我们介绍了Thread的特点,和实例。可以很明显发现局限性(返回值不好获取(必须在一个作用域中)),当我们线程执行完之后不能很好的进行下一次任务的执行,需要多次销毁和创建 阅读全文 posted @ 2020-04-11 23:26 是你晨曦哥呀 阅读(1174) 评论(3) 推荐(3) 编辑 多线程之旅(ThreadPool 线程池) 摘要:一、什么是ThreadPool 线程池(源码) 1.线程池顾名思义,有我们的系统创建一个容器装载着我们的线程,由CLR控制的所有AppDomain共享。线程池可用于执行任务、发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。所以使用线程池不需要自己创建线程,而是通过线程池来创建和执行和管 阅读全文 posted @ 2020-03-30 22:17 是你晨曦哥呀 阅读(853) 评论(2) 推荐(1) 编辑 多线程之旅(Thread) 摘要:在上篇文章中我们已经知道了多线程是什么了,那么它到底可以干嘛呢?这里特别声明一个前面的委托没看的同学可以到上上上篇博文查看,因为多线程要经常使用到委托。源码 一、异步、同步 1.同步(在计算的理解总是要你措不及防,同步当线程做完一件事情之后,才会执行后续动作),同步方法慢,只有一个线程执行,异步方法 阅读全文 posted @ 2020-03-29 07:34 是你晨曦哥呀 阅读(604) 评论(0) 推荐(0) 编辑 多线程之旅(准备阶段) 摘要:1、初识那个它(多线程) 1:可以看到我的电脑有234个进程正在运行、有2749个线程正在运行,这个时候你们是不是和我一样有很多问号呢? 2、什么是进程 1:当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用的内存和系统资源,而一个进程又是由多个线程所组成的。 3、什么是线程 1 阅读全文 posted @ 2020-03-27 21:56 是你晨曦哥呀 阅读(240) 评论(0) 推荐(0) 编辑 Expression表达式目录树 摘要:一、初识Expression 源码 1、在上一篇我们讲到了委托(忘记了可以在看看,点赞在看养成习惯),今天要讲的Expression也和委托有一点点关系吧(没有直接关系,只是想要大家看看我其他的文章),Expression是.NET准备为Linq to Sql准备的,它的命名空间是System.Li 阅读全文 posted @ 2020-03-17 15:15 是你晨曦哥呀 阅读(1099) 评论(2) 推荐(2) 编辑 深入浅出之委托 摘要:一、什么是委托 源码下载 1.委托是面向对象的、类型安全的,是引用类型。使用delegate关键字进行定义。委托的本质就是一个类,继承自System.MulticastDelegate,而它又派生自System.Delegate。里面内置了几个方法 ,可以在类的外面声明委托,也可以在类的内部声明委托 阅读全文 posted @ 2020-03-13 12:04 是你晨曦哥呀 阅读(899) 评论(5) 推荐(0) 编辑 .Net 特性分析与妙用 摘要:一.特性是什么 源码 1、想象很多小伙伴们都看过在一个类上方、或者在控制器见过类似的东东,加上之后就可以标识这个类或者方法就具备了某些特点 ,那我们就进入它的内心一探究竟吧。 2.我们进入某个特性之后,可以发现它又单独继承于Attribute 它的意思就是属性、特质的意思。那它到底能干嘛呢?能让我们 阅读全文 posted @ 2020-03-08 12:21 是你晨曦哥呀 阅读(1072) 评论(1) 推荐(6) 编辑
标签:Abp,阅读,模型,ABP,源码,context,异常,posted 来源: https://www.cnblogs.com/Leo_wl/p/16264820.html