WebAssembly和Blazor:解决了一个存在十年的老问题

本文要点

  • WebAssembly 是一种新的客户端技术,可以在所有现代浏览器(包括移动浏览器)中实现近乎原生的性能,而且不需要插件。

  • 许多语言,包括 C、C#、Go 和 Rust,都可以编译成面向基于栈的 WebAssembly 虚拟机的代码。

  • .NET 代码可以在任何地方运行,包括浏览器内部。

  • Blazor 是一个客户端库,它在 WebAssembly 上使用.NET 来支持借助 Razor 模板使用 C# 编写的单页应用程序。

  • Blazor 支持代码重用和将遗留代码移植到现代 Web 应用程序的能力。

在 2019 年 4 月中旬,微软悄悄地推出了一个年轻的框架,从“一切皆有可能”的实验阶段过渡到“我们致力于实现这一目标”的预览版。这个框架名为Blazor,因为它在浏览器中运行,并利用了一个名为 Razor 的模板系统或“视图引擎”,促成了这个.NET 开发人员几乎放弃了的场景。它不仅允许开发人员使用 C# 构建客户端代码(不需要 JavaScript),还允许开发人员在没有插件的情况下在浏览器中运行现有的.NET 标准 DLL。

Blazor 有两种托管模式。本文主要关注客户端版本。你可以阅读“Blazor 服务器端托管模型”了解更多关于服务器端版本的信息。

Silverlight 的希望

在任何地方运行.NET 的梦想始于 2006 年,当时有一个名为“Windows Presentation Foundation/Everywhere(WPF/E)”的应用程序框架以 Silverlight 的形式向公众发布。第一个版本支持通过 WPF 引入的声明性用户界面,即可扩展应用程序标记语言(Extensible Application Markup Language,简称 XAML)。该平台提供了对 UI 元素的细粒度控制,并提供了自己的文档对象模型(DOM),可以通过 JavaScript 访问。

当 Silverlight 2 在 2008 年发布时,它通过一个作为浏览器插件运行的公共语言运行时(CLR)实现.NET 的完全支持,从而加快了采用速度。开发人员可以使用任何.NET 语言来构建 Web 应用程序,利用成熟的数据绑定模式,如 Model-View-ViewMode(MVVM),并使用 REST 或 Windows Communication Foundation(WCF)客户端与 Web API 通信。看起来,.NET 开发人员可以摆脱 JavaScript 的束缚,不用再担心跨浏览器测试,而是专注于一个具有公共代码库的平台来交付他们的应用程序。

Silverlight 开发者不知道的是,2007 年对于这个平台来说是艰难的一年。两个看似不相干的事件发生了,最终导致了它的灭亡。首先,Web 超文本应用技术工作组(WHATWG)和万维网联盟(W3C)之间开始着手合作编写将于 2008 年发布的 HTML5 规范初稿。

第二,2007 年 6 月 29 日,苹果发布了 iPhone

每隔一段时间,我们就会有一件革命性的产品横空出世,并彻底改变一切。
——史蒂夫•乔布斯

比赛开始了。手机几乎是在一夜之间从带有联系人列表的翻盖手机发展到带有游戏和内置网络浏览器的便携式电脑。在很短的一段时间内,Silverlight 的未来似乎充满了希望。微软对 iPhone 的回应是 Windows Phone 7,支持以 Silverlight 作为开发平台。Chrome 支持即将到来。如果微软能够找到一种将 Silverlight 应用到 iPhone 和 Android 手机上的方法,那么“一次编写,到处运行”的圣杯将最终被发现。

只是,它没有找到。

出于许多原因,包括运行“浏览器中的虚拟机”的安全性考虑,以及潜在的电池消耗,通向浏览器插件的大门砰地关上了,特别是在移动设备上。业界开始期待 HTML5 在打造移动体验方面的前景。微软改变了自己的关注点,到 2011 年 Silverlight 5 发布时,大多数开发人员已经看到了不祥之兆:不会再有新版本了。

HTML5 和 JavaScript 继续赢得 Web 开发人员的青睐。jQuery 等工具对 DOM 进行了标准化,使构建多浏览器应用程序变得更加容易,同时,浏览器引擎开始采用通用的 DOM 标准,使“一次构建,到处运行”变得更加容易。Angular、React 和 Vue.js 等前端框架的爆炸式增长使单页应用程序(SPA)成为主流,并巩固了 JavaScript 作为浏览器操作系统首选语言的地位。

JavaScript 即平台

2013 年 3 月,asm.js正式推出。其文档把它描述为JavaScript 的一个严格子集,可以用作编译器的一种低级、高效的目标语言。该规范本质上定义了一组 JavaScript 约定,这些约定使通过提前编译优化代码成为可能,并提供了强类型(JavaScript 本身是一种动态语言)和基于堆的内存模型。

Asm.js 的推出使将 C/C++ 代码编译成 JavaScript 成为可能,从而开启了一个新的可能性领域。对约定的限制使得“支持 asm.js”的引擎可以有效地将 JavaScript 编译成高性能的本地代码。为了更好地理解这是如何实现的,请考虑下面的 C 代码片段:

该代码有效地扫描一个字符串,寻找标记其结束的测试字符或零字节,并计算偏移量。C++ 已经可以使用一个名为Clang的工具编译成字节码,该工具与LLVM 工具链兼容。LLVM 是一组支持快速跨平台编译代码的技术。一个名为Emscripten的项目利用该工具链来生成 asm.js。

使用 Emscripten 编译 C++ 代码可以生成几十行高度优化的 JavaScript。以下代码经过简化,用于说明生成的内容:

function find(buf, test) {

buf = buf|0;

var cur = buf|0;

var result = -1|0;

while (1) {

var check = HEAP8[cur>>0]|0;

var foundZero = (check) === (0);

if (foundZero) {

break;

}

var foundTest = (check) === (test|0);

if (foundTest) {

result = (cur - buf)|0;

break;

}

}

return result|0;

}

生成的 JavaScript 与所有浏览器兼容并且运行良好。带零操作的异或(|0)可以很容易地将任何数字转换为带符号整数。在较老的浏览器中,这可以确保数字没有小数部分。在现代浏览器中,该约定可以提前通知编译器使用 32 位整数(使数学运算更快),而不是默认的 64 位浮点值。0 右移(>>0)可以防止溢出,它还声明了一个“索引”整数类型,该类型在 HEAP8 上迭代,而 HEAP8 是一个可以在 asm.js 中使用的类型化的字节缓冲区。

在 asm.js 中没有定义 for 循环。所有内容都被转换为 while(1) 循环。这使得应用编译器优化变得更容易。这些优化非常有效,以至于一个团队能够将 Unreal 4 引擎移植到 Web 浏览器中,以近乎原生的性能直接运行 3D 第一人称视角游戏。

WebAssembly:新希望

时间很快来到 2017 年,WebAssembly发布了,这是一种基于栈的虚拟机的二进制指令格式。WebAssembly 提供了一个可移植的编译目标(简称 Wasm),与 asm.js 相比,它有几个优点:

  • 作为字节码格式,不需要解析脚本和预编译来进行优化。代码可以直接翻译成本机指令。与 asm.js 相比,加载和开始执行代码的启动时间要快几个数量级。

  • 字节码格式是一种更紧凑的代码交付方式。

  • Wasm 实现了自己的指令集,因此不受 JavaScript 语言的限制。

任何编译成 asm.js 的代码都可以把 WebAssembly 作为目标。对于前面的示例,编译器标志的一个简单修改就会生成一个扩展名为.wasm 的文件。该文件只有 116 字节长。尽管该文件包含字节码,但也存在代码的标准化文本表示形式,名为WebAssembly 文本格式。这是 WebAssembly 中 find 模块的文本表示:

(module

(type $t0 (func (param i32 i32) (result i32)))

(import "env" "memory" (memory $env.memory 256 256))

(func $a (type $t0) (param $p0 i32) (param $p1 i32) (result i32)

(local $l0 i32) (local $l1 i32) (local $l2 i32) (local $l3 i32)

get_local $p0

set_local $l0

loop $L0

get_local $l0

i32.load8_s

tee_local $l2

i32.eqz

set_local $l1

get_local $l0

i32.const 1

i32.add

set_local $l3

get_local $l1

i32.const 1

i32.xor

get_local $p1

i32.const 24

i32.shl

i32.const 24

i32.shr_s

get_local $l2

i32.ne

i32.and

if $I1

get_local $l3

set_local $l0

br $L0

end

end

i32.const -1

get_local $l0

get_local $p0

i32.sub

get_local $l1

select)

代码大小进行了优化,因此函数被重命名为了 a。

WebAssembly 现在是 1.x 稳定版,支持所有的现代浏览器,包括手机。若干语言都以 Wasm 作为有效的编译目标。你可以使用 C、C++、Go、Rust、TypeScript 和许多其他语言来构建 WebAssembly 程序。它已经应用于计算机视觉、音频混合、视频编解码器支持、数字信号处理、医学成像、物理模拟、加密、压缩等解决方案中。

但是 C# 呢?

在 WebAssembly 推出之后,将. NET 框架的工作版本(包括它的公共语言运行时)移植到 WebAssembly 上运行的工作就立即开始了。

这一努力取得了成功。

浏览器和 Razor 视图引擎

2017 年底,微软软件工程师 Steve Sanderson 在他的个人博客上宣布了 Blazor 的消息。当时,它“只是一个实验”,并不是正式产品。它始于这样一个问题:“我们如何让.NET 在 WebAssembly 中运行?”第一个答案是比较老的简化版.NET 运行时,他能够在几个小时内将其编译成 Wasm 二进制文件。.NET 本身在浏览器中并不是非常有用:你需要一个 UI 和某种与用户交互的方式。Razor 文件将标记和 C# 结合起来创建 Web 模板,基于这项扎实的工作,Blazor 添加了大量的服务,从数据绑定和依赖注入到可重用组件、布局,以及调用 JavaScript 和从 JavaScript 调用。所有这些服务结合使得使用.NET 和 C# 构建单页面应用程序(SPA)成为可能。

640?wx_fmt=jpeg

图 1 默认 Blazor 应用程序

为什么会有人在意呢?开发人员最初对 Blazor 的反应非常积极,这主要是因为:

  • 它允许开发人员使用他们已经熟悉的语言(C#)和框架(.NET)来构建以前深深扎根在 JavaScript 中的客户端应用程序。

  • 它可以在所有现代浏览器中运行,包括移动浏览器,而且不需要插件。

  • 它使开发人员能够进入.NET 生态系统并“按原样”使用现有的库。例如,如果你正在构建一个使用 Markdown 的博客引擎,那么你可以为现有的 Markdown 引擎安装 NuGet 包,并将 Markdown 直接转换为 HTML,以便在浏览器中预览。

  • .NET 的性能会随着时间的推移不断提高,因此在浏览器的 Wasm 上运行已经足够了。

  • Blazor 是一个真正的单页应用程序,它从一组静态资产运行,可以使用Azure Storage 静态网站等服务以非常低的成本托管这些静态资产。

现在,你已经了解了 Blazor 背后的历史和动机,让我们来研究一些技术细节。

本文中的所有代码示例都可以在Blazor WebAssembly GitHub 存储库中找到。

安装 Blazor 并开始使用所需要了解的所有内容都可以在Blazor 入门这篇文章中找到。在安装了 Blazor 之后,你可以选择只创建客户端或带有ASP.NET Core后端的客户端。对于现有的基于 MVC 的服务器端项目来说,该项目看起来非常熟悉。但是,生成的 DLL 直接加载到浏览器中,并由.NET 的 WebAssembly 版本运行。

640?wx_fmt=jpeg

图 2 Blazor 应用中的网络活动

Mono.js JavaScript 动态加载 mono.wasm 并开始在浏览器中运行.NET。其余的加载是组成应用程序的实际 DLL 文件。

浏览器中的 C#(带依赖注入)

默认模板包含一个获取模拟天气信息的页面。这是 Razor 视图,完全由 Wasm 在客户端上渲染。

<h1>Weather forecast</h1>


<p>This component demonstrates fetching data from the server.</p>


@if (forecasts == null)

{

<p><em>Loading...</em></p>

}

else

{

<tableclass="table">

<thead>

<tr>

<th>Date</th>

<th>Temp. (C)</th>

<th>Temp. (F)</th>

<th>Summary</th>

</tr>

</thead>

<tbody>

@foreach (var forecast in forecasts)

{

<tr>

<td>@forecast.Date.ToShortDateString()</td>

<td>@forecast.TemperatureC</td>

<td>@forecast.TemperatureF</td>

<td>@forecast.Summary</td>

</tr>

}

</tbody>

</table>

}

在模板的上部,一组指令决定了页面的路径,声明了一个 using 指令,并使用依赖注入来获取.NETFramework 的 HttpClient 副本,该副本可以在浏览器中使用。

@page "/fetchdata"

@using GetStarted.Shared

@inject HttpClient Http

最后,页面上的一小段代码嵌入到 @functions 块中。这里需要注意的是,代码完全是 C# 的。你可以使用熟悉的 HttpClient 执行网络操作,并且支持 async/wait。

WeatherForecast[] forecasts;


protected override async Task OnInitAsync()

{

forecasts = await Http.GetJsonAsync<WeatherForecast[]>("api/SampleData/WeatherForecasts");

}

视图模板渲染一个页面,但是控件呢?

可重用组件

Blazor 基于分层组件的可组合 UI。天气预报组件与其他组件的唯一区别是提供路由的页面指令。下面是一个名为 LabelSlider.razor 的组件的模板,使用一个显示当前值的 span 扩展内置的 HTML Input Range。

<inputtype="range"min="@Min"max="@Max"bind-value-oninput="@CurrentValue"/>

<span>@CurrentValue</span>


绑定语法的格式为 bind-{property}-{event}。事件是可选的,触发事件时绑定会更新。如果没有这个,滑块只会在用户停止移动滚动条时更新 span。通过连接到 oninput,该值将随着滑块的移动而刷新。

关联的代码暴露了参数,这些参数允许父组件设置最小和最大范围值,并将数据绑定到当前值。Action 属性暴露一个与 CurrentValue 关联的事件,并按照约定将其命名为 CurrentValueChanged,以方便双向数据绑定(父组件可以“侦听”更改事件并相应更新绑定值)。

[Parameter]

int ; set; }


[Parameter]

int ; set; }


private int _currentValue;


[Parameter]

int

{

get ;

set

{

if

{

_currentValue ;

CurrentValueChanged?.Invoke(value);

}

}

}


[Parameter]

Action<int> CurrentValueChanged ; set; }

注意,没有使用 Parameter 属性标记的属性只对组件可见。组件重用非常简单,只需把组件名置入标签并提供必要的参数,用法如下:

<LabelSlider Min="0" Max="99" bind-CurrentValue="@currentCount"/>

在本例中,一个与父组件上的 currentCount 属性之间的双向绑定建立起来了。

使用现有的库

Blazor 的一个非常强大的优点是能够“按原样”集成现有的类库。例如,考虑一个使用Markdown的博客引擎,它能够在浏览器中预览生成的 HTML。在 Blazor 中构建它就像安装一个 NuGet 包一样简单,在本例中是开源的MarkDig处理器。然后,可以直接调用库:

var html = Markdig.Markdown.ToHtml(SourceText);

NuGet DLL 像其他项目引用一样被导入浏览器,并且可以从客户端应用程序调用。

640?wx_fmt=jpeg

图 3 浏览器中的 Markdown 转换

调用 JavaScript/ 从 JavaScript 调用

Blazor 提供的一个重要服务是能够从.NET 调用 JavaScript,反之亦然。你希望从 Blazor 调用的任何 JavaScript 方法都必须能够从全局 window 对象访问,调用方法如下:

window.jsAlert = msg => alert(msg);

该互操作功能的使用方式如下:

await JsRuntime.InvokeAsync<object>("jsAlert", "Wow!");

InvokeAsync 方法支持传递和返回值,这些值将自动在 JavaScript 与.NET 之间转换并由 Blazor 运行时编组。使用 JsInvokable 属性来暴露 C# 方法,以便可以从 JavaScript 调用它。下面是一个例子,它封装了 Markdown 转换调用:

public static class Markdown

{

[JSInvokable]

public static string Convert(string src)

{

return Markdig.Markdown.ToHtml(src);

}

}

从 JavaScript 调用 DotNet.invoke 方法并传递程序集名称、暴露的方法名称和任何参数。

640?wx_fmt=jpeg

图 4 从 JavaScript 调用.NET

这使得扩展遗留应用程序和使用现有的 JavaScript 库成为可能。你甚至可以从 Blazor 应用程序调用其他 WebAssembly 模块。

Blazor 在发展

微软将 Blazor 移出了实验阶段,进入了官方预览版。使用组件模型进行服务器端渲染的 Blazor 版本将与.NET Core 3 的最终版本一起发布(请参阅.NET Core 路线图),客户端版本将在随后不久发布。还有工作要完成:调试体验极其有限,必须改进;有机会通过提前编译生成本机 Wasm 来优化代码性能;在将未使用的代码库发送到浏览器之前,需要从库中删除未使用的代码,从而降低总体大小(这个过程称为树抖动)。对 WebAsssembly 的兴趣和采用与日俱增,借助 Blazor,编写可以在任何地方运行的 C# 和.NET 代码的梦想终于实现了。

关于作者

Jeremy Likness是微软 Azure 的云推广专员。Jeremy 在 1982 年编写了他的第一个程序,并且已经开发企业应用程序 25 年了。他是四本科技书籍的作者,曾做过 8 年微软 MVP,是国际性的主题演讲家。Jeremy 的饮食以植物为主,在大部分空闲时间里,他都在太平洋西北部他的家附近跑步、徒步旅行和露营。关注Jeremy 的博客

640?wx_fmt=jpeg

原文地址:https://www.infoq.cn/article/GERYOPIV4B8OSD3_kSmB

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

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

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

相关文章

《电商后台系统产品逻辑解析》学习笔记

文是我阅读《电商产品经理宝典&#xff1a;电商后台系统产品逻辑全解析》一书的学习笔记&#xff0c;为后续我司做家居电商后台系统储备相关领域的业务知识。一、支撑线后台概览“前端用户的一小步&#xff0c;后台系统的一大步”&#xff0c;平时常见的功能如购物车、优惠券等…

P3403 跳楼机 同余最短路

传送门 题意&#xff1a; 思路&#xff1a; 转换一下题目就是用若干x,y,zx,y,zx,y,z能凑出来多少个<h<h<h的数。先考虑两个数y,zy,zy,z的情况&#xff0c;我们如果能求出来这两个数能凑出来的数设为sumsumsum&#xff0c;让后sumkx<hsumkx<hsumkx<h求出来…

NopCommerce 4.2的安装与运行

、关于NopCommerceNopCommerce是国外ASP.Net领域一个高质量的B2C开源电商项目&#xff0c;最新版本4.2基于ASP.NET Core MVC 2.2和EF Core 2.2开发&#xff0c;其强大的功能特性和插件机制使其成为了.NET领域开源电商项目的标杆。当然&#xff0c;还有一些其他的开源电商项目如…

P1527 [国家集训队]矩阵乘法 整体二分 + 二维树状数组

传送门 题意&#xff1a; 思路&#xff1a; 算是个整体二分的板子啦&#xff0c;不过这个是二维的矩阵&#xff0c;我们只需要把一位树状数组改成二维的&#xff0c;让后动态维护单点加&#xff0c;区间查询前缀和即可。 //#pragma GCC optimize(2) #include<cstdio>…

应用性能问题解决实际案例

某项目在上线前的APT&#xff08;Application Performance Testing应用程序性能测试&#xff09;过程中发现性能问题&#xff0c;性能测试结果影响是否上线&#xff0c;紧急求助外部项目组技术专家。因分属不同项目&#xff0c;只能通过项目组提供的信息进行分析。第一轮评审现…

Worker Service in ASP .NET Core

介绍提到 ASP.NET Core&#xff0c;我们多半会想到 ASP.NET MVC、ASP.NET Web API、Razor page 及 Blazor。随着 .NET Core 3.0 的推出&#xff0c;今天会介绍一个全新推出的功能&#xff1a;Work Service 。我们可以在 Visual Studio 2019 中通过预定的项目模版快速创建一个 W…

ASP.NET Core 奇淫技巧之动态WebApi

一.前言接触到动态WebApi&#xff08;Dynamic Web API&#xff09;这个词的已有几年&#xff0c;是从ABP框架里面接触到的&#xff0c;当时便对ABP的这个技术很好奇&#xff0c;后面分析了一波&#xff0c;也尝试过从ABP剥离一个出来作为独立组件来使用&#xff0c;可是后来因与…

Codeforces Round #693 (Div. 3) E. Correct Placement 思维

传送门 题意&#xff1a; 思路&#xff1a; 对于每个人都有个二元组(x,y)(x,y)(x,y)&#xff0c;从题意中提取有效信息就是&#xff1a;当(x1,y1)(x_1,y_1)(x1​,y1​)的最大值大于(x2,y2)(x_2,y_2)(x2​,y2​)的最大值&#xff0c;(x1,y1)(x_1,y_1)(x1​,y1​)的最小值大于(…

程序员过关斩将--你为什么还在用存储过程?

点击上面“蓝字”关注&#xff0c;带你看好电影菜菜哥&#xff0c;我新接手了一个项目&#xff0c;看的我头疼呀业务有这么复杂呀&#xff1f;不是的&#xff0c;这个老项目完全是用存储过程写的&#xff0c;每个存储过程都好几百行这样呀&#xff0c;是够头疼的~有没有办法帮我…

Educational Codeforces Round 101 (Rated for Div. 2) C. Building a Fence 思维取范围

传送门 题意&#xff1a; 思路&#xff1a; 刚看到这个题其实是没什么思路&#xff0c;想过从前往后推或者从后往前推&#xff0c;但是都不是很可行。因为两边都有一个固定的挡板挡住&#xff0c;我们可以根据其中的一个算出来每个位置高度的范围&#xff0c;让后检查一下范…

asp.net core 集成JWT

【什么是JWT】JSON Web Token&#xff08;JWT&#xff09;是目前最流行的跨域身份验证解决方案。JWT的官网地址&#xff1a;https://jwt.io/通俗地来讲&#xff0c;JWT是能代表用户身份的令牌&#xff0c;可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权…

xBIM(eXtensible Building Information Modelling)可扩展的建筑信息模型

一、xBIM 简介BIM&#xff08;Building Information Modelling&#xff09;建筑信息模型&#xff0c;xBIM&#xff08;eXtensible Building Information Modelling&#xff09;可扩展的建筑信息模型。它是一个.NET 开源软件开发BIM工具包&#xff0c;支持BuildingSmart数据模型…

Codeforces Global Round 12 C1 C2. Errich-Tac-Toe 思维构造 好题

传送门 题意&#xff1a; 给了如下规则&#xff0c;上面三个只要出现一个情况就是非平局&#xff0c;现在给你个字符矩阵&#xff0c;让后其中XXX字符有KKK个(hardhardhard版本XXX和OOO一共KKK个)&#xff0c;每次操作可以将XXX变成OOO&#xff0c;OOO变成XXX&#xff0c;用不…

译 | .NET Core 3.0 Preview 6 已发布

原文&#xff1a;Richard Lander翻译&#xff1a;Edi Wang今天&#xff0c;我们宣布 .NET Core 3.0 Preview 6。它的更新包括编译程序集以改进启动、使用链接器和 EventPipe 改进优化应用程序的大小。我们还在 ARM64 上发布了针对 Alpine 的新 Docker 镜像。立即在 Windows、ma…

庆祝.NET Core悄然崛起:免费送50本优秀技术书籍,请笑纳!!

为了庆祝 .NET社区蓬勃发展&#xff0c;今天特地联合几位.NET大佬给大家带来50本高质量技术书籍。.NET Core自开源以来&#xff0c;依托微软强大的科技实力日趋完善&#xff0c;再也不是10年前那种封闭状态。强大的跨平台&#xff0c;强大的IDE&#xff0c;强大的语言特性&…

P2371 [国家集训队]墨墨的等式 同余最短路

传送门 题意&#xff1a; 思路&#xff1a; 一个同于最短路的板子题&#xff0c;初始的时候值为0&#xff0c;所以设dis[0]0dis[0]0dis[0]0&#xff0c;让后选择一个最小的a[i]a[i]a[i]作为basebasebase&#xff0c;跑一遍同余最短路就好啦。跑完dis[i]dis[i]dis[i]表示在模b…

ASP.NET Core WebAPI帮助页--Swagger简单使用1.0

1、什么是Swagger&#xff1f;Swagger是一个规范且完整的框架&#xff0c;提供描述、生产、消费和可视化RESTful API&#xff0c;它是为了解决Web API生成有用文档和帮助页的问题。2、为啥选用swagger?1&#xff09;它具有交互式文档、客户端SDK生成和API可发现性等优点。2&am…

Codeforces Global Round 12 E. Capitalism 差分约束

传送门 题意&#xff1a; 思路&#xff1a; 一开始被题意迷惑了&#xff0c;没看出来差分约束&#xff0c;老菜鸡啦。首先看到ajai1a_ja_i1aj​ai​1可以把aia_iai​分成奇偶&#xff0c;让后这个图就变成一个二分图了。再考虑如何连边&#xff1a; (1) 对于b1b1b1的情况&…

8个月打磨,一份送给程序员的「分布式系统」合集

这里是Z哥的个人公众号每周五早8点 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「75」篇原创敬上整理好的文章目录在文末&#xff0c;可直接拉到最后是的&#xff0c;这份礼物最佳受众是程序员。但是&#xff0c;如果你不是程序员&#xff0c;相信这些能使你…

【翻译】无需安装Python,就可以在.NET里调用Python库

原文地址&#xff1a;https://henon.wordpress.com/2019/06/05/using-python-libraries-in-net-without-a-python-installation/pythonnet这个屌爆的项目的出现&#xff0c;使得我们可以用一种新的方式&#xff0c;让C#可以和Python之间进行互操作。但是它的设置和部署可能有点…