Serilog Tutorial

在过去的几年中,结构化日志已经大受欢迎。而Serilog是 .NET 中最著名的结构化日志类库 ,我们提供了这份的精简指南来帮助你快速了解并运用它。

0. 内容

  1. 设定目标

  2. 认识Serilog

  3. 事件和级别

  4. 触发和收集结构化数据

  5. 为过滤和关联添加事件标记

  6. 大海捞针 [Finding needles in the haystack]

  7. 下一步是什么?

  8. 获得帮助

1. 设定目标

你可能之前已经在项目中使用了Serilog,或者你有一个新的项目希望使用Serilog,又或者你只是对结构化日志记录感兴趣: 那就非常好! 你来对地方了。

然而,更进一步来说,你的目标可能是:

  1. 希望在用户之前发现代码中的BUG和错误

  2. 为了更快的找到生产环境中的问题

  3. 深入的了解系统运行表现

Serilog使用json格式来记录应用程序中的事件,方便我们可以快速的查询日志,关键是可以方便地过滤和查询日志,而不用编写正则表达式。

在本教程中,我们将介绍最关键的几个部分,帮助我们可以在生成环境中提供令人惊叹的诊断能力。[注:原文这句挺拗口]

2. 认识 Serilog

那就让我们开始吧!为了更好的理解,你可以先创建一个新的.Net console 项目,可以是netcore或者传统的NETFramework版本。

Serilog 通过NuGet分发,项目包括一个Seirlog核心项目Seirlog和很多接收器sinks(超过100个),这些接收是通过插件的方式来实现将日志写入到各种终端,文件,邮件,数据库或日志服务器

我们将通过使用SerilogSerilog.Sinks.Console这两个组件开始,在稍后讨论其他选项:

dotnet add package Serilog
dotnet add package Serilog.Sinks.Console

这是世界上最简单的Serilog配置:

using Serilog;class Program  {    public static void Main(string[] args)    {        using (var log = new LoggerConfiguration().WriteTo.Console().CreateLogger()){log.Information("Hello, Serilog!");log.Warning("Goodbye, Serilog.");}}
}

让我们稍微分解一下:

  • LoggerConfiguration 类提供一个流式接口用于构建一个日志记录管道

  • WriteTo.Console() 将控制台接收器添加到上述管道中

  • CreateLogger() 组装并返回一个实现ILogger接口的Logger对象

  • 上述Logger对象同样实现了IDisposable,所以我们可以在using中调用它

  • 最后log.Information()log.Warning() 触发记录日志

这个日志记录管道是一个可释放的[disposable],这可能会让你有点意外,但是请记住,记录器通常是要写入文件,数据库等等: 很多sinks 必须被完全地关闭掉。尽管这样,也仅仅在应用程序退出前,根logger才需要被释放。而在应用程序中使用logger是不需要关心这些细节的。

你运行了这个程序嘛?这是你看到的效果吧?

Apart from just passing it around everywhere, there are two possibilities. [ 除了在各地传递外,还有两种可能性。] If you're using an IoC container, you might have components receive an ILogger through dependency injection. [ 如果您使用的是IoC容器,则可能会让组件通过依赖注入来接收ILogger。] Packages like AutofacSerilogIntegration can help with that. [ 像AutofacSerilogIntegration这样的软件包可以提供帮助。]

现在最直接的问题是:我们在应用程序的其他类里面如何获得这个log对象,除了到处传递之外,还有两个办法。

  1. 如果你使用IoC容器,你可以组件注入一个ILogger对象来接收,像AutofacSerilogIntegration的包括帮助你实现这种方式。

  2. 或者,您可以将Logger对象存储在众所周知的位置; Serilog 已经内容内置了一个静态的Log对象,就像这样:

Log.Logger = new LoggerConfiguration()  .WriteTo.Console().CreateLogger();Log.Information("Hello again, Serilog!");Log.CloseAndFlush();  

Log类提供所有与ILogger接口相同的方法,这里我们显示调用Log.CloseAndFlush()来关闭它,而不是使用using代码块

你可以使用依赖注入的方式,也可以是静态属性的方式 - 这取决你的个人喜好问题。为了简单起见,我们在本教程中使用了静态Log的方式。

也许,你不是在编写一个控制台应用程序。我们将使用Console应用作为广为人知的示例,但是你一旦完成了本教程,您应该查看目标平台的文档(例如,ASP.NET Core)。

3. Event and Level [时间和级别]

和一些老的日志类库相比(如log4net),在使用Serilog时,你需要做的就是最大改变就是思考日志事件[log events],而不是日志消息[log message],一条事件[event]由以下几个内容组成:

  • 事件发生时的时间戳[timestamp]

  • 描述何时应该捕获事件的级别[level]

  • 记录事件的消息[message]内容]

  • 描述事件的命名属性[properties]

  • 还可能有一个Exception对象

您可以将日志事件格式化为控制台的可读文本,正如我们在第一个示例中看到的那样:

11:33:01 [INF] Hello, Serilog!  

或者,您可以将相同的事件格式化为JSON并将其发送到远程日志服务器:

json  {"@t":"2017-11-20T11:33:01.22138","@m":"Hello, Serilog!"}

在背后,应用程序中的日志语句会创建LogEvent对象,而连接到管道的接收器[sinks]会知道如何记录它们。

### Logging levels

Serilog速度很快,但始终构建和记录详细的日志事件会浪费CPU,磁盘和网络资源。为了管理这个,Serilog事件被赋予了多种级别:DebugInformationWarning 和 Error等。对应的有一个Log.*()方法来对应各个级别。

在开发过程中,可能会打开调试级别的事件:

```csharp
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() // <- Set the minimum level
.WriteTo.Console()
.CreateLogger();

// In a tight loop...
Log.Debug("Processing item {ItemNumber} of {ItemCount}", itemNumber, itemCount);

```

在生成环境中,通常关闭调试的日志,并将最小的日志级别设置成Information,以便只记录重要的事件,在这篇文档中可以获得有关Serilog Logger Lever的更多信息

Tip: Serilog has special handling for Exception objects; methods like Log.Error() take the exception as the first parameter, e.g. [ 提示:Serilog对Exception对象有特殊的处理;] Log.Error(ex, "Task {TaskName} was canceled", task). [ Log.Error(例如,“任务{任务名称}被取消”,任务)。] Don't include exceptions in the log message itself. [ 不要在日志消息本身中包含异常。]
提示:Serilog对Exception对象有特殊的处理; 像方法Log.Error() 将 exception 作为第一个参数,例如Log.Error(ex, "Task {TaskName} was canceled", task),不要将异常的包括在message消息中

4. 触发和收集结构化数据

让我们回到最后一个代码片段:

var itemNumber = 10;  var itemCount = 999;  
Log.Debug("Processing item {ItemNumber} of {ItemCount}", itemNumber, itemCount);  

您是否注意到日志消息中的{ItemNumber}这样的占位符? 这不是一个C#的内插字符串[Interpolated string C# 6.0的新特性],Log.*()方法接收一个消息模板,另外一种.NET格式化字符串,除了支持传统的{0}的方式,还支持{Name}的方式。

这看起来有点奇怪,除非您意识到通过这样做,Serilog可以将这些消息的一部分作为类的属性与人性化的文本一起捕获:

{"@t": "2017-11-20T11:33:01.22138","@l": "Debug","@m": "Processing item 10 of 999","ItemNumber": 10,"ItemCount": 999}

我们为什么要这样做?因为通过这种有趣的字段插入方式,并作为属性记录到事件日志中,我们可以立即使用优雅的简单的过滤器来查找事件,就像ItemNumber > 900,而无需通过正则表达式从消息中提取了。

进一步,我们可以使用 @ 结构捕获运算符 来获取不仅仅是平坦的属性值,而是完整的对象:

var user = new { Name = "Nick", Id = "nblumhardt" };  
Log.Information("Logged on user {@User}", user);  

在这里,user对象被捕获,并生成的JSON中,以便我们可以使用查询来查找事件,如:User.Id = 'nblumhardt'

{"@t": "2017-11-20T11:33:01.22138","@m": "Logged on user {\"Name\": \"Nick\", \"Id\": \"nblumhardt\"}","User": {"Name": "Nick", "Id": "nblumhardt"}}

生产环境的监控和调试已经非常困难和耗时,而且经常是压力山大的任务:而通过将相关的数据放在手边,Serilog除去了运维操作相关活动的最大难题之一。

Tip: 从Visual Studio Marketplace安装令人惊叹的Serilog Analyzer,可以帮助你检查你的消息模板类型( 注:这个插件还能帮你通过配置代码生成appsetting.json的内容,但是只支持生成一级配置:( )

这实际上有多大的差异取决于你如何收集Serilog的事件。一般来说,日志事件进入文本文件并用grep进行搜索。Serilog也可以记录文本文件,但不能在记事本中执行ItemNumber> 900,因此您需要评估更强大的工具来执行此操作。

写 JSON 格式的日志文件

如果您的需求很简单,您可以将JSON写入日志文件,并使用支持JSON的工具直接查询文件。] [ Serilog的文件接收器[sink]和紧凑的JSON格式化类库[compact JSON formatter]使第一部分变得简单。 让我们重新建一个控制台应用程序,并安装下列软件包:

dotnet add package Serilogdotnet add package Serilog.Sinks.File  dotnet add package Serilog.Formatting.Compact  

Main函数中插入:

Log.Logger = new LoggerConfiguration()  .MinimumLevel.Debug().WriteTo.File(new CompactJsonFormatter(), "log.clef").CreateLogger();var itemCount = 99;  for (var itemNumber = 0; itemNumber < itemCount; ++itemNumber)  Log.Debug("Processing item {ItemNumber} of {ItemCount}", itemNumber, itemCount);Log.CloseAndFlush();  

运行这个程序将产生使用Serilog的紧凑格式[compact],在文件log.clef中生成以换行符分隔的JSON流,如果没有使用CompactJsonFormatter,则会创建一个简单饿扁平日志文件。

如果你在文本编辑器中打开文件,你会看到JSON事件,就像我们上面使用的例子。

CLEF-tool 是查询CLEF格式的日志文件的方便的命令行应用程序:(注:貌似只支持windows)

注意第二行的过滤器ItemNumber> 95:毫不费力地在大型日志流中定位事件,就是结构化日志记录的好处吧。

将日志写入日志服务器

将日志事件从多个应用程序发送到中央服务器或日志聚合服务非常方便,而不是试图在生产环境中多个日志进行浑水摸鱼[shuffle log files]

日志服务器通常通过HTTP/S或UDP在网络上接收事件,并为开发人员和操作员工程师提供用户界面,以便在出现问题时搜索和分析日志流。

Serilog接收器[sinks]支持大量的日志服务器,其中许多具有结构化数据支持。

注:这段是广告就不翻译了,读者可以根据实际需求选择自己的日志服务器。

5. 为过滤和关联标记事件

我们刚刚看到消息模板如何实现我们传统上认为可以有效搜索和分析的日志“消息”。

结构化日志记录的另一方面是通过某种因果关系或空间关联来识别相关事件集合。事件触发:[Events raised: ]

  • 在处理单个HTTP请求期间

  • 从特定的机器,应用程序,服务或组件

  • 关于单个客户,订单或交易

  • 起因于事件的因果链

Serilog通过enrichment来处理所有这些情况(以及其他情况)。Enrichment只是为事件添加附加属性,而不是源自消息模板的属性

添加[Enriching]特定的属性

最简单的enrichment方法将固定属性值添加到源自日志记录管道的所有事件,可以通过Enrich.WithProperty()方法快速实现

Log.Logger = new LoggerConfiguration()  .Enrich.WithProperty("Application", "Demo").WriteTo.Seq("http://localhost:5341") //Seq 日志服务器.CreateLogger();

LogEvents上,通过enrichment添加的属性看起来与源自消息模板的属性相同

json  {     "@t": "2017-11-20T11:33:01.22138",     "@l": "Debug",     "@m": "Processing item 10 of 999",     "ItemNumber": 10,     "ItemCount": 999,     "Application": "Demo" }

丰富特殊的属性

通过创建和使用上下文记录器,可以将属性添加到一个或几个相关事件中,而不是增加具有相同值的所有事件

var orderLog = Log.ForContext("OrderId", order.Id);  
orderLog.Information("Looking up product codes");  // ...orderLog.Information("Product lookup took {Elapsed} ms", elapsed.TotalMilliseconds);  

在这里,通过orderLog发出的两个事件都会附加一个OrderId属性。
Enrichmen是附加的:如果应用程序属性设置在管道级别,则上面的第二个事件将携带Elapsed(来自消息),OrderId(来自上下文记录器)和Application(来自记录管道)。

丰富消息源类型信息

记录器特定的enrichment一个特例是关于如何使用创建它们的类标记事件

在名为HomeController的类中,使用以下命令创建类型特定的记录器:

private readonly ILogger _log = Log.ForContext<HomeController>();  

通过_log发出的事件将携带一个值为MyApp.Controllers.HomeControllerSourceContext属性。

充分利用上下文

为了丰富工作单元中所有事件[为所有事件添加特定属性],Serilog提供了LogContext,首先需要使用Enrich.FromLogContext()LoggerConfiguration级别启用:

Log.Logger = new LoggerConfiguraition()  .Enrich.FromLogContext()     // ...

LogContext可以被认为是一堆(key,value)键值对;

using (LogContext.PushProperty("MessageId", message.Id))  
{Log.Debug("Dispatching message of type {MessageType}", message.GetType());    await handler.HandleAsync(message);
}

关于LogContext有趣的是没有什么需要对象需要传递。在示例代码中,HandleAsync()以及由它调用的任何其他方法的实现可以直接使用LogILogger - MessageId属性将自动T并添加LogEvent中。

TipLogContext是一个堆栈;推送到堆栈上的属性必须通过释放从PushProperty()返回的对象, -- 上述通过手动使用using块的方式

已经存在的Enricher

所有enrichment API都是使用Enricher的实现Serilog的ILogEventEnricher接口的对象来实现的。

NuGet中为线程细节,机器信息和用户详细信息等内容提供了一些有趣的预先构建的Enricher实现。

Serilog.Enrichers.Thread 通过 Enrich.WithThreadId() 来添加线程ID相关的扩展:

Log.Logger = new LoggerConfiguration()  .Enrich.WithThreadId()    // ...

这将为事件附加一个ThreadId属性,以便交错事件可以再次分开。

我们将在下一节中看到一个简单的例子,说明如何编写和插入自己的应用程序专用的Enricher程序。

6. 大海捞针 Finding needles in the haystack

如果我们已经知道如何使用Serilog调用消息模板和enrichment结构化日志的两个支柱,那么第三个支柱就是隐式事件类型的概念。

结构化日志适合有效处理大量日志数据。关于大型日志流的一个有趣的观察是,真实产生的事件比编写日志语句代码块时要多的多(注:这算什么发现)

Log.Debug("Processing item {ItemNumber} of {ItemCount}", itemNumber, itemCount);  

这意味着,尽管生成了许多独特的消息字符串,如"Processing item 31 of 4159",但由此日志记录语句生成的每个事件共享相同的消息模板,即"Processing item {ItemNumber} of {ItemCount}"

Serilog及其许多sinks 利用这一事实从根本上改进了查询和过滤日志事件的体验。如果消息模板与事件一起保存,则下面的过滤器可以立即从嘈杂的日志记录语句中排除成千上万的事件,从而更容易看到否则会被淹没的有趣事件:

@MessageTemplate <> 'Processing item {ItemNumber} of {ItemCount}'

反转也适用 - 放大事件类型可以从单个日志记录语句中查找所有事件

如何利用此功能取决于您存储和搜索日志的位置。接下来我们会看看细节。

Tip:字符串链接,C#内插字符串,以及其他技术手段来预格式化传递给Serilog的消息内容,会取消此功能。详细请看 How (not) to parameterize Serilog events

隐式事件类型

存储,然后过滤罗嗦的消息模板并不总是理想的。 相反,通常从消息模板创建一个数字哈希值,并将其与事件一起存储:

事件类型 enrichment

日志文件和本地不支持消息模板的日志服务器仍然可以通过在Serilog管道中明确地enricher事件来接收事件类型。

为此,自定义enricher程序将EventType属性附加到每个事件

// Install-Package Murmurhashclass EventTypeEnricher : ILogEventEnricher  {   public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)   {      var murmur = MurmurHash.Create32();      var bytes = Encoding.UTF8.GetBytes(logEvent.MessageTemplate.Text);      var hash = murmur.ComputeHash(bytes);      var numericHash = BitConverter.ToUInt32(hash, 0);      var eventType = propertyFactory.CreateProperty("EventType", numericHash);logEvent.AddPropertyIfAbsent(eventType);}
}

当插入管道时,这会使{EventType}属性可用于sinks

Log.Logger = new LoggerConfiguration()  .Enrich.With<EventTypeEnricher>().WriteTo.Console(outputTemplate:       "{Timestamp:HH:mm:ss} [{EventType:x8} {Level:u3}] {Message:lj}{NewLine}{Exception}").CreateLogger();

WriteTo.Console()的参数是一个Serilog输出模板,描述了如何将日志事件的属性格式化为文本。 大多数基于文本的sinks(包括Serilog.Sinks.File)都可以接受输出模板来指导格式化。

[ 输出如下所示:]

7. 下一步做什么

Serilog是一个强大的库,拥有广泛的插件和工具生态系统。我们只涉及绝对的基础知识 - 取决于您希望如何使用Serilog以及您使用的框架和平台,还有很多可以发现的地方。

这里有一些文章和扩展,供你参考:

  • Debugging and diagnostics - if you're having trouble getting Serilog or a sink to work, check out this page on the Serilog wiki

  • appsettings.json configuration - in this article we've only shown the C# configuration API; Serilog.Settings.Configuration adds support for logger configuration in .NET Core JSON settings

  • XML <appSettings> configuration - Serilog.Settings.AppSettings adds support for reading logger configuration from .NET Framework configuration files

  • ASP.NET Core integration - the Serilog.AspNetCore package seamlessly integrates Serilog into ASP.NET Core 2.0 apps to take advantage of the structured log events emitted by the framework

  • ASP.NET integration - check out SerilogWeb.Classic for a quick-and-painless way to record unhandled exceptions and request timings from ASP.NET projects

  • Smart logging middleware for ASP.NET Core - improve the quality of request logging in ASP.NET Core with the middleware from this article

  • Timed operations - SerilogTimings is a small wrapper for Serilog that makes it easy to log operation timings

  • Autofac-Serilog integration - use AutofacSerilogIntegration to inject Serilog ILoggers through Autofac with type information automatically added

  • Code analysis for Serilog - mentioned earlier, Serilog Analyzer checks message template syntax in Visual Studio as-you-type, and detects many potential Serilog usage issues

  • Dynamic filtering - Serilog.Filters.Expressions makes it possible to filter events using a simple domain-specific language

  • Async wrapper - the latency of logging to files or the console can be reduced further using the Serilog.Sinks.Async package

  • Sink READMEs - most sinks, including Serilog.Sinks.File, Serilog.Sinks.Console, Serilog.Sinks.Seq and others, have good README documents in their GitHub repositories with detailed instructions for using the sink

  • Structured Logging Concepts in .NET series - this blog series on structured logging has more detail on much of what we've covered in this tutorial

  • F# support - if your application is written in F#, Destructurama.FSharp will let you log F# types seamlessly through Serilog

  • JSON.NET support - Destructurama.JsonNet extends Serilog to allow JSON.NET dynamic objects to be logged as structured data

  • Exception enricher - Serilog.Exceptions collects additional exception-type-specific information and attaches it to log events

  • Async stack trace unmangling - Serilog.Enrichers.Demystify plugs in Ben Adams' Demystifier to improve the readability of exception stack traces

8. 获得帮助

Serilog有三大优秀的社区支持渠道:

  • Stack Overflow - 如果您有Serilog使用问题,Stack Overflow上的Serilog标签是一个很好的开始; 它被积极监控,并且您将通过留下一个容易找到的答案来帮助其他人解决同一个问题

  • Gitter Chat - 如果您的问题不符合Stack Overflow格式,或者您只是想完善检查方法,那么Gitter聊天室是与Serilog社区中的其他人联系的快捷方式

  • GitHub Issues - 最后,如果你发现了一个bug或者想要对Serilog进行改进,GitHub就是这个地方; Serilog organization包括了serilog所有的核心库和问题跟踪。

Happy logging!

原文地址http://blog.getseq.net/serilog-tutorial/


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321785.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用DDD、事件风暴和Actor来设计反应式系统

领域驱动设计&#xff08;domain-driven design&#xff0c;DDD&#xff09;通常在微服务领域用于查找边界&#xff08;限界上下文&#xff09;。同样来自DDD的聚合&#xff08;aggregate&#xff09;对于定义持久化和一致性的范围来讲也是很重要的。 但是&#xff0c;并不是领…

站在巨人肩上的.NET Core 2.1

.NET Core 1.0自发布两年以来&#xff0c;得到了开发者群体相当高地认可。 下图来自Stack overflow survey 2018的统计&#xff1a;.NET Core已经成为前五的主流框架工具&#xff0c;现今借鉴了优秀的设计原则和开发体验可谓站在巨人肩上。这一切归功于.NET团队认识和总结了大量…

5、java中的数组

1、简介 数组是一种具有随机存取特性的数据结构&#xff0c;是内存上一段连续区域的表示&#xff0c;是实现顺序存储的基础&#xff0c;数组只能用于存储同一类型的数据。数组的长度在初始化时定义之后就不可更改&#xff0c;并且在初始化数组时必须指定数组的长度。 2、数组…

动态规划训练19、最短路 [Help Jimmy POJ - 1661 ]

Help Jimmy POJ - 1661 题意&#xff1a;大致是一个人从某个点开始下落&#xff0c;下落的速度是1m/s&#xff0c;然后在平台上的时候可以左右移动&#xff0c;移动的速度也是1m/s&#xff0c;但是这里有一个限制&#xff0c;就是说每次下落的距离不能超过一个给定的数值。问你…

【活动(北京)】Global Azure Bootcamp

活动议程活动内容08:30-08:50报到08:50-09:10活動开场Study4 - 陈科融(MVP)STB Chain Foundation - 劉海峰(MVP)MVP Program - Christina Liang(MVP CPM)09:10-10:00区块链让软件资产化成为现实刘海峰(MVP) - STBChain Foundation主席10:10-11:00基于Azure PaaS的网站应用刘元纶…

6、java中的排序算法

1、简介 排序是将元素按着指定关键字的大小递增或递减进行数据的排列&#xff0c;排序可以提高查找的效率 2、排序算法的分类 排序算法可大致分为四类七种&#xff0c;具体分类如下&#xff1a; 插入排序&#xff1a;直接插入排序、希尔排序 交换排序&#xff1a;冒泡排序、…

用.NET Core实现装饰模式和.NET Core的Stream简介

该文章综合了几本书的内容.某咖啡店项目的解决方案某咖啡店供应咖啡, 客户买咖啡的时候可以添加若干调味料, 最后要求算出总价钱.Beverage是所有咖啡饮料的抽象类, 里面的cost方法是抽象的. description变量在每个子类里面都需要设置(表示对咖啡的描述).每个子类实现cost方法, …

这个拖后腿的“in”

问题之源C# 7.2推出了全新的参数修饰符in&#xff0c;据说是能提升一定的性能&#xff0c;官方MSDN文档描述是&#xff1a;Add the in modifier to pass an argument by reference and declare your design intent to pass arguments by reference to avoid unnecessary copyin…

Surging 微服务框架使用入门

前言本文非 Surging 官方教程&#xff0c;只是自己学习的总结。如有哪里不对&#xff0c;还望指正。 我对 surging 的看法我目前所在的公司采用架构就是类似与Surging的RPC框架&#xff0c;在.NET 4.0框架上搭建Socket RPC&#xff0c;通过分组轮询的方式调度RPC&#xff0c;经…

RabbitMQ教程C#版 - 工作队列

先决条件本教程假定RabbitMQ已经安装&#xff0c;并运行在localhost标准端口&#xff08;5672&#xff09;。如果你使用不同的主机、端口或证书&#xff0c;则需要调整连接设置。从哪里获得帮助如果您在阅读本教程时遇到困难&#xff0c;可以通过邮件列表联系我们。1.工作队列&…

IdentityServer4实战 - 基于角色的权限控制及Claim详解

一.前言大家好&#xff0c;许久没有更新博客了&#xff0c;最近从重庆来到了成都&#xff0c;换了个工作环境&#xff0c;前面都比较忙没有什么时间&#xff0c;这次趁着清明假期有时间&#xff0c;又可以分享一些知识给大家。在QQ群里有许多人都问过IdentityServer4怎么用Role…

11、java中的I/O流(1)

我对于流的理解是这样的&#xff0c;计算机的本质本来就是对输入的数据进行操作&#xff0c;然后将结果输出的一种工具&#xff0c;数据在各个数据源节点之间进行流动&#xff0c;感觉流就是对这种状态的一种抽象&#xff0c;一个数据流表示的就是一系列数据序列&#xff0c;ja…

ASP.NET Core 集成测试

集成测试集成测试&#xff0c;也叫组装测试或联合测试。在单元测试的基础上&#xff0c;将所有模块按照设计要求&#xff08;如根据结构图&#xff09;组装成为子系统或系统&#xff0c;进行集成测试。实践表明&#xff0c;一些模块虽然能够单独地工作&#xff0c;但并不能保证…

使用C#开发Android应用之WebApp

近段时间了解了一下VS2017开发安卓应用的一些技术&#xff0c;特地把C#开发WebApp的一些过程记录下来&#xff0c;欢迎大家一起指教、讨论&#xff0c;废话少说&#xff0c;是时候开始表演真正的技术了。。1、新建空白Android应用2、拖一个WebView控件进来3、打开模拟器Genymot…

ASP.NET Core依赖注入深入讨论

这篇文章我们来深入探讨ASP.NET Core、MVC Core中的依赖注入&#xff0c;我们将示范几乎所有可能的操作把依赖项注入到组件中。依赖注入是ASP.NET Core的核心&#xff0c;它能让您应用程序中的组件增强可测试性&#xff0c;还使您的组件只依赖于能够提供所需服务的某些组件。举…

使用静态基类方案让 ASP.NET Core 实现遵循 HATEOAS Restful Web API

Hypermedia As The Engine Of Application State (HATEOAS)HATEOAS&#xff08;Hypermedia as the engine of application state&#xff09;是 REST 架构风格中最复杂的约束&#xff0c;也是构建成熟 REST 服务的核心。它的重要性在于打破了客户端和服务器之间严格的契约&…

【招聘(北京)】.NETCORE开发工程师(微服务方向)

组织&#xff1a;华汽集团北京研发中心位置&#xff1a;北京市朝阳区焦奥中心官网&#xff1a;www.sinoauto.com邮箱&#xff1a;taoxu.weisinoauto.com 项目&#xff1a;打造面向国内汽车后市场用户的一站式云服务平台&#xff08;华汽云&#xff09;&#xff0c;形态包括B2B、…

确保线程安全下使用Queue的Enqueue和Dequeue

场景是这样&#xff0c;假设有一台设备会触发类型为Alarm的告警信号&#xff0c;并把信号添加到一个Queue结构中&#xff0c;每隔一段时间这个Queue会被遍历检查&#xff0c;其中的每个Alarm都会调用一个相应的处理方法。问题在于&#xff0c;检查机制是基于多线程的&#xff0…

编写一个Java程序,其中包含三个线程: 厨师(Chef)、服务员(Waiter)和顾客(Customer)

编写一个Java程序&#xff0c;其中包含三个线程: 厨师(Chef)、服务员(Waiter)和顾客(Customer)。他们的行动如下: 厨师准备菜肴&#xff0c;每次准备一个。服务员等待菜肴准备好&#xff0c;然后将其送到顾客那里。顾客等待服务员送来菜看后才开始吃。所有三个角色应该循环进行…

Hangfire使用ApplicationInsigts监控

起因我司目前使用清真的ApplicationInsights来做程序级监控。&#xff08;ApplicationInsights相关文档: https://azure.microsoft.com/zh-cn/services/application-insights/ &#xff09;其实一切都蛮好的&#xff0c;但是我们基于Hangfire的Job系统却无法被Ai所监控到&#…