├── .github └── ISSUE_TEMPLATE │ ├── 01_oss.md │ ├── 02_news.md │ ├── 03_article.md │ └── 04_video.md ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── episode-001.md ├── episode-002.md ├── episode-003.md ├── episode-004.md ├── episode-005.md ├── episode-006.md ├── episode-007.md ├── episode-008.md ├── episode-009.md ├── episode-010.md ├── episode-011.md ├── episode-012.md ├── episode-013.md ├── episode-014.md ├── episode-015.md ├── episode-016.md ├── episode-017.md ├── episode-018.md ├── episode-019.md ├── episode-020.md ├── episode-021.md ├── episode-022.md ├── episode-023.md ├── episode-024.md ├── episode-025.md ├── episode-026.md ├── episode-027.md ├── episode-028.md ├── episode-029.md ├── episode-030.md ├── episode-031.md ├── episode-032.md ├── episode-033.md ├── episode-034.md ├── episode-035.md ├── episode-036.md ├── episode-037.md ├── episode-038.md ├── episode-039.md ├── episode-040.md ├── episode-041.md ├── episode-042.md ├── episode-043.md ├── episode-044.md ├── episode-045.md ├── episode-046.md ├── episode-047.md ├── episode-048.md ├── episode-049.md ├── episode-050.md ├── episode-051.md ├── episode-052.md ├── episode-053.md ├── episode-054.md ├── episode-055.md ├── episode-056.md ├── episode-057.md ├── episode-058.md ├── episode-059.md ├── episode-060.md ├── episode-061.md ├── episode-062.md ├── episode-063.md ├── episode-064.md ├── episode-065.md ├── episode-066.md ├── episode-067.md ├── episode-068.md └── images │ ├── 001 │ └── world-of-dotnet.svg │ ├── 002 │ ├── anders.jpeg │ ├── dotnetroadmap.png │ └── polly.jpeg │ ├── 003 │ ├── autofac.jpeg │ ├── dotnet-conf-china.png │ ├── ef-plus.jpeg │ ├── linq.jpeg │ ├── vs-widget.png │ └── xmas.webp │ ├── 004 │ ├── const-readonly.png │ ├── dotnet-oss.png │ ├── error-body.png │ ├── non200.png │ ├── status-200.png │ └── using.png │ ├── 005 │ ├── benchmark.png │ ├── dotnet-oss-ms.png │ ├── maui-11.png │ ├── spring-vs-dotnet.png │ └── vs.png │ ├── 006 │ ├── csharp.jpeg │ ├── stringbuilder.jpeg │ └── vs.gif │ ├── 007 │ ├── aspnet-core-performance.png │ ├── datetimeoffset.png │ ├── dotnet-core-framework.png │ ├── guard.png │ ├── performance.jpeg │ └── powershell-rdp.png │ ├── 008 │ ├── Backend-.NET-Developer-Roadmap-2022.png │ ├── das-blog.jpeg │ ├── deconstructor.jpeg │ ├── dotnet-20.jpeg │ ├── maui-12.png │ └── miguel-de-icaza.jpeg │ ├── 009 │ ├── dotnet-7-preview.jpeg │ ├── linux.svg │ ├── nullable.jpeg │ └── vs_2012.jpeg │ ├── 010 │ ├── csharp-11.png │ ├── github-action.png │ ├── mispell-dotnet.png │ ├── morelinq.png │ ├── stryke.svg │ └── vs-debug.jpeg │ ├── 011 │ ├── asp-net-core-pipeline.png │ ├── exception.png │ ├── property.jpeg │ ├── service.png │ ├── sys-command-line.png │ └── vs-25.png │ ├── 012 │ ├── Timer.png │ ├── avaloniaui.png │ ├── cancellation.jpg │ ├── github-co-pilot.webp │ ├── nano.png │ └── nuget.png │ ├── 013 │ ├── bayes.png │ ├── cpp.png │ ├── format.png │ ├── graphapi.png │ ├── ienumerable.gif │ ├── interview.webp │ ├── jonskeet.jpg │ └── roslyn.png │ ├── 014 │ ├── bayes.png │ ├── cosmosdb.jpeg │ ├── gprcjson.png │ ├── regex.jpeg │ └── wcf.png │ ├── 015 │ ├── aspnetcore.jpg │ ├── cache.png │ ├── cleanup.png │ ├── gui.png │ ├── httpclient.png │ ├── maui.png │ ├── msbuild.png │ └── nuget.png │ ├── 016 │ ├── benchmark.png │ ├── enum.png │ ├── exchange.jpg │ ├── gc.png │ ├── globalusing.jfif │ ├── greenthread.png │ ├── lambdadotnet.png │ ├── maui.png │ ├── memory.png │ ├── omnisharp.png │ └── stringempty.png │ ├── 017 │ ├── antdesign.png │ ├── dotnet101.png │ ├── hava.png │ ├── ienumerable.png │ ├── linq.png │ ├── memory.png │ ├── regex.png │ ├── roslynpad.png │ ├── string.png │ └── vscode.png │ ├── 018 │ ├── AwesomeBlazor.png │ ├── DotnetEdition.png │ ├── EssentialFsharp.png │ ├── FirstOrSingle.png │ ├── MauiAndDevOps.png │ ├── NeuralNetwork.png │ ├── PublishAWS.png │ ├── RangesAndIndices.png │ └── VSCodeServer.png │ ├── 019 │ ├── APISIX.png │ ├── Base64.png │ ├── CSharp11.jpg │ ├── CSharpUnsafe.png │ ├── DotNetConf.png │ ├── MiniExcelWork.png │ ├── Nlog.jpg │ ├── RateLimiter.png │ ├── ThrowEx.png │ ├── miniExcel.jpg │ └── systemd.png │ ├── 020 │ ├── azure.png │ ├── communityTool.png │ ├── gc.png │ ├── linq.png │ ├── maui.png │ ├── restclient.png │ ├── threadsafe.png │ └── unit.png │ ├── 021 │ ├── C11.png │ ├── appservice.png │ ├── asyncyieldreturn.png │ ├── bogus.png │ ├── cocurrent.png │ ├── controller.png │ ├── memortytool.png │ ├── muai.png │ ├── nunit.png │ └── yieldreturn.png │ ├── 022 │ ├── IEnumerable.png │ ├── async.png │ ├── docker.png │ ├── dotnet7.png │ ├── file.png │ ├── gcinternal.png │ ├── linq.png │ ├── timer.png │ └── toolbox.png │ ├── 023 │ ├── aspdotnetcore7.png │ ├── csharp11.png │ ├── dotnet7arm64.png │ ├── dotnet7rc.png │ ├── madstorgersen.png │ ├── muai.png │ ├── playwright.png │ ├── sealclass.png │ ├── thrift.png │ └── winget.png │ ├── 024 │ ├── ASP.NETCoreConfigure.png │ ├── AspDotNETCore.png │ ├── DockerSQLServer.png │ ├── DotNETName.png │ ├── EFCore.jfif │ ├── JsonConfigure.png │ ├── LINQUse.png │ ├── RateLimter.png │ ├── dotnetCallJS.png │ └── exposeMAUI.png │ ├── 025 │ ├── aspnetcore7.png │ ├── cake.png │ ├── cleanarchiture.png │ ├── davidfowler.png │ ├── dotnetcsharp.png │ ├── httpquery.png │ ├── imagesharp.png │ ├── odata.png │ ├── vstheme.png │ └── waitall.png │ ├── 026 │ ├── .net7.png │ ├── .netconf.png │ ├── cliwrap.png │ ├── dump.png │ ├── githubvs.png │ ├── litedb.png │ ├── muai.png │ ├── random.png │ ├── respwarn.png │ ├── using.png │ └── vs2022.png │ ├── 027 │ ├── .netconfi.png │ ├── .netopenday.png │ ├── Csharp11.png │ ├── fleet.png │ ├── humanizer.png │ ├── performance.png │ ├── so.png │ └── span.png │ ├── 028 │ ├── fluentui.png │ ├── imagesharp.png │ ├── lambda.png │ ├── openAI.png │ ├── ployglot.png │ ├── ramstring.png │ ├── todo.png │ └── xmas.png │ ├── 029 │ ├── call.png │ ├── dotnetcli.png │ ├── eric.png │ ├── gc.png │ ├── json.png │ ├── markdown.png │ ├── minimalapi.png │ ├── newfile.png │ ├── quartz.png │ └── stopwatch.png │ ├── 030 │ ├── csharpbeginner.png │ ├── defaultmethod.png │ ├── opensource.png │ ├── oracle.png │ ├── scottplot.png │ └── tuple.png │ ├── 031 │ ├── bflat.png │ ├── cobol.png │ ├── constructor.png │ ├── encryption.png │ ├── methodtimer.png │ ├── questpdf.png │ ├── suvery.png │ └── vssearch.png │ ├── 032 │ ├── asynchronous.png │ ├── dotnet.png │ ├── languages.png │ ├── powershell.png │ ├── security.png │ └── stride.png │ ├── 033 │ ├── cleanarchitecture.png │ ├── dotnet8.png │ ├── dotnetupgrade.png │ ├── linq2sql.png │ ├── onnx.png │ ├── readme.png │ └── vsintelligence.png │ ├── 034 │ ├── dotnetday.png │ ├── dotnethistory.png │ ├── gitrider.png │ ├── refactor.png │ ├── repl.png │ ├── roadmap.png │ ├── sdk.png │ └── validator.png │ └── 035 │ ├── ai.png │ ├── aspnetcore.png │ ├── javacsharp.png │ ├── netstandard.png │ ├── openai.png │ ├── package.png │ ├── stringobject.png │ ├── timer.png │ ├── virutalevent.png │ └── wasm.png ├── linter.yml └── tools ├── Request-PublishEpisode.ps1 └── Request-UploadImages.ps1 /.github/ISSUE_TEMPLATE/01_oss.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 开源项目 3 | about: Describe this issue template's purpose here. 4 | title: "【开源项目】" 5 | labels: 开源项目 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02_news.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 行业资讯 3 | about: Describe this issue template's purpose here. 4 | title: "【行业资讯】" 5 | labels: 行业资讯 6 | assignees: "" 7 | --- 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/03_article.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 文章推荐 3 | about: Describe this issue template's purpose here. 4 | title: "【文章推荐】" 5 | labels: 文章推荐 6 | assignees: "" 7 | --- 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/04_video.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 视频推荐 3 | about: Describe this issue template's purpose here. 4 | title: "【视频推荐】" 5 | labels: 视频推荐 6 | assignees: "" 7 | --- -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Feng Gao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![linter]()](https://dev.azure.com/tindi/DotNETWeekly/_build/latest?definitionId=10&branchName=master) 2 | 3 | # 介绍 4 | 5 | .NET 周刊是一个专注于`.NET`生态的资源中心,它的目标是收集`.NET` 生态中的有价值的内容,并且每周定期发布。它受到[科技爱好者周刊](https://github.com/ruanyf/weekly)和[Go 语言爱好者周刊](https://github.com/polaris1119/golangweekly) 的启发。 6 | 7 | 欢迎投稿,请[提交 issue](https://github.com/DotNETWeekly-io/DotNetWeekly/issues)。 8 | 9 | 我们在三个平台上发布 10 | 11 | - [GitHub订阅通道(首选)](https://github.com/DotNETWeekly-io/dotnet-monthly) 12 | - [Web](https://www.fungkao.net/searchByTag/.NET%20Weekly) 13 | - [知乎](https://www.zhihu.com/column/c_1775053216763277312) 14 | 15 | ## 周刊 16 | 17 | ### 2025 18 | 19 | **六月份** : [第 068 期](docs/episode-068.md) :high_brightness: 20 | 21 | **五月份** : [第 067 期](docs/episode-067.md) 22 | 23 | **四月份** : [第 066 期](docs/episode-066.md) 24 | 25 | **三月份** : [第 065 期](docs/episode-065.md) 26 | 27 | **一月份** : [第 064 期](docs/episode-064.md) 28 | 29 | ### 2024 30 | 31 | **十二月份** : [第 063 期](docs/episode-063.md) 32 | 33 | **十月份** : [第 062 期](docs/episode-062.md) | [第 061 期](docs/episode-061.md) 34 | 35 | **八月份** : [第 060 期](docs/episode-060.md) 36 | 37 | **七月份** : [第 059 期](docs/episode-059.md) | [第 058 期](docs/episode-058.md) 38 | 39 | **六月份** : [第 057 期](docs/episode-057.md) | [第 056 期](docs/episode-056.md) 40 | 41 | **五月份** : [第 055 期](docs/episode-055.md) | [第 054 期](docs/episode-054.md) 42 | 43 | **四月份** : [第 053 期](docs/episode-053.md) 44 | 45 | **三月份** : [第 052 期](docs/episode-052.md) | [第 051 期](docs/episode-051.md) 46 | 47 | **二月份**: [第 050 期](docs/episode-050.md) 48 | 49 | **一月份**: [第 049 期](docs/episode-049.md) | [第 048 期](docs/episode-048.md) 50 | 51 | ### 2023 52 | 53 | **十二月份**: [第 047 期](docs/episode-047.md) | [第 046 期](docs/episode-046.md) 54 | 55 | **十一月份**: [第 045 期](docs/episode-045.md) | [第 044 期](docs/episode-044.md) 56 | 57 | **十月份**: [第 043 期](docs/episode-043.md) 58 | 59 | **九月份**: [第 042 期](docs/episode-042.md) | [第 041 期](docs/episode-041.md) 60 | 61 | **八月份**: [第 040 期](docs/episode-040.md) 62 | 63 | **七月份**: [第 039 期](docs/episode-039.md) | [第 038 期](docs/episode-038.md) 64 | 65 | **六月份**: [第 037 期](docs/episode-037.md) 66 | 67 | **五月份**: [第 036 期](docs/episode-036.md) | [第 035 期](docs/episode-035.md) 68 | 69 | **三月份**: [第 034 期](docs/episode-034.md) | [第 033 期](docs/episode-033.md) 70 | 71 | **二月份**: [第 032 期](docs/episode-032.md) 72 | 73 | **一月份**: [第 031 期](docs/episode-031.md) | [第 030 期](docs/episode-030.md) 74 | 75 | ### 2022 76 | 77 | **十二月份**: [第 029 期](docs/episode-029.md) | [第 028 期](docs/episode-028.md) 78 | 79 | **十一月份**: [第 027 期](docs/episode-027.md) | [第 026 期](docs/episode-026.md) 80 | 81 | **十月份**: [第 025 期](docs/episode-025.md) | [第 024 期](docs/episode-024.md) 82 | 83 | **九月份**: [第 023 期](docs/episode-023.md) | [第 022 期](docs/episode-022.md) 84 | 85 | **八月份**: [第 021 期](docs/episode-021.md) | [第 020 期](docs/episode-020.md) | [第 019 期](docs/episode-019.md) 86 | 87 | **七月份**: [第 018 期](docs/episode-018.md) | [第 017 期](docs/episode-017.md) 88 | 89 | **六月份**: [第 016 期](docs/episode-016.md) | [第 015 期](docs/episode-015.md) 90 | 91 | **五月份**: [第 014 期](docs/episode-014.md) | [第 013 期](docs/episode-013.md) 92 | 93 | **四月份**: [第 012 期](docs/episode-012.md) 94 | 95 | **三月份**: [第 011 期](docs/episode-011.md) | [第 010 期](docs/episode-010.md) 96 | 97 | **二月份**: [第 009 期](docs/episode-009.md) | [第 008 期](docs/episode-008.md) 98 | 99 | **一月份**: [第 007 期](docs/episode-007.md) | [第 006 期](docs/episode-006.md) |[第 005 期](docs/episode-005.md)| [第 004 期](docs/episode-004.md) 100 | 101 | ### 2021 102 | 103 | **十二月份**: [第 003 期](docs/episode-003.md)| [第 002 期](docs/episode-002.md) | [第 001 期](docs/episode-001.md) 104 | -------------------------------------------------------------------------------- /docs/episode-001.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 1 期 2 | 3 | ## 开卷语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c85647ee-0210-4dcf-bfd8-3b059996a1a4) 6 | 7 | 各种各样的原因,`.NET` 在国内的流行程度仍然赶不上 `Java`, `C/C++` 这样的编程语言。作为 `.NET` 生态的参与者,常常想能不能做一些事情来改变这个情况。由于语言的原因,很多外网 `.NET` 社区的内容并没有在国内传播过来。因此 `DotNET Weekly` 将会专注于分享全球 `.NET` 社区内容,通常会包含下面三种的类型的资源: 8 | 9 | - 行业资讯 10 | - 文章推荐 11 | - 开源项目 12 | 13 | 通常周刊会在周末发布。 14 | 15 | > Stay Turned 16 | 17 | ## 行业资讯 18 | 19 | 1、[Open .NET 来了?](https://www.infoq.cn/article/ut0oDCTQmT7Sdu5Ega2k) 20 | 21 | 上个月一群人 Fork 了 .NET 平台下的开源项目,并且成立 Open .NET 组织,导火索是微软在 .NET 6 发布的时候,将 CLI 工具中删除了 Hot Reload 相关的代码,使它变成了 Visual Studio 2022 独占功能。这个引发了微软在开发者社区的信任危机,他们希望借助 Open .NET 来摆脱微软对 .NET 的掌控。 22 | 23 | 2、[.NET Conf 回顾](https://devblogs.microsoft.com/dotnet/net-conf-2021-recap-videos-slides-demos-and-more/) 24 | 25 | 上个月微软举办了一年一度的 `.NET Conf` , 在会议中发布了 `.NET 6` 和 `Visual Studio`, 这篇文章可以帮你回顾一下这次会议和其中的亮点。 26 | 27 | - Roslyn 和 AI 的整合。 28 | - C# 10 的介绍。 29 | - 使用 `.NET 6` 开发出一个跨平台(Web,Desktop,Mac, iOS, Android)的播客应用示例。 30 | - Q & A Session。 31 | 32 | 还有一个 `.NET Conf` 2021 的 [Youtube Playlist](https://www.youtube.com/playlist?list=PLdo4fOcmZ0oVFtp9MDEBNbA2sSqYvXSXO)。 33 | 34 | 3、[Microsoft 技术社区](https://techcommunity.microsoft.com/) 35 | 36 | [StackOverflow](https://stackoverflow.com/) 是业界知名的的技术社区,上面有无数个问题得到了解答。Microsoft 也推出了自己的技术社区,专注于微软推出的技术,包含但不局限于 `C#`, `ASP.NET Core`, `Visual Studio`, `Windows` 等等。 37 | 38 | ## 文章推荐 39 | 40 | 1、[如何给 .NET 社区做贡献](https://rion.io/2017/04/28/contributing-to-net-for-dummies/) 41 | 42 | 作者分享了如何给 .NET 社区做共享,那怕你仍然还是一个新手。作者提出了一般人会提出的四个问题,并且一一回答它们 43 | 44 | - 我需要一个指导人来帮助我因为这些 issue 已经超出了我的理解范围。 45 | - 所有简单的 issue 已经被别人处理了。 46 | - 由于这个是 issue 已经被提出好久,如果我去做的话,我好像被暴露成一个垃圾开发者。 47 | - 我从来没有在这个规模的项目开发过,我可能干不好。 48 | 49 | 2、[如何 Review .NET 代码? 来听听别人的观点](https://levelup.gitconnected.com/my-tips-for-net-code-review-f1a47feece43) 50 | 51 | 在 DevOps 开发流程中,我们常常会 Review 别人的代码。那么该如何 Review 呢?这位 Microsoft MVP 给出了若个建议,这些不单单是给 Reviewer,而且对开发人员还有很大的帮助。 52 | 53 | 3、[学习 .NET GC](https://tooslowexception.com/net-gc-internals-mini-series/) 54 | 55 | `Pro .NET Memory Management` 图书的作者在 YouTube 上连载 .NET GC 的分享,内容十分翔实。无论是否从事 .NET 相关开发与否,都能从中学到 GC 相关的知识。 56 | 57 | ## 开源项目 58 | 59 | 1、 [单元测试框架](https://github.com/moq/moq4) 60 | 61 | 在软件开发中,单元测试是必不可少的部分。但是代码中存在一些外部的依赖,因此需要对它们进行 **Mock**。在 `.NET` 平台,最有名的框架就是 `Moq`,借助它可以帮助我们有效编写单元测试,并且辅助我们遵循面向接口编程原则。 62 | 63 | 2、[FluentAssertions](https://fluentassertions.com/) 64 | 65 | 不管在什么单元测试框架中,单元测试的形式一般如下 66 | 67 | ```Csharp 68 | var result = GetResult(); 69 | Assert.AreEqual("Hello World", result); 70 | ``` 71 | 72 | 这样的测试表明,我们期望得到的值是 `Hello World`。但是这样要求我们记住 `actual` 和 `expect` 的参数位置,对于其他类型的比较,比如集合,需要写很多琐碎的代码来判断结果是否满足预期。 73 | 74 | 而 `FluentAssertions` 就非常直接 75 | 76 | ```Csharp 77 | var result = GetResult(); 78 | result.Should().Be("Hello World"); 79 | ``` 80 | 81 | 在这里我们通过 `Should` 的拓展方法,然后进行判断。主要有两个好处: 82 | 83 | - 避免 `Assert` 的引入,使判断的流程线性化 84 | - 通过 `Should()` 返回的类型的方法,使不同类型可以定制化比较方法,比如对于 `Guid`, `Collection` 或者 `Date` 都有相应额外的操作。 85 | -------------------------------------------------------------------------------- /docs/episode-002.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 2 期 2 | 3 | ## 开卷语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/78799ce0-0770-4f0e-843b-30af6e86c6f2) 6 | 7 | 最近 `C#` 之父 _Anders Hejlsberg_ 接受了一个专访,回顾了一下在 `C#` 开发过程中历程和对最新版本的思考。有趣的是,采访的主持人是 _Anders_ 的亲弟弟。 8 | 9 | [Youtube](https://youtu.be/K3qf8gRFESU) 10 | 11 | 采访中包含了这些问题: 12 | 13 | - 为什么选择编程语言作为职业生涯的主要工作内容? 14 | - 关于开源的看法,不单单代码开源,还要开发开源。 15 | - 虽然现在专注于 `TypeScript`,那么现在在 `C#` 团队中担任的角色。 16 | - 对于目前 `C# 10` 有什么看法。 17 | - 由于疫情的影响,团队中敏捷性开发。 18 | - `TypeScript` 对工业界带来的影响。 19 | 20 | ## 行业资讯 21 | 22 | 1、[.NET Ketchup](https://dotnetketchup.com/) 23 | 24 | 怎样实时的抓住 `.NET` 的最新动态呢?访问 [.NET Ketchup](https://dotnetketchup.com/),它会定时的抓取最新的 `.NET` 信息,比如官方博客,Youtube,Twitter 等等。而且它和周刊一样,以按照周的形式组织信息源。 25 | 26 | 2、[一张图了解 .NET 发展历程](https://www.reddit.com/r/dotnet/comments/rcg391/net_history_timeline_its_not_finished_yet_so_if/) 27 | 28 | Reddit 有人发布了一张 `.NET` 的发展历程 29 | 30 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/45f0b132-26f0-406c-82f2-96ca05ee578c) 31 | 32 | - 上面是操作系统,Visual Studio, C# 语言 33 | - 下面是 CLR 的版本 34 | 35 | ## 文章推荐 36 | 37 | 1、[使用正确的方式日志记录异常信息](https://blog.stephencleary.com/2020/06/a-new-pattern-for-exception-logging.html) 38 | 39 | 如果你用日志来记录异常,通常会写这样的代码 40 | 41 | ```Csharp 42 | try 43 | { 44 | ... 45 | } 46 | catch (Exception e) 47 | { 48 | _logger.LogError(e, "Unexcepted error"); 49 | throw; 50 | } 51 | ``` 52 | 53 | 对于早期刀耕火种的时期日志,这样做是没有问题的,但是现代日志有更加丰富的功能,称之为语义化日志或者结构化日志。在遇到异常的时候,`runtime` 会在栈向上查找,在匹配后展开(unwind),这样的问题就会将日志的上下文丢弃了。而 `.NET` 支持异常过滤器,如果在异常过滤器中记录日志,就能保留下日志的上下文。 54 | 55 | ```Csharp 56 | try 57 | { 58 | ... 59 | } 60 | catch (Exception e) when (False(() => _logger.LogError(e, "Unexpected error."))) 61 | { 62 | throw; 63 | } 64 | 65 | public static bool False(Action action) 66 | { 67 | action(); 68 | return false; 69 | } 70 | ``` 71 | 72 | 2、[Jeffery Snover 专访](https://evrone.com/jeffrey-snover-interview) 73 | 74 | [Jeffery Snover](https://en.wikipedia.org/wiki/Jeffrey_Snover) 是微软的 `Technical Fellow` 也是 `PowerShell` 的发明人,这是一篇最近对他的专访,介绍了 `PowerShell` 发明背后的故事,还分享一些有趣的观点 75 | 76 | - PowerShell 诞生的三个节点 77 | 78 | 1. 在处理 `XML` 的时候,需要一种管道的处理方式 79 | 2. 尝试用 `.NET` 实现通用的 Shell 80 | 3. 编写了 Monad Manifesto 81 | 82 | - Linux 是一种基于文件的操作系统,而 Windows 是基于 API。这个也就导致了 `Bash` 基于文本这种非结构化数据,而 `PowerShell` 更专注于结构化数据。 83 | - 对于 `PowerShell` 的推广,我们更加关注于别人是否用了我们的工具取得了更大的成功,而不是他们是否在使用我们的工具。 84 | 85 | 3、[使用 HttpClient 地正确方法](https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) 86 | 87 | `HttpClient` 是 C# 广泛使用的类,但是大部分人都错误的使用了它,比如: 88 | 89 | ```Csharp 90 | using(var httpClient = new HttpClient()) 91 | { 92 | } 93 | ``` 94 | 95 | 虽然 `HttpClient` 实现了 `IDisposable` 接口,但是本质上它是一个共享的对象,调用 `Dispose` 方法并没有关闭对应的 `TCP` 对象,如果频繁地调用会消耗机器地所有 `Socket` 接口。 那么该如何修复这个问题呢? 96 | 97 | - 使用单个 `HttpClient` 对象 98 | - 使用 `Microsoft.Extension.HttpFactory` 库 99 | 100 | ## 开源项目 101 | 102 | 1、 [构建 Resilient 的引用程序 - Polly](https://github.com/App-vNext/Polly) 103 | 104 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/92393e7a-eccd-4faa-9801-4603cf0aee17) 105 | 106 | 我们都知道一个最基本的事实 107 | 108 | > 网络不可靠 109 | 110 | 那么为了构建一个 **Resillient** 的代码,需要我们着重考虑这些情况,`Polly` 这个库就够帮助我们简单地完成这份工作,主要包含以下这些策略(Policy) 111 | 112 | - 重试 (Retry) 113 | - 熔断器 (Circuit Breaker) 114 | - 回退 (Fallback) 115 | - 超时 (Timeout) 116 | - 隔断 (Bulk) 117 | - 缓存 (Cache) 118 | - 组合 (Combination) 119 | 120 | 2、[检测你的代码是否正确使用异步](https://www.poppastring.com/blog/fixing-sync-over-async-issues-in-net) 121 | 122 | `async` 和 `await` 已经在 `.NET` 生态中存在了好多年了,但是大家在写代码的时候,还是会使用 `Result`, `Wait` 和 `GetAwaiter()` 等方法让异步代码编程同步执行。微软推出了 `Microsoft.VisualStudio.Threading.Analyzers` 这个扩展包,它可以检测代码中是否出现异步代码但是同步执行的情况。 123 | -------------------------------------------------------------------------------- /docs/episode-003.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 3 期 2 | 3 | ## 开卷语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/2ef63404-4614-4c26-b15d-8b3242d471c6) 6 | 7 | 圣诞节快乐! 8 | 9 | ## 行业资讯 10 | 11 | 1、[.NET 中文官网来了](https://dotnet.microsoft.com/zh-CN/) 12 | 13 | 近日,`.NET` 中文官网已经上线。虽然说英语是每个优秀程序员必备的技能,但是作为非母语的开发人员,中文文档对于新人入手是一个不错的选择。 14 | 15 | 2、[创建 Visual Studio Widget](https://developercommunity.visualstudio.com/t/Visual-Studio-should-have-customizable-w/1586166) 16 | 17 | 与 Windows 11 中的 Widget 一下,Visual Studio 团队打算为其增加一个类似 Kanban 的功能 `Widget`,通过它可以避免在不同的应用程序之间跳转。 18 | 19 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/0ecc0c0e-c7e6-46b6-b21e-4a6f913f284c) 20 | 21 | 3、[.NET Conf 2021 中国大会回顾](https://www.cnblogs.com/shanyou/p/15707498.html) 22 | 23 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/e8ea64a7-f964-4a4a-a1b1-66e2c8f3257c) 24 | 25 | 上周一年一度的中国 `.NET Conf` 圆满落幕,这是中国 `.NET` 开发者的峰会,也是学习,分享和拓展 `.NET` 生态的重要途径。由于疫情原因,今年的大会全部由线上举办。但是大会的质量并没有因此而下降,这篇文章带你回顾一下本次大会。 26 | 27 | ## 文章推荐 28 | 29 | 1、[C# 10 特性一览](https://thomaslevesque.com/2021/11/04/a-quick-review-of-csharp-10-new-language-features/) 30 | 31 | `C# 10` 已经推出一个多月了,这篇文章快速浏览一下最新版本的特定,主要有 32 | 33 | - Record structs 34 | - Static abstract members in interfaces 35 | - Lambda improvements 36 | - Extended property patterns 37 | - File-scoped namespace 38 | - Global usings and implicit usings 39 | - Parameterless constructors and field initializers in structs 40 | - Mix declarations and variables in deconstruction 41 | 42 | 2、[字符串插入在 .NET 6 中的提升](https://btburnett.com/csharp/2021/12/17/string-interpolation-trickery-and-magic-with-csharp-10-and-net-6) 43 | 44 | 字符串插值已经在 `C#` 代码中广泛使用,但是之前的实现的还是最终通过 `string.Format(...)` 方法实现,这里可能存在无数次的装箱(Boxing) 和拆箱(Unboxing) 的操作。那么在 `.NET 6` 中有了哪些改进了? 45 | 在 `.NET 6` 中引入了 `InterpolateStringHandler` 这个类,它会根据不同的情况采用不同实现的策略。 46 | 47 | 3、[Linq via C#](https://weblogs.asp.net/dixin/linq-via-csharp) 48 | 49 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/94574dab-1638-447c-b3f6-a90c966ce308) 50 | 51 | `Linq` 是 `C#` 开发者中的*利器*, 但是很多时候,我们知道如何使用 `API`, 但是关于 `Linq` 背后的实现又掌握多少呢?这一些列文章可以帮你了解 `Linq` 的种种,主要分为三块 52 | 53 | - `.NET` 和 `C#` 54 | - `Linq` 可以操纵的数据类型 55 | - `Linq` 背后的理论支持 56 | 57 | ## 开源项目 58 | 59 | 1、[依赖注入框架 Autofac](https://autofac.org/) 60 | 61 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/b81d481a-080d-4deb-ab5e-0cb5c7628182) 62 | 63 | `Microsoft.Extension.DependencyInjection` 是在 `ASP.NET Core` 中广泛使用的依赖注入框架,在 `.NET` 生态中还有一个著名的框架叫 `autofac`。作为一个老牌的依赖注入框架,它提供了很多 `M.E.DependencyInjection` 不具备的功能 64 | 65 | - 不同类型的生命周期 66 | - MetaData 服务 67 | - 惰性初始化 68 | - ... 69 | 70 | 如果你向在你的 `ASP.NET Core` 应用程序中使用 `autofac`,可以参考[这篇文章](https://autofaccn.readthedocs.io/en/latest/integration/aspnetcore.html)。 71 | 72 | 2、[Entity Framework Plus](https://entityframework-plus.net/) 73 | 74 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c0f05558-5077-48fd-a212-39ddb4e1e80d) 75 | 76 | `Entity Framework` 是一个优秀的 `ORM` 框架,但是由于设计取舍的问题,一些必要(Must Have)的特性的缺失在一些情况下会导致性能不够理想。因此 `Entity Framework Plus` 插件可以解决这个问题,它主要有一下的功能 77 | 78 | - 批量操作 79 | - Linq 支持 80 | - 查询增强功能 81 | -------------------------------------------------------------------------------- /docs/episode-004.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 4 期 2 | 3 | ## 开卷语 4 | 5 | 欢迎来到 2022 年! 6 | 7 | ```Csharp 8 | global using System; 9 | Console.WriteLine("Hello .NET 2022!"); 10 | ``` 11 | 12 | ## 文章推荐 13 | 14 | 1、[using 语句的使用](https://www.youtube.com/watch?v=iqt7bqAm27U&ab_channel=NickChapsas) 15 | 16 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a68a8dc0-69de-474c-a9fa-30606bd400eb) 17 | 18 | 我们都知道使用 `using(var obj = new SomeClass())` 语句可以帮助我们安全的释放需要的内存,从本质上来讲,这是一个编译器的语法糖,上面的语句转换为如下 19 | 20 | ```Csharp 21 | var obj = new SomeClass(); 22 | try 23 | { 24 | //... 25 | } 26 | finally 27 | { 28 | obj.Dispose(); 29 | } 30 | ``` 31 | 32 | 借助这个特性, 我们可在非业务性代码中使用它们,比如说日志。 33 | 34 | ```Csharp 35 | class LogHandler: IDisposable 36 | { 37 | private ILogger _logger; 38 | private StopWatcher _sw; 39 | public LogHandler(ILogger logger) { 40 | _logger = logger; 41 | _sw = StopWatcher.NewStart(); 42 | } 43 | 44 | public void Dispose() { 45 | _sw.Stop(); 46 | _logger.Log($"Operation has completed in {_sw.ElapsedMilesecond} miliesecond"); 47 | } 48 | } 49 | ``` 50 | 51 | 2、[.NET 6 中增加的 API](https://blog.okyrylchuk.dev/20-new-apis-in-net-6) 52 | 53 | `.NET 6` 不仅仅带来了性能上提高,还增加了一些 API 以便更加方便使用它们。这篇文章介绍了这些新的 API,如果它正是你需要的,试着去使用它们。 54 | 55 | - DateOnly and TimeOnly 56 | - Paralle.ForEachAsync 57 | - ArgumentNullException.ThrowIfNull() 58 | - PriorityQueue 59 | - Reading and Writing Files 60 | - Periodic Timer 61 | - Metrics API 62 | - Reflection API 63 | - Process Path and ID 64 | - Configuration Helper 65 | - CSPNG 66 | - Native Memory API 67 | - WaitAsync 68 | - Math APIs 69 | - ... 70 | 71 | 3、[readonly 和 const 的区别](https://medium.com/@serhat21zor/c-readonly-vs-const-43a1799fd07d) 72 | 73 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/53e25614-f10d-4150-aa32-e828fe7a85f1) 74 | 75 | `readonly` 和 `const` 广泛使用在 `C#` 代码中,它们的主要目的是降低程序中的可变性。它们的主要区别如下 76 | 77 | **readonly** 78 | 79 | - 只能在变量的初始化行和构造函数中赋值。 80 | - 可以在构造函数中多次赋值。 81 | - 用 `static` 修饰的 `readonly` 变量只能在 `static` 修饰的构造函数中初始化。 82 | 83 | **const** 84 | 85 | - 只能在初始化行赋值。 86 | - 不能在构造函数中覆盖。 87 | - 赋值只能是在编译时候已知。 88 | - 不能使用引用类型 (reference type)。 89 | - `static const` 是没有意义的。 90 | 91 | 注意编译器会修改所有的 `const` 变量,替换为真实的值。所以如果引用了第三方库的 `const` 变量,如果第三方库升级后, 应用程序没有重新编译的话,会导致意想不到的错误。 92 | 93 | 假设现在有一个库提供了一个 `const` 变量 94 | 95 | ```Csharp 96 | public class MyLib 97 | { 98 | public const int StatusCode = 200; 99 | } 100 | ``` 101 | 102 | 我们的应用程序使用了这个库中 `StatusCode` 这个变量 103 | 104 | ```Csharp 105 | Console.WriteLine(MyLib.StatusCode); // 200 106 | ``` 107 | 108 | 如果 `MyLib` 修改了 `StatusCode = 304` 变量的字面值,我们的应用程序没有重新编译最新的版本,那么输出的结果仍然是 `200`。 109 | 110 | 4、[WebAPI 中正确处理异常](https://codeopinion.com/problem-details-for-better-rest-http-api-errors/) 111 | 112 | 开发 `WebAPI` 中除了要正确地返回需要地结果,还需要对异常情况进行处理。通常会有两种处理方式: 113 | 114 | 1. 返回非 2xx 的状态码,然后在 body 中填写响应的错误信息; 115 | 116 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/66df84e8-3652-47d0-86f0-5041cb5a7675) 117 | 118 | 2. 返回 200 的状态码,然后在 Body 中填写响应的错误信息 119 | 120 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/91820f3b-04b1-4a9e-b267-2acc35080b58) 121 | 122 | 两者有本质上的不同,第一种叫做 `error.info`, 而第二种叫做 `message`。 其实标准的做法叫做 **Problem Details** (RFC7807) 123 | 124 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/d0f7752a-32f7-44fa-bea1-5202af18149c) 125 | 126 | 这里的字段都是有特定的意义。 127 | 128 | ## 开源项目 129 | 130 | 1、[2021 最活跃的 .NET 项目](https://twitter.com/sbwalker/status/1476976431972462601) 131 | 132 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/dc3b86af-71ee-4c1c-8850-d035561ca819) 133 | 134 | 这里是 2021 年最活跃的 `.NET` 开源项目列表,主要 `Pull Request`, `Commit` 和 `New Contributor` 三个指标统计。注意这里并不包含由 Microsoft 维护或者支持的项目。 135 | -------------------------------------------------------------------------------- /docs/episode-005.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 5 期 2 | 3 | ## 开卷语 4 | 5 | 中文互联网中关于 `.NET` 存在着大量的偏见,比如 6 | 7 | - 不能跨平台 8 | - 收费 9 | - 性能差 10 | - 生态差 11 | - ... 12 | 13 | 关于这些争论,一般不会去争辩什么,因为: 14 | 15 | - 这些偏见并不会因为在网络争辩而纠正 16 | - 世界上并没有一种完美的编程语言,只有被人骂的和没人用的两种。 17 | 18 | ## 行业资讯 19 | 20 | 1、[EF 7 Plan](https://devblogs.microsoft.com/dotnet/announcing-the-plan-for-ef7/) 21 | 22 | `Entity Framework` 是 `.NET` 中广泛使用的 ORM 框架,`EF Core` 是基于 `.NET Core` 而且在 `EF Core 7` 中将会移除 `Core`, 升级为 `EF 7`, 现在 `EF` 团队发布 `EF 7` 的 Feature Request 计划,主要包含: 23 | 24 | - JSON 数据存储 25 | - 批量更新 26 | - 生命周期勾子 27 | - ... 28 | 29 | 除此之外,还有周边生态建设工作 30 | 31 | - 分布式事务 32 | - `dotnet ef` 工具集成 33 | 34 | 2、[.NET MAUI Preview 11 发布](https://devblogs.microsoft.com/dotnet/announcing-dotnet-maui-preview-11/) 35 | 36 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/ceba514b-1b74-49d9-8c6c-eb269c63075e) 37 | 38 | 虽然 `MAUI` 并没有随着 `.NET 6` 一同发布,但是微软并没有停止对 `MAUI` 的开发工作,最近 `Preview 11` 随着 `Visual Studio 2022 17.1 Preview 2` 一同发布,此次更新包含的内容有 39 | 40 | - Fluent Design System 41 | - Multi-Windows 42 | - Template and C# 10 43 | - Documentation 44 | 45 | ## 文章推荐 46 | 47 | 1、[ASP.NET Core 和 Spring Boot 比较](https://medium.com/@putuprema/spring-boot-vs-asp-net-core-a-showdown-1d38b89c6c2d) 48 | 49 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/d1ccc832-5940-4657-8bce-8ab72e66e77f) 50 | 51 | `Java` 和 `C#` 都是成熟的工业级软件开发语言,在 `Web` 后端开发方面,`Java` 有 `Spring` 框架,而 `C#` 有 `ASP.NET Core`, 这篇文章带你分析这两个框架在后端开发的区别,主要有 52 | 53 | - 控制器 (Controller) 54 | - 数据绑定和验证 (Model Binding & Validation) 55 | - 异常处理 (Exception Handling) 56 | - 数据访问 (Repository & ORM) 57 | - 依赖注入 (Dependency Injection) 58 | - 权限管理(Authentication & Authorization) 59 | - 性能 (Performance) 60 | 61 | 2、[旧闻回顾:Visual Studio 会毁掉你的心智吗?](http://charlespetzold.com/etc/DoesVisualStudioRotTheMind.html) 62 | 63 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/401fb1be-a94d-4d03-b1a1-363161206c13) 64 | 65 | 这是一篇十几年前的演讲稿,作者是开发 `Window Form` 应用程序,在 `Visual Studio 2005` 发布之后,对其功能做了一些*吐槽*。 66 | 67 | - 智能感知 (IntelliSense) : 作者认为 `IntelliSense` 并不会让我们变成一个好的程序员,而是一个编码快速的程序员。 68 | - 代码生成(Generated Code): 在使用 `Visual Studio` 创建一个 `Windows Form` 应用程序的时候,会自动生成若干代码,这些代码是 `Visual Studio` 不想让你知道的。 69 | - 设计页面 (Designers): `Visual Studio` 引入了交互式的设计页面,这是一个好的技术进步。 70 | - 资源脚本: `Visual Studio` 隐藏了资源的,不是通过显式代码形式。而且每个 Control 的默认行为非常丑陋。 71 | - ... 72 | 73 | 作者认为他更倾向于用纯文本的方式开发应用程序。 74 | 75 | 站在 2022 年的今天,你该如何看待他的观点呢? 76 | 77 | ## 开源项目 78 | 79 | 1、[2021 .NET 最活跃的 Microsoft 的开源项目](https://pbs.twimg.com/media/FICYOcDWUAIFkXw?format=png&name=900x900) 80 | 81 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/39ef9c43-9663-4a65-b318-66fca92fc703) 82 | 83 | 这里是 2021 年最活跃的由 Microsoft 维护或者支持 `.NET` 开源项目列表,主要 `Pull Request`, `Commit` 和 `New Contributor` 三个指标统计。 84 | 85 | 2、[Benchmarkdotnet 库](https://benchmarkdotnet.org/articles/overview.html) 86 | 87 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/b841b8d4-7ff9-4587-b786-7afa6322e277) 88 | 89 | 在进行代码性能分析的时候,我们需要准确地知道其运行时间和内存消耗数据。同时针对不同的环境和数据量的情况,也需要进行相关分析。 90 | 91 | > Code is cheaper, show me statistic. 92 | 93 | `BenchmarkDotnet` 库就是 `.NET` 世界的性能测量工具。它的功能有 94 | 95 | - 支持统计学模型 96 | - 不同运行环境统计,比如 CLR, Mono,CoreCLR 等等 97 | - 丰富的统计图标输出 98 | - 基准测试 99 | - 交叉参数组合 100 | - 内存诊断 101 | - ... 102 | -------------------------------------------------------------------------------- /docs/episode-006.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 6 期 2 | 3 | ## 开卷语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/9e5eb65f-bd1c-484c-a53d-397ae7de5f0c) 6 | 7 | `Tiobe` 公布了 2021 年度语言,`Python` 再一次夺得头名。但是之前都是 `C#` 处于领头羊的位置,只不过在最后一个月被 `Python` 反超。不管怎样,都说明了 `C#` 仍然往好的方向发展。 8 | 9 | ## 行业资讯 10 | 11 | 1、[在 Visual Studio 2022 中聊天](https://devblogs.microsoft.com/visualstudio/integrated-chat-in-live-share-for-visual-studio-2022/) 12 | 13 | 在过去的一段时间内,软件开发往往被认为是一种单独的行动 14 | 15 | > 程序员在漆黑的屋子里,面对的屏幕敲击着花花绿绿的字符,然后就完成了一件匪夷所思的事情。 16 | 17 | 随着开源运动的兴起,这个时代已经过去了,我们希望在开发过程中也与他人交流和沟通。现在 `Visual Studio 2022` 中也加入了实时聊天的功能,快去尝试一下! 18 | 19 | 2、[Visual Studio 2022 格式化文件](https://devblogs.microsoft.com/visualstudio/bringing-code-cleanup-on-save-to-visual-studio-2022-17-1-preview-2/) 20 | 21 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/33aab5ed-98d3-4a3b-b999-7bd02f6e1e81) 22 | 23 | 代码有两个主要目的: 24 | 25 | - 让别人阅读 26 | - 让机器执行 27 | 28 | 统一的代码风格是方便他人阅读是重要。 不少开发语言都规定了风格规范,甚至比如 `Go` 语言将代码风格作为语法的一部分。`C#` 也有 `StyleCop` 来定义代码规范。`Visual Studio 2022` 将会引入了一个功能能够帮助我们在保存代码文件的时候,自动按照预先设置的规范调整代码,类似于 `Go` 语言中 `go fmt` 命令。 29 | 30 | ## 文章推荐 31 | 32 | 1、[PowerShell 学习课程](https://www.youtube.com/playlist?list=PLDjtLML5l9l-y_MPI5qThjZqvcIwHnMzw) 33 | 34 | PowerShell 是一个强大的 Shell 工具,这一系列课程帮你学习如何它。 35 | 36 | 2、[StringBuilder 探秘](https://www.stevejgordon.co.uk/how-does-the-stringbuilder-work-in-dotnet-part-1-why-do-we-need-a-stringbuilder-and-when-should-we-use-one) 37 | 38 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/f17acd1e-6e75-4ea4-b5fe-b44dcdf85811) 39 | 40 | `StringBuilder` 是一个广泛使用的 `C#` 类,关于它有哪些具体的细节可以探索的呢?这一系列文章可以帮你了解它们 41 | 42 | - [什么时候使用它?](https://www.stevejgordon.co.uk/how-does-the-stringbuilder-work-in-dotnet-part-1-why-do-we-need-a-stringbuilder-and-when-should-we-use-one) 43 | - [理解开销](https://www.stevejgordon.co.uk/how-does-the-stringbuilder-work-in-dotnet-part-2-understanding-the-overhead) 44 | - [Append 的工作机制](https://www.stevejgordon.co.uk/how-does-the-stringbuilder-work-in-dotnet-part-1-why-do-we-need-a-stringbuilder-and-when-should-we-use-one) 45 | 46 | ## 开源项目 47 | 48 | 1、[通过 Roslyn analyzer 提高代码质量](https://github.com/meziantou/Meziantou.Analyzer) 49 | 50 | `StyleCop` 可以帮助我们检测 `C#` 代码中不符合风格的部分。`Meziantou.Analyzer` 包借助了 `Roslyn analyzer` 来分析代码中是否出现了不是 `Best Practice` 的情况,它包含下面几个大类 51 | 52 | - Usage 53 | - Style 54 | - Usage 55 | - Performance 56 | - Security 57 | - ... 58 | 59 | [这里](https://github.com/meziantou/Meziantou.Analyzer/tree/main/docs) 通过例子展示了错误的 `C#` 代码姿势。 60 | -------------------------------------------------------------------------------- /docs/episode-007.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 7 期 2 | 3 | ## 开卷语 4 | 5 | 新春快乐 6 | 7 | ## 文章推荐 8 | 9 | 1、[优化 .NET 性能的 11 个最佳实践](https://michaelscodingspot.com/cpu-bound-memory-bound/) 10 | 11 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/fdcd3105-49f1-4cc7-bd83-c99d6de0688c) 12 | 13 | 应用程序的性能通常会分为两种 14 | 15 | - Memory-Bound 16 | - CPU-Bound 17 | 18 | 如果我们的 `.NET` 程序的性能出现了问题,那么首先就需要确定属于哪方面出现了瓶颈,针对不同的情况,有不同的调优方法。 19 | 20 | 2、[.NET Framework 和 .NET Core 介绍](https://procodeguide.com/dotnet/getting-started-net-core-framework/) 21 | 22 | 23 | `.NET Framework` 和 `.NET Core` 是 `.NET` 世界讨论最多的两个话题。一个代表了过去,一个代表了现在和未来。这系列文章能够再一次帮你回顾一下它们的联系和区别。 24 | 25 | 3、[避免 Logger 错误的使用姿势](https://www.youtube.com/watch?v=bnVfrd3lRv8&ab_channel=NickChapsas) 26 | 27 | 在任何一个应用程序中日志是非常重要的,在 `.NET` 中广泛使用的日志库就是 `Microsoft.Extensions.Logger` ,但是在使用的时候如果使用不注意,会导致性能方面的问题。 28 | 29 | ```Csharp 30 | private ILogger _logger; 31 | public void Method() { 32 | _logger.LogInformation("This is the {0} days", days); 33 | } 34 | ``` 35 | 36 | 当 `_logger` 的输出 level 小于或者等于 `Infomation` 的时候,才会输出结果。但是 `LogInformation` 的方法的签名是 37 | 38 | ```Csharp 39 | public static void LogInformation(this ILogger logger, string? message, params object?[] args) 40 | { 41 | logger.Log(LogLevel.Information, message, args); 42 | } 43 | ``` 44 | 45 | 所以即使 `LogLevel=Warning`,也会带来了装箱(Box)的过程,增加了内存的消耗。因此需要在日志输出前进行判断。 46 | 47 | ```Csharp 48 | public void Method() { 49 | if (_logger.IsEnable(LogLevel.Infomation) 50 | { 51 | _logger.LogInformation("This is the {0} days", days); 52 | } 53 | } 54 | ``` 55 | 56 | 4、[使用 DateTimeOffset](https://ardalis.com/why-use-datetimeoffset/?utm_sq=gyiamfvfod) 57 | 58 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/efa0df4b-ddbe-495b-8ddb-9410b43643dd) 59 | 60 | `DataTime` 是在 `C#` 中广泛使用地类型,但是它最大地问题是它没有包含时区信息,而是根据运行系统确定时区,所以导致了这样一个问题。 61 | 62 | ```Csharp 63 | var rightNow = new DateTime(2022, 1, 30, 10, 50, 0); 64 | rightNow.ToLocalTime(); // 1/30/2022 6:50:00 PM 65 | rightNow.ToUniversalTime(); // 1/30/2022 2:50:00 AM 66 | ``` 67 | 68 | - ToLocalTime() 默认是从 UTC + 0 转换到本地时间 69 | - ToUniversalTime() 默认是从本地时间转化成 UTC+0 时间 70 | 71 | 这样导致了在不同的机器上执行的结果是不一致的,这是我们需要 `DataTimeOffset` 类型,其包含了时区信息。 72 | 73 | ```Csharp 74 | var rightNow = new DateTime(2022, 1, 30, 10, 50, 0); 75 | DateTimeOffset rightNowHere = new DateTimeOffset(rightNow); 76 | rightNowHere.ToLocalTime(); // 1/30/2022 10:50:00 AM +08:00 77 | rightNow.ToUniversalTime(); // 1/30/2022 2:50:00 AM 78 | ``` 79 | 80 | 4、[ASP.NET Core 6 中性能提升](https://devblogs.microsoft.com/dotnet/performance-improvements-in-aspnet-core-6/) 81 | 82 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c477855f-401e-4cc4-b4e7-d951f362c8db) 83 | 84 | 得益于 `.NET 6` 在性能方面的提升,`ASP.NET Core 6` 在性能方面也到了提升,这边文章带你展示了这些提升的示例。 85 | 86 | - Span``:使用 `Span` 可以大幅提高字符串操作方面性能的提升。 87 | - Idle Connection: 在 `ASP.NET Core` 应用程序中广泛使网络链接,`ASP.NET Core 6` 中通过三种类型的数据类型来提高性能。 88 | - Blazor: 之前 `byte[]` 和 `Javascript` 中进行数据交换的使用 `Base64` 编码,这并不是一个高效的做饭,在 `ASP.NET Core` 中使用 `byte[]` 和 `Uint8Array` 进行转换。 89 | - ... 90 | 91 | ## 开源项目 92 | 93 | 1、[防御性编程](https://github.com/safakgur/guard) 94 | 95 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/35b884ad-ccab-47e8-804e-902628b46f78) 96 | 97 | 防御性编程要求在函数在接受参数的时候,验证这些参数的合法性,比如说 98 | 99 | ```Csharp 100 | public Person(string name, int age) 101 | { 102 | if (name == null) 103 | throw new ArgumentNullException(nameof(name), "Name cannot be null."); 104 | 105 | if (name.Length == 0) 106 | throw new ArgumentException("Name cannot be empty.", nameof(name)); 107 | 108 | if (age < 0) 109 | throw new ArgumentOutOfRangeException(nameof(age), age, "Age cannot be negative."); 110 | 111 | Name = name; 112 | Age = age; 113 | } 114 | ``` 115 | 116 | 这样的话参数越多,函数中验证部分的逻辑就越长。`Guard` 这个库可以帮助我们的很好地验证函数地参数。 117 | 118 | ```Csharp 119 | using Dawn; // Bring Guard into scope. 120 | 121 | public Person(string name, int age) 122 | { 123 | Name = Guard.Argument(name, nameof(name)).NotNull().NotEmpty(); 124 | Age = Guard.Argument(age, nameof(age)).NotNegative(); 125 | } 126 | ``` 127 | 128 | 2、[PowerShell RDP](https://github.com/DarkCoderSc/PowerRemoteDesktop) 129 | 130 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/608d340e-c139-4ea4-b498-f70bf8277763) 131 | 132 | 我们都知道 `PowerShell` 很 `Power`, 这个开源项目实现了通过 `PowerShell` 实现了 `RDP (Remote Desktop Protocols)` 。 133 | -------------------------------------------------------------------------------- /docs/episode-008.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 8 期 2 | 3 | ## 开卷语 4 | 5 | `.NET` 已经 20 周年啦。现在[官网](https://dotnet.microsoft.com/en-us/?utm_source=dotnetblog&utm_medium=banner&utm_campaign=.netanniversary)正在举办一系列活动。 6 | 7 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/f98a6f25-df51-4616-acf9-0213bab4c86d) 8 | 9 | > Check it out 10 | 11 | ## 行业资讯 12 | 13 | 1、[.NET MAUI Preview 12 发布](https://devblogs.microsoft.com/dotnet/announcing-net-maui-preview-12/) 14 | 15 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/3b4bb42b-02cc-4fb0-b8f6-07f5f1727ed0) 16 | 17 | `.NET MAUI` 发布新的 Preview 版本,该版本包含了如下 18 | 19 | - 文档更新 20 | - Android 版本的 `FlyoutView` 21 | - Z index 属性 22 | - .NET 6 统一化 23 | - Windows 拓展工具栏 24 | 25 | 2、[Null 检查](https://github.com/dotnet/runtime/pull/64720) 26 | 27 | 本周 `.NET` 宣布了一个热点更新,主要内容可以用一行代码表示。之前在方法参数 `null` 检查如下 28 | 29 | ```Csharp 30 | void M(object arg) 31 | { 32 | if (arg is null) 33 | { 34 | throw new ArgumentNullException(nameof(arg)); 35 | } 36 | } 37 | ``` 38 | 39 | 转变成 40 | 41 | ```Csharp 42 | void M(object arg!!) 43 | { 44 | ... 45 | } 46 | ``` 47 | 48 | 本质上,这就是一个语法糖。 49 | 50 | ## 文章推荐 51 | 52 | 1、[Web Form 到 .NET 6](https://www.poppastring.com/blog/modernizing-dasblog-from-web-forms-to-net-6) 53 | 54 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/b18581aa-3705-4131-b004-eb2bb0938348) 55 | 56 | 这边播客介绍如何将一个 19 年历史基于 `.NET` Web Forms 的播客转换为一个 `.NET 6` 的跨平台的应用程序。这里讨论了如何移除已有的解决方案,并且选择开源社区的解决的各种决策。 57 | 58 | 2、[Miguel de Icaza 访谈](https://www.dotnetrocks.com/default.aspx?ShowNum=1779) 59 | 60 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/221b688d-d00e-4c10-8f31-e0e2f80c9669) 61 | 62 | 这篇播客是和 `Miguel de Icaza` 讨论一下 `.NET` 20 周年,他是 `Mono Project` 的发起人,之后他创造了 `Mono Touch`, `Xamarin` 等等。在这里对话中,他讨论了开源的演化,科技公司对开源项目的影响还有开源项目维护者在将来的展望。 63 | 64 | 3、[C# 返回值拆包](https://twitter.com/buhakmeh/status/1488197682392973314) 65 | 66 | 一张图了解如何实现返回值拆包。 67 | 68 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c5808caf-b5d9-4799-beb4-abeac4c298a7) 69 | 70 | 4、[C# 日志处理新方法](https://www.youtube.com/watch?v=MHIheQ2_Yb4&t=329s&ab_channel=NickChapsas) 71 | 72 | 在防御性编程中,我们通常需要对接受到的参数进行校验,以便脏数据导致程序运行的非正常行为,比如说 73 | 74 | ```Csharp 75 | public static void IsNotNull(T value) 76 | { 77 | if (value is null) 78 | { 79 | throw new ArgumentNullException(nameof(value)); 80 | } 81 | } 82 | ``` 83 | 84 | 那么这样调用的结果是 85 | 86 | ```Csharp 87 | List list = null; 88 | IsNotNull(list); 89 | ``` 90 | 91 | > System.ArgumentNullException: Value cannot be null. (Parameter 'value') 92 | 93 | 但是这样在日志中并不会知道究竟是哪个穿入的参数导致了 `Null`。如果 `IsNotNull` 的方法这样定义 94 | 95 | ```Csharp 96 | public static void IsNotNull(T value, [CallerArgumentExpression("value")] string message = "") 97 | { 98 | if (value is null) 99 | { 100 | throw new ArgumentNullException(message); 101 | } 102 | } 103 | ``` 104 | 105 | 这时候,得到的异常错误是这样的 106 | 107 | > System.ArgumentNullException: Value cannot be null. (Parameter 'list') 108 | 109 | 可以看到它将穿入的参数也也作为 CallStack 的一部分。 110 | 111 | 5、[Cast 的性能消耗](https://www.tabsoverspaces.com/233888-what-is-the-cost-of-casting-in-net-csharp) 112 | 113 | `C#` 是一个强类型开发语言,类型之前转换需要进行 `Cast`, 那么 `Cast` 的性能消耗怎样的,有没有更好的方法呢? 114 | 115 | ```Csharp 116 | public ITuple UnsafeCastArgument(object o) 117 | { 118 | return Unsafe.As(o); 119 | } 120 | public ITuple RegularCastArgument(object o) 121 | { 122 | return (ITuple)o; 123 | } 124 | ``` 125 | 126 | 答案是显而易见的,`Benchmark` 127 | 128 | | Method | o | Mean | Error | StdDev | Ratio | Code Size | 129 | | ------------------- | ------------------ | --------- | --------- | --------- | ----- | --------- | 130 | | UnsafeCastArgument | ? | 0.0002 ns | 0.0003 ns | 0.0003 ns | 0.000 | 4 B | 131 | | RegularCastArgument | ? | 1.0396 ns | 0.0044 ns | 0.0036 ns | 1.000 | 25 B | 132 | | UnsafeCastArgument | (10) | 0.0003 ns | 0.0005 ns | 0.0005 ns | 0.000 | 4 B | 133 | | RegularCastArgument | (10) | 2.1023 ns | 0.0044 ns | 0.0041 ns | 1.000 | 25 B | 134 | | UnsafeCastArgument | (10, 20) | 0.0001 ns | 0.0002 ns | 0.0002 ns | 0.000 | 4 B | 135 | | RegularCastArgument | (10, 20) | 2.1028 ns | 0.0056 ns | 0.0049 ns | 1.000 | 25 B | 136 | | UnsafeCastArgument | (10, (…)8, 9) [38] | 0.0002 ns | 0.0005 ns | 0.0005 ns | 0.000 | 4 B | 137 | | RegularCastArgument | (10, (…)8, 9) [38] | 2.3068 ns | 0.0033 ns | 0.0027 ns | 1.000 | 25 B | 138 | 139 | 为什么使用 `Unsafe` 就能提高性能呢?从汇编代码中可以看出,它的操作非常简洁。 140 | 141 | ```assembly 142 | mov rax,rdx 143 | ret 144 | ``` 145 | 146 | 而更加安全的 `Cast` 的汇编代码如下 147 | 148 | ```Csharp 149 | sub rsp,28 150 | mov rcx,offset MT_System.Runtime.CompilerServices.ITuple 151 | call CORINFO_HELP_CHKCASTINTERFACE 152 | nop 153 | add rsp,28 154 | ret 155 | ``` 156 | 157 | ## 开源项目 158 | 159 | 1、[依赖注入的生命周期](https://exceptionnotfound.net/dependency-injection-in-dotnet-6-service-lifetimes/) 160 | 161 | 在 `Microsoft.Extension.DependencyInjection` 包中,服务的生命周期是非常重要的概念,它们有 162 | 163 | - Transient 164 | - Scoped 165 | - Singleton 166 | 167 | 这篇文章用实例展示了这三个概念的定义和区别。 168 | 169 | 2、[.NET 后端程序员之路 2022](https://github.com/Elfocrash/.NET-Backend-Developer-Roadmap) 170 | 171 | 对 `.NET` 后端程序员程序员,查看一下 2022 年的 `Roadmap` 172 | 173 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/565e5973-82f0-4465-a52e-6d0b2c64f671) 174 | 175 | -------------------------------------------------------------------------------- /docs/episode-009.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 9 期 2 | 3 | ## 开卷语 4 | 5 | 20 年前,微软发布了 `Visual Studio .NET` 这个产品,20 年后,`.NET` 平台已经发生了巨大的变化,最大的变化是从之前 `Windows-Only` 平台变成了开源跨平台的产品,并且得到了开源社区的广泛支持。 6 | 7 | ## 行业资讯 8 | 9 | 1、[Visual Studio 生命周期支持到期](https://devblogs.microsoft.com/visualstudio/support-ends-for-older-versions-of-visual-studio-feb2022/) 10 | 11 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/cf1ecd07-56a6-4826-802d-728163d90189) 12 | 13 | 微软发布了老版本的 `Visual Studio` 的支持周期,`Visual Studio 2012` 和 `Visual Studio 2017` 已经快到达支持周期的末尾。 14 | 15 | 2、[.NET 7 Preview 发布](https://devblogs.microsoft.com/dotnet/announcing-net-7-preview-1/) 16 | 17 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/4daa31da-54fc-4daa-ae75-cfb2fa7a4522) 18 | 19 | 作为 `.NET` 20 周年的活动的一部分,微软已经发布了 `.NET 7` Preview 版本,主要包含一下几个重要的内容: 20 | 21 | - MAUI 22 | - 云原生和容器支持 23 | - .NET 应用程序无缝升级 24 | - ... 25 | 26 | ## 文章推荐 27 | 28 | 1、[C# 代码中 Nullable Type](https://csharp.christiannagel.com/2022/02/14/nullable/) 29 | 30 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/337246a3-7e25-43ba-9b4c-a3b12cce381c) 31 | 32 | 我们都知道 `NULL` 类型是一个 33 | 34 | > 百万美元的错误 35 | 36 | 在 `C#` 代码中就会抛出 `NullReferenceException` 的异常, C# 在消除这种异常的道路上不停的探索 37 | 38 | - Nullable Value Type 39 | 40 | 因为值类型不能为 `Null`, 那么就会带来歧义:1) 值本身就是指空值;2)不存在。 因此在 `C# 2` 中引入了这个值空类型 41 | 42 | - Null-Conditional Operator 43 | 44 | 在使用对象的方法之前,需要判断一下是否为 `null` 45 | 46 | ```Csharp 47 | if (instance != null) 48 | { 49 | instance.DoSomething(); 50 | } 51 | ``` 52 | 53 | 在 `C# 6` 之后,就可以这样使用 54 | 55 | ```Csharp 56 | instance?.DoSomething(); 57 | ``` 58 | 59 | - Null-Coalescing Operator 60 | 61 | 如果为 `null` 之后,需要进行其他的操作,通常需要写 `if-else` 语句,在 `C# 8` 之后,可以使用 `??` 开执行 `null` 条件下的语句。 62 | 63 | ```Csharp 64 | get => instance ??= new Instance(); 65 | ``` 66 | 67 | - Null Reference Type 68 | 69 | 值类型不可以赋值 `null`, 但是引用类型可以赋值 `null`, 这也是很多 `NullReferenceException` 异常的来源,那么在 C# 中,如果给一个变量没有显式的标记为 `nullable` 类型,那么就不能直接赋值 `null`,由于这是一个 break change, 需要手动开启这个功能 70 | 71 | ````Csharp 72 | string? s = ReturnANullableString(); 73 | if (s is not null) 74 | { 75 | string uppercase1 = s.ToUpper(); 76 | } 77 | string uppercase2 = s?.ToUpper(); 78 | 79 | - ArgumentNullException 80 | 81 | 在防御性编程中,需要对输入的参数进行校验,如果为 `null` , 则抛出异常,通常需要写很多 `if-else` 语句。 在 `.NET 6` 和 `C# 10` 中可以简化这个流程 82 | 83 | ```Csharp 84 | public void Foo(string s) 85 | { 86 | ArgumentNullException.ThrowIfNull(s); 87 | } 88 | ```` 89 | 90 | 2、[关于 .NET 运行在 Linux, 你需要这些事情](https://dotnetcore.show/episode-92-a-few-things-i-wish-i-knew-before-writing-net-on-linux/) 91 | 92 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c05fb42a-a8c7-4dd0-9641-d17f41454e1c) 93 | 94 | 对于 `.NET` 开发者而言,`Windows` 是最熟悉的开发平台。但是 `.NET` 已经是一个跨平台的开发平台,了解 `Linux` 已经是 `.NET` 开发人员必需能力。如果你是 `Linux` 的小白的话,这篇文章带你熟悉这个平台。 95 | 96 | ## 开源项目 97 | 98 | 1、[字面字符串提案](https://github.com/dotnet/csharplang/blob/main/proposals/raw-string-literal.md) 99 | 100 | 我们都知道在 `C#` 中,字面字符串支持的还是不够好,虽然说可以通过 `@""` 完成,但是还是需要填上大量转义的字符, 因此该提案借鉴了 `Python` 的方式,比如 101 | 102 | ```Csharp 103 | var xml = """ 104 | 105 | """; 106 | ``` 107 | 108 | 通过至少 3 个 `"` 符号表示字面字符串的开始,用相同数量的 `"` 表示结束,这样就可以很方便的表示字面字符串。 109 | -------------------------------------------------------------------------------- /docs/episode-010.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 10 期 2 | 3 | ## 开卷语 4 | 5 | 最近俄罗斯和乌克兰的局势从战场蔓延到整个科技圈,很多知名的开源项目已经开始*站队*。`.NET` 社区也不例外,也发出了 6 | 7 | > Stand for Ukraine 8 | 9 | 我的观点是作为标榜自由,开源的项目,这本质上应当保持中立,如果非要是支持,就应当只关心人道主义方面的内容,而不是一味的制裁单方面,因为作为一个开源项目,项目的参与者是整个人类,而不是筛选的部分人。 10 | 11 | ## 行业资讯 12 | 13 | 1、[C# 11 抢先看](https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/) 14 | 15 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/88705deb-746c-4cd4-acbf-d36cf167ea7c) 16 | 17 | 随着 `Visual Studio 17.1` 发布,`C# 11` 已经可以尝试了。 18 | 首先需要修改 `.csproj` 文件 19 | 20 | ```xml 21 | 22 | 23 | Exe 24 | net6.0 25 | enable 26 | enable 27 | preview 28 | 29 | 30 | ``` 31 | 32 | 1. 插入字符串支持新行 33 | 34 | 在过去如果多行字符串中添加新行,需要使用 `\r\n` 来进行转义,但是在 `C# 11` 中,我们可以直接使用原始多行字符串 35 | 36 | ```Csharp 37 | var v = $"Count ist: { this.Is.Really.Something() 38 | .That.I.Should( 39 | be + able)[ 40 | to.Wrap()] }."; 41 | ``` 42 | 43 | 2. List Pattern 44 | 45 | 模式匹配现在可以支持数组或者列表,比如 46 | 47 | ```Csharp 48 | public static int CheckSwitch(int[] values) 49 | => values switch 50 | { 51 | [1, 2, .., 10] => 1, 52 | [1, 2] => 2, 53 | [1, _] => 3, 54 | [1, ..] => 4, 55 | [..] => 50 56 | }; 57 | ``` 58 | 59 | 也可以捕获列表中的切片变量 60 | 61 | ```Csharp 62 | public static string CaptureSlice(int[] values) 63 | => values switch 64 | { 65 | [1, .. var middle, _] => $"Middle {String.Join(", ", middle)}", 66 | [.. var all] => $"All {String.Join(", ", all)}" 67 | }; 68 | ``` 69 | 70 | 3. 参数 null 检查 71 | 72 | 过去需要在函数/方法中对输入的参数进行 null 检查 73 | 74 | ```Csharp 75 | public static void M(string s) 76 | { 77 | if (s is null) 78 | { 79 | throw new ArgumentNullException(nameof(s)); 80 | } 81 | // Body of the method 82 | } 83 | ``` 84 | 85 | 现在只需要在参数中使用双感叹号(`!!`), 也能达到同样的效果。 86 | 87 | ```Csharp 88 | public static void M(string s!!) 89 | { 90 | // Body of the method 91 | } 92 | ``` 93 | 94 | ## 文章推荐 95 | 96 | 1、[Dictionary 循环的比较](https://code-maze.com/csharp-iterate-through-dictionary/) 97 | 98 | 对于一个 `Dictionary` 有多少中循环方式呢? 99 | 假设存在一个字典如下 100 | 101 | ```Csharp 102 | var monthsInYear = new Dictionary(); 103 | ``` 104 | 105 | 1. 使用 `Foreach` 方法 106 | 107 | ```Csharp 108 | public static void SubDictionaryUsingForEach(Dictionary monthsInYear) 109 | { 110 | foreach (var month in monthsInYear) 111 | { 112 | Console.WriteLine($"{month.Key}: {month.Value}"); 113 | } 114 | } 115 | ``` 116 | 117 | 2. 使用 `For` 方法 118 | 119 | ```Csharp 120 | public static void SubDictionaryForLoop(Dictionary monthsInYear) 121 | { 122 | for (int index = 0; index < monthsInYear.Count; index++) 123 | { 124 | KeyValuePair month = monthsInYear.ElementAt(index); 125 | 126 | Console.WriteLine($"{month.Key} : {month.Value}"); 127 | } 128 | } 129 | ``` 130 | 131 | 3. 使用 `ParallelEnumerable.ForAll` 方法 132 | 133 | ```Csharp 134 | public static void SubDictionaryParallelEnumerable(Dictionary monthsInYear) 135 | { 136 | monthsInYear.AsParallel() 137 | .OrderBy(month => month.Key) 138 | .ForAll(month => Console.WriteLine($"{month.Key} : {month.Value}")); 139 | } 140 | ``` 141 | 142 | 那么结果比较结果如何呢? 143 | 144 | | Method | Mean | Error | StdDev | 145 | | -------------------------------- | ------------: | ----------: | ----------: | 146 | | WhenDictionaryUsingForEach | 4.7635 ns | 0.0314 ns | 0.0245 ns | 147 | | WhenDictionaryUsingForLoop | 0.5715 ns | 0.0475 ns | 0.0421 ns | 148 | | WhenDictionaryParallelEnumerable | 7,662.7620 ns | 150.1402 ns | 172.9016 ns | 149 | 150 | 显而易见, `For` 和 `Foreach` 的性能更好点,而且 `For` 的性能还更好点。 151 | 152 | 2、[如何使用 Visual Studio 进行 Debug](https://code-maze.com/debugging-csharp-visual-studio/) 153 | 154 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/9c8138c6-f21d-4fcb-96af-4c0752586a93) 155 | 156 | Visual Studio 被誉为 157 | 158 | > 宇宙第一 IDE 159 | 160 | 它的强大不仅仅在于编写代码,而是强大的 `Debug` 功能,这篇文章基本上介绍 `Visual Studio` Debug 功能 161 | 162 | - 什么是 Debug 163 | - 如何设置断点 164 | - 如何查看变量 165 | - 条件 debug 166 | - 调用栈 167 | 168 | 3、[在 .NET 中使用 GitHub Action](https://devblogs.microsoft.com/dotnet/dotnet-loves-github-actions/) 169 | 170 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/03f542a4-7227-445d-843a-3c4873eb751a) 171 | 172 | GitHub Action 是一套 CI/CD 的的工具,通过它能够实现自动化运维的目的,比如自动测试,自动构建和自动部署等功能。对于 .NET 用户而言需要掌握这些 GitHub Action 的功能。 173 | 174 | 4、[.NET 存在的 6 个误解](https://blog.devgenius.io/6-net-myths-dispelled-celebrating-21-years-of-net-652795c2ea27) 175 | 176 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/1474d48b-2465-4f79-889b-fd38278c4e17) 177 | 178 | `.NET` 已经存在了 20 年了,但是大家仍然对他存在误解,这里挑选了 6 个误解并且解释它们 179 | 180 | - .NET 只为 Windows 181 | - .NET 比 Node,Python,Go,Rust 慢 182 | - .NET 是一个老旧的开发平台 183 | - .NET 开发工具太贵了 184 | - .NET 对开源并不友好 185 | - .NET 只为企业级开发 186 | 187 | ## 开源项目 188 | 189 | 1、[C# Reverse Proxy](https://github.com/microsoft/reverse-proxy) 190 | 191 | Ngnix 是著名的反向代理工具, 微软开源了一款用 `C#` 编写的反向代理库:`YARP`。 192 | 193 | 2、[MoreLinq 来增强 Linq 的功能](https://morelinq.github.io/) 194 | 195 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/62adda23-cb00-4082-a67e-c5b2052ec195) 196 | 197 | Linq 是 `C#` 最受欢迎的功能之一,但是内置的 `Linq to Object` 的功能还是无法满足部分开发需求,因此 `MoreLinq` 扩展了这部分内容。 198 | 199 | 3、[stryker 测试你的单元测试](https://stryker-mutator.io/docs/stryker-net/introduction) 200 | 201 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/1bcd99f0-2248-49a1-953b-2dffbc940016) 202 | 203 | 单元测试是软件开发中重要组成部分,通常我们评价单元测试好坏使用的是**覆盖率**。但是实时真的如此吗?如果单元测试用例正好通过了代码分支,而且是一个特殊用例,这样说明这个单元测试质量并不好。`Stryker.NET` 包能够帮助我们检查我们单元测试质量。 204 | 205 | 首先它引入了 `Mutation` 的的概念,它是修改我们代码中的部分片段,比如 `+` 修改为 `-`, `i++` 修改为 `i--` 等等,然后再去执行我们单元测试,这是会有两种情况: 206 | 207 | - `Killed`: 表明单元测试在修改之后失败 208 | - `Survived`: 表明单元测试在修改之后仍然通过 209 | 210 | `Killed` 情况越多表明单元测试质量越高。 211 | -------------------------------------------------------------------------------- /docs/episode-014.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 14 期 2 | 3 | ## 卷首语 4 | 5 | Result 和 GetResult 的区别 6 | 7 | 如果代码中存在异步方法,一般而言建议是尽可能使用异步代码,但是有时候我们还是不得已继续使用同步方法来调用异步方法,那么既有两种方式获取异步结果返回的值 8 | 9 | - `Result` 10 | - `GetAwaiter().GetResult()` 11 | 12 | 那么这两种方法有什么区别呢? 13 | 使用 `Result` 方法,如果结果抛出异常,则会包装成一个 `AggregateException` 对象,在下面的例子中, catch `HttpException` 异常会被忽略。 14 | 15 | ```Csharp 16 | try 17 | { 18 | _ = GetSomethingAsync().Result; 19 | } 20 | catch(HttpException e) 21 | { 22 | // ignored 23 | } 24 | catch(AggregateException ae) 25 | { 26 | // hit code 27 | } 28 | ``` 29 | 30 | 但是如果使用 `GetAwaiter().GetResult()` 则将正确的异常抛出 31 | 32 | ```Csharp 33 | try 34 | { 35 | _ = GetSomethingAsync().GetAwaiter().GetResult(); 36 | } 37 | catch(HttpExcpetion e) 38 | { 39 | // hit. 40 | } 41 | ``` 42 | 43 | ## 行业资讯 44 | 45 | 1、[.NET 7 中 正则表达式性能提升](https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/) 46 | 47 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/48c6771c-2bcb-4290-990a-c42a82657d9b) 48 | 49 | 正则表达式是 `.NET` 中字符串操作必不可少工具,在 `.NET 7` 中重新设计了正则表达式,在性能上取得了很大的提升。 50 | 51 | 2、[gRPC 和 Rest JSON 互转换](https://devblogs.microsoft.com/dotnet/announcing-grpc-json-transcoding-for-dotnet/) 52 | 53 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/02d9f02f-e9d6-4005-9258-2fa1e7c3b302) 54 | 55 | `gPRC` 和 `REST JSON` 是两种广泛使用的 Web API 数据通信的格式,两者各有优劣。其中 `gPRC` 在性能方面有显著的优势,但是 `REST JSON` 更加格式更加友好,在 `Debug` 的时候更加方便。那么有没有办法同时支持两种方式呢? 56 | 57 | `Microsoft.AspNetCore.Grpc.JsonTranscoding` 包可以帮助我们完成这个目标,我们可以在 `proto` 文件中定义好 `REST` 请求的方式,比如 58 | 59 | ```proto 60 | syntax = "proto3"; 61 | 62 | import "google/api/annotations.proto"; 63 | 64 | package greet; 65 | 66 | service Greeter { 67 | rpc SayHello (HelloRequest) returns (HelloReply) { 68 | option (google.api.http) = { 69 | get: "/v1/greeter/{name}" 70 | }; 71 | } 72 | } 73 | 74 | message HelloRequest { 75 | string name = 1; 76 | } 77 | 78 | message HelloReply { 79 | string message = 1; 80 | } 81 | ``` 82 | 83 | 通过 `/v1/greeter/world` 请求返回 JSON 格式。 84 | 85 | ## 文章推荐 86 | 87 | 1、[M.E.DependencyInjection 添加服务的方法](https://www.youtube.com/watch?v=iQ8cNI7a6mk&ab_channel=NickChapsas) 88 | 89 | `Microsoft.Extensions.DependencyInjection` 是微软提供的依赖注入的包,其中可以通过 `ISeriviceCollection` 接口添加相应的服务,那么 `AddSingleton`, `TryAddSingleton` 和 `TryAddEnumerable` 的区别是哪些呢? 90 | 91 | - AddSingleton 是将实现接口的服务添加到依赖注入的容器中,不过后来添加的实现优先级大于先添加的 92 | - TryAddSingleton 是尝试将服务添加到实现的接口中,如果接口实现已经存在了,则不会添加进去 93 | - TryAddEnuermable 是尝试将服务添加到容器中,不过判断的标准是接口和实现的类型,如果存在就不再添加 94 | 95 | 2、[Azure Cosmos DB .NET 6 之旅](https://devblogs.microsoft.com/dotnet/the-azure-cosmos-db-journey-to-net-6/) 96 | 97 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/16fe1a89-3941-41a5-9d3c-5fbf02eefa3b) 98 | 99 | Azure Cosmos DB 是 Azure 中的 NoSQL 数据库产品,最近他们分享了一篇迁移到 `.NET 6` 之后,在性能上得到的成就。 100 | 101 | 3、[ASP.NET Core 架构](https://speakerdeck.com/davidfowl/asp-dot-net-core-architecture-overview) 102 | 103 | 这是来自 David Fowler 分享的 Slides, 从高层角度分享了 ASP.NET Core 的架构。 104 | 105 | 4、[使用 C# 实现 k-NN 分类](https://visualstudiomagazine.com/articles/2022/05/19/weighted-k-nn-classification.aspx) 106 | 107 | K-NN 分类是著名的无监督分类方法,那么如果使用 C# 实现呢? 108 | 109 | ## 开源项目 110 | 111 | 1、[CoreWCF 发布](https://github.com/corewcf/corewcf) 112 | 113 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/9d04c53d-4c8b-418f-a714-0f1dd2071b9b) 114 | 115 | WCF 是 .NET Framework 3.0 推出的一套服务间通信的标准,随着 `.NET Core` 的推出,微软宣布不再支持 `WCF`, 将全部交给社区维护,近日 `CoreWCF` 1.0 版本正式发布。 116 | -------------------------------------------------------------------------------- /docs/episode-019.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 19 期 2 | 3 | ## 卷首语 4 | 5 | [C#11 的新特性和改进前瞻](https://www.cnblogs.com/hez2010/p/whats-new-in-csharp-11.html) 6 | 7 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/57990cd5-c175-47d3-9bd0-3b2ecb72c78e) 8 | 9 | .NET 7 的开发还剩下一个多月就要进入 RC,C# 11 的新特性和改进也即将敲定。该文按照方向从 5 个大类来进行介绍,提前向大家讲述了 C# 11 的新特性和改进都有那些。 10 | 11 | 文章的主要内容: 12 | 13 | - 类型系统的改进 14 | - 抽象和虚静态方法 15 | - 泛型 Attribute 16 | - ref 字段和 scoped ref 17 | - 文件局部类型 18 | - required 成员 19 | - 运算改进 20 | - checked 运算符 21 | - 无符号右移运算符 22 | - 移位运算符放开类型限制 23 | - IntPtr、UIntPtr 支持数值运算 24 | - 模式匹配改进 25 | - 列表模式匹配 26 | - 对 `Span` 的模式匹配 27 | - 字符串处理改进 28 | - 原始字符串 29 | - UTF-8 字符串 30 | - 字符串插值允许换行 31 | - 其他改进 32 | - struct 自动初始化 33 | - 支持对其他参数名进行 nameof 34 | - 自动缓存静态方法的委托 35 | 36 | ## 行业资讯 37 | 38 | 1、[.NET 7 支持 Rate Limiter](https://devblogs.microsoft.com/dotnet/announcing-rate-limiting-for-dotnet) 39 | 40 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/518007e7-9b1a-4c36-a2bf-7b48912a63b2) 41 | 42 | 限流是服务可靠性的一种方式,如果我们的资源不能承受巨大的请求量,需要拒绝额外的请求。在 .NET 7 中包含了内置一些 Rate Limiter ,都放在 System.Threading.RateLimiting 包中,主要有四种类型: 43 | 44 | 1. Concurrency limit 45 | 2. Token bucket limit 46 | 3. Fixed window limit 47 | 4. Sliding window limit 48 | 49 | 2、[专注于 MAUI 的 .NET conf 来了](https://devblogs.microsoft.com/dotnet/announcing-dotnet-maui-focus-reactor-community-events) 50 | 51 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/cb89ce2e-e25b-47d6-829d-bf459419f157) 52 | 53 | [.NET Conf:Focus on MAUI](https://focus.dotnetconf.net/?utm_campaign=savedate&utm_medium=blog&utm_source=dotnet) 是一个为期一天的免费直播活动,将于太平洋时间 8 月 9 日上午 9 点开始,来自社区和 Microsoft 团队的演讲者将参与开发并使用 .NET 多平台应用 UI。了解如何使用 .NET MAUI 使用单个代码库为 Android、iOS、macOS 和 Windows 构建原生应用。聆听构建 .NET MAUI 框架和工具的团队以及构建 .NET MAUI 应用程序、库、组件和控件的专家的意见。 54 | 55 | ## 文章推荐 56 | 57 | 1、[C# unsafe 使用](https://code-maze.com/unsafe-code-csharp) 58 | 59 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/d16b2109-b619-4c80-a922-06d93ef2fb68) 60 | 61 | 我们都知道,`C#` 是一门托管语言,也就是代码运行的特定的运行时 (`runtime`) 上,这样运行时的垃圾回收机制会帮我们管理好内存。但是 `C#` 也支持非托管的代码,这样就可以像 `C/C++` 一样操作指针,自己管理内存够空间,在 `C#` 中只要一个 `unsafe` 关键字即可。 62 | 什么时候我们会用到非托管代码呢?两种情况: 63 | 64 | 1. 需要和 `C/C++` 这样的语言进行交互的,比如 `P/Invoke` 65 | 2. 需要性能方面加强的地方 66 | 67 | 2、[异常抛出的区别](https://twitter.com/BelloneDavide/status/1549080459052736512) 68 | 69 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/ff46529f-ec3f-42f9-b9c2-20bb525c1199) 70 | 71 | 在 `catch` 语句,如果还要将异常往调用层抛,那么有两种方式 72 | 73 | - `throw` 74 | - `throw ex` 75 | 76 | 在第一种方式中,它会将全部调用栈信息抛出; 而第二种则则只会抛出 `throw ex` 所在位置及以后的调用栈信息。 77 | 78 | 3、[C#中 Base64 使用方式](https://code-maze.com/base64-encode-decode-csharp) 79 | 80 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/61038f29-ee00-4b68-ab3b-19949465361e) 81 | 82 | Base64 是字符串操作中一个重要部分,注意 `Base64` 不是加密方式,而是一种转码方式。所以分为两种情况 83 | 84 | - 编码 85 | - 解码 86 | 87 | `System.Convert` 类的 `ToBase64String` 是将一个字节数组转为 Base64 的字符串。注意这个方法的签名 88 | 89 | ```csharp 90 | public static string ToBase64String(byte[] inArray, int offset, int length, Base64FormattingOptions option) 91 | ``` 92 | 93 | 第一个参数是 `byte[]` 类型, 这样对于要编码的字符串需要转换成字符串, 那么不同的 `Encoding` 方式选择,比如 `UTF-8`, `UTF-16` 等等;`offset` 和 `length` 参数可以指定传入字节的子数组;最后 `option` 可以格式化输出结果。 94 | 95 | `FromBaseString` 将 Base64 的字符串转换为字节数组,方法签名 96 | 97 | ```csharp 98 | public static byte[] FromBase64String(string s); 99 | ``` 100 | 101 | 注意返回的结果是 `byte[]` 类型,如果想要完成解码的过程,需要选择特定的 `Encoding` 的 `GetString`方法。 102 | 103 | 4、[.NET 应用程序作为 Linux 服务](https://code-maze.com/aspnetcore-running-applications-as-linux-service) 104 | 105 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/62323d6a-a15e-45f2-9d90-9c17df89cc75) 106 | 107 | `Systemd` 是 `Linux` 中广泛使用的的工具,它可以将一个应用程序作为一个服务启动, 这篇文章介绍了如何将 `.NET` 应用程序作为 `Linux` 的一个服务。 108 | 109 | 5、[APISIX 和 ASP.NET Core 集成](https://techcommunity.microsoft.com/t5/web-development/manage-net-microservices-apis-with-apache-apisix-api-gateway/m-p/3583980) 110 | 111 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/9ce46f53-8ca1-441d-8940-606e8f7f3852) 112 | 113 | `APISIX` 是一个著名的开源网关框架,在微服务时代,这是非常重要的一部分。这篇文章介绍了如何在 `.NET` 应用程序中使用 APISIX。 114 | 115 | ## 开源项目 116 | 117 | 1、[NLog](https://github.com/NLog/NLog) 118 | 119 | NLog 是 .NET 的免费日志记录平台,具有丰富的日志路由和管理功能。它使您可以轻松地为应用程序生成和管理高质量的日志,无论其大小或复杂性如何。 120 | 121 | 它可以处理从任何 .NET 语言发出的诊断消息,使用上下文信息对其进行扩充,根据您的首选项设置其格式,并将它们发送到一个或多个目标(如文件或数据库)。NLog 可以很容易地写入几个[targets](https://nlog-project.org/config/?tab=targets)(数据库、文件、控制台)并动态更改日志记录配置。NLog 支持[结构化](https://github.com/NLog/NLog/wiki/How-to-use-structured-logging)和传统日志记录。 122 | 123 | NLog 的重点:高性能,易于使用,易于扩展和灵活配置。 124 | 125 | 2、[MiniExcel](https://github.com/MiniExcel/MiniExcel) 126 | 127 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/77470377-82f9-4552-bbc3-4ec7fd8021b8) 128 | 129 | 简单、高效避免 OOM 的.NET 处理 Excel 查、写、填充数据工具。 130 | 131 | 目前主流框架大多需要将数据全载入到内存方便操作,但这会导致内存消耗问题,MiniExcel 尝试以 Stream 角度写底层算法逻辑,能让原本 1000 多 MB 占用降低到几 MB,避免内存不够情况。 132 | 特点: 133 | 134 | - 低内存耗用,避免 OOM、频繁 Full GC 情况 135 | - 支持即时操作每行数据 136 | - 兼具搭配 LINQ 延迟查询特性,能办到低消耗、快速分页等复杂查询轻量,不需要安装 Microsoft Office、COM+,DLL 小于 150KB 简便操作的 API 风格 137 | -------------------------------------------------------------------------------- /docs/episode-020.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 20 期 2 | 3 | ## 卷首语 4 | 5 | [关于 .NET 的偏见](https://www.youtube.com/watch?v=ouuTgwblvJI&ab_channel=NickChapsas) 6 | 7 | 这是一期非常有意思的视频,UP 主浏览了一篇 `Java VS C#` 的文章,虽然是发布日期就在最近,也就是 2022 年 6 月,但是文章中充满了对 `C#` 的偏见和无数个互相排斥的观点。 8 | 9 | ## 行业资讯 10 | 11 | 1、[MAUI 设计网站上线](https://devblogs.microsoft.com/dotnet/announcing-dotnet-maui-beautiful-ui-challenge/) 12 | 13 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/5f2315d8-3c9f-4d09-822a-d9ef3d2388df) 14 | 15 | 想要在自己 `MUAI` 应用程序中包含漂亮的 UI ?`Snppts` 网站可以帮助到你。它提供了众多的 `MUAI` 应用程序的 UI,并且包含源码。 16 | 17 | ## 文章推荐 18 | 19 | 1、[Azure 开发平台](https://michaelscodingspot.com/deploying-to-azure/) 20 | 21 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/0b63e68e-26ff-4df6-9af5-9ad772ea07ac) 22 | 23 | 在 `.NET` 的开发世界里,`Azure` 是一个绕不开的开发平台,在这个平台上有多种服务可以选择,这篇文章介绍了 Azure 上常见的服务: 24 | 25 | - Window/Linux 26 | - 容器化 27 | - 微服务 28 | - Azure Storage/CDN 29 | - Static Web Apps 30 | - Azure App Service 31 | - Azure 虚拟机 32 | - Azure Functions 33 | - Azure Kubernetes Service 34 | - Container App 35 | - Service Fabric 36 | 37 | 2、[集合拼接比较](https://code-maze.com/csharp-concatenate-lists/) 38 | 39 | 将两个集合拼接起来是常见的开发需求,那么在 `C#` 中该如何实现呢?这篇文章尝试了多种方式,主要有 40 | 41 | - `List` 的 `Add` 方法 42 | - `Enumerable.Concat` 方法 43 | - `Enumerable.Union` 方法 44 | - `List` 的 `AddRange` 方法 45 | - `Array` 的 `CopyTo` 方法 46 | - `SelectMany` 方法 47 | 48 | 通过 `Benchmark` 比较,一般而言`AddAndRange` 是性能最好。 49 | 50 | 3、[线程安全的异步方法](https://www.youtube.com/shorts/mr8kdAauc7E) 51 | 52 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/52fd1b84-fd50-4f13-96ce-d7612a22b2b6) 53 | 54 | 在同步代码中,如果要避免条件竞争,通常会选择 `lock` 关键字来保证任何时刻只有一个线程能够访问该资源,例如: 55 | 56 | ```csharp 57 | private object obj = new object(); 58 | lock(obj) 59 | { 60 | // code 61 | } 62 | ``` 63 | 64 | 但是对于异步方法,首先编译器会报错,因为异步方法不能在 `lock` 的语句中,那么我们该怎么办呢?答案是 `SemaphoreSlim` 类。 65 | 66 | ```csharp 67 | private SemaphoreSlim semaphore = new SemaphoreSlim(1); 68 | 69 | async Task DoWork() 70 | { 71 | await semaphore.WaitAsync(); 72 | await DoAnotherWork(); 73 | semaphore.Release(); 74 | } 75 | ``` 76 | 77 | 4、[Linq 在 .NET 6 上的提升](https://medium.com/@omer.ingec24/linq-improvements-in-net-6-280a475d1801) 78 | 79 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c76e34e0-6c10-4368-873e-b4ab2ee9e8cd) 80 | 81 | `LINQ` 是 `.NET` 平台上最强大的工具之一,它在 `.NET 6` 中也有新的提升,主要包含 82 | 83 | - `FirstOrDefault` 和 `SingleOrDefault` 可以指定默认返回值,而不是类型的默认值 84 | - `MinBy`, `MaxBy`, `DistinctBy` 等方法,可以指定属性 85 | - `Chunk` 方法可以将枚举类型按照相应的数量分块 86 | - `Zip` 方法支持三个枚举类型 87 | - 新的 `Index` 和 `Range` 语法糖支持 88 | 89 | 5、[GC 文章推荐](https://github.com/Maoni0/mem-doc) 90 | 91 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/db4fd897-af0a-4347-b350-7e1f90280ac1) 92 | 93 | Maoni Stephens 是微软负责 `.NET` GC 的架构师,这个仓库包含了她过去对 `GC` 内容的分享的材料,也是我们 GC 性能调优的参考资料。 94 | 95 | ## 开源项目 96 | 97 | 1、[UnitNet](https://github.com/angularsen/UnitsNet) 98 | 99 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/4e5b0271-fedb-4b76-8786-8b260f20aa14) 100 | 101 | 单位运算是开发过程中常常会遇到的问题,比如长度,面积,体积等等。这时候不仅仅需要编程的知识,还需要相应的物理知识。`UnitsNet` 包可以帮助你解决大部分问题。 102 | 103 | 2、[.NET Community Toolkit 发布](https://devblogs.microsoft.com/dotnet/announcing-the-dotnet-community-toolkit-800/) 104 | 105 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a13a608f-e28e-40cb-835b-ff7e37ee8864) 106 | 107 | 最近 `Community Toolkit` 包已经发布,它是从 `Windows Community Toolkit` 演化过来,所以版本号直接变成 `8.0.0` , 这次发布移除的 `Windows` 系统的依赖,变成一个通用的跨平台工具包。随着 `MAUI` 的正式发布,该包对 `MUAI` 提供了大量的帮助,最重要的是 `MVVM` 的支持。 108 | 109 | 3、[Visual Studio 插件 RestClient](https://coderethinked.com/rest-client-for-visual-studio-2022/) 110 | 111 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/7296e179-adfe-4cf9-9625-a153fec2e8ba) 112 | 113 | `Visual Studio` 有一个 `Rest Client` 的插件,可以直接在 `Visual Studio` 中执行一个 `.http` 的问题,该文件可以直接直接发起 `HTTP` 请求。 114 | 115 | ```bash 116 | GET https://bing.com 117 | 118 | @hostname = localhost 119 | @port = 5143 120 | @host = http://{{hostname}}:{{port}} 121 | @contentType = application/json 122 | PUT {{host}}/user/update/1 123 | Content-Type: {{contentType}} 124 | { 125 | "userName": "kchintala", 126 | "firstName": "Karthik", 127 | "lastName": "Chintala" 128 | } 129 | ``` 130 | 131 | 4、[quartznet](https://github.com/quartznet/quartznet) 132 | 133 | quartnet 是一个开源的作业调度框架,是 OpenSymphony 的 Quartz API 的.NET 移植,它用 C#写成,可用于各种 C#应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而 创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持 cron-like 表达式等等。 134 | -------------------------------------------------------------------------------- /docs/episode-023.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 23 期 2 | 3 | ## 卷首语 4 | 5 | [MAUI Blazor App 教程](https://www.c-sharpcorner.com/article/build-a-blazor-hybrid-app-with-net-maui-for-cross-platform-application) 6 | 7 | 在本文中介绍了下列内容: 8 | 9 | - 什么是 Hybrid Blazor App 10 | - 什么是.NET MAUI 11 | - .NET MAUI Blazor app 12 | - 开始使用 .NET MAUI Blazor App 13 | - .NET MAUI Blazor App 的先决条件 14 | - 使用 Visual Studio 创建 .NET MAUI Blazor 应用 15 | - 在 Windows 中运行和测试 .NET MAUI Blazor 应用 16 | - 在 Android 模拟器中运行并测试 .NET MAUI Blazor 应用 17 | - 为什么要使用 .NET MAUI Blazor 应用 18 | - 使用 Blazor,我们可以同时使用 .NET 和 C# 来构建前端 Web UI 和后端逻辑 19 | - 我们可以对前端 Web UI 和后端逻辑使用相同的 C# 技能集,这将加速开发并降低成本。 20 | - 我们不需要对使用哪些前端框架而感到疑惑。 21 | - 我们可以开发 .NET MAUI for Windows、安卓、iOS、macOS、Web 的跨平台应用程序。 22 | - 适用于跨平台应用的相同 C# 和 .NET 23 | - 共享代码和 UI 布局 24 | - 共享设计和一致的 UI 25 | - 共享相同的逻辑,测试 26 | - 适用于所有平台的原生应用 27 | - 可以使用 Windows 或 Mac 进行开发,并且可以在每个设备上运行 28 | - 我们可以使用单个项目,这将易于维护和工作 29 | - 我们可以使用所有 .NET 库和 C# 特性 30 | - 最新技术和强大的社区支持 31 | 32 | ## 行业资讯 33 | 34 | 1、[ASP.NET Core RC1 发布](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-rc-1) 35 | 36 | ![image](https://user-images.githubusercontent.com/11272110/192072695-b629ade8-7e7f-4591-95ac-b65f27088b85.png) 37 | 38 | 随着 `.NET 7` RC1 发布, `ASP.NET Core 7` 的 RC 也发布了,其中包含了若干个更新,现在可以体验起来。 39 | 40 | 2、[.NET 7 RC1 发布](https://devblogs.microsoft.com/dotnet/announcing-dotnet-7-rc-1) 41 | 42 | ![image](https://user-images.githubusercontent.com/11272110/192072275-bb35de37-8ff6-4bda-846a-0a97beb4aa59.png) 43 | 44 | 毫无疑问,一年一度的 `.NET` 发布日期即将到来。最近 `.NET 7 RC1` 已经发布了,包含以下的重点 45 | 46 | - MAUI 47 | - Cloud Native 支持 48 | - ARM 64 性能提升 49 | - Modernization 无痛升级 50 | - Performance 提升 51 | 52 | 3、[.NET 7 在 arm 上性能提升](https://devblogs.microsoft.com/dotnet/arm64-performance-improvements-in-dotnet-7) 53 | 54 | ![image](https://user-images.githubusercontent.com/11272110/192071887-db8cde92-c60e-4665-ae52-8366e1db9068.png) 55 | 56 | `.NET` 从 Day 1 就是完全开放的,不仅仅是 `Windows`, `Linux` 或者 `MacOS`,而且能够运行在不同的 `CPU` 指令集中。最近即将发布的 `.NET 7` 在 `ARM64` 上有着很大的性能提升。 57 | 58 | 4、[Winget 管理 .NET SDK](https://devblogs.microsoft.com/dotnet/dotnet-now-on-windows-package-manager) 59 | 60 | ![image](https://user-images.githubusercontent.com/11272110/192071276-eb699bbb-f526-4997-9496-7ef18b61d4df.png) 61 | 62 | `Winget` 是微软官方发布的 `Windows` 包管理器,通过它可以通过命令行安装一些软件和包。现在通过它可以安装 `.NET` SDK。 63 | 64 | - winget search Microsoft.DotNet 65 | - winget Install Microsoft.DotNet.SDK.6 66 | - winget uninstall Microsoft.DotNet.SDK.6 67 | 68 | `Winget`主要命令如下: 69 | 70 | | 命令 | 用途 | 71 | | --------- | -------------------------- | 72 | | install | 安装给定的程序包 | 73 | | show | 显示包的相关信息 | 74 | | source | 管理程序包的来源 | 75 | | search | 查找并显示程序包的基本信息 | 76 | | list | 显示已安装的程序包 | 77 | | upgrade | 显示并执行可用升级 | 78 | | uninstall | 卸载给定的程序包 | 79 | | hash | 哈希安装程序的帮助程序 | 80 | | validate | 验证清单文件 | 81 | | settings | 打开设置或设置管理员设置 | 82 | | features | 显示实验性功能的状态 | 83 | | export | 导出已安装程序包的列表 | 84 | | import | 安装文件中的所有程序包 | 85 | 86 | ## 文章推荐 87 | 88 | 1、[MadsTorgersen 采访](https://dotnetcore.show/episode-104-c-sharp-with-mads-torgersen) 89 | 90 | ![image](https://user-images.githubusercontent.com/11272110/189531050-2370ae2f-d61d-45b0-905b-396ebdab7ee0.png) 91 | 92 | Mads 目前是 `C#` 语言的首席架构师,这篇播客是对他的采访,主要分为下面几个方面 93 | 94 | - 背景介绍,和 `Anders` 那里学到的团队的内容 95 | - C# 中的 `async/await` 对其他语言的影响 96 | - C# 的语言和 `.NET` 版本的分离对开发的体验 97 | - 如何对 `C#` 社区做出贡献 98 | 99 | 2、[Sealed class 有助于提高性能](https://www.youtube.com/watch?v=d76WWAD99Yo&ab_channel=NickChapsas) 100 | 101 | ![image](https://user-images.githubusercontent.com/11272110/192070635-0c56d136-1876-4658-80ab-2d66f79f5f26.png) 102 | 103 | `Sealed` 修饰符 `C#` 语法的一部分,它表示这个类不能被继承,不为人知道的是它在性能上有很好的提升。 104 | 如果 `sealed` 修饰的类,那么得到下面的好处 105 | 106 | - `override` 方法可以直接调用而不是查看虚方法表,也就是这些方法可以内联 107 | - `is` 和 `as` 这样的类型转换可以高效实现,因为不需要比较类型本身而不是潜在的继承关系 108 | - 数组不需要进行考虑协变的问题 109 | - 创建 `Span` 类型的时候不要验证其真正的类型 110 | 111 | 3、[C# 11 的新特性以及它能够解决的问题](https://rubikscode.net/2022/09/19/c-11-top-5-features-in-the-new-c-version) 112 | 113 | ![image](https://user-images.githubusercontent.com/11272110/192073685-94e8db85-aa8e-4fb8-8700-593f0acc17d1.png) 114 | 115 | `C#11` 即将发布,这里详细分析了 5 个重要的功能 116 | 117 | 1. 原始字符串 118 | 在 `C#11` 中可以通过至少 3 个 `"` 表示一个原生字符串,这样避免了繁琐的转义操作 119 | 120 | 2. Attribute 泛型 121 | 122 | 过去 `Attribute` 是不支持泛型,类型需要作为一个属性参数表示,`C# 11` 解除了这个限制。 123 | 124 | 3. 数学方法的通用支持 125 | 126 | 定义接口的抽象方法,可以使数学计算更加方便。 127 | 128 | 4. 列表匹配 129 | 130 | 增加的列表匹配的方法 131 | 132 | 5. Struct 属性 133 | 134 | 对于 `init` 的 `Struct` 属性,可以设定默认值。 135 | 136 | 4、[使用 PlayWright 测试 ASP.NET Core 应用程序](https://www.twilio.com/blog/test-web-apps-with-playwright-and-csharp-dotnet) 137 | 138 | ![image](https://user-images.githubusercontent.com/11272110/192077644-f586458d-5797-43df-84a6-d904902f758c.png) 139 | 140 | 在本篇文章中首先介绍了`Playwright`该库的一些特性,例如: 141 | 142 | - 支持多种测试类型(单元测试、集成测试、端到端测试) 143 | - 无需手动安装浏览器和该浏览器兼容的驱动程序 144 | - 支持多种浏览器:Chromium、Edge、Safari、Firefox 145 | - 通过.NET(C#),TypeScript,JavaScript,Python 和 Java 提供跨平台和跨语言支持 146 | - 支持通过[Codegen](https://playwright.dev/dotnet/docs/codegen-intro)录制脚本。 147 | 148 | 然后在本文其他大部分内容中通过`NUnit`和`Playwright`,一步一步讲述了如何对一个`ASP.NET Core` Web 应用进行了单元测试。 149 | 150 | 6、[ASP.NET Core 中如何将 Delegate 转换成 RequestDelegate](https://stackoverflow.com/questions/73426685/how-is-delegate-being-cast-to-requestdelegate-in-asp-net-core/73427800#73427800) 151 | 152 | StackOverflow 中某位用户提出了一个问题:在下列代码中`handler`参数是如何从`Delegate`类型转换为`RequestDelegate`类型的。另一位用户给出了回答具体详情请查阅文章。 153 | 154 | ```Csharp 155 | public static RouteHandlerBuilder MapGet( 156 | this IEndpointRouteBuilder endpoints, 157 | string pattern, 158 | Delegate handler) 159 | { 160 | return MapMethods(endpoints, pattern, GetVerb, handler); 161 | } 162 | public static IEndpointConventionBuilder MapMethods( 163 | this IEndpointRouteBuilder endpoints, 164 | string pattern, 165 | IEnumerable httpMethods, 166 | RequestDelegate requestDelegate) 167 | { 168 | // 略 169 | } 170 | ``` 171 | 172 | ## 开源项目 173 | 174 | 1、[Apache Thrift](https://github.com/apache/thrift) 175 | 176 | Thrift 是一个轻量级的、与语言无关的技术栈,可以用于点对点 RPC 实现。Thrift 为数据传输、数据序列化和应用程序级处理提供了清晰的抽象和实现。Thrift 的代码生成系统采用了简单的定义语言作为输入,并生成跨编程语言的代码,通过这些抽象代码来构建可互操作的 RPC 客户端和服务器。 177 | 178 | Thrift 使用不同编程语言编写的程序可以轻松共享数据和调用远程过程。当前支持的[28 种语言](https://github.com/apache/thrift/blob/master/LANGUAGES.md)。可以参考的 Thrift[指南](https://diwakergupta.github.io/thrift-missing-guide/#_versioning_compatibility) 179 | -------------------------------------------------------------------------------- /docs/episode-024.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 24 期 2 | 3 | ## 卷首语 4 | 5 | [Docker SQL Server 使用](https://www.twilio.com/blog/containerize-your-sql-server-with-docker-and-aspnet-core-with-ef-core) 6 | 7 | ![image](https://user-images.githubusercontent.com/11272110/193408927-e98d464f-ceca-46e0-8281-8fd876c431a4.png) 8 | 9 | SQL Server 是 `.NET` 中广泛使用的关系型数据库,一般我们需要在本地机器上安装,但是这样会带来一些缺陷,比如会和其他引用和程序共享一个数据库,或者在 `Linux` 环境中测试就比较困难。这篇文章介绍了如何在 `Docker` 中安装 `SQL Server`。 10 | 11 | ## 行业资讯 12 | 13 | 1、[Entity Framework Core 7 (EF7) RC2发布](https://devblogs.microsoft.com/dotnet/announcing-ef7-release-candidate-2) 14 | 15 | Entity Framework Core RC2现在已经发布,RC2版本包含GA版本计划的所有功能。主要包括下面内容: 16 | 17 | - 映射到 `SQL Server` JSON列 18 | - `ExecuteUpdate` 和 `ExecuteDelete` (批量更新) 19 | - 改进了 `SaveChanges` 的性能 20 | - 每个具体类型的表 (TPC) 继承映射 21 | - 自定义逆向工程模板 (Database First) 22 | - 可定制的模型生产约定 23 | - 用于插入、更新和删除的存储过程映射 24 | - 新增和改进的拦截器和事件 25 | - 查询增强功能,包括更多分组依据和分组连接翻译 26 | 27 | ## 文章推荐 28 | 29 | 1、[.NET 中调用 JavaScript](https://devblogs.microsoft.com/dotnet/use-net-7-from-any-javascript-app-in-net-7) 30 | 31 | ![image](https://user-images.githubusercontent.com/11272110/193435343-dd975d39-cc47-4892-8125-801701c76df2.png) 32 | 33 | `.NET 7` 为在基于 `JavaScript` 的应用程序中的 `WebAssembly` 提供了改进的支持,包括丰富的 `JavaScript` 互操作机制。 34 | .NET 7 中的 `WebAssembly` 支持是 `Blazor WebAssembly` 应用程序的基础,但也可以独立于 Blazor 使用。 35 | 现有的 `JavaScript` 应用程序可以使用 .NET 7 中扩展的 `WebAssembly` 支持来重用 `JavaScript` 中的 .NET 库或构建全新的基于 .NET 的应用程序和框架。 36 | `Blazor WebAssembly` 应用程序还可以使用新的 `JavaScript` 互操作机制来优化与 `JavaScript` 和 `Web` 平台的交互。 37 | 在这篇文章中,我们将了解 .NET 7 中新的 `JavaScript` 互操作支持,并使用它来构建经典的 `TodoMVC` 示例应用程序。 38 | 39 | 2、[Linq 学习](https://anthonygiretti.com/2022/09/29/net-learn-linq-as-you-never-have-before/?utm_source=isaacl&utm_medium=twitter&utm_campaign=link&WT.mc_id=link-twitter-isaacl) 40 | 41 | ![image](https://user-images.githubusercontent.com/11272110/194697415-7a8c81c3-d7c9-4b1d-b911-d553b9af46f3.png) 42 | 43 | 这份文档详细的介绍了几乎所有的 `LINQ` 基本使用场景和方法。 44 | 例如: 45 | 46 | - 过滤 47 | - 查询投影 48 | - 聚合 49 | - 查询数量 50 | - 合并 51 | - 队列比较 52 | - 查询元素 53 | - 转换数据类型 54 | - 分组 55 | - 集合操作,连接 56 | 57 | 3、[RateLimter 中间件介绍](https://blog.maartenballiauw.be/post/2022/09/26/aspnet-core-rate-limiting-middleware.html) 58 | 59 | ![image](https://user-images.githubusercontent.com/11272110/194707875-1f2fcb05-4825-4b94-981c-fdd72bdb260d.png) 60 | 61 | `ASP.NET Core 7` 引入了 `RateLimit` 中间件,通过它可以保护我们资源(CPU,内存和磁盘 I/O)不会因为大量访问而导致服务不够用。这篇播客详细介绍了如何使用这个中间件: 62 | 63 | - 全局的访问限制 64 | - 内置不同种类的 RateLimter 65 | - 自定义 RateLimiter 66 | - 不同 API 的 RateLimiter 67 | 68 | 4、[.NET 名字的故事](https://www.cnet.com/tech/tech-industry/net-name-ties-microsoft-in-knots) 69 | 70 | ![image](https://user-images.githubusercontent.com/11272110/194709931-e80176e3-fdee-48df-97ed-28d335490087.png) 71 | 72 | 现在不少大 V 呼吁微软将 `.NET` 重新命名为 `dotnet`,因为这样更加有助于市场推广和搜索。这篇文章带你回顾了 `.NET` 名字刚刚推出的时候,媒体和社区对其的困惑。 73 | 74 | 6、[ASP.NET Core 的配置验证](https://andrewlock.net/adding-validation-to-strongly-typed-configuration-objects-in-dotnet-6) 75 | 76 | ![image](https://user-images.githubusercontent.com/11272110/194710445-35bfca36-b106-4f33-8bc4-4b85d3b674d3.png) 77 | 78 | `IConfiguration` 和 `IOption` 是 `ASP.NET Core` 引入的配置组件,`IConfiguration` 可以提供多种多样的配置来源,比如 `JSON` 文件,环境变量和命令行参数等等。再通过 `IOption` 将它转换成一个 POCO 对象,但是这样会带来一个两个问题: 79 | 80 | - 如果配置由于 `typo` 导致某些 key 不匹配,这样就会变成默认值 81 | - 由于配置的 `Value` 格式没有满足一定的要求,导致其变成非法值 82 | 83 | 在 `ASP.NET Core 6` 中支持校验配置的类型值 84 | 85 | - POCO 对象 86 | 87 | ```csharp 88 | public class SlackApiSettings 89 | { 90 | [Required, Url] 91 | public string WebhookUrl { get; set; } 92 | [Required] 93 | public string DisplayName { get; set; } 94 | public bool ShouldNotify { get; set; } 95 | } 96 | ``` 97 | 98 | - JSON 配置源 99 | 100 | ```json 101 | { 102 | "SlackApi": { 103 | "Url": "http://example.com/test/url", 104 | "DisplayName": "My fancy bot", 105 | "ShouldNotify": true 106 | } 107 | } 108 | ``` 109 | 110 | - 注册配置 111 | 112 | ```csharp 113 | builder.Services.AddOptions() 114 | .BindConfiguration("SlackApi") // 👈 Bind the SlackApi section 115 | .ValidateDataAnnotations() // 👈 Enable validation 116 | .ValidateOnStart(); // 👈 Validate on app start 117 | ``` 118 | 119 | 7、[如何在 ASP.NET Core 中配置多个JSON格式](https://thomaslevesque.com/2022/09/19/using-multiple-json-serialization-settings-in-aspnet-core) 120 | 121 | ![image](https://user-images.githubusercontent.com/11272110/195961241-ad16fa29-4286-406e-8b2c-f3b83ee98715.png) 122 | 123 | `ASP.NET Core` 拥有丰富的扩展性,用户可以根据自己需求来自定义拓展来完成。这篇文章以不同的 `Controller` 使用不同的 `JSON` 格式化需求为例子,展示了 `ASP.NET Core` 的扩展性。 124 | 125 | ## 开源项目 126 | 127 | 1、[ASP.NET Core 最佳实践](https://github.com/davidfowl/AspNetCoreDiagnosticScenarios) 128 | 129 | ![image](https://user-images.githubusercontent.com/11272110/194705108-ad8e024d-a72f-420f-94e6-20ee70df8254.png) 130 | 131 | 这个仓库介绍了 `ASP.NET Core` 应用程序在使用的时候的注意点,还有异步方法在调用的时候最佳实践。 132 | 133 | 2、[Figma 导出成 MAUI](https://github.com/jsuarezruiz/figma-to-maui-graphics) 134 | 135 | ![image](https://user-images.githubusercontent.com/11272110/194705261-09b2dcdc-1eb8-4719-8ec2-cf1f96a90f73.png) 136 | 137 | Figma 是专业的 UI 在线设计软件,几乎每个设计师都在使用它。而 MAUI 是跨平台的 UI 设计库,自然而然我们希望将 Figma 中的设计自动转换成 MAUI 的设计代码,而这个库就能帮助我们做到这一点。 138 | -------------------------------------------------------------------------------- /docs/episode-025.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 25 期 2 | 3 | ## 卷首语 4 | 5 | 下个月就是每年的 `.NET` 发布新版本的时候,大家都有什么期待呢? 6 | 7 | ## 行业资讯 8 | 9 | 1、[Imagesharp 离开 .NET Foundation](https://dotnetfoundation.org/blog/2022/10/20/imagesharpupdate) 10 | 11 | ![image](https://user-images.githubusercontent.com/11272110/198753745-fccaa652-63ea-4e51-bd60-bef5d7cf2ed6.png) 12 | 13 | 最近 `.NET Foundation` 宣布了著名的图像处理库 `Imagesharp` 离开了 `.NET Foundation` 组织,因为他们修改了开源软件的协议,变成了一个付费使用的库。 14 | 15 | 2、[Microsoft Ignite 2022 中 ASP.NET Core 7 介绍](https://learn.microsoft.com/en-us/events/ignite-2022/brk203h-hidden-gems-live-coding-with-net-7) 16 | 17 | ![image](https://user-images.githubusercontent.com/11272110/198597633-a3fc3e62-0164-45ac-980d-f2a459432299.png) 18 | 19 | 前一阵子 Microsoft Ignite 大会上,`Damian Edwards` 和 `David Fowler` 展示了 `ASP.NET Core 7` 的一些新特性,没有幻灯片,只有实际的例子,包含了下面的主题 20 | 21 | - RateLimiter 22 | - Logging Middleware 23 | - Output Caching 24 | - Problem Detail 25 | - Hook setup 26 | - Native AOT 27 | 28 | ## 文章推荐 29 | 30 | 1、[如何扩展 ASP.NET Core 应用程序](https://speakerdeck.com/davidfowl/scaling-asp-dot-net-core-applications) 31 | 32 | ![image](https://user-images.githubusercontent.com/11272110/198805070-99af89b3-3fcb-4f54-8ebe-072438cd67f7.png) 33 | 34 | David Fowler 的一个演讲的 Slide,从内存,CPU,I/O 的角度如何拓展的 `ASP.NET Core` 的应用程序。 35 | 36 | 2、[Task.WaitAll 异常处理方法](https://thesharperdev.com/csharps-whenall-and-exception-handling/) 37 | 38 | ![image](https://user-images.githubusercontent.com/11272110/198297407-c2993da1-d4dc-4e52-99ea-14e4edab7d59.png) 39 | 40 | C# 中的 `WaitAll` 可以接受一些列异步的 `Task` 并且等所有的 `Task` 都完成之后才会自己返回。如果其中一个任务抛出异常,那么 `WaitAll` 只会抛出第一个异常。所以该怎么解决这个问题,这篇文章给出一个可行的方案 41 | 42 | 3、[自定义 HTTP 的方法](https://khalidabuhakmeh.com/adding-experimental-http-methods-to-aspnet-core) 43 | 44 | ![image](https://user-images.githubusercontent.com/11272110/198298652-54c3870a-0a13-4854-aad6-22a6a4c923ca.png) 45 | 46 | 标准的 `HTTP` 请求方法有 `GET`, `POST`, `PUT` 等等。那么如果想要自定义一个方法,比如 `QUERY`,改如何实现呢? `ASP.NET Core` 有很强的扩展性,这篇文章介绍了怎么完成这件事。 47 | 48 | 4、[C# 最差实践](https://code-maze.com/csharp-programming-mistakes/) 49 | 50 | C# 代码中有很多规范和陷阱,这篇文章介绍了其中的一部分。 51 | 52 | 6、[OData 在 ASP.NET Core 中使用](https://code-maze.com/aspnetcore-webapi-using-odata/) 53 | 54 | ![image](https://user-images.githubusercontent.com/11272110/198753965-07986e44-7766-420d-989b-6740916312b4.png) 55 | 56 | OData 是微软提出的基于 `Rest` 的客户-服务端请求,通过客户端的请求的参数的不同,服务端就可以返回不同的参数,而且服务端不需要编写相应的逻辑,而且请求的参数和普通的 Rest 请求不一样。 57 | 58 | ```bash 59 | https://localhsot/odata/companies?$filter=Size gt 20 60 | ``` 61 | 62 | 该请求是从 `Company` 实体中返回属性 `Size` 大于 20 是实体,而 `Controller` 中定义如下 63 | 64 | ```Csharp 65 | [EnableQuery] 66 | [HttpGet("{id}")] 67 | public SingleResult Get([FromODataUri] int key) 68 | { 69 | return SingleResult.Create(_repo.GetById(key)); 70 | } 71 | ``` 72 | 73 | 7、[高难度学习 .NET](https://www.slideshare.net/petabridge/net-systems-programming-learned-the-hard-waypptx) 74 | 75 | ![image](https://user-images.githubusercontent.com/11272110/198755900-bf9058b2-d17d-4983-b6f9-84284883a013.png) 76 | Aaron Stannard 是 `Akka.NET` 的作者,这里有一份演讲的 Slide,介绍了如何是用 `C#` 的高级特性来提高 `Akka.NET` 的性能。 77 | 78 | ## 开源项目 79 | 80 | 1、[ASP.NET Core 的 Clean Architecture 模板](https://github.com/jasontaylordev/CleanArchitecture) 81 | 82 | ![image](https://user-images.githubusercontent.com/11272110/198299936-aa1dffe5-050f-4564-b582-845341a3f22f.png) 83 | 84 | 在创建 `ASP.NET Core` 应用程序的时候, `Visual Studio` 模板已经做的足够好了。这个开源项目遵顼 `Clean Architecture` 的原则,提供了模板,包含了大量现代化软件开发的框架和类库。 85 | 86 | 2、[Cake](https://github.com/cake-build/cake) 87 | 88 | ![image](https://user-images.githubusercontent.com/11272110/198627475-d80961c6-5189-47dd-bd02-516e8864feb3.png) 89 | 90 | 虽然 `dotnet` 命令行工具已经非常工具已经非常强大了,但是我们仍然想要拥有一个类似 `Cmake` 一样的编译,测试工具。`Cake` 就是这样一个开源项目,让 `C#` 项目也具有强大的功能。 91 | 92 | 3、[十个免费的 VS 主题推荐](https://blog.dotnetsafer.com/best-visual-studio-2022-themes/) 93 | 94 | ![image](https://user-images.githubusercontent.com/11272110/198773487-1ba3ee41-7c6e-48cf-b068-32ba37865d16.png) 95 | 96 | 在颜值即正义的时代,挑选一款漂亮的 `Visual Studio` 主题也是一件重要的事情,这篇文章介绍了作者认为比较好看的主题,你认为呢? 97 | -------------------------------------------------------------------------------- /docs/episode-028.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 28 期 2 | 3 | ## 卷首语 4 | 5 | [ChatGPT 在 .NET 上的表现](https://www.youtube.com/watch?v=z2CKQFi746Q&ab_channel=NickChapsas) 6 | 7 | ![image](https://user-images.githubusercontent.com/11272110/206719245-40d422ed-ba74-48ec-a7d9-9dfc6c4f1e26.png) 8 | 9 | `ChatGpt` 是当前 IT 界的当红炸子鸡,几乎所有人都在讨论它。这是 OpenAI 公司基于 GPT 神经网络模型推出的聊天机器人,它不仅仅可以回答问题,还可以帮助我们编写代码。在这个视频中,展示了如果让 `ChatGPT` 帮助我们编写按照要求的代码。 10 | 11 | - 首先要求编写一个方法,接受一个 `guid` 字符串,然后将它转换成 `Base64` 的形式并且返回。 12 | 13 | ```csharp 14 | public string GetBase64FromGuid(string guidString) 15 | { 16 | Guid guid = Guid.Parse(guidString); 17 | byte[] bytes = guid.ToByteArray(); 18 | string base64 = Convert.ToBase64String(bytes); 19 | return base64; 20 | } 21 | ``` 22 | 23 | - 需要处理不合法的输入 24 | 25 | ```Csharp 26 | public string GetBase64FromGuid(string guidString) 27 | { 28 | if (!Guid.TryParse(guidString, out guid)) 29 | { 30 | // Return an empty string if the input is not a valid GUID 31 | return ""; 32 | } 33 | byte[] bytes = guid.ToByteArray(); 34 | string base64 = Convert.ToBase64String(bytes); 35 | return base64; 36 | } 37 | ``` 38 | 39 | - 优化代码,避免推内存分配 40 | 41 | ```csharp 42 | public string GetBase64FromGuid(string guidString) 43 | { 44 | if (!Guid.TryParse(guidString, out guid)) 45 | { 46 | // Return an empty string if the input is not a valid GUID 47 | return ""; 48 | } 49 | Span bytes = stackalloc byte[16]; 50 | guid.TryWriteBytes(bytes); 51 | string base64 = Convert.ToBase64String(bytes); 52 | return base64; 53 | } 54 | ``` 55 | 56 | `ChatGPT` 完全超出了人们的预期,尤其是在编程这一领域。但是: 57 | 58 | > 人们总是高估技术的短期效益,而忽视的技术的长期效益 59 | 60 | ## 行业资讯 61 | 62 | 1、[.NET Interactive Notebook 改名](https://devblogs.microsoft.com/dotnet/dotnet-interactive-notebooks-is-now-polyglot-notebooks/) 63 | 64 | ![image](https://user-images.githubusercontent.com/11272110/205306787-6459a1f1-2fad-4b0c-bf1e-6b338a9b10e2.png) 65 | 66 | 微软*改名部*再次发力,将直接的 `.NET Interactive Notebook` 更名为 `Polyglot Notebook`。不过这样做也是合理的,因为现在这个 `Kernal` 不单单只支持 `.NET` 语言,还支持很多其他语言: 67 | 68 | - C# 69 | - F# 70 | - PowerShell 71 | - JavaScript 72 | - SQL 73 | - KQL (Kusto Query Language) 74 | - HTML\* 75 | - Mermaid\* 76 | 77 | 2、[官方文档中事否推荐收费的开源库?](https://twitter.com/runfaster2000/status/1599196714539560960) 78 | 79 | ![image](https://user-images.githubusercontent.com/11272110/206716814-a83d3ff3-f441-4ac5-950d-db6b19579412.png) 80 | 81 | ImageSharp 是 `.NET` 社区中广泛使用的 2D 图像处理库,但是最近该库的作者将改为商业库。所以在 `.NET` 官方文档中,将该库被移除,该库的作者最近在 `Twitter` 上抱怨了这件事。你怎么看这件事呢? 82 | 83 | 3、[Fluent UI 支持 Blazor 2.0](https://medium.com/fast-design/whats-new-in-the-microsoft-fluent-ui-library-for-blazor-version-2-0-b3ac0eb5d02c) 84 | 85 | ![image](https://user-images.githubusercontent.com/11272110/206718593-b1e446c4-b927-4378-997c-e26246267122.png) 86 | 87 | Fluent UI 和 Blazor 都是微软推出的前端 UI 框架,最近 2.0 版本已经发布。 88 | 89 | ## 文章推荐 90 | 91 | 1、[.NET 7 在网络上的提升](https://devblogs.microsoft.com/dotnet/dotnet-7-networking-improvements/) 92 | 93 | .NET 7 在网络处理上有很大的提升,主要有 94 | 95 | - HTTP 协议 96 | - 提高链接错误处理能力 97 | - HttpHeader 线程安全 98 | - 删除 HTTP/2 和 HTTP/3 协议错误 99 | - HTTP/3 支持 100 | - QUIC 协议 101 | - 开放更多的 API 接口 102 | - 提供 QuicStream 类型 103 | - 安全 104 | - Negotiate API 105 | - Certificates 校验选项 106 | - TLS 协议 107 | 108 | 2、[Raw string Literals 最大支持引号数量](https://www.tabsoverspaces.com/233911-having-fun-with-csharp-11-raw-string-literals) 109 | 110 | ![image](https://user-images.githubusercontent.com/11272110/205310996-22730768-57ff-4f05-b12b-42bbdd4e6a8e.png) 111 | 112 | C# 11 推出了很强大的 `Raw String Literals`, 通过至少三个引号来表示一个字面字符串,那么最大可以有多少个引号呢?这篇文章作者尝试编写出一个很大的代码文件,其中包含了很多的引号的字符串。 113 | 114 | 3、[NET AOT 对于 Serverless 服务痛点的解决](https://www.youtube.com/watch?v=3QJDJl-zDFM&ab_channel=NickChapsas) 115 | 116 | ![image](https://user-images.githubusercontent.com/11272110/206711626-d204af36-a987-4cb8-8e45-078cbc385714.png) 117 | 118 | .NET 7 正式推出了 `AOT`, 它可以将 C# 代码编译成目标机器的机器码,这样在运行的过程中就不再需要转换,大大提高了的运行效率。对于 `Serverless` 服务,通常是事件驱动,那么每次在加载的时候,都需要进行机器码转换,而 `.NET AOT` 就解决了这一痛点。 119 | 120 | 4、[Visual Studio 愿望清单](https://michaelscodingspot.com/extending-visual-studio-wish-list/) 121 | 122 | ![image](https://user-images.githubusercontent.com/11272110/206852966-f6f83786-a387-46fb-96bc-703b9ed36557.png) 123 | 124 | 圣诞节要到了,这篇文章的作者列出了一些列对于 `Visual Studio` 和 `Nuget` 的愿望清单,希望 `.NET` 生态能够像 `JavaScript` 生态一样开放。 125 | 126 | ## 开源项目 127 | 128 | 1、[TodoApi](https://github.com/davidfowl/TodoApi) 129 | 130 | ![image](https://user-images.githubusercontent.com/11272110/205304657-ca5f122f-45cd-4451-ab68-3be54dbd9fba.png) 131 | 132 | 这是个 `.NET` 示例的仓库,通过 `ToDo` 这样简单的应用,展示很多 `.NET` 最新的技术,主要有 133 | 134 | - Blazor WebAssembly 135 | - Minimal APIs 136 | - EF + SQLite 137 | - OpenAPI 138 | - ASP.NET Core Identity 139 | - Cookie Authentication 140 | - JWT Authentction 141 | - YARP's Proxy 142 | - Rate Limiting 143 | - Integration Tests 144 | 145 | 2、[SmartEnum](https://github.com/ardalis/SmartEnum) 146 | 147 | SmartEnum 库是 John Skeet 关于 C# [Enum 类型的增强提议](https://codeblog.jonskeet.uk/2006/01/05/classenum/)。 它主要解决 `C#` 中枚举类型只是简单的继承 `Int` 类型,因为很多时候,我们需要将枚举类型同其他数据放在一起。在 `C#` 中只能通过 if-else 或者 switch 语句完成。`SmartEnum` 可以实现类似 `Java` 这样的语法。 148 | 149 | ```csharp 150 | public sealed class Subscription : SmartEnum 151 | { 152 | public static readonly Subscription Standard = new Subscription("Standard", 1.0); 153 | 154 | public static readonly Subscription Prime = new Subscription("Prime", 0.75); 155 | 156 | public static readonly Subscription VIP = new Subscription("VIP", 0.5); 157 | 158 | private Subscription(string name, double discount) : base(name, discount) { } 159 | 160 | 161 | public double GetPrice(double price) 162 | { 163 | return price * this.Value; 164 | } 165 | } 166 | 167 | // program.cs 168 | Console.WriteLine($"{Subscription.VIP}'s price is {Subscription.VIP.GetPrice(1000)}"); 169 | ``` 170 | -------------------------------------------------------------------------------- /docs/episode-036.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 36 期 2 | 3 | ## 卷首语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c9d52e73-b127-4e8c-b5f6-79389a2ac9c5) 6 | 7 | 今年 [Microsoft Build](https://build.microsoft.com/en-US/home) 大会在 5 月份召开,其中最重要的关键词就是 `AI` 和 `Copliot`。当然对于 `.NET`也是有涉及,主要是在性能上的提升,还介绍了 Windows11 的 `DevHome`, 可以非常方便开发者进行环境搭建,开发机器性能监控和 `GitHub` 看板功能。 8 | 9 | ## 行业资讯 10 | 11 | 1、[Fleet C# 支持更新](https://blog.jetbrains.com/dotnet/2023/05/04/csharp-support-in-fleet-solution-view-unit-testing-and-more/) 12 | 13 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/0349a44d-94a0-4e75-9f97-933f4c60c182) 14 | 15 | JetBrains 更新了 Fleet 对 C# 支持的特性,主要包括 16 | 17 | 1. 解决方案视图 18 | 2. Build/Rebuild/Clean 操作 19 | 3. 单元测试 20 | 21 | 2、[Visual Studio UI 更新](https://devblogs.microsoft.com/visualstudio/visual-studio-ui-refresh/) 22 | 23 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/69d07887-7763-4795-be3c-6e1613f12630) 24 | 25 | Visual Studio 团队打算遵循 `Fluent UI` 的为 VS 重新设计 UI 界面,主要处于下面三个考虑 26 | 27 | - 一致性 28 | - 可访问行 29 | - 效率 30 | 31 | 下拉菜单对比: 32 | 33 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/9194ca38-5a64-4004-885a-8ef0b00a8ec2) 34 | 35 | 2、[Visual Studio Sticky 滚动](https://devblogs.microsoft.com/visualstudio/sticky-scroll-stay-in-the-right-context/) 36 | 37 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/0a5d58fd-3f39-48fb-920f-4f07c07d9a88) 38 | 39 | `Sticky` 是一个非常使用的功能,非常类似在 `Excel` 中将表头固定,然后向下翻动行。在编写代码的时候,有很多 `for`, `foreach` 等循环,如果循环体非常长,或者存在嵌套循环,那么这个功能还是非常有用的。 40 | 41 | ## 文章推荐 42 | 43 | 1、[NET 8 中 NativeAOT 编译](https://www.youtube.com/watch?v=G5RiC9qQNvw&ab_channel=NickChapsas) 44 | 45 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a70c58c5-7b50-4e49-9b5a-bb2d32f79603) 46 | 47 | .NET 8 中支持 `Native AOT` 编译,也就是说编译出来的应用程序就是原生的应用程序,而不是需要 `.NET` 运行时才能的执行,跟 `Rust` 和 `Go` 一样。 48 | 只需要在 `csproj` 文件中配置 `true` 即可。 49 | 50 | 2、[C# IDisposable 和 Go defer 的区别](https://blog.cellfish.se/2023/05/go-for-c-developers-defer-is-not.html) 51 | 52 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c2d120db-6ddc-4052-9d7b-237dbe15d393) 53 | 54 | `C#` 和 `Go` 中有两个非常相似的功能叫,分别为 `IDisposable` 和 `defer`, 通常是在方法执行完毕后,执行一些清理工作。比如关闭开打的文件流和网络 `socket`。但是这两者还是有一些区别 55 | 56 | - `IDisposable` 并不保证的 `Dispose` 方法肯定被调用,除非放在 `using` 的语句块中,而且变量离开了作用域就会执行。 57 | - `defer` 只会在函数 `return` 之后才会执行,而且肯定会执行。 58 | 59 | 3、[正确的输出日志](https://www.youtube.com/watch?v=PvQGVmozCdU&ab_channel=NickChapsas) 60 | 61 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/1d7b4497-959a-4e67-8bf2-dd07ac54fb92) 62 | 63 | 日志是应用程序中不可或缺的的组成部分,随着 `Microsoft.Extensions.Logging` 扩展包推出,不同的日志输出源只要配置好 `LoggerProvider` 就可以了。 `ILogger` 的 `LogInformation`, `LogWarning` 方法就是公开的接口,方法签名是这样的 64 | 65 | ```csharp 66 | /// 67 | /// Formats and writes an informational log message. 68 | /// 69 | /// The to write to. 70 | /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" 71 | /// An object array that contains zero or more objects to format. 72 | /// logger.LogInformation("Processing request from {Address}", address) 73 | public static void LogInformation(this ILogger logger, string? message, params object?[] args) 74 | ``` 75 | 76 | 请注意第三个参数 `message`, 但是注释中却是 `message template format`。所以我们的日志是应该这样 77 | 78 | ```chsarp 79 | logger.LogInformation("data: {Data}, {now}", Data, DateTime.Now); 80 | ``` 81 | 82 | 而不是这样 83 | 84 | ```csharp 85 | logger.LogInformation($"data: {Data}, {DateTime.Now}"); 86 | ``` 87 | 88 | 应为日志库是将模板缓存下来,而不是在输出的时候,就开始构造日志字符串。benchmark 测试 89 | 90 | ```csharp 91 | [MemoryDiagnoser] 92 | public class BenchmarkLogging 93 | { 94 | public static readonly ILogger logger; 95 | 96 | public static readonly Random random; 97 | 98 | private int Data => random.Next(); 99 | 100 | static BenchmarkLogging() 101 | { 102 | logger = new LoggerFactory().CreateLogger(); 103 | random = new Random(); 104 | } 105 | 106 | [Benchmark] 107 | public void Templated() 108 | { 109 | logger.LogInformation("data: {Data}, {now}", Data, DateTime.Now); 110 | } 111 | 112 | [Benchmark] 113 | public void Interpolated() 114 | { 115 | logger.LogInformation($"data: {Data}, {DateTime.Now}"); 116 | } 117 | 118 | [Benchmark] 119 | public void Formatted() 120 | { 121 | logger.LogInformation(string.Format("data: {0}, {1}", Data, DateTime.Now)); 122 | } 123 | } 124 | ``` 125 | 126 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/48fb7cbb-55fa-4ab2-80f0-785ef6964d63) 127 | 128 | 可以看出,模板方法在性能和内存方面都优势。 129 | 130 | 4、[.NET 云应用程序](https://www.infoq.com/presentations/net-apps-cloud/) 131 | 132 | [![image](https://dotnetweeklyimages.blob.core.windows.net/035/openai.png)](https://www.infoq.com/presentations/net-apps-cloud/) 133 | 134 | 最近 `InfoQ` 组织了一场讨论 `.NET` 和云应用迁移的讨论,主要包含下面主题 135 | 136 | - `.NET` 开发者在面对云的主要痛点 137 | - 最小的迁移成本 138 | - 当迁移到云之后,下一步该怎么办 139 | - 选择 `Serverless` 还是 `Kubernetes` 140 | - 托管容器平台 141 | - 除了 `App Service` 还有其他最有选择 142 | - .... 143 | 144 | ## 开源项目 145 | 146 | 1、[Visual Studio 环绕选择](https://github.com/madskristensen/Surrounder) 147 | 148 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/246dc60e-3ebb-4a38-b61e-32d65c7215d8) 149 | 150 | 在编辑器中,我们常常需要一个功能就选择为一段文本或者代码添加双引号,括号等等。通常我们的操作是分别找到开始位置和结束位置,然后分别输入开始字符和结束字符。`Surrounder` 插件可以帮助我们方便的完成,只要选择该文件,然后输入开始字符,结束字符会自动开结尾添加上。 151 | -------------------------------------------------------------------------------- /docs/episode-037.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 37 期 2 | 3 | ## 卷首语 4 | 5 | VS Code C# 官方插件 6 | 7 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6ede63a7-4765-4b43-8b59-3a2d80ed4984) 8 | 9 | 之前 VS Code 中的 `C#` 支持都是由 `OmniSharp` 提供的。但是官方并没有明确的 `C#` 支持,现在 `C# Dev Kit` 插件弥补了这个缺失。 10 | 安装完成后,你可与在 `VS code` 中体验 `VS` 开发的感觉: 11 | 12 | 1. 创建项目 13 | 14 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/00a5e3be-a01c-4928-97ac-a019565e96e6) 15 | 16 | 2. 解决方案视图 17 | 18 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/f13eb789-aeb7-4d0a-9b7a-27f9312cca64) 19 | 20 | 3. 运行单测 21 | 22 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/03ff46f8-2517-4a24-895e-62e63ae729c6) 23 | 24 | 4. Debug 25 | 26 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/f98a7250-8af7-4eaf-a5b7-88b79ae71a18) 27 | 28 | 注意,这个插件不是开源免费的,商业使用需要购买许可证。 29 | 30 | ## 行业资讯 31 | 32 | 1、[CLI 版的 Upgrade Assistant](https://devblogs.microsoft.com/dotnet/upgrade-assistant-cli/) 33 | 34 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/bdb87860-5772-4644-8d37-2f86cdcd54bd) 35 | 36 | `.NET Upgrade Assistant` 是`.NET`应用程序的升级工具,比如从`.NET Framework`迁移到`.NET`, 或者不同的 `.NET`版本升级,之前这个是作为`Visual Studio`的一个插件,现在提供了`CLI` 版本。 37 | 38 | ## 文章推荐 39 | 40 | 1、[动态构建查询表达式](https://code-maze.com/dynamic-queries-expression-trees-csharp/) 41 | 42 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/47938402-df3e-488f-bec7-695ffc609878) 43 | 44 | 在 `C#` LINQ 中,除了我们显式地写查询语句,比如 `persons.Where(p => p.FirstName == "feng")` 之外,我们还可以通过 `Experssion` 的方式动态构建查询语句。这样查询就可以在动态运行时执行,达到数据驱动的的目的,比如 45 | 46 | ```csharp 47 | static Expression> CreateEqualExpression(string propertyName, object value) 48 | { 49 | var param = Expression.Parameter(typeof(Person), "p"); 50 | 51 | var member = Expression.Property(param, propertyName); 52 | 53 | var constant = Expression.Constant(value); 54 | 55 | var body = Expression.Equal(member, constant); 56 | 57 | return Expression.Lambda>(body, param); 58 | } 59 | 60 | var expression = CreateEqualExpression("FirstName", "feng"); 61 | persion.Where(expression); 62 | ``` 63 | 64 | 2、[ASP.NET Core 应用程序部署到 Linux Nginx 中](https://code-maze.com/deploy-aspnetcore-linux-nginx/) 65 | 66 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/fbd68ddf-7b4a-4461-9bc7-bf49ac04577a) 67 | 68 | 这篇文章介绍了如何将一个 ASP.NET Core 的应用程序部署到 `Linux` 中,并且使用 `Nginx` 作为反向代理 69 | 70 | 3、[ASP.NET Core 健康检查](https://www.youtube.com/watch?v=p2faw9DCSsY&ab_channel=NickChapsas) 71 | 72 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6445589c-0de5-4514-b7a8-a098e0156e0b) 73 | 74 | 在 `ASP.NET Core` 应用程序中,我们需要检查服务的健康状态,比如 `database`, 外部依赖服务等等。`ASP.NET Core` 提供了 `HealthCheck` 的组件,可以帮助我们完成这样工作。 75 | 76 | ```csharp 77 | // 实现 78 | public class DatabaseHealthCheck : IHealthCheck 79 | { 80 | public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) 81 | { 82 | try 83 | { 84 | string connectionString = "Server=localhost,1433;database=TestDb;User Id=SA;Password=xxxxxx"; 85 | using var connection = new SqlConnection(connectionString); 86 | connection.Open(); 87 | var command = connection.CreateCommand(); 88 | command.CommandText = "Select 1"; 89 | command.ExecuteScalar(); 90 | return Task.FromResult(HealthCheckResult.Healthy()); 91 | } 92 | catch (Exception e) 93 | { 94 | return Task.FromResult(HealthCheckResult.Unhealthy()); 95 | } 96 | } 97 | } 98 | // 注册服务 99 | builder.Services.AddHealthChecks() 100 | .AddCheck("database"); 101 | 102 | // 定义路由 103 | app.MapHealthChecks("/_health", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions 104 | { 105 | ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse 106 | }); 107 | ``` 108 | 109 | 4、[.NET StringComparer 优化](https://blog.ndepend.com/net-micro-optimization-and-refactoring-trick/) 110 | 111 | 下面两个 `Dictionary` 对象 112 | 113 | ```csharp 114 | var dict1 = new Dictionary(); 115 | var dict2 = new Dictionary(StringComparer.Ordinal); 116 | ``` 117 | 118 | 它们在 `.NET framework` 和 `.NET Core` 中性能表现是不一样的,也就是说,在 `.NET Core` 中 `dict1` 的性能比 `dict2` 好。这是为什么呢?在这个[ Github issue](https://github.com/dotnet/runtime/issues/29714#issuecomment-497537103) 中解释说,在 `dict2` 中使用的是 `EqualityComparer.Default`, 它其实并不是 `StringComparer.Ordinal` 类型,它避免了随机哈希操作直到必要的时候。 119 | 120 | 5、[使用连接池优化性能](https://devblogs.microsoft.com/premier-developer/the-art-of-http-connection-pooling-how-to-optimize-your-connections-for-peak-performance/) 121 | 122 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a26eb06f-7669-434f-988b-9c6f66012d79) 123 | 124 | 这是微软工程师帮助科技工程从 `on-prem` 向 `cloud` 转型过程中,遇到了并发性的问题,通过连接池 `connection pool` 技术,解决了客户的问题 125 | 126 | ```csharp 127 | builder.setKeepAliveStrategy((response, context) -> { 128 | String header = response.getFirstHeader("Keep-Alive").getValue(); 129 | if (header == null) { 130 | header = response.getFirstHeader("Connection").getValue(); 131 | } 132 | if (header != null && header.equalsIgnoreCase("keep-alive")) { 133 | return 30 * 1000; // keep the connection alive for 30 seconds 134 | } 135 | return -1; // close the connection otherwise 136 | }); 137 | ``` 138 | 139 | 6、[.NET Native AOT](https://ericsink.com/native_aot/index.html) 140 | 141 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/63c008a0-9e77-43e7-ac21-27bd97f22e07) 142 | 143 | 这是 `.NET Native AOT` 介绍的网站,作者在这里会分享 `Native AOT` 细节。 144 | 145 | ## 开源项目 146 | 147 | 1、[.NET roadmap 查询](https://themesof.net/) 148 | 149 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/0ec56d3f-2daf-470c-a19e-1f83f979a118) 150 | 151 | 这是一个非常有意思的项目,它收集了 .NET 的运行时库,工具以及其他的基础设施中的 issue,Task 和 Milestone 以方便查询。 152 | 153 | 2、[serilog](https://github.com/serilog/serilog) 154 | 155 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/518f5bdb-bb3d-45e0-9c40-f0689792417d) 156 | 157 | Serilog 是 `.NET` 社区著名地日志库,相对于 `Microsoft.Extensions.Logging` , 它是一个结构化日志输出库。 158 | -------------------------------------------------------------------------------- /docs/episode-045.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 45 期 2 | 3 | ## 卷首语 4 | 5 | .NET 8 正式发布 6 | 7 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c050ada1-5ba8-4380-9f99-c80ef22bf2ab) 8 | 9 | 一年一度的 `.NET` 新版本发布如约而至,上周 `.NET 8` 正式推出,主要包含如下几个主题 10 | 11 | 1. 性能提升 12 | 2. Aspire 推出 13 | 3. Native AOT 14 | 4. Artificial Intelligence 集成 15 | 5. Blazor 16 | 6. .NET MAUI 17 | 18 | ## 文章推荐 19 | 20 | 1、[.NET 8 中的新内容](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8) 21 | 22 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/7d5dc9eb-439c-4ea2-8ae0-68507ba1a9b8) 23 | 24 | 官方文档关于 .NET 8 的新内容介绍,主要有 25 | 1. .NET Aspire 26 | 2. ASP.NET Core 27 | 3. Core .NET libraries 28 | 4. Extension libraries 29 | 30 | 2、[C# 12 中所有特色](https://www.youtube.com/watch?v=Gv2uBJzBAms&ab_channel=NickChapsas) 31 | 32 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/72d38a87-ffee-4797-a994-86b782dc995c) 33 | 34 | 随着 `.NET 8` 一同发布还有 `C# 12`, 它包含了如下的新功能 35 | 36 | 1. Primary Constructor 37 | 2. Collection Expression 38 | 3. Ref read-only parameter 39 | 4. Default Lambda parameter 40 | 5. Alias of type 41 | 6. Inline array 42 | 7. Experimental attribute 43 | 8. Interceptor 44 | 45 | 3、[使用 Switch 简化判断条件](https://www.youtube.com/watch?v=dji9QDstOG0&ab_channel=MilanJovanovi%C4%87) 46 | 47 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/3f9286f0-b849-4df2-afbb-2d11b272fe9f) 48 | 49 | C# 中的 `switch` 语句可以用在模式匹配,而且功能非常强大。 50 | 51 | ```csharp 52 | internal class Error {} 53 | internal class NotFoundError : Error {} 54 | internal class ConflictError : Error { } 55 | internal class Result 56 | { 57 | public bool IsSuccess { get; set; } 58 | public Error Error { get; set; } 59 | } 60 | ``` 61 | 62 | 那么 switch 语句可以根据 `Result` 的不同的结果可以选择不同的执行语句 63 | 64 | ```csharp 65 | Result result = new Result 66 | { 67 | IsSuccess = false, 68 | Error = new ConflictError(), 69 | }; 70 | 71 | var r = result switch 72 | { 73 | { IsSuccess: true } => 0, 74 | { Error: NotFoundError } => 404, 75 | { Error: ConflictError } => 500, 76 | _ => -1 77 | } ; 78 | ``` 79 | 80 | 5、[Dotnet CLI 列表](https://cheatography.com/oba/cheat-sheets/dotnet-cli/) 81 | 82 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/8f07be00-bc04-41af-b933-3aaf611a7992) 83 | 84 | 开发 `.NET` 应用程序除了使用 VS 或者 Rider, 我们还可以使用 CLI 命令来操作相关的事情,这里有一张表列出了所有命令行工作的集合 85 | 86 | 87 | 6、[SearchValues](https://www.youtube.com/watch?v=IzDMg916t98&ab_channel=NickChapsas) 88 | 89 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c92740c2-96e1-4499-ba2c-cebe0a6adabc) 90 | 91 | 92 | .NET 8 提供了一个新的类型 `SearchValues`, 它可以用来判断某个数据是否在一个集合。它的性能非常优秀,这是 `Benchmark` 的结果 93 | 94 | ```csharp 95 | private static string Base64Text = "abcdefghijklmnopgrstuvwxyzABCDEFGHIJKLMNOPGRSTUVWXYZ0123456789+/"; 96 | 97 | private static char[] base64Chars = new char[] 98 | { 99 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 100 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 101 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 102 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 103 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 104 | }; 105 | 106 | 107 | private static SearchValues base64SearchValue = SearchValues.Create(Base64Text); 108 | 109 | public static bool ContainsNaive(string input) 110 | { 111 | for (int i = 0; i < input.Length; i++) 112 | { 113 | var character = input[i]; 114 | if (!base64Chars.Contains(character)) 115 | { 116 | return false; 117 | } 118 | } 119 | return true; 120 | } 121 | 122 | public static bool ContainsAsSpan(string input) 123 | { 124 | return input.AsSpan().IndexOfAnyExcept(Base64Text) == -1; 125 | } 126 | 127 | public static bool ContainsSearchValue(string input) 128 | { 129 | return input.AsSpan().IndexOfAnyExcept(base64SearchValue) == -1; 130 | } 131 | 132 | ``` 133 | 134 | ## 开源项目 135 | 136 | 1、[Aspire](https://github.com/dotnet/aspire) 137 | 138 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/cd9279c0-4df9-47f5-a4d1-ad2c1fbb8c50) 139 | 140 | `Aspire` 是一个开源的微服务管理平台,云原生的应用程序通常是由小的,互相链接和微服务组成,这个项目能够管理这些项目,包含: 141 | 1. Orchestration 142 | 2. Components 143 | 3. Tooling 144 | 145 | 146 | 2、[refit](https://github.com/reactiveui/refit) 147 | 148 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/4a24b07b-3a6a-42fd-9523-f5f6e6a0c158) 149 | 150 | `refit` 是一个非常有意思的库,它只需要我们定义好 `HTTP` 请求的格式,它会自动帮我们创建好需要的执行的方法,比如 151 | 152 | ```csharp 153 | public interface IGitHubApi 154 | { 155 | [Get("/users/{user}")] 156 | Task GetUser(string user); 157 | } 158 | ``` 159 | 我们这定义了一个 `IGithubApi` 的接口,然后依赖注入的方式,创建一个具体实现的类 160 | 161 | ```csharp 162 | var gitHubApi = RestService.For("https://api.github.com"); 163 | ``` 164 | 165 | 这样就可以用 `gtihubAPi` 实例来调用 `GetUser` 方法。 166 | 167 | 168 | 3、[HashIds](https://github.com/ullmark/hashids.net) 169 | 170 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/2cbdc949-edc1-437a-8cc2-e9640b30fdc6) 171 | 172 | 173 | 当我们在浏览 YouTube 的时候,我们会发现 URL类似 `https://www.youtube.com/watch?v=k0AV7cL9qSc`, 其中 query parameter 中的 `k0AV7cL9qSc` 通常是是一个 ID 值的编码,通过这种方式可以隐藏细节。 174 | 175 | `.NET` 社区中的 `HashIds` 库可以完成这一项工作 176 | 177 | ```csharp 178 | using HashidsNet; 179 | 180 | var hashIds = new Hashids("tizan"); 181 | var hash = hashIds.Encode(42); 182 | Console.WriteLine($"42 encode => {hash}"); 183 | 184 | var numbers = hashIds.Decode("jR"); 185 | if (numbers.Length == 1) 186 | { 187 | Console.WriteLine($"jR decode => {numbers[0]}"); 188 | } 189 | ``` 190 | 191 | `"tizan"` 是整个 hashIds 的 `salt`, 通过它可以将数值转化成为成字符串,也可以将字符串转换成特定的数值。 192 | 193 | 194 | 4、 [Moonsharp](https://github.com/moonsharp-devs/moonsharp/) 195 | 196 | 197 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6cb74b43-0ffd-4bd4-b903-10d51c5e6db7) 198 | 199 | `Moonsharp` 这个库可以实现在 `C#` 和 `Lua` 代码的互操作。 200 | -------------------------------------------------------------------------------- /docs/episode-046.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 46 期 2 | 3 | ## 卷首语 4 | 5 | [C# 受欢迎指数超过 Java](https://visualstudiomagazine.com/articles/2023/10/17/tiobe-oct23.aspx) 6 | 7 | 最新编程语言统计网站 `Tiobe` 显示,`C#` 的受欢迎程度在今年会超过 `JAVA`。 8 | 9 | ## 行业资讯 10 | 11 | 1、[.NET 8 新手开发教程](https://devblogs.microsoft.com/dotnet/learn-dotnet8-beginner-videos/) 12 | 13 | 随着 `.NET 8` 的推出,微软也更新对于新手的教程,包含 14 | 15 | 1. C# 学习 16 | 2. .NET 中的生成式 AI 17 | 3. .NET 18 | 4. Azure 中的 .NET 开发 19 | 5. Visual Studio 中开发 .NET 20 | 6. VS Code 开发 .NET 21 | 7. NuGet 学习 22 | 8. Blazor 混合开发 23 | 9. IoT 开发 24 | 10. .NET 升级 25 | 26 | 2、[.NET 生态趋势](https://blog.jetbrains.com/dotnet/2023/11/30/the-developer-ecosystem-in-2023-key-trends-for-csharp/) 27 | 28 | JetBrains 发布了最新的 `.NET` 社区调查问卷,可以看出 `.NET` 社区的生态趋势。 29 | 30 | ## 文章推荐 31 | 32 | 1、[.NET Native AOT Compatible 的建议](https://devblogs.microsoft.com/dotnet/creating-aot-compatible-libraries/) 33 | 34 | .NET Native AOT 是一个非常吸引人的功能,但是有一些限制条件,简单来讲有 35 | 1. 代码是可以削减的 36 | - 不能动态加载运行库 37 | - 反射可以用,但是浏览执行类型图 38 | 2. 不能再运行时产生新的代码 39 | 40 | 为了让代码和 `Native AOT` 尽可能的兼容,可以通过下面的方式 41 | 42 | 通过代码静态分析工作,可以找到可能不兼容的代码,第一个可以选择 `Roslyn Analyzer`;另一种是发布测试 AOT 应用程序。 43 | 44 | 2、.NET 8 新语法 45 | 46 | `.NET 8` 提供了一个新的语法,甚至在官方文档都找不到相应的说明。这个新语法非常简单,如果对于空内容的类,结构体或者接口,不需要一组花括号。 47 | 48 | ```csharp 49 | class Foo; 50 | struct Bar; 51 | interface IFoo; 52 | ``` 53 | 54 | 这些都是合法的定义。 55 | 56 | 3、[C# 中的奇技淫巧](https://www.youtube.com/watch?v=lr1GtiF05EM&ab_channel=NickChapsas) 57 | 58 | C# 中有很多奇技淫巧,让一下看上去不合法的代码也能正常运行。 59 | 60 | 1. 重载操作符 61 | 62 | ```csharp 63 | public record FilePath(string Path){ 64 | public static FilePath operator / (FilePath left, string right) { 65 | return new FilePath(System.IO.Path.Combine(left.Path, right)); 66 | } 67 | public override string ToString() { 68 | return Path; 69 | } 70 | } 71 | ``` 72 | 73 | 这里重载的 `/` 操作符,这样可以这样使用 74 | 75 | ```csharp 76 | var basePath = new FilePath("C:/foo"); 77 | var filePath = basePath / "bar" / "baz.txt"; 78 | ``` 79 | 80 | 2. Await 81 | 82 | 任何一个对象在调用 `GetAwaiter` 方法后能够返回一个 `TaskAwaiter` 的话,就能够使用 `await` 语句 83 | ```csharp 84 | public static TaskAwaiter GetAwaiter(this int seconds){ 85 | return Task.Delay(TimeSpan.FromSeconds(seconds)).GetAwaiter(); 86 | } 87 | ``` 88 | 89 | 这样在调用 `await 2` 方法之后,就能够实现暂停 2 秒钟的效果。 90 | 91 | 3. Enumerator 92 | 93 | 任何对象实现了 `Current` 和 `MoveNext` 的方法,就可以在 `Foreach` 中使用 94 | 95 | ```csharp 96 | public static class CutomIntExtensions 97 | { 98 | public static CustomIntEnumerator GetEnumerator(this Range range 99 | { 100 | return new CustomIntEnumerator(range); 101 | } 102 | 103 | public static CustomIntEnumerator GetEnumerator(this int number) 104 | { 105 | return new CustomIntEnumerator(new Range(0, number)); 106 | } 107 | } 108 | 109 | public struct CustomIntEnumerator 110 | { 111 | private int _current; 112 | private readonly int _end; 113 | 114 | public CustomIntEnumerator(Range range) 115 | { 116 | if (range.End.IsFromEnd) 117 | { 118 | throw new NotSupportedException(); 119 | } 120 | 121 | _current = range.Start.Value - 1; 122 | _end = range.End.Value; 123 | } 124 | 125 | public int Current => _current; 126 | 127 | public bool MoveNext() 128 | { 129 | _current++; 130 | return _current <= _end; 131 | } 132 | } 133 | ``` 134 | 135 | 这样可以就能够 `foreach(var i in 10)` 使用。 136 | 137 | 4、[Keyed Dependency Service](https://blog.elmah.io/dependency-injection-using-keyed-services-is-finally-in-asp-net/) 138 | 139 | 之前 `M.E.DepdendencyInjection` 包在使用的时候会有一个没法解决的问题,假设一个接口有多种实现,那么在构造其他的服务的时候,该怎么指定所需要的实现呢? 140 | 在 `8.0` 版本中推出了 `Keyed service`, 这样可以在构造的时候指定实现的类型。 141 | 142 | ```csharp 143 | public interface IService; 144 | public class FooService : IService; 145 | public class BarService : IService; 146 | ``` 147 | 148 | `IService` 接口有两个实现累心 `FooService` 和 `BarService`, 将它们注册到服务容器的时候可以指定 `key`。 149 | 150 | ```csharp 151 | IServiceProvider services = new ServiceCollection() 152 | .AddKeyedSingleton("foo", new FooService()) 153 | .AddKeyedSingleton("bar", new BarService()) 154 | ``` 155 | 156 | 那么在需要该服务地方的构造函数,指定相应的 `key`. 157 | 158 | ```csharp 159 | public Application( 160 | [FromKeyedServices("foo")] IService fooService, 161 | [FromKeyedServices("bar")] IService barService) 162 | { 163 | _fooService = fooService; 164 | _barService = barService; 165 | } 166 | ``` 167 | 168 | 5、[关于 Aspire 你需要知道的 5 件事](https://www.growthaccelerationpartners.com/blog/5-things-you-need-to-know-about-aspire-and-net-8) 169 | 170 | Aspire 是随着 `.NET 8` 推出的分布式应用程序解决方案,需要知道下面 5 件事情 171 | 172 | 1. Aspire 包含很多组件,对应了不同的云服务 173 | 2. Aspire 能够简化组件编排 174 | 3. Aspire 不等同于 `k8s` 175 | 4. Aspire 包含不同的项目模板 176 | 5. 开发看板 177 | 178 | 6、[Aspire 实例](https://learn.microsoft.com/en-us/samples/browse/?products=dotnet-aspire) 179 | 180 | 微软文档提供了很多 `Aspire` 示例。 181 | 182 | 7、[.NET 在硬件加速方面汇总](https://devblogs.microsoft.com/dotnet/dotnet-8-hardware-intrinsics/) 183 | 184 | 每次 `.NET` 新版本推出,都利用了硬件加速的功能让 `.NET` 的运行时越来越快。本文回顾了所有 `.NET` 版本中对其的利用,并且介绍了 `.NET 8` 在这方面的工作。 185 | 186 | ## 开源项目 187 | 188 | 1、[Debug Output Filter](https://marketplace.visualstudio.com/items?itemName=GrantDavies.NiahTextFilter2022&ssr=false#overview) 189 | 190 | Visual Studio output 功能增强拓展,主要包含下面功能 191 | 1. 动态过滤 192 | 2. 链式过滤 193 | 3. 支持文件或者粘贴板 194 | 4. 主窗体 debug 195 | 5. 输出项目聚合 -------------------------------------------------------------------------------- /docs/episode-047.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 47 期 2 | 3 | ## 卷首语 4 | 5 | 2023 年最后一期,感谢大家一直以来的支持,我们会在 2024 年继续为大家带来更多的内容。 6 | 7 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/fc3fb062-5d50-424a-a88c-d703a56b38c3) 8 | 9 | ## 行业资讯 10 | 11 | 1、[.NET 8 Hack 活动获奖](https://devblogs.microsoft.com/dotnet/great-dotnet-8-hack-winners/) 12 | 13 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/df5a9fb7-b0df-4a53-bb24-a87858806b56) 14 | 15 | 前几个月 `.NET` 社区发起了 "黑客"活动,最近这个活动的获奖情况揭晓: 16 | 17 | - 最佳:NASA TechPort Headlines 18 | - AI 最佳:Betakads 19 | - 云原生最佳:AI Counselor 20 | 21 | 22 | 2、[.NET Conf 2023 回顾](https://devblogs.microsoft.com/dotnet/dotnet-conf-2023-recap-videos-slides-demos-and-more/) 23 | 24 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/10b5bdf6-e3fb-4442-aa87-e683981b78cb) 25 | 26 | 2023 年的 `.NET Conf` 已经结束,这个文章给出活动的回顾,主要有: 27 | 28 | - 全局视频列表 29 | - 幻灯片和 Demo 代码 30 | - eShop 应用程序 31 | - 客户故事 32 | - 本地 `.NET` 活动 33 | 34 | ## 文章推荐 35 | 36 | 1、[HttpClient 定制化日志](https://josef.codes/customize-the-httpclient-logging-dotnet-core/) 37 | 38 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/4238b0a3-431c-4cc1-a5c8-3b71bf4a77f0) 39 | 40 | `HttpClient` 默认的日志格式是这样的 41 | 42 | ```csharp 43 | info: System.Net.Http.HttpClient.my-client.LogicalHandler[100] 44 | Start processing HTTP request GET https://www.google.com 45 | ``` 46 | 47 | 如果想要定制化,可以实现 `IHttpClientLogger` 接口 48 | 49 | ```csharp 50 | public class HttpLogger : IHttpClientLogger 51 | { 52 | private readonly ILogger _logger; 53 | 54 | public HttpLogger(ILogger logger) 55 | { 56 | _logger = logger 57 | } 58 | 59 | public void LogRequestFailed(object? context, HttpRequestMessage request, HttpResponseMessage? response, Exception exception, TimeSpan elapsed) 60 | { 61 | } 62 | 63 | public object? LogRequestStart(HttpRequestMessage request) 64 | { 65 | } 66 | 67 | public void LogRequestStop(object? context, HttpRequestMessage request, HttpResponseMessage response, TimeSpan elapsed) 68 | { 69 | } 70 | } 71 | 72 | ``` 73 | 74 | 这样可以将它注册到容器中 75 | 76 | ```csharp 77 | service.AddSingleton(); 78 | service.AddHttpClient("my-client", client => 79 | { 80 | client.BaseAddress = new Uri("https://www.google.com"); 81 | }).RemoveAllLoggers().AddLogger(true); 82 | ``` 83 | 为了移除默认的日志格式,需要调用 `RemoveAllLoggers()` 方法。 84 | 85 | 2、[All 和 TrueForAll](https://www.youtube.com/watch?v=cpL-fuiEfwU&ab_channel=NickChapsas) 86 | 87 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/3fe83a36-b1b0-4932-8f61-165f5f5d4b1e) 88 | 89 | 在 `List` 类型中有一个 `TrueForAll` 和 `IEnumerable` 中 `All` 方法都是完成同一件事,但是它们在性能上有显著的区别。 90 | ```csharp 91 | public class Benchmarks 92 | { 93 | private List _list; 94 | 95 | [GlobalSetup] 96 | public void Setup() 97 | { 98 | Random rnd = new Random(42); 99 | _list = Enumerable.Range(0, 1000).Select(i => rnd.Next()).ToList(); 100 | } 101 | 102 | 103 | [Benchmark(Baseline = true)] 104 | public bool All() 105 | { 106 | return _list.All(x => x < 1000); 107 | } 108 | 109 | [Benchmark] 110 | public bool TrueForAll() 111 | { 112 | return _list.TrueForAll(x => x < 1000); 113 | } 114 | } 115 | ``` 116 | 它们在性能和内存使用上,`TrueForAll` 有着显著的优势。它们区别这在于 117 | ```csharp 118 | public static bool All(this IEnumerable source, Func predicate) 119 | { 120 | foreach (TSource element in source) 121 | { 122 | if (!predicate(element)) 123 | { 124 | return false; 125 | } 126 | } 127 | return true; 128 | } 129 | 130 | public bool TrueForAll(Predicate match) 131 | { 132 | for (int i = 0; i < _size; i++) 133 | { 134 | if (!match(_items[i])) 135 | { 136 | return false; 137 | } 138 | } 139 | return true; 140 | } 141 | ``` 142 | 143 | 答案显而易见,因为 `All` 方法使用 `Foreach` 方法,因为它存在装箱和拆箱的操作。 144 | 145 | 146 | 3、[OR 操作符](https://www.youtube.com/watch?v=wPmh_ZtFQ5k&ab_channel=MilanJovanovi%C4%87) 147 | 148 | C# 中 `or` 操作符可以简化 `||` 操作。 149 | 150 | ```csharp 151 | if (student.Grade == Grade.Excellent || 152 | (student.Grade == Grade.Good) 153 | { 154 | Console.WriteLine("Well done"); 155 | } 156 | ``` 157 | 那么 `OR` 操作符可以简化成一行代码 158 | 159 | ```csharp 160 | if (student.Grade is Grade.Excellent or Grade.Good) 161 | { 162 | Console.WriteLine("Well done"); 163 | } 164 | ``` 165 | 166 | 4、[为什么我现在不用 Aspire](https://event-driven.io/en/nay_to_aspire/) 167 | 168 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/85173524-c1c9-4ca7-b466-c67faba93412) 169 | 170 | 作者在使用了 `Aspire` 之后,给出了负面的评价,观点如下 171 | 172 | - 启动太复杂 173 | - 所有项目都在同一个解决方案下 174 | - 在 Linux 下,本地环境非常难管理 175 | 176 | 5、[c# 中的不可变类型](https://blog.stephencleary.com/2023/12/the-joy-of-immutable-update-patterns.html) 177 | 178 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/72cde29b-db07-42bc-99ff-e31ae19ac050) 179 | 180 | `Immutable` 类型有很多好处,在 `C#` 中存在两种不可变类型 181 | 182 | - 基础类型,比如 int, double 等 183 | - 值类型,比如 struct 184 | 185 | 除此之外,还有 `System.Collections.Immutable` 命名空间下类型。如果要对不可变类型做修改,通常是需要创建也给新的对象,比如在 switch 和 `with` 语句是现代 `C#` 代码创新不可变类型的方法。 186 | 187 | 6、[Visual Studio Git 集成汇总](https://devblogs.microsoft.com/visualstudio/a-year-of-making-you-more-productive-using-git-in-visual-studio/) 188 | 189 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/4a4b4d13-69a9-4697-9563-eadfb9c96cb6) 190 | 191 | 过去一年 `Visual Studio` 在 `Git` 上面的提升汇总。 192 | 193 | ## 开源项目 194 | 195 | 1、[GitHub Action Visual Studio 插件](https://marketplace.visualstudio.com/items?itemName=TimHeuer.GitHubActionsVS) 196 | 197 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a52952b5-4147-49e0-bd06-9bee48ad6e71) 198 | 199 | Visual Studio 包含了 `GitHub Action` 的插件,它可以帮助我们浏览,管理和运行 `GitHub Action`. 200 | 201 | 2、[Cocona](https://github.com/mayuki/Cocona) 202 | 203 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/f73b2d4b-3561-4a9e-b5f7-9157c4a05fd4) 204 | 205 | `Cocona` 库可以帮助我们非常简单写出应用台应用程序。 206 | 207 | ```csharp 208 | using Cocona; 209 | 210 | CoconaApp.Run((string name) => 211 | { 212 | Console.WriteLine($"hello {name}"); 213 | }); 214 | ``` 215 | 这样运行 `dotnet run -- --name .netwekly` 就可以输出 `hello .netweekly` 。 -------------------------------------------------------------------------------- /docs/episode-048.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 48 期 2 | 3 | ## 卷首语 4 | 5 | Happy New Year. 6 | 7 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/244e65c7-fded-486f-8c7c-34e5b158b4c4) 8 | 9 | [Tiobe](https://www.tiobe.com/tiobe-index/) 发布了年度语言, `C#` 以 +1.43% 的增长率荣获 2023 年度开发语言。 10 | 11 | ## 文章推荐 12 | 13 | 1、[按条件加载中间件](https://blog.elmah.io/conditionally-add-middleware-in-asp-net-core/) 14 | 15 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/42527584-a5dd-42e6-b20d-8be74e6d40ae) 16 | 17 | 在 ASP.NET Core 应用程序中,我们通常注册中间件的方式定义自己的业务开发逻辑,如果有些中间你需要在满足特定的条件的时候才会执行,那么可以使用 `UseWhen` 的拓展方法。 18 | 19 | 中间件 20 | 21 | ```csharp 22 | internal class TimingMiddleware 23 | { 24 | private readonly RequestDelegate _next; 25 | 26 | public TimingMiddleware(RequestDelegate next) 27 | { 28 | _next = next; 29 | } 30 | 31 | public async Task InvokeAsync(HttpContext context) 32 | { 33 | var stopWatch = Stopwatch.StartNew(); 34 | 35 | context.Response.OnStarting(() => 36 | { 37 | context.Response.Headers["X-took"] = $"{stopWatch.ElapsedMilliseconds} ms"; 38 | return Task.CompletedTask; 39 | }); 40 | 41 | await _next(context); 42 | } 43 | } 44 | ``` 45 | 46 | 注册中间件 47 | 48 | ```csharp 49 | app.UseWhen( 50 | context => context.Request.Path.StartsWithSegments("/api"), 51 | builder => builder.UseMiddleware() 52 | ); 53 | ``` 54 | 55 | 这里只有请求的 `path` 中包含了 `api` 才会执行 `TimingMiddleware`。从源码上看,它是通过创建一个新的 `IApplication` ,在条件满足的时候使用新的 `IApplication` 执行。 56 | 57 | 2、[WPF 已经死了](https://avaloniaui.net/Blog/is-wpf-dead) 58 | 59 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/194e1aa9-ec48-468a-ad65-d14320d0ce54) 60 | 61 | WPF 是 Windows 平台上开发桌面应用程序的利器,随着 `.NET` 的开源和 `WPF` 并不支持其他桌面系统,WPF 的生态前景不容乐观,和 `Avalonia` 比起来,不管是开源社区的积极性和下载量,都有取代的可能。 62 | 63 | 3、[SearchValue](https://endjin.com/blog/2024/01/dotnet-8-searchvalues-string-search-performance-boost) 64 | 65 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c6cbaef5-d5ab-4b75-8970-2b17dec13589) 66 | 67 | .NET 一直致力于性能提升,有一种性能提升是 “先付款,再收益”的模式。那么“付款”的形式有两种 68 | 69 | 1. 在编译的时候,比如 build task 或者 source generator 70 | 2. 在运行的时候,存在冷启动的问题 71 | 72 | .NET 8 中的 `SearchValue` 就是第二种。 73 | 74 | 4、[var 关键字](https://www.reddit.com/r/dotnet/comments/18o1zsx/is_using_var_okay/) 75 | 76 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a567cd8e-764b-4239-b707-e3345b3f25c3) 77 | 78 | 这是 Reddit 上的一个讨论 79 | 80 | > 使用 `var` 关键字是否可行 81 | 82 | 原帖作者认为 `var` 关键字使得变量类型变得不清晰。但是我认为 `var` 类型是不错的类型 83 | 84 | 1. 使用 IDE 可以很方便的查看 85 | 2. 不适用 var, 是的一些代码的长度变得非常长,比如 `List list = new List()` 86 | 3. 在 `Linq` 中,var 可以避免写一些隐式类型,比如 `var obj = list.Select(i => new { Val = i; Name = i.ToString()})` 87 | 88 | 5、[.NET 平台密码管理最佳实践](https://dev.to/asimmon/evolutive-and-robust-password-hashing-using-pbkdf2-in-net-34pc) 89 | 90 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a2595635-b466-4474-ac74-f191f0d1519b) 91 | 92 | 在密码存储过程中,最重要的一点的是不能存储用户密码的原文,因为哪怕是数据库泄露,也不会产生密码泄露的问题。在安全领域还有一个重要原则是不能自己发明安全领域的算法。`.NET` 提供了 `PBKDF2` 算法来提供加密,而且在 `ASP.NET Core Identity` 包中使用。 93 | 整个流程包含四个步骤: 94 | 95 | 1. 用户提供密码 96 | 2. 使用一个 Salt 97 | 3. 使用一个伪随机算法比如 SHA-256 98 | 4. 迭代若干次 99 | 100 | 代码如下 101 | 102 | ```csharp 103 | var password = "Correct Horse Battery Staple"u8; 104 | const int keySize = 256 / 8; 105 | var salt = RandomNumberGenerator.GetBytes(keySize); 106 | const int iterations = 600000; 107 | var key = Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, HashAlgorithmName.SHA256, keySize); 108 | ``` 109 | 110 | 6、[关闭 DbConnection?](https://khalidabuhakmeh.com/what-should-i-dispose-with-dotnet-database-connections) 111 | 112 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/fe51f4ae-3668-4a8f-be8f-b099bb890a9d) 113 | 114 | 在 database 中我们会涉及到 `DbConnection`, `DbCommand` 和 `DbReader` , 它们都有 `Close` 的方法用来释放相应的资源,那么我们需要依次调用它们吗?本文作者查看了 `SqliteConnection` 的实现,发现在调用 `DbConnection` 的 `Close` 方法会关闭相关的 `DbCommand`, 而调用 `DbCommand` 的 `Close` 方法,也会调用关联的的 `DbReader` 的 `Close` 方法,所以没有必要依次调用它们的 `Close` 方法。 115 | 116 | ## 开源项目 117 | 118 | 1、2023 .NET 开源统计 119 | 120 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/ef953a38-aca5-4437-bdef-43d8ec2ff9d6) 121 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6cac978e-6df3-43bd-ba50-72234c93237c) 122 | 123 | 2、[2024 年 .NET 技能提升](https://github.com/milanm/DotNet-Developer-Roadmap) 124 | 125 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/81b576cf-748e-40f1-8e75-7418ca327a8a) 126 | 127 | 新的一年,查看一下这个开源项目列出的 .NET 技能提升清单. 128 | 129 | 3、[TestContainer](https://dotnet.testcontainers.org/) 130 | 131 | `TestContainer` 是一个集成测试的工具,我们都知道单元测试是应该不依赖外部服务,比如数据库,网络。我们都需要在单元测试中将他们抽象。但是我们在集成测试中还是需要完整的测试他们,所以 `TestContainer` 可以借助容器化工具完成完整的测试。 132 | 133 | 4、[One Billion Row Challenge](https://github.com/buybackoff/1brc#results) 134 | 135 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/7c94f7d6-f5fe-4863-8525-b0c325de5a4d) 136 | 137 | 在 GitHub 上出现了一个有趣的挑战,使用任何编程语言读取十亿行的文件,该文件的内容是一个气象站获取的温度采样点,输出的内容是该气象站的平均温度,最低温度和最高温度。可以使用任何优化的方法,让这个程序在最短的时间内完成。这个repo 包含了 `.NET` 编程语言的实现。 -------------------------------------------------------------------------------- /docs/episode-051.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 51 期 2 | 3 | ## 卷首语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/56914e24-b8be-4706-aa6c-91ea478a0724) 6 | 7 | `2024` 年是一个闰年,也就是存在 2 月 29 日。在 C# 中的时间中,有一个特殊的处理情况, 8 | 9 | ```csharp 10 | var testDate = new DateTime(2024, 2, 10); 11 | var var0 = testDate.AddDays(19); 12 | var var1 = testDate.AddDays(19).AddYears(2); 13 | ``` 14 | 15 | 由于 `2024` 年是闰年,所以 `var0` 是 `2024-02-29` 日,但是 2026 年不是闰年,所以 `var1` 的值为 `2026-02-28`, 这是 C# 对 闰年的特殊处理。在 C# 的时间处理库中是这么处理的: 16 | 17 | ```csharp 18 | public DateTime AddYears(int value) 19 | { 20 | // ... some validation code 21 | uint n = DaysToYear((uint)y); 22 | 23 | int m = month - 1, d = day - 1; 24 | if (IsLeapYear(y)) 25 | { 26 | n += DaysToMonth366[m]; 27 | } 28 | else 29 | { 30 | if (d == 28 && m == 1) d--; // <-- THIS RIGHT HERE 31 | n += DaysToMonth365[m]; 32 | } 33 | // ... return new date 34 | } 35 | ``` 36 | 37 | 所以我们在处理这种问题的时候,可以这么处理: 38 | 39 | - 如果天数重要,先添加年,然后添加天 40 | - 如果真实日期重要,先添加天,然后添加年 41 | 42 | ## 行业资讯 43 | 44 | 1、[WinForms 在 64 位应用程序的策略](https://devblogs.microsoft.com/dotnet/winforms-designer-64-bit-path-forward/) 45 | 46 | 随着 64 位的 Visual Studio 到来, WinForms 开发也伴随着挑, 比如 47 | 48 | 1. 32 位遗留组件 49 | 2. 进程外设计器 50 | 3. 遗留组件支持 51 | 52 | ## 文章推荐 53 | 54 | 1、[dotnet profiler tools](https://dev.to/mohammadkarimi/cross-platform-diagnostic-tools-for-net-applications-2366) 55 | 56 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6f977ced-49fd-43e5-8026-7fa3ca140315) 57 | 58 | 对于应用程序而言,profiler 是非常重要的,这样可以帮助我们找到应用程序的瓶颈,然后提高他们。在 `.NET` 生态中提供了三种跨平台的工具: 59 | 60 | 1. dotnet-counter 61 | 2. dotnet-trace 62 | 3. dotnet-dump 63 | 64 | 2、[异步任务集合抛出所有异常](https://www.meziantou.net/getting-all-exceptions-thrown-from-parallel-foreachasync.htm) 65 | 66 | 在 `Parallel.ForEachAsync` 或者 `Task.WhenAll` 这样的方法中,如果有多个异常抛出,在 `catch` 语句中只会抛出第一个异常,那么改如果那抛出各个线程的异常呢?可以用到 `ConfigureAwaitOptions.SuppressThrowing` 参数 67 | 68 | ```csharp 69 | public static async Task WithAggregateException(this Task task) 70 | { 71 | await task.ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing); 72 | task.Wait(); 73 | } 74 | 75 | try 76 | { 77 | var tasks = Enumerable.Range(0, 10).Select(i => WorkAsync(i)); 78 | await Task.WhenAll(tasks).WithAggregateException(); 79 | } 80 | catch (Exception e) 81 | { 82 | Console.WriteLine(e.ToString()); 83 | } 84 | ``` 85 | 86 | 这里会抛出所有执行的异常。 87 | 88 | 3、[避免多个 boolean 型参数](https://steven-giesel.com/blogPost/9994b00c-8bc2-4794-ae74-80e6ee4cd5e5/avoid-multiple-boolean-parameters) 89 | 90 | 如何你看到这样的一个方法, `void Refresh(bool force, bool lazy);`, 你会觉得有多少种调用方法?由于 `boolean` 型有两种情况 `true` 或者 `false` ,那么这种方法就会有 4 (2^2)种,这样增加了使用者的心里负担。 91 | 那么该怎么解决这个问题呢?可以添加多个方法 92 | 93 | ```csharp 94 | void Refresh(); 95 | void RefreshForce(); 96 | void RefreshLazy(); 97 | ``` 98 | 99 | 或者使用枚举类型,列举出所有可能情况 100 | 101 | ```csharp 102 | enum RefreshMode { Default, Force, Lazy } 103 | void Refresh(RefreshMode mode); 104 | ``` 105 | 106 | 4、[EntityFrame Core 记录执行 SQL 语句](https://dev.to/karenpayneoregon/ef-core-log-to-file-benefits-13jp) 107 | 108 | 在 `EntityFramework Core` 应用程序中,如果想要记录所有生成 `SQL` 的语句,可以将它们写入一个文本文件中。 109 | 110 | 1. 配置文件 111 | 112 | ```xml 113 | 114 | 115 | 116 | ``` 117 | 118 | 2. 配置写文件 119 | 120 | ```csharp 121 | public class DbContextToFileLogger 122 | { 123 | private readonly string _fileName = 124 | Path.Combine(AppDomain.CurrentDomain.BaseDirectory, 125 | "LogFiles", $"{Now.Year}-{Now.Month:D2}-{Now.Day:D2}", 126 | "EF_Log.txt"); 127 | 128 | public DbContextToFileLogger() 129 | { 130 | if (!File.Exists(_fileName)) 131 | { 132 | using (StreamWriter w = File.AppendText(_fileName)) ; 133 | } 134 | } 135 | 136 | [DebuggerStepThrough] 137 | public void Log(string message) 138 | { 139 | StreamWriter streamWriter = new(_fileName, true); 140 | streamWriter.WriteLine(message); 141 | streamWriter.WriteLine(new string('-', 40)); 142 | streamWriter.Flush(); 143 | streamWriter.Close(); 144 | } 145 | } 146 | ``` 147 | 148 | 3. 配置 DBContextOptions 149 | 150 | ```csharp 151 | optionsBuilder.UseSqlServer(ConnectionString()) 152 | .EnableSensitiveDataLogging() 153 | .LogTo(new DbContextToFileLogger().Log, 154 | new[] { DbLoggerCategory.Database.Command.Name }, 155 | Microsoft.Extensions.Logging.LogLevel.Information); 156 | ``` 157 | 158 | 5、[Blazor Fluent UI 控件故事](https://devblogs.microsoft.com/dotnet/the-fast-and-the-fluent-a-blazor-story/) 159 | 160 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/12df9ced-ddb9-4a53-b0f0-aa626fc74cc8) 161 | 162 | Fluent 是微软推出的 UI 库,用来统一 Web, 桌面和移动应用程序的界面设计。而 Blazor 是随着 `.NET` 一起推出的前端开发框架,可以使用 `C#` 编写前端交互逻辑。那么 `Blazor` 版的 `Fluent` 的历史是怎样的,这篇博客介绍了这段内容。 163 | 164 | 6、[Visual Studio 使用 Tips](https://www.youtube.com/watch?v=td81h--afxM&ab_channel=IAmTimCorey) 165 | 166 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/e6c7e744-3dea-47c3-a65b-fad240f55d3a) 167 | 168 | Visual Studio 是 `.NET` 开发者广泛使用的开发工具,那么除了开箱即用之外,还有很多配置可以帮助你提供开发体验。 169 | 170 | 7、[拼接两个 Array](https://www.youtube.com/watch?v=R5Shxt1dx58&ab_channel=MilanJovanovi%C4%87) 171 | 172 | C# 中拼接多个数组的简化表示方式: 173 | 174 | ```csharp 175 | int[] arr1 = new int[] { 1, 2, 3 }; 176 | int[] arr2 = Enumerable.Range(10, 15).ToArray(); 177 | int[] arr3 = [..arr1, ..arr2]; 178 | ``` 179 | 180 | ## 开源项目 181 | 182 | 1、[SimdLinq](https://github.com/Cysharp/SimdLinq) 183 | 184 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6cff3595-92ec-4f44-8e64-24a048f7f1b9) 185 | 186 | 至从 `.NET 7` 支持 `SIMD` 之后,`Linq` 的性能得到直线上升。但是官方的由于安全的兼容的问题,只支持 `int` 和 `long` 类型的加速,`SimdLinq` 库将它支持的类型增加到更多类型。 从 benchmark 结果来看,效果非常明显。 -------------------------------------------------------------------------------- /docs/episode-052.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 52 期 2 | 3 | ## 卷首语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/5e208358-5523-4dbe-8806-99ee8729a2f2) 6 | 7 | [garent](https://github.com/microsoft/garnet) 是微软研究院推出的内存 `key-value` 存储系统,它可以完全兼容 `Redis` 的所有协议,而且在性能上比 `Redis` 还要好,而且这个完全是使用 `C#` 开发,只需要 执行 `dotnet run -c Release -f net8.0` 命令就可以将服务端运行起来。 最近 `Redis` 也修改协议,或许这是 `garent` 的一个机会。 8 | 9 | ## 文章推荐 10 | 11 | 1、[ASP.NET Core Scoped Service](https://www.youtube.com/watch?v=FSjCGdkbiCA&ab_channel=MilanJovanovi%C4%87) 12 | 13 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/a77dfd6f-a8bf-45b2-87b0-49e518697a81) 14 | 15 | 在`ASP.NET Core`中,依赖注入有三种类型的服务,分别为`Transient`,`Scoped`和`Signleton` ,其中对于 `Transient` 和 `Singleton` 比较容易理解,而且如果高级别的服务依赖于低级别的服务,程序在运行的时候会抛出异常,比如 `Singleton` 的服务依赖于一个 `Transient` 的服务。 16 | 17 | 对于 `Scoped` 服务,该怎么解决这个问题呢,比如 18 | 19 | ```csharp 20 | internal class WeatherReport ( 21 | ILogger logger, 22 | WeatherSerivce weahtherService) 23 | : BackgroundService 24 | { 25 | private readonly TimeSpan _period = TimeSpan.FromSeconds(5); 26 | } 27 | 28 | builder.Services.AddHostedService(); 29 | builder.Services.AddScoped(); 30 | ``` 31 | 32 | 这里的 `WeatherReport` 是一个注册为 `singleton` 的服务,而 `WeatherService` 是注册为 `Scoped` 类型的服务,所以在运行的时候就会抛出异常。该怎么解决这个问题呢? 33 | 34 | ```csharp 35 | internal class WeatherReport ( 36 | ILogger logger, 37 | IServiceScopeFactory serviceScopeFactory) 38 | : BackgroundService 39 | { 40 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 41 | { 42 | using var scope = serviceScopeFactory.CreateScope(); 43 | var weatherService = scope.ServiceProvider. GetRequiredService(); 44 | } 45 | } 46 | ``` 47 | 在这里,`WeatherReport` 依赖了一个 `ISeviceScopeFactory` 对象,通过创建一个 `IServiceScope` 对象,就能获得 `WeatherService` 的服务,并且在执行完毕了,`IServiceScope` 对象会调用 `Dispose` 方法释放当前创建的对象。 48 | 49 | 那么在 `ASP.NET Core` 中什么时候会使用 `IServiceScope` 呢?答案是每一次 `HTTP` 请求的处理声明周期内,会分享这个 `IServiceSecope` 对象,比如 50 | 51 | ```csharp 52 | public class RequestLoggingMiddleware(RequestDelegate next) 53 | { 54 | public async Task Invoke(HttpContext context, AppDbContext appDbContext) 55 | { 56 | appDbContext.ApiRequests.Add(new ApiRequest(context.TraceIdentifier)); 57 | await appDbContext.SaveChangesAsync(); 58 | await next(context); 59 | } 60 | } 61 | 62 | app.MapGet("current-request", async (HttpContext httpContext, AppDbContext dbContext) => 63 | { 64 | var entity = dbContext.ApiRequests.Local.FindEntry(httpContext.TraceIdentifier); 65 | 66 | return entity?.Entity; 67 | 68 | }); 69 | 70 | builder.Services.AddDbContext(options => options.UseInMemoryDatabase("db")); 71 | ``` 72 | 73 | 在这里,`AddDbContext` 会将 `AppDbContext` 注册为一个 `Scoped` 类型的服务,那么每个请求中间件中看到的 `AppDbContext` 都是同一个对象。 74 | 75 | 2、[集合表达式](https://blog.jetbrains.com/dotnet/2024/03/26/collection-expressions-using-csharp-12-in-rider-and-resharper/) 76 | 77 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6c59a66f-2003-42d8-88a3-fff9ae3875aa) 78 | 79 | `C# 12` 引入了集合表达式,它简化了集合的字面表达方式,比如之前 80 | 81 | ```csharp 82 | var array = new[] { 1, 2 }; 83 | var spread = array.Concat(new[] { 3, 4 }); 84 | ``` 85 | 86 | 那么现在就可以这么 87 | 88 | ```csharp 89 | int[] array = [1, 2]; 90 | int[] spread = [..array, 3, 4]; 91 | ``` 92 | 93 | 注意由于 `C#`集合是强类型的,所以不能使用 `var` 方式去定义。我们都知道这些背后都是编译器帮助实现的,那么可以借助 [sharplab.io](https://sharplab.io/) 展示生成 `C#` 代码。而且也可以自定义类型来支持集合表达式。 94 | 95 | 3、[Rust for .NET](https://microsoft.github.io/rust-for-dotnet-devs/latest/introduction.html) 96 | 97 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/859caeae-c198-4c82-b9fa-72e7c113070e) 98 | 99 | 这是微软开源的一本 `Rust` 语言学习手册,主要是针对已经熟悉 `.NET` 开发的程序员。 100 | 101 | 4、[.NET 开发者期望社区毁灭?](https://aaronstannard.com/dotnet-eventing-backslide/) 102 | 103 | 最近 `.NET 9 ` 开发计划中的一个 [Epic](https://github.com/dotnet/aspnetcore/issues/53219) 引来了巨大的讨论,它主要讨论是在 `.NET 9` 中引入事件框架。但是 `.NET` 社区中已经包含了很多这样的框架。这个给开发人员带来的疑问:为什么微软作为第一方为什么要吃掉开源社区的市场? 104 | 这篇文章的作者分析了这种现象,并且认为这种做法是伤害 `.NET` 社区的生态。 105 | 106 | 5、[MSBuild 新体验](https://devblogs.microsoft.com/visualstudio/experimental-msbuild-editor/) 107 | 108 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/0e072bd2-641f-482e-9939-8a049c543741) 109 | 110 | MSBuild 是 `.NET` 生态中非常重要的组成部分,在 `C#` 项目中体现为 `csproj` 文件。不管是经验丰富还是萌新,对于直接修改 `csproj` 文件都是一个充满挑战的事情。Vistual Studio 最近为 `csproj` 文件编辑提供了新的功能,更多的智能提示和补全,已经错误提示。 111 | 112 | 6、[Stephen Toub 教你从头开始写异步](https://www.youtube.com/watch?v=R-z2Hv-7nxk&ab_channel=dotnet) 113 | 114 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/3caf7e22-679b-4264-a954-c5507534106a) 115 | 116 | `.NET` 社区的大佬 `Stephen Toub` 教你从头写一个异步实现,这个将会帮助你更加容易理解 `C#` 的异步。 117 | 118 | ## 开源项目 119 | 120 | 1、[spectre.console](https://github.com/spectreconsole/spectre.console) 121 | 122 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/88d9ff95-ad2e-4301-ac08-5db3431b31fd) 123 | 124 | Spectre.Console 是 `dotnet` 的一款开源库,它能够绘制出非常漂亮的控制台交互页面。 125 | 126 | 2、[dotnet-outdated](https://github.com/dotnet-outdated/dotnet-outdated) 127 | 128 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/8811f3b7-adca-475a-a136-d6762f56ee6a) 129 | 130 | `dotnet-outdated` 是一款检测 `dotnet` 项目的依赖是否出现过时的情况。安装只需要执行 `dotnet outdated` 命令,就可以知道那些包出现了最新的版本。 131 | 132 | 3、[WireMock.Net](https://github.com/WireMock-Net/WireMock.Net) 133 | 134 | `WireMock-Net` 是一款模拟服务端的库,这样可以在单元测试或者集成测试中访问远端的 HTTP 服务器,并且设定相应的返回结果。 135 | -------------------------------------------------------------------------------- /docs/episode-054.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 54 期 2 | 3 | ## 卷首语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/53c2ddc2-5170-462f-b466-fb73f4298085) 6 | 7 | Hack News 上关于 `Powershell` 的[讨论](https://news.ycombinator.com/item?id=40204256),每个人都有自己的看法和偏好。 8 | 9 | ## 文章推荐 10 | 11 | 1、[和 Stephen Toub 学习 Linq](https://www.youtube.com/watch?v=xKr96nIyCFM&ab_channel=dotnet) 12 | 13 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/2645d86f-c451-42b3-85ef-758935fbd6e3) 14 | 15 | `LINQ` 是 `C#` 中非常要中的功能,其中 `IEnunerable` 是重要的接口。我们都知道 `C#` 编译器为其中做了很多工作,这里 `.NET` 社区著名开发者 `Stephen Toub` 展示了徒手实现编译器完成的这个工作。 16 | 17 | 2、[使用 Primary 构造函数重构 C# 代码](https://devblogs.microsoft.com/dotnet/csharp-primary-constructors-refactoring/) 18 | 19 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/7100cdb7-a289-41d9-8cce-f67732b4d3de) 20 | 21 | C# 12引入了 `Primary Constructor` 这个新的语法糖,这篇文章介绍了这个语法糖的使用 22 | 23 | 1. 它是从 `Record` 类型启发而来 24 | 2. 它会创建同名的的成员变量 25 | 3. 如果使用使用 `readonly` 修饰成员变量,那么需要显示写出 26 | 4. 如果有多个构造函数,那么其他的构造函数必须使用 `this` 调用 `primary` 构造函数 27 | 28 | 3、[IO操作没有线程](https://blog.stephencleary.com/2013/11/there-is-no-thread.html?ref=codetraveler.io) 29 | 30 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c8991779-3edd-40a4-b2ea-064bbed34616) 31 | 32 | 在 `C#` 异步代码中,常常有人会有这样的一个疑问,是不是有一个线程在等待异步的完成,比如 33 | 34 | ```csharp 35 | private async void Button_Click(object sender, RoutedEventArgs e) 36 | { 37 | byte[] data = ... 38 | await myDevice.WriteAsync(data, 0, data.Length); 39 | } 40 | ``` 41 | 42 | 在 `WriteAsync` 方法中,是不是有一个线程在调用这个方法。答案是否定的。没有任何一个线程调用这个方法,这个要从 CPU 的硬件底层来讲,当硬件开始一个 `I/O` 操作的时候,CPU 会继续处理其他事情,当 `I/O` 操作完成之后,会给 `CPU` 发出一个中断的信号,这时候内容的应用程序会将后续的操作作为一个 `continuation` 塞入某个线程的队列中。 43 | 44 | 4、[ThreadPool](https://learn.microsoft.com/en-us/dotnet/standard/threading/the-managed-thread-pool?WT.mc_id=dotnet-0000-bramin&ref=codetraveler.io) 45 | 46 | ThreadPool 是 `.NET` 异步并发编程中的重要的概念,这个官方文章详细介绍这个概念。首先 `ThreadPool` 是 `backgroud` 线程,而且通过 `pool` 的方式,在完成任务后,线程还会放回 pool 中。 47 | 而且 `ThreadPool` 中的线程的数量是由 [ThreadPool.GetMaxThreads](https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool.getmaxthreads) 决定的,任务的数量是由内存大小决定。使用 `ThreadPool` 也非常简单,只需要调用 `Task` 或者 `Task` 相关方法就能将一个任务塞给线程池。 48 | 49 | 5、[.NET 8 中的 ConfigureAwait](https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html?ref=codetraveler.io) 50 | 51 | 在 `.NET` 异步中, `ConfigureAwait` 方法通常用来只配置异步方法后续调用过程中的执行情况,默认为 `true`, 那么它会捕获当前线程的 `Context`,然后在异步操作完成后,在该线程上执行后续操作,反之则使用任何一个线程来处理后续的 `continuation·。 52 | 在`.NET 8` 中增加了新的参数,它是一个枚举类型 53 | 54 | ```csharp 55 | public enum ConfigureAwaitOptions 56 | { 57 | None = 0x0, 58 | ContinueOnCapturedContext = 0x1, 59 | SuppressThrowing = 0x2, 60 | ForceYielding = 0x4, 61 | } 62 | ``` 63 | 64 | - None 65 | 相当于 `ConfigureAwait(false)`, 表明不需要任何捕获之前 `Context` 66 | 67 | - ContinueOnCapturedContext 68 | 69 | 相当于 `ConfigureAwait(true)` 后续操作是在之前的 `context` 执行 70 | 71 | - SuppressThrowing 72 | 73 | 它会把所有的异常忽略掉 74 | 75 | - ForceYielding 76 | 77 | 当异步中遇到一个异步操作的时候,如果这个操作已经完成,则不会发生线程回退,但是 `ForceYielding` 会强制交出线程。 78 | 79 | 6、[ValueTask 和 ValueTask](https://devblogs.microsoft.com/dotnet/understanding-the-whys-whats-and-whens-of-valuetask/) 80 | 81 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/769b9435-39f6-4b3d-abfb-3a07fe76312a) 82 | 83 | `Task` 和 `Task` C# 异步编程中主要的组成部分,在`.NET 2.0` 之后,又引入了 `ValueTask` 和 `ValueTask` 类型,显而易见,它是一个值类型,主要是为了解决那些非异步操作的在内存消耗上的性能问题,当然在使用的时候还有一些注意点。 84 | 85 | 7、[F# 学习之旅](https://www.youtube.com/watch?v=l6-WurPT5K8&ab_channel=AmplifyingFSharp) 86 | 87 | `F#` 社区的 `Scott Wlaschin` 分享了自己 F# 学习之旅。 88 | 89 | 8、[C# 中的设计模式](https://dev.to/adrianbailador/design-patterns-in-c-n9) 90 | 91 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/28052344-35ad-42d8-a37b-b4e298c5bc07) 92 | 93 | 这篇文章详细介绍了使用 `C#` 实现常见的设计模式。 94 | 95 | 9、[使用集合表达式重构代码](https://devblogs.microsoft.com/dotnet/refactor-your-code-with-collection-expressions/) 96 | 97 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/019c6a61-4274-45ae-a77b-8d5db97154b3) 98 | 99 | C# 12 中引入集合表达式,它可以辅助我们写出更加简洁的代码。 100 | 101 | - 初始化 102 | 103 | ```csharp 104 | var numbers1 = new int[3] { 1, 2, 3 }; 105 | var numbers2 = new int[] { 1, 2, 3 }; 106 | var numbers3 = new[] { 1, 2, 3 }; 107 | int[] numbers4 = { 1, 2, 3 }; 108 | ``` 109 | 110 | 注意最后一个不能使用 `var` 变量。 111 | 112 | - 空集合 113 | 114 | ```csharp 115 | int[] emptyCollection = []; 116 | ``` 117 | 118 | 通过这种方式,编译器可以生成最好的的空集合表达方式。 119 | 120 | - 展开 121 | 122 | 可以使用 `..` 命令,将多个集合凭借起来 123 | 124 | ```csharp 125 | int[] onetwothree = [1, 2, 3]; 126 | int[] fourfivesix = [4, 5, 6]; 127 | 128 | int[] all = [.. fourfivesix, 100, .. onetwothree]; 129 | ``` 130 | 131 | 这里可以优化我们的代码,比如 `ToList` 132 | 133 | ```csharp 134 | static List QueryStringToList(string queryString) => [.. from queryPart in queryString.Split('&') 135 | let keyValue = queryPart.Split('=') 136 | where keyValue.Length is 2 137 | select new Query(keyValue[0], keyValue[1])]; 138 | ``` 139 | 140 | - 性能区别 141 | 142 | 下面两种集合初始化的方法有什么区别? 143 | 144 | ```csharp 145 | List someList1 = new() { 1, 2, 3 }; 146 | List someList2 = [1, 2, 3]; 147 | ``` 148 | 149 | 如果我们查看编译器生成的代码,可以发现其中的不同 150 | 151 | ```csharp 152 | List list = new List(); 153 | list.Add(1); 154 | list.Add(2); 155 | list.Add(3); 156 | List list2 = list; 157 | List list3 = new List(); 158 | 159 | CollectionsMarshal.SetCount(list3, 3); 160 | Span span = CollectionsMarshal.AsSpan(list3); 161 | int num = 0; 162 | span[num] = 1; 163 | num++; 164 | span[num] = 2; 165 | num++; 166 | span[num] = 3; 167 | num++; 168 | List list4 = list3; 169 | ``` 170 | 171 | 第一种方式首先创建了一个 `List` 对象,然后将元素依次加入其中;第二种方式是创建 `List` 对象,然后修改内部集合数据大小,然后在相应的位置修改元素值。当数据量大的时候,第二种方式性能更加好。 172 | 173 | ## 开源项目 174 | 175 | 1、[roslynpad](https://github.com/roslynpad/roslynpad) 176 | 177 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/d5c360ba-d48b-495a-8921-e224bf94d2e2) 178 | 179 | 使用 Roslyn 和 AvalonEdit 开发的开源 C# 编辑器,可以简单替换 `LinqPad`。 180 | 181 | 2、[.NET Benchmark 集锦](https://dotnetbenchmarks.com/) 182 | 183 | `.NET` 在每个版本中都强调了在性能上的优化,相同结果的不同代码在性能上也有不同的表现。这个网站收集了很多社区提交的性能比较的案例,大家可以在浏览,借鉴和学习,当然也可以通过提交自己的 Benchmark 的例子丰富这个社区。 184 | -------------------------------------------------------------------------------- /docs/episode-055.md: -------------------------------------------------------------------------------- 1 | # .NET 每周分享第 55 期 2 | 3 | ## 卷首语 4 | 5 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/43a5200e-6bbe-425a-8851-27449cc0b566) 6 | 7 | 5 月 21 号到 23 号是一年一度的 Microsoft Build 大会。大会中会涉及到很多 `.NET` 相关的内容,包括 `Aspire`, `AI` 与 `.NET`, `Visual Studio` 等相关内容,如果感兴趣,可以线上加入。 8 | 9 | ## 行业资讯 10 | 11 | 1、[Avalonia项目宣布离开.NET基金会](https://github.com/AvaloniaUI/Avalonia/discussions/14666) 12 | 13 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/ca12318a-e245-4d7c-b2e7-4d6484f05647) 14 | 15 | Avalonia 团队宣布离开 `.NET Foundation` , 主要原因是想要让项目的主导权保留在开发核心团队。至于说具体的原因导致这次分手,声明中并没有提及,不过这篇[文章](https://www.glennwatson.net/posts/dnf-problems-solutions)指出了 `.NET Foundation` 存在的问题和可能的解决方案。 16 | 17 | 2、[Twitter .NET团队成员列表](https://twitter.com/i/lists/120961876) 18 | 19 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/9af91c03-b051-4ae7-b70c-91f494edddc3) 20 | 21 | `.NET` 团队成员的 `Twitter` 账号列表,关注他们,获得最新的资讯。 22 | 23 | 3、[Twitter Azure Cloud Advocates 列表](https://x.com/i/lists/847470660712505346) 24 | 25 | `Azure Cloud Advocates` 团队成员的 `Twitter` 账号列表,关注他们,获得最新的资讯。 26 | 27 | ## 文章推荐 28 | 29 | 1、[跟 Stephen Toub 学习 Span](https://www.youtube.com/watch?v=5KdICNWOfEQ) 30 | 31 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/3dbfb0b2-99dd-48d8-8b9b-ec8f95b60fb6) 32 | 33 | `Span` 是高性能 `C#` 代码的秘诀之一,`.NET` 社区大佬 `Stephen Toub` 深入探究了什么是 `Span` 并且从头完成一个简易版的实现。 34 | 35 | 首先 `Span` 要解决什么问题?假设我们现在有一个方法是这样的: 36 | 37 | ```csharp 38 | private int Sum(int[] array) 39 | { 40 | int sum = 0; 41 | foreach(var val in array) sum += val; 42 | return sum; 43 | } 44 | ``` 45 | 46 | 如果 `Sum` 方法的是求和数组的部分内容,那么方法的签名需要修改成这样 47 | 48 | ```csharp 49 | private int Sum(int[] array, int offset, int length) 50 | { 51 | int sum = 0; 52 | for(int i = offset; i < length; i++) sum += array[offset+i]; 53 | return sum; 54 | } 55 | ``` 56 | 57 | 这样会带来一个问题,就是这个方法只支持 `int[]` 数据类型,而 `C#` 中有很多类型都是表示连续的一段空间,比如 `List` 。所以 `Span` 这个类型结构就被提出来了,如果仅仅是表示一段连续空间,`Span` 并没有什么特殊之处,`C/C++` 中的指针,或者 `C#` 中的 `unsafe` 代码块也能够完成同样的工作,但是 `Span` 是内存安全的类型,而且还是一个值类型。 58 | 59 | ```csharp 60 | readonly ref struct MySpan 61 | { 62 | private readonly ref T _reference; 63 | private readonly int _length; 64 | 65 | 66 | public MySpan(T[] array) 67 | { 68 | _reference = ref MemoryMarshal.GetArrayDataReference(array); 69 | _length = array.Length; 70 | } 71 | 72 | public MySpan(ref T reference) 73 | { 74 | _reference = ref reference; 75 | _length = 1; 76 | } 77 | 78 | public MySpan(ref T reference, int length) 79 | { 80 | _reference = ref reference; 81 | _length = length; 82 | } 83 | 84 | 85 | public ref T this[int index] 86 | { 87 | get 88 | { 89 | if (index < 0 || index >= _length) 90 | { 91 | throw new IndexOutOfRangeException(); 92 | } 93 | 94 | return ref Unsafe.Add(ref _reference, index); 95 | } 96 | } 97 | 98 | public MySpan Slice(int offset) 99 | { 100 | if (offset < 0 || offset >= _length) 101 | { 102 | throw new IndexOutOfRangeException(); 103 | } 104 | 105 | return new MySpan(ref Unsafe.Add(ref _reference, offset), _length - offset); 106 | } 107 | } 108 | ``` 109 | 110 | - `ref struct` 表明它只能用在方法中,而不能作为一个类的成员 111 | - `ref T _reference` 指向了连续空间的第一个元素 112 | - `ref T this[int index]` 说明连续空间的每个元素获取都是引用类型 113 | - `Unsafe.Add` 该方法避免了访问非法内存 114 | 115 | 2、[如何往已有的代码中添加 Nullability](https://blog.maartenballiauw.be/talk/2024/01/21/bringing-csharp-nullability-into-existing-code.html) 116 | 117 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/fb6fb8d9-0bf4-47cb-9531-0c8d200bba5b) 118 | 119 | `Nullable Reference Type` 是 `C# 8` 引入新的语法,它可以解决我们应用程序中的 `System.NullReferenceException` 的异常。但是从来没有银弹,这个工作需要程序在编译时候付出额外的付出。那么如何将已有的项目中开启这个功能呢?这个幻灯片介绍了其中的概念,方法和工具。 120 | 121 | 3、[JavaScript, TypeScript, C#代码实现对比](https://github.com/CharlieDigital/js-ts-csharp) 122 | 123 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/3c4f8172-b019-4fbf-802f-0f8039432451) 124 | 125 | 对于前端开发人员,`JavaScript` 或者 `TypeScript` 是两个非常熟悉的开发编程语言。但是 `C#` 这种后端开发语言和 `JavaScript` 或者 `TypeScript` 却越来越像,它们在语法,工具链上面相互学习。 126 | 127 | 4、[.NET 9 将要移除 Swagger,那怎么替换呢?](https://www.youtube.com/watch?v=8xEkVmqlr4I) 128 | 129 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/180ad6df-ebd3-4851-ba73-bc86537e7da1) 130 | 131 | `.NET 9` 中将会移除之前内置的 `Swagger` ,并且全面拥抱 `OpenAPI`。那么以后就不会有 Swagger 页面,只有一个 Web API 定义的 JSON 文件,但是 [Scalar](https://github.com/scalar/scalar?tab=readme-ov-file) 项目可以将其渲染成漂亮的 UI。 132 | 133 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/b957ddb3-cd97-4050-869a-1ec6d0442abb) 134 | 135 | 5、[.NET 9 LINQ 性能提升](https://steven-giesel.com/blogPost/783a404a-e39e-480f-bc99-a514a75d752d?utm_source=devdigest.today&utm_medium=website&utm_campaign=feature_promo&utm_content=link_click) 136 | 137 | `.NET 9` 在 Linq 上继续有新的性能上的更新 138 | 139 | - `Orderby.ToList` 140 | 141 | 通过 `Vector` 这个 SIMD 指令集提升 142 | 143 | - `Chunk` 144 | 145 | 通过 `ReadOnlySpan` 提升性能 146 | 147 | - `OfType` 148 | 149 | 通过处理特定的类型而不是通用的类型 150 | 151 | - `Any` 152 | 153 | 通过调用 `TryGetNonEnumeratedCount` 方法提高性能 154 | 155 | ## 开源项目 156 | 157 | 1、[TeslaLogger](https://github.com/bassmaster187/TeslaLogger) 158 | 159 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6bc12ebc-ec11-4080-86d2-8fc610eb26d6) 160 | 161 | TeslaLogger 是一个自托管的数据记录器,适用于您的 Tesla Model S/3/X/Y。目前,它支持 Raspberry Pi 3B、3B+、4B、Docker 和 Synology NAS。 162 | 163 | 2、[ILGPU](https://github.com/m4rs-mt/ILGPU) 164 | 165 | ILGPU 是一个即时编译器(JIT),用于编写高性能 GPU 程序的 .NET 语言。ILGPU 完全用 C# 编写,没有任何本地依赖。它结合了 C++ AMP 的灵活性和便利性,以及 CUDA 程序的高性能。内核范围内的函数不需要注解(默认 C# 函数),并且可以作用于值类型。所有内核(包括共享内存和原子操作等硬件特性)都可以使用集成的多线程 CPU 加速器在 CPU 上执行和调试。 166 | 167 | 3、[以太坊.NET库](https://github.com/Nethereum/Nethereum) 168 | 169 | Nethereum 是 .NET 的以太坊集成库,简化了与公共或许可的以太坊节点(如 Geth、Parity 或 Quorum)的访问和智能合约交互。 170 | 171 | 4、[币安.NET客户端库](https://github.com/JKorf/Binance.Net) 172 | 173 | ![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/d5bc7acd-a0b8-446b-90b9-abc9b5e4bb8d) 174 | 175 | Binance.Net 是一个强类型的客户端库,用于访问 Binance 的 REST 和 Websocket API。所有数据都映射到可读的模型和枚举值。其他功能包括实现客户端订单簿维护、与其他交易所客户端库的轻松集成等。 -------------------------------------------------------------------------------- /docs/images/002/anders.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/002/anders.jpeg -------------------------------------------------------------------------------- /docs/images/002/dotnetroadmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/002/dotnetroadmap.png -------------------------------------------------------------------------------- /docs/images/002/polly.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/002/polly.jpeg -------------------------------------------------------------------------------- /docs/images/003/autofac.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/003/autofac.jpeg -------------------------------------------------------------------------------- /docs/images/003/dotnet-conf-china.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/003/dotnet-conf-china.png -------------------------------------------------------------------------------- /docs/images/003/ef-plus.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/003/ef-plus.jpeg -------------------------------------------------------------------------------- /docs/images/003/linq.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/003/linq.jpeg -------------------------------------------------------------------------------- /docs/images/003/vs-widget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/003/vs-widget.png -------------------------------------------------------------------------------- /docs/images/003/xmas.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/003/xmas.webp -------------------------------------------------------------------------------- /docs/images/004/const-readonly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/004/const-readonly.png -------------------------------------------------------------------------------- /docs/images/004/dotnet-oss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/004/dotnet-oss.png -------------------------------------------------------------------------------- /docs/images/004/error-body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/004/error-body.png -------------------------------------------------------------------------------- /docs/images/004/non200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/004/non200.png -------------------------------------------------------------------------------- /docs/images/004/status-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/004/status-200.png -------------------------------------------------------------------------------- /docs/images/004/using.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/004/using.png -------------------------------------------------------------------------------- /docs/images/005/benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/005/benchmark.png -------------------------------------------------------------------------------- /docs/images/005/dotnet-oss-ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/005/dotnet-oss-ms.png -------------------------------------------------------------------------------- /docs/images/005/maui-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/005/maui-11.png -------------------------------------------------------------------------------- /docs/images/005/spring-vs-dotnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/005/spring-vs-dotnet.png -------------------------------------------------------------------------------- /docs/images/005/vs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/005/vs.png -------------------------------------------------------------------------------- /docs/images/006/csharp.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/006/csharp.jpeg -------------------------------------------------------------------------------- /docs/images/006/stringbuilder.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/006/stringbuilder.jpeg -------------------------------------------------------------------------------- /docs/images/006/vs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/006/vs.gif -------------------------------------------------------------------------------- /docs/images/007/aspnet-core-performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/007/aspnet-core-performance.png -------------------------------------------------------------------------------- /docs/images/007/datetimeoffset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/007/datetimeoffset.png -------------------------------------------------------------------------------- /docs/images/007/dotnet-core-framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/007/dotnet-core-framework.png -------------------------------------------------------------------------------- /docs/images/007/guard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/007/guard.png -------------------------------------------------------------------------------- /docs/images/007/performance.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/007/performance.jpeg -------------------------------------------------------------------------------- /docs/images/007/powershell-rdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/007/powershell-rdp.png -------------------------------------------------------------------------------- /docs/images/008/Backend-.NET-Developer-Roadmap-2022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/008/Backend-.NET-Developer-Roadmap-2022.png -------------------------------------------------------------------------------- /docs/images/008/das-blog.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/008/das-blog.jpeg -------------------------------------------------------------------------------- /docs/images/008/deconstructor.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/008/deconstructor.jpeg -------------------------------------------------------------------------------- /docs/images/008/dotnet-20.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/008/dotnet-20.jpeg -------------------------------------------------------------------------------- /docs/images/008/maui-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/008/maui-12.png -------------------------------------------------------------------------------- /docs/images/008/miguel-de-icaza.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/008/miguel-de-icaza.jpeg -------------------------------------------------------------------------------- /docs/images/009/dotnet-7-preview.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/009/dotnet-7-preview.jpeg -------------------------------------------------------------------------------- /docs/images/009/nullable.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/009/nullable.jpeg -------------------------------------------------------------------------------- /docs/images/009/vs_2012.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/009/vs_2012.jpeg -------------------------------------------------------------------------------- /docs/images/010/csharp-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/010/csharp-11.png -------------------------------------------------------------------------------- /docs/images/010/github-action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/010/github-action.png -------------------------------------------------------------------------------- /docs/images/010/mispell-dotnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/010/mispell-dotnet.png -------------------------------------------------------------------------------- /docs/images/010/morelinq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/010/morelinq.png -------------------------------------------------------------------------------- /docs/images/010/vs-debug.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/010/vs-debug.jpeg -------------------------------------------------------------------------------- /docs/images/011/asp-net-core-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/011/asp-net-core-pipeline.png -------------------------------------------------------------------------------- /docs/images/011/exception.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/011/exception.png -------------------------------------------------------------------------------- /docs/images/011/property.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/011/property.jpeg -------------------------------------------------------------------------------- /docs/images/011/service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/011/service.png -------------------------------------------------------------------------------- /docs/images/011/sys-command-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/011/sys-command-line.png -------------------------------------------------------------------------------- /docs/images/011/vs-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/011/vs-25.png -------------------------------------------------------------------------------- /docs/images/012/Timer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/012/Timer.png -------------------------------------------------------------------------------- /docs/images/012/avaloniaui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/012/avaloniaui.png -------------------------------------------------------------------------------- /docs/images/012/cancellation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/012/cancellation.jpg -------------------------------------------------------------------------------- /docs/images/012/github-co-pilot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/012/github-co-pilot.webp -------------------------------------------------------------------------------- /docs/images/012/nano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/012/nano.png -------------------------------------------------------------------------------- /docs/images/012/nuget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/012/nuget.png -------------------------------------------------------------------------------- /docs/images/013/bayes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/bayes.png -------------------------------------------------------------------------------- /docs/images/013/cpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/cpp.png -------------------------------------------------------------------------------- /docs/images/013/format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/format.png -------------------------------------------------------------------------------- /docs/images/013/graphapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/graphapi.png -------------------------------------------------------------------------------- /docs/images/013/ienumerable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/ienumerable.gif -------------------------------------------------------------------------------- /docs/images/013/interview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/interview.webp -------------------------------------------------------------------------------- /docs/images/013/jonskeet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/jonskeet.jpg -------------------------------------------------------------------------------- /docs/images/013/roslyn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/013/roslyn.png -------------------------------------------------------------------------------- /docs/images/014/bayes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/014/bayes.png -------------------------------------------------------------------------------- /docs/images/014/cosmosdb.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/014/cosmosdb.jpeg -------------------------------------------------------------------------------- /docs/images/014/gprcjson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/014/gprcjson.png -------------------------------------------------------------------------------- /docs/images/014/regex.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/014/regex.jpeg -------------------------------------------------------------------------------- /docs/images/014/wcf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/014/wcf.png -------------------------------------------------------------------------------- /docs/images/015/aspnetcore.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/aspnetcore.jpg -------------------------------------------------------------------------------- /docs/images/015/cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/cache.png -------------------------------------------------------------------------------- /docs/images/015/cleanup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/cleanup.png -------------------------------------------------------------------------------- /docs/images/015/gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/gui.png -------------------------------------------------------------------------------- /docs/images/015/httpclient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/httpclient.png -------------------------------------------------------------------------------- /docs/images/015/maui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/maui.png -------------------------------------------------------------------------------- /docs/images/015/msbuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/msbuild.png -------------------------------------------------------------------------------- /docs/images/015/nuget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/015/nuget.png -------------------------------------------------------------------------------- /docs/images/016/benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/benchmark.png -------------------------------------------------------------------------------- /docs/images/016/enum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/enum.png -------------------------------------------------------------------------------- /docs/images/016/exchange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/exchange.jpg -------------------------------------------------------------------------------- /docs/images/016/gc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/gc.png -------------------------------------------------------------------------------- /docs/images/016/globalusing.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/globalusing.jfif -------------------------------------------------------------------------------- /docs/images/016/greenthread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/greenthread.png -------------------------------------------------------------------------------- /docs/images/016/lambdadotnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/lambdadotnet.png -------------------------------------------------------------------------------- /docs/images/016/maui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/maui.png -------------------------------------------------------------------------------- /docs/images/016/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/memory.png -------------------------------------------------------------------------------- /docs/images/016/omnisharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/omnisharp.png -------------------------------------------------------------------------------- /docs/images/016/stringempty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/016/stringempty.png -------------------------------------------------------------------------------- /docs/images/017/antdesign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/antdesign.png -------------------------------------------------------------------------------- /docs/images/017/dotnet101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/dotnet101.png -------------------------------------------------------------------------------- /docs/images/017/hava.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/hava.png -------------------------------------------------------------------------------- /docs/images/017/ienumerable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/ienumerable.png -------------------------------------------------------------------------------- /docs/images/017/linq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/linq.png -------------------------------------------------------------------------------- /docs/images/017/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/memory.png -------------------------------------------------------------------------------- /docs/images/017/regex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/regex.png -------------------------------------------------------------------------------- /docs/images/017/roslynpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/roslynpad.png -------------------------------------------------------------------------------- /docs/images/017/string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/string.png -------------------------------------------------------------------------------- /docs/images/017/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/017/vscode.png -------------------------------------------------------------------------------- /docs/images/018/AwesomeBlazor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/AwesomeBlazor.png -------------------------------------------------------------------------------- /docs/images/018/DotnetEdition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/DotnetEdition.png -------------------------------------------------------------------------------- /docs/images/018/EssentialFsharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/EssentialFsharp.png -------------------------------------------------------------------------------- /docs/images/018/FirstOrSingle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/FirstOrSingle.png -------------------------------------------------------------------------------- /docs/images/018/MauiAndDevOps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/MauiAndDevOps.png -------------------------------------------------------------------------------- /docs/images/018/NeuralNetwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/NeuralNetwork.png -------------------------------------------------------------------------------- /docs/images/018/PublishAWS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/PublishAWS.png -------------------------------------------------------------------------------- /docs/images/018/RangesAndIndices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/RangesAndIndices.png -------------------------------------------------------------------------------- /docs/images/018/VSCodeServer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/018/VSCodeServer.png -------------------------------------------------------------------------------- /docs/images/019/APISIX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/APISIX.png -------------------------------------------------------------------------------- /docs/images/019/Base64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/Base64.png -------------------------------------------------------------------------------- /docs/images/019/CSharp11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/CSharp11.jpg -------------------------------------------------------------------------------- /docs/images/019/CSharpUnsafe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/CSharpUnsafe.png -------------------------------------------------------------------------------- /docs/images/019/DotNetConf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/DotNetConf.png -------------------------------------------------------------------------------- /docs/images/019/MiniExcelWork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/MiniExcelWork.png -------------------------------------------------------------------------------- /docs/images/019/Nlog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/Nlog.jpg -------------------------------------------------------------------------------- /docs/images/019/RateLimiter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/RateLimiter.png -------------------------------------------------------------------------------- /docs/images/019/ThrowEx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/ThrowEx.png -------------------------------------------------------------------------------- /docs/images/019/miniExcel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/miniExcel.jpg -------------------------------------------------------------------------------- /docs/images/019/systemd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/019/systemd.png -------------------------------------------------------------------------------- /docs/images/020/azure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/azure.png -------------------------------------------------------------------------------- /docs/images/020/communityTool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/communityTool.png -------------------------------------------------------------------------------- /docs/images/020/gc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/gc.png -------------------------------------------------------------------------------- /docs/images/020/linq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/linq.png -------------------------------------------------------------------------------- /docs/images/020/maui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/maui.png -------------------------------------------------------------------------------- /docs/images/020/restclient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/restclient.png -------------------------------------------------------------------------------- /docs/images/020/threadsafe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/threadsafe.png -------------------------------------------------------------------------------- /docs/images/020/unit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/020/unit.png -------------------------------------------------------------------------------- /docs/images/021/C11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/C11.png -------------------------------------------------------------------------------- /docs/images/021/appservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/appservice.png -------------------------------------------------------------------------------- /docs/images/021/asyncyieldreturn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/asyncyieldreturn.png -------------------------------------------------------------------------------- /docs/images/021/bogus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/bogus.png -------------------------------------------------------------------------------- /docs/images/021/cocurrent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/cocurrent.png -------------------------------------------------------------------------------- /docs/images/021/controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/controller.png -------------------------------------------------------------------------------- /docs/images/021/memortytool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/memortytool.png -------------------------------------------------------------------------------- /docs/images/021/muai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/muai.png -------------------------------------------------------------------------------- /docs/images/021/nunit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/nunit.png -------------------------------------------------------------------------------- /docs/images/021/yieldreturn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/021/yieldreturn.png -------------------------------------------------------------------------------- /docs/images/022/IEnumerable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/IEnumerable.png -------------------------------------------------------------------------------- /docs/images/022/async.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/async.png -------------------------------------------------------------------------------- /docs/images/022/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/docker.png -------------------------------------------------------------------------------- /docs/images/022/dotnet7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/dotnet7.png -------------------------------------------------------------------------------- /docs/images/022/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/file.png -------------------------------------------------------------------------------- /docs/images/022/gcinternal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/gcinternal.png -------------------------------------------------------------------------------- /docs/images/022/linq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/linq.png -------------------------------------------------------------------------------- /docs/images/022/timer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/timer.png -------------------------------------------------------------------------------- /docs/images/022/toolbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/022/toolbox.png -------------------------------------------------------------------------------- /docs/images/023/aspdotnetcore7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/aspdotnetcore7.png -------------------------------------------------------------------------------- /docs/images/023/csharp11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/csharp11.png -------------------------------------------------------------------------------- /docs/images/023/dotnet7arm64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/dotnet7arm64.png -------------------------------------------------------------------------------- /docs/images/023/dotnet7rc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/dotnet7rc.png -------------------------------------------------------------------------------- /docs/images/023/madstorgersen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/madstorgersen.png -------------------------------------------------------------------------------- /docs/images/023/muai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/muai.png -------------------------------------------------------------------------------- /docs/images/023/playwright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/playwright.png -------------------------------------------------------------------------------- /docs/images/023/sealclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/sealclass.png -------------------------------------------------------------------------------- /docs/images/023/thrift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/thrift.png -------------------------------------------------------------------------------- /docs/images/023/winget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/023/winget.png -------------------------------------------------------------------------------- /docs/images/024/ASP.NETCoreConfigure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/ASP.NETCoreConfigure.png -------------------------------------------------------------------------------- /docs/images/024/AspDotNETCore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/AspDotNETCore.png -------------------------------------------------------------------------------- /docs/images/024/DockerSQLServer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/DockerSQLServer.png -------------------------------------------------------------------------------- /docs/images/024/DotNETName.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/DotNETName.png -------------------------------------------------------------------------------- /docs/images/024/EFCore.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/EFCore.jfif -------------------------------------------------------------------------------- /docs/images/024/JsonConfigure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/JsonConfigure.png -------------------------------------------------------------------------------- /docs/images/024/LINQUse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/LINQUse.png -------------------------------------------------------------------------------- /docs/images/024/RateLimter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/RateLimter.png -------------------------------------------------------------------------------- /docs/images/024/dotnetCallJS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/dotnetCallJS.png -------------------------------------------------------------------------------- /docs/images/024/exposeMAUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/024/exposeMAUI.png -------------------------------------------------------------------------------- /docs/images/025/aspnetcore7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/aspnetcore7.png -------------------------------------------------------------------------------- /docs/images/025/cake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/cake.png -------------------------------------------------------------------------------- /docs/images/025/cleanarchiture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/cleanarchiture.png -------------------------------------------------------------------------------- /docs/images/025/davidfowler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/davidfowler.png -------------------------------------------------------------------------------- /docs/images/025/dotnetcsharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/dotnetcsharp.png -------------------------------------------------------------------------------- /docs/images/025/httpquery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/httpquery.png -------------------------------------------------------------------------------- /docs/images/025/imagesharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/imagesharp.png -------------------------------------------------------------------------------- /docs/images/025/odata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/odata.png -------------------------------------------------------------------------------- /docs/images/025/vstheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/vstheme.png -------------------------------------------------------------------------------- /docs/images/025/waitall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/025/waitall.png -------------------------------------------------------------------------------- /docs/images/026/.net7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/.net7.png -------------------------------------------------------------------------------- /docs/images/026/.netconf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/.netconf.png -------------------------------------------------------------------------------- /docs/images/026/cliwrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/cliwrap.png -------------------------------------------------------------------------------- /docs/images/026/dump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/dump.png -------------------------------------------------------------------------------- /docs/images/026/githubvs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/githubvs.png -------------------------------------------------------------------------------- /docs/images/026/litedb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/litedb.png -------------------------------------------------------------------------------- /docs/images/026/muai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/muai.png -------------------------------------------------------------------------------- /docs/images/026/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/random.png -------------------------------------------------------------------------------- /docs/images/026/respwarn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/respwarn.png -------------------------------------------------------------------------------- /docs/images/026/using.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/using.png -------------------------------------------------------------------------------- /docs/images/026/vs2022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/026/vs2022.png -------------------------------------------------------------------------------- /docs/images/027/.netconfi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/.netconfi.png -------------------------------------------------------------------------------- /docs/images/027/.netopenday.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/.netopenday.png -------------------------------------------------------------------------------- /docs/images/027/Csharp11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/Csharp11.png -------------------------------------------------------------------------------- /docs/images/027/fleet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/fleet.png -------------------------------------------------------------------------------- /docs/images/027/humanizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/humanizer.png -------------------------------------------------------------------------------- /docs/images/027/performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/performance.png -------------------------------------------------------------------------------- /docs/images/027/so.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/so.png -------------------------------------------------------------------------------- /docs/images/027/span.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/027/span.png -------------------------------------------------------------------------------- /docs/images/028/fluentui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/fluentui.png -------------------------------------------------------------------------------- /docs/images/028/imagesharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/imagesharp.png -------------------------------------------------------------------------------- /docs/images/028/lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/lambda.png -------------------------------------------------------------------------------- /docs/images/028/openAI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/openAI.png -------------------------------------------------------------------------------- /docs/images/028/ployglot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/ployglot.png -------------------------------------------------------------------------------- /docs/images/028/ramstring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/ramstring.png -------------------------------------------------------------------------------- /docs/images/028/todo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/todo.png -------------------------------------------------------------------------------- /docs/images/028/xmas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/028/xmas.png -------------------------------------------------------------------------------- /docs/images/029/call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/call.png -------------------------------------------------------------------------------- /docs/images/029/dotnetcli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/dotnetcli.png -------------------------------------------------------------------------------- /docs/images/029/eric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/eric.png -------------------------------------------------------------------------------- /docs/images/029/gc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/gc.png -------------------------------------------------------------------------------- /docs/images/029/json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/json.png -------------------------------------------------------------------------------- /docs/images/029/markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/markdown.png -------------------------------------------------------------------------------- /docs/images/029/minimalapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/minimalapi.png -------------------------------------------------------------------------------- /docs/images/029/newfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/newfile.png -------------------------------------------------------------------------------- /docs/images/029/quartz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/quartz.png -------------------------------------------------------------------------------- /docs/images/029/stopwatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/029/stopwatch.png -------------------------------------------------------------------------------- /docs/images/030/csharpbeginner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/030/csharpbeginner.png -------------------------------------------------------------------------------- /docs/images/030/defaultmethod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/030/defaultmethod.png -------------------------------------------------------------------------------- /docs/images/030/opensource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/030/opensource.png -------------------------------------------------------------------------------- /docs/images/030/oracle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/030/oracle.png -------------------------------------------------------------------------------- /docs/images/030/scottplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/030/scottplot.png -------------------------------------------------------------------------------- /docs/images/030/tuple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/030/tuple.png -------------------------------------------------------------------------------- /docs/images/031/bflat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/bflat.png -------------------------------------------------------------------------------- /docs/images/031/cobol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/cobol.png -------------------------------------------------------------------------------- /docs/images/031/constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/constructor.png -------------------------------------------------------------------------------- /docs/images/031/encryption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/encryption.png -------------------------------------------------------------------------------- /docs/images/031/methodtimer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/methodtimer.png -------------------------------------------------------------------------------- /docs/images/031/questpdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/questpdf.png -------------------------------------------------------------------------------- /docs/images/031/suvery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/suvery.png -------------------------------------------------------------------------------- /docs/images/031/vssearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/031/vssearch.png -------------------------------------------------------------------------------- /docs/images/032/asynchronous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/032/asynchronous.png -------------------------------------------------------------------------------- /docs/images/032/dotnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/032/dotnet.png -------------------------------------------------------------------------------- /docs/images/032/languages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/032/languages.png -------------------------------------------------------------------------------- /docs/images/032/powershell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/032/powershell.png -------------------------------------------------------------------------------- /docs/images/032/security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/032/security.png -------------------------------------------------------------------------------- /docs/images/032/stride.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/032/stride.png -------------------------------------------------------------------------------- /docs/images/033/cleanarchitecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/033/cleanarchitecture.png -------------------------------------------------------------------------------- /docs/images/033/dotnet8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/033/dotnet8.png -------------------------------------------------------------------------------- /docs/images/033/dotnetupgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/033/dotnetupgrade.png -------------------------------------------------------------------------------- /docs/images/033/linq2sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/033/linq2sql.png -------------------------------------------------------------------------------- /docs/images/033/onnx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/033/onnx.png -------------------------------------------------------------------------------- /docs/images/033/readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/033/readme.png -------------------------------------------------------------------------------- /docs/images/033/vsintelligence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/033/vsintelligence.png -------------------------------------------------------------------------------- /docs/images/034/dotnetday.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/dotnetday.png -------------------------------------------------------------------------------- /docs/images/034/dotnethistory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/dotnethistory.png -------------------------------------------------------------------------------- /docs/images/034/gitrider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/gitrider.png -------------------------------------------------------------------------------- /docs/images/034/refactor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/refactor.png -------------------------------------------------------------------------------- /docs/images/034/repl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/repl.png -------------------------------------------------------------------------------- /docs/images/034/roadmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/roadmap.png -------------------------------------------------------------------------------- /docs/images/034/sdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/sdk.png -------------------------------------------------------------------------------- /docs/images/034/validator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/034/validator.png -------------------------------------------------------------------------------- /docs/images/035/ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/ai.png -------------------------------------------------------------------------------- /docs/images/035/aspnetcore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/aspnetcore.png -------------------------------------------------------------------------------- /docs/images/035/javacsharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/javacsharp.png -------------------------------------------------------------------------------- /docs/images/035/netstandard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/netstandard.png -------------------------------------------------------------------------------- /docs/images/035/openai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/openai.png -------------------------------------------------------------------------------- /docs/images/035/package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/package.png -------------------------------------------------------------------------------- /docs/images/035/stringobject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/stringobject.png -------------------------------------------------------------------------------- /docs/images/035/timer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/timer.png -------------------------------------------------------------------------------- /docs/images/035/virutalevent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/virutalevent.png -------------------------------------------------------------------------------- /docs/images/035/wasm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNETWeekly-io/DotNetWeekly/98593a00e05023c58e41df16841333963090b37a/docs/images/035/wasm.png -------------------------------------------------------------------------------- /linter.yml: -------------------------------------------------------------------------------- 1 | pr: 2 | branches: 3 | include: 4 | - master 5 | paths: 6 | include: 7 | - docs/* 8 | 9 | jobs: 10 | - job: lint 11 | pool: 12 | vmImage: 'ubuntu-20.04' 13 | steps: 14 | - script: docker pull github/super-linter:latest 15 | displayName: Pull GitHub Super-Linter image 16 | - script: >- 17 | docker run \ 18 | -e RUN_LOCAL=true \ 19 | -e VALIDATE_MARKDOWN=true \ 20 | -e FILTER_REGEX_INCLUDE=.*docs/.* \ 21 | -v $(System.DefaultWorkingDirectory):/tmp/lint \ 22 | github/super-linter 23 | displayName: 'Run Linter' -------------------------------------------------------------------------------- /tools/Request-PublishEpisode.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [Parameter(Mandatory=$true)] 4 | [string] 5 | $Title, 6 | 7 | [Parameter(Mandatory=$true)] 8 | [string] 9 | $FileName, 10 | 11 | [Parameter(Mandatory=$true)] 12 | [string] 13 | $SecretKey, 14 | 15 | [Parameter(Mandatory=$true)] 16 | [string] 17 | $TenantId, 18 | 19 | [Parameter(Mandatory=$true)] 20 | [string] 21 | $ClientId, 22 | 23 | [Parameter(Mandatory=$true)] 24 | [string] 25 | $ResourceScope, 26 | 27 | # Parameter help description 28 | [Parameter(Mandatory=$true)] 29 | [string] 30 | $EndPoint 31 | ) 32 | 33 | function Get-EpisodeFromMarkdown 34 | { 35 | [CmdletBinding()] 36 | param ( 37 | [Parameter(Mandatory=$true)] 38 | [string] 39 | $FileName 40 | ) 41 | 42 | $url = "https://api.github.com/repos/gaufung/DotNetWeekly/contents/docs/$($FileName)" 43 | $response = Invoke-RestMethod -Method GET -Uri $url 44 | if (-not $response -or -not $response.content) 45 | { 46 | Write-Host "Failed to get $FileName from GitHub" -ForegroundColor Red 47 | return 48 | } 49 | 50 | return [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(($response.content))) 51 | 52 | } 53 | 54 | function Get-AADToken 55 | { 56 | [CmdletBinding()] 57 | param ( 58 | [Parameter(Mandatory=$true)] 59 | [string] 60 | $TenantId, 61 | 62 | [Parameter(Mandatory=$true)] 63 | [string] 64 | $ClientId, 65 | 66 | [Parameter(Mandatory=$true)] 67 | [string] 68 | $ResourceScope, 69 | 70 | [Parameter(Mandatory=$true)] 71 | [string] 72 | $SecretKey 73 | ) 74 | $url = "https://login.microsoftonline.com/" + $TenantId + "/oauth2/v2.0/token"; 75 | $body = @{ 76 | grant_type = "client_credentials" 77 | client_id = $ClientId 78 | scope = $ResourceScope 79 | client_secret = $SecretKey 80 | } 81 | 82 | $headers = @{ 83 | "Content-Type" = "application/x-www-form-urlencoded" 84 | "Accept" = "*/*" 85 | "Accept-Encoding" = "gzip, deflate, br" 86 | } 87 | 88 | $response = Invoke-RestMethod -Uri $url -Method POST -Body $body -Headers $headers 89 | return $response.access_token; 90 | 91 | } 92 | 93 | $content = Get-EpisodeFromMarkdown -FileName $FileName 94 | $data = @{ 95 | Title = $Title 96 | Content = $content 97 | } 98 | 99 | $url = "$($EndPoint)/api/episodes" 100 | 101 | $body = $data | ConvertTo-Json -Depth 99 102 | $token = Get-AADToken -TenantId $TenantId -ClientId $ClientId -ResourceScope $ResourceScope -SecretKey $SecretKey 103 | $headers = @{ 104 | Authorization = "Bearer $($token)" 105 | } 106 | 107 | Invoke-RestMethod -Method Post -Uri $url -Body $body -ContentType "application/json; charset=utf-8" -Headers $headers -------------------------------------------------------------------------------- /tools/Request-UploadImages.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [Parameter(Mandatory = $false)] 4 | [string] 5 | $ResourceGroupName = 'dotnetweekly', 6 | 7 | [Parameter(Mandatory = $false)] 8 | [string] 9 | $StorageAccountName = 'dotnetweeklyimages', 10 | 11 | [Parameter(Mandatory = $true)] 12 | [string] 13 | $EpisodeName, 14 | 15 | [Parameter(Mandatory = $false)] 16 | [string] 17 | $AccessKey, 18 | 19 | [Parameter(Mandatory = $true)] 20 | [string] 21 | $ImagesDirPath 22 | ) 23 | 24 | function Get-ImageMimeMapping { 25 | param ( 26 | [Parameter(Mandatory = $true)] 27 | [string] 28 | $fileName 29 | ) 30 | $extension = [System.IO.Path]::GetExtension($fileName); 31 | $mimeTypeMap = @{ 32 | '.png' = 'image/png' 33 | '.jpe' = 'image/jpeg' 34 | '.jpeg' = 'image/jpeg' 35 | '.jpg' = 'image/jpeg' 36 | '.gif' = 'image/gif' 37 | '.bmp' = 'image/bmp' 38 | '.svg' = 'image/svg+xml' 39 | '.webp' = 'image/webp' 40 | '.jfif' = 'image/jfif' 41 | } 42 | 43 | return $mimeTypeMap[$extension]; 44 | } 45 | 46 | $ImageFilePaths = get-ChildItem $ImagesDirPath | Select-Object -ExpandProperty FullName 47 | 48 | if (-not $AccessKey) { 49 | if (Get-ChildItem Env: | Where-Object { $_.Name -eq 'DotNETWeeklyStorageKey' }) { 50 | $AccessKey = Get-ChildItem Env: | Where-Object { $_.Name -eq 'DotNETWeeklyStorageKey' } | Select-Object -ExpandProperty Value 51 | } 52 | } 53 | 54 | if (-not $AccessKey) { 55 | $accessToken = Get-AzAccessToken; 56 | if (-not $accessToken -or $accessToken.ExpiresOn.UtcDateTime -gt [System.DateTime]::UtcNow) { 57 | Connect-AzAccount 58 | } 59 | $storageAccount = Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName -ErrorAction SilentlyContinue -ErrorAction SilentlyContinue 60 | 61 | if (-not $storageAccount) { 62 | Write-Error "Storage Account $($StorageAccountName) doesn't exist in the $($ResourceGroupName) resource group"; 63 | return 64 | } 65 | $context = $storageAccount.Context 66 | } 67 | else { 68 | $context = New-AzStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $AccessKey 69 | } 70 | 71 | $container = Get-AzStorageContainer -Context $context -Container $EpisodeName 72 | 73 | if (-not $container) { 74 | New-AzStorageContainer -Name $EpisodeName -Permission Container -Context $context 75 | } 76 | 77 | $container = Get-AzStorageContainer -Context $context -Name $EpisodeName 78 | 79 | $ImageFilePaths | Foreach-Object { 80 | $fileName = [System.IO.Path]::GetFileName($_); 81 | $contentType = Get-ImageMimeMapping $fileName 82 | $blob2HT = @{ 83 | File = $_ 84 | Container = $EpisodeName 85 | Blob = $fileName 86 | Context = $context 87 | StandardBlobTier = 'Cool' 88 | Properties = @{"ContentType" = $contentType } 89 | } 90 | $blob = Set-AzStorageBlobContent @blob2HT 91 | $uri = $blob.ICloudBlob.Uri 92 | Write-Host "$($_) -> $($uri)" 93 | } 94 | --------------------------------------------------------------------------------