用ASP.NET Core 2.1 建立规范的 REST API -- 翻页/排序/过滤等

本文所需的一些预备知识可以看这里:  用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 和  用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 (2) + 准备项目

建立Richardson成熟度2级的POST、GET、PUT、PATCH、DELETE的RESTful API请看这里: 用ASP.NET Core 2.0 建立规范的 REST API -- DELETE, UPDATE, PATCH 和 Log

本文需要的代码 (右键另存,把后缀改为zip):https://images2018.cnblogs.com/blog/986268/201806/986268-20180604151009219-514390264.jpg

本代码已经更新至ASP.NET Core 2.1. (从ASP.NET Core 2.0 迁移至 ASP.NET Core 2.1: https://docs.microsoft.com/en-us/aspnet/core/migration/20_21?view=aspnetcore-2.1)

 

本文主要介绍一些常见情况的实现,包括:集合更新、翻页、排序、过滤等等。但是仍然是Richardson成熟度顶多为2级的Web API,未达到RESTful API的标准和约束。

 

集合的更新操作

640?wx_fmt=png

 

看这种更新集合的情况,原来数据库里中国存了4个城市(北平,上海,盛京,海参崴);而几个世纪后北平改名叫北京了,盛京名为沈阳了,海参崴不属于中国了就删除了,威海从县成为市就算是新增,而上海保持不变。现在就是要对中国的城市进行整体性的更新操作,里面会包含:添加、删除、更新操作。看代码:

640?wx_fmt=png

集合更新,我一共分了三步进行的操作:

1. 把数据库中存在的但是传进来的数据里没有的城市删掉

2. 把数据库中没有的而传进来的数据里有的数据进行添加操作,其实这里只判断id为0即可

3. 把数据库中原有和传进来的参数里也存在的数据条目进行更新。

然后保存即可。

先看一下原有的数据:

640?wx_fmt=png

然后我们执行集合的更新:

640?wx_fmt=png

执行之后,再次查询:

640?wx_fmt=png

集合按预期更新了。

我相信大家肯定会写这段代码,或者有更简单的实现方式(请贴出来)。但这不是重点,我看到有人这样写,把上面那三步代码写在了AutoMapper的配置文件里:

640?wx_fmt=png

首先,需要忽略Country的Cities属性的映射操作,然后把那部分代码写在AfterMap里面即可,这样在Action方法里面就简单了,可以使用Automapper了:

640?wx_fmt=png

这只是一种可选的写法而已,不一定就必须放在AutoMapper的配置文件里。

 

翻页

翻页可以避免一些性能问题,不必一次性加载所有数据。所以最好默认就采用分页,而且每页的条目数量必须有限制,不能太大。

分页信息应该使用查询字符串(query stringg)传递参数。格式应该这样:

http://localhost:5000/api/country?pageIndex=12&pageSize=10

这里我喜欢使用pageIndex这个词,这也意味着页数是从0开始的;当然很多人喜欢用pageNumber等词,也就是说更喜欢页数从1开始,这个其实随意吧。

在ASP.NET Core里,我要使用Linq来动态组建一个查询的表达式(IQueryable<T>,可以创建表达式树),它是延迟执行的,直到各种条件都判断完了并组建出最终的查询表达式之后才去执行(查询数据库)。这个查询表达式只有在进行迭代的时候才会查询数据库。

触发迭代动作可以使用下面的方法:

  • foreach 循环

  • ToList(), ToArray(), ToDictionary() 以及相应的异步版本(ToXxxxAsync())

  • 单项查询,例如 Average(), Count(), First(), FirstOrDefault(), SingleOrDefault()等等,以及相应的异步版本。

需要确保的是要在迭代发生之前,使用Skip()和Take()以及Where()。

下面我一点一点来写代码:

640?wx_fmt=png

首先我们需要从参数(query string参数)传进来pageIndex和pageSize,还要赋默认值,以防止API的消费者没有设置pageIndex和pageSize;由于pageSize的值是由API的消费者来定的,所以应该在后端设定一个最大值,以免API的消费者设定一个很大的值。

由于所有的资源几乎都要使用翻页,所以我们最好使用一个公共类来封装这些翻页相关的信息:

640?wx_fmt=jpeg

(我暂时把这个类放在了Core项目里)

这个公共类很简单,可以为pageIndex和pageSize设定默认值,也设置了一个每页的最多条目数是100;这里面还有一个OrderBy属性,默认值是“Id”,因为翻页必须要先排序,但目前这个OrderBy属性还没用上。

而针对具体的资源,我们可以再建立一个类继承于PaginationBase,这个类就是Country的参数类:

640?wx_fmt=png

由于暂时还没有什么特别的参数,所以里面是空的。

下面我修改一下CountryRepository:

640?wx_fmt=png

可以看到我组建了这个查询的表达式,并且直接出发了迭代动作,返回查询结果。

回到Action方法里:

640?wx_fmt=png

我使用了这个参数类代替了之前的pageIndex和pageSize参数,因为ASP.NET Core足够智能,可以把这两个参数解析到这个类里面。

下面测试一下:

640?wx_fmt=jpeg

我就不进行多次测试了,这个是好用的。

如果你是用的是关系型数据库的话,应该可以在Log的输出媒介上看到打印出的SQL语句(但我这里使用的是内存数据库,所以看不到),如果使用关系型数据库还是看不到SQL语句的话,请配置一下:

640?wx_fmt=png

返回翻页的元数据

很显然只返回当前页的数据是不满足需求的,至少还需要返回总页数,总数等信息,还有可能需要返回前一页或者后一页的链接。但是如何把这些信息连同当页的数据一起返回给API消费者呢?

下面的做法是可以把这些数据都返回去的:

{“data”: [{country1}, {country2}...],“metadata”: {"prev": "/api/...", ....}    
}

但是这样做的话就导致了响应的body不再符合Accept Header了(不是资源的JSON表述了),也就不是application/json了,而是一种新的media type。

所以如果返回这样的数据就违反了REST的规则了(尽管本文代码的Richardson成熟度最多也就是2级),它违反了自我描述的约束(请参考本系列的预备知识文章),API消费者不知道如何通过application/json这个设定的contety-type来解释响应数据了。

所以说翻页的元数据并不是资源表述的一部分。我们应该使用自定义的Header,例如“X-Pagination”来表述翻页元数据,这个名也是比较常用的。

首先,我创建一个类可以存放翻页的数据:

640?wx_fmt=png

可以向上面这样做这个类:该类继承于List<T>,同时还包含PaginationBase作为属性,还可以判断是否有前一页和后一页。使用静态方法创建该类的实例。

这个静态方法也许会有一点点问题,这里没有使用异步方法,这样做是OK的;但是如果使用异步方法,例如source.CountAsync()和source.ToListAsync(),就会有一些问题,因为我需要修改CountryRepository的GetCountriesAsync方法的返回类型,改成上面这个类型,所以它的接口ICountryRepository也需要改;而它的接口是整个项目的核心并放在Core项目里,而整个项目的核心(合约)我个人认为应该是和具体的ORM无关的,但是这里依赖于EntityFrameworkCore了(ToListAsync())。所以我最后决定去掉这个静态方法,这样可能会导致多写一些代码;此外还添加HasPrevious和HasNext属性,判断是否有前一页和后一页:

640?wx_fmt=png

(暂时放在Core项目里面了)

然后修改CountryRepository:

640?wx_fmt=jpeg

然后在Action方法里,我们还需要生成前一页和后一页的URI,所以这里可以使用UrlHelper,需要在Startup的ConfigureServices方法里面注册:

640?wx_fmt=png

然后回到Controller里面建立一个方法来生成URI:

640?wx_fmt=png

在这里我还建立了一个枚举,PaginationResourceUriType。我还为PaginationBase添加了一个Clone()方法,目的是创建出一个属性值和它相同的另一个实例,因为这里有修改pageIndex属性这个操作;也许Clone不是最好的办法,直接new可能更合适。

下面就是修改Action方法了:

640?wx_fmt=png

通过之前的方法分别创建出两个链接,然后把翻页相关的数据组成一个匿名类,使用JSON.NET将其串行化,并放到响应的自定义Header:“X-Pagination”里面。

而body部分还是资源的集合数据。

测试一下:

640?wx_fmt=png

响应的body正常的返回来了,再看一下响应的Header:

640?wx_fmt=png

可以看到自定义的X-Pagination Header了,然后我复制一下里面的NextPageLink链接,并发送该请求:

640?wx_fmt=png

640?wx_fmt=jpeg

都没有问题。

这个Action目前的Richardson成熟度已经接近3级了(HATEOAS),但还不是。翻页现在是到这,下面要进行过滤并翻页。

 

过滤和搜索

过滤的意思就是对集合资源附加一些条件然后筛选出结果,它的URI是下面的形式:

http://localhost:5000/api/countries?englishName=China

所以需要在查询字符串里写上属性的名字和属性的值来表示要按这个属性的值来进行过滤,当然也可以写多个过滤的条件。

过滤的条件是应用于ResourceModel(或叫做Dto,ViewModel),例如CountryResource,而不应用于其它级别的Model,因为API消费者只知道ResourceModel,它不知道内部实现的细节,也就是不知道EntityModel的样子。

 

搜索呢,是通过一个搜索关键字来模糊的筛选集合资源,可能会有多个属性针对这个关键字进行模糊筛选。

搜索的URI大致是下面的形式:

http://localhost/api/countries?searchTerm=hin

 

上面这个URI可以理解为针对Countries资源,凡是字符串类型的属性,它的值包含hin的都符合条件,就返回符合这个条件的结果。

首先看一下过滤的实现。在Countries的GET Action方法里,我使用CountryResourceParameters类作为参数,所以要增加针对某个属性的过滤条件,只需扩展这个类即可,而增加的属性名要和ResourceModel里面的属性名一致:

640?wx_fmt=png

然后是修改CountryRepository里面的方法:

640?wx_fmt=png

首先要在执行分页动作之前附加过滤条件,query的类型必须是IQueryable<Country>才可以动态组建查询表达式,所以使用了AsQueryable()方法;然后分别判断两个条件并附加条件(注意大小写问题和两头空格的问题),最后再执行分页查询。

由于添加了参数,所以CreateUri的方法也需要改:

640?wx_fmt=png

这个方法参数变成了CountryResourceParameters,而且Clone方法克隆出来的也是CountryResourceParameters类:

640?wx_fmt=jpeg

下面测试:

640?wx_fmt=png

没有问题的,但是还要看看Header:

640?wx_fmt=png

针对这个结果是OK的。

下面我做一些数据,使其拥有同样的EnglishName,然后测试:

640?wx_fmt=jpeg

 

 OK,再看看Header:

640?wx_fmt=png

使用NextLink再次发送请求, 结果是OK的,我就不贴图了。

但是你应该注意到,X-Pagination的属性名不符合camelCase命名规范,所以需要在转化成JSON的时候添加一些配置:

640?wx_fmt=png

然后再测试一下:

640?wx_fmt=png

属性的命名符合camelcase规范了,但是previousLink和nextLink里面的查询字符串的大小写依然不正确,所以我干脆去掉了Clone()方法,然后在CreateCountryUri的方法里直接new出来新链接的参数:

640?wx_fmt=png

测试:

640?wx_fmt=png

现在命名终于符合规范了。

 

排序

之前做的翻页都需要排序,暂时都是按照Id进行排序的。而实际上API消费者可能让资源按照资源的某个属性或多个属性进行正向或反向的排序

我们先从最简单的例子开始,只考虑只按照某一个属性(针对的是资源的属性,例如CountryResource的EnglishName)进行排序,针对这个例子,我先使用比较笨的方法。

首先我假定,参数类里面的OrderBy属性如果以" desc" 结尾,例如:“EnglishName desc”,那么就是按照EnglishName倒序排列,而“EnglishName”就是正序排列。

只需在CountryRepository里面修改代码即可:

640?wx_fmt=png

 

嗯,很笨重的代码。

先测试一下:

640?wx_fmt=png

至少功能是OK的,再看一下倒序:

640?wx_fmt=png

也OK,所以虽然代码很笨重,但是针对这种简单的情况是可以应付的。

下面我们对它进行第一次优化。像上面这样挨个属性的判断实在是太费劲了,所以我们来分析一下,OrderBy的值是字符串,而OrderBy()方法里面的lambda表达式的类型是Expression具体的类型是Expression<Func<Country, object>>。这里简单讲一下,万一您不知道lambda表达式的话可以看一下。lambda表达式就是匿名的函数,它的类型是Func(可以赋值给Func类型的变量):

640?wx_fmt=png

同时我们也可以把这个lambda表达式赋值给Expression:

640?wx_fmt=png

而OrderBy()这个Linq方法接收的参数类型就是Expression<Func<Country, object>>。

使用Expression,我们可以构建Expression Tree;使用Expression Tree,可以表示一些逻辑。而在运行时,Linq的提供商将会解析这个Expression Tree,并把这些逻辑转化为SQL语句:

640?wx_fmt=png

再看上面的排序条件判断,我们可以把OrderBy的字符串和Expression映射起来,就像Key-Value 键值对那样,这样做也许就会是代码稍微好看一些。所以你肯定会想到Dictionary<K, V>。

所以修改后的代码如下:

640?wx_fmt=png

我相信你能看懂,我就不解释了,下面测试:

640?wx_fmt=png

总之是好用的,我就不贴其他测试结果的图片了。

应该把上面这段代码提取出来封装成一个方法函数并泛型化,但是我暂时先不这样做。

 

经过第一次优化,使用Dictionary,代码简洁了许多,但是期间还是有手动把属性名字符串转化为Expression的动作。之所以这么写是因为OrderBy仅支持Expression的参数类型,如果支持字符串,那就完美了。

幸好有一个微软的库支持这种操作,它叫做System.Linq.Dynamic.Core(其作者是红衣教主啊)

640?wx_fmt=png

我把它安装在了Infrastructure项目里供Repository使用。

再次修改排序那部分的代码:

640?wx_fmt=jpeg

注意这里OrderBy的命名空间是:System.Linq.Dynamic.Core

经过第二次优化,代码已经很简洁了,但是还有很多待完善的地方,例如:

  • Resource Model的一个属性可能会映射到Entity Model的多个属性上:Name 属性通常会映射成EntityModel的 FirstName 和 LastName属性

  • Resource Model上的正序可能在Entity Model上就是倒序的:Age 升序,而Entity Model的BirthDate就是降序

  • 需要支持多属性的排序:EnglishName desc, Id, ChineseName。

  • 复用

 

第三次优化,要解决Model属性映射引起的问题。

也就是说要从ResourceModel的一个属性映射到Entity Model的一个或者多个属性上,而且它们之间的排列顺序可能是不同的,举一个极端的例子:

假设ResourceModel 有个属性叫做 Rank(排名) ,它所映射Entity Model的两个属性Result(成绩)和Weight(体重);假设这是举重比赛的Model,排名结果(Rank)是按照成绩(Result)从高到低排序的,但是如果多名选手的成绩相同,则体重轻的排名靠前。

也就是Rank asc -> Result desc, Weight asc。

用程序来说就是,一个字符串“Rank asc”要映射成一个集合,而集合元素的类型有两个属性:Entity Model的属性名和排序的方向。

所以先把集合里这种元素的类建立出来:

640?wx_fmt=png

这里方向我是用的Revert这个单词,表示其方向是否与Resource Model的属性方向相反即可。

然后在做针对CountryResource的整套映射,不过首先我考虑建立一个抽象父类,里面可能有些公用的东西:

640?wx_fmt=png

由于Id这个属性可能是每个相关的Model共有的,所以在这个父类里,我添加了Id属性的映射,Id是一对一的映射,排序方向相同。

然后我针对CountryResource,写一个派生于PropertyMapping的子类:

640?wx_fmt=png

注意红框很重要,比较key的时候忽略大小写。

到这里,Resource和Entity Model之间映射的部分差不多做完了,接下来要考虑整个排序的问题,做这样一个扩展方法:

640?wx_fmt=png

它应用于IQueryable,并把orderBy字符串和属性映射表传进来。

经过一些初步检验之后,把orderBy按“,”分解成字段属性的数组。然后去掉两边可能存在的空格,判断是否是倒序,提取出属性的名称。如果在映射表里面找不到该名称或者该名称对应的值是空,那就抛出异常。

然后先循环字段数组,然后内层循环该字段映射的属性集合。

最后通过DynamicLinq即可组建出所需的排序表达式。

使用DynamicLinq的OrderBy时要注意,排序条件必须反向附加,不信可以试试。

随后我们修改一下Repository:

640?wx_fmt=jpeg

就剩下一句话了,很简洁了。但是这里需要new一个CountryPropertyMapping类,这样做对单元测试就不友好了,也许把它放在一个容器里取出来用更合适?

那么就建立一个容器:

640?wx_fmt=png

该容器的Register和Resolve分别用来注册和提取映射表。

下面还有个检查映射是否存在的方法,fields是一个或者多个字段属性组成的字符串,其格式如“EnglishName,ChineseName”;它检查是否能在映射配置表(MappingDictionary)找到相应的Key,如果找不到就验证失败。

这个容器在整个应用范围内也是个容器,所以需要在Startup里面注册,由于它的代码可能比较多(因为本身它也是个容器,还有很多注册内容用的代码),所以我单独写了个扩展方法:

640?wx_fmt=jpeg

该方法可以在Startup里面调用,从而注册到ASP.NET Core的服务容器里:

640?wx_fmt=png

然后再次修改CountryRepository:

640?wx_fmt=png

先注入了该容器服务,然后从该容器中按照映射两端的Model类型取出需要的映射表:

640?wx_fmt=jpeg

 测试:

640?wx_fmt=png

看起来是OK的,那我们针对排序,暂时先优化到这里。

 

排序的异常

还需要考虑到如果OrderBy里面的字段在映射表里面不存在的情况,所以我使用这个方法来进行判断:

640?wx_fmt=png

我把这个方法放在了PropertyMappingContainer里,因为PropertyMappingContainer本身实际上就是一个服务,放在里还是比较合适的。

这里需要注意的是fileds里面的字段可能是这种形式的“EnglishName desc”,所以需要把空格和desc部分去掉。

随后在Action方法里调用即可:

640?wx_fmt=png

测试:

640?wx_fmt=png

应该是没问题的,我就不多测试了,以后要实行单元测试的。

 

资源塑形

如果某个资源的属性比较多,那么客户端的API消费者可能只需要一部分属性,这时就应该进行数据塑形,而且这样做有可能会提升性能。

数据塑形要考虑两种情况,集合资源单个资源

集合资源塑形

先考虑集合资源,首先我做一个扩展方法,把IEnumerable<T>可以转化为IEnumerable<dynamic>,这里要用到dynamic(ExpandoObject):

640?wx_fmt=png

由于反射比较消耗资源,所以在这里,我一次性把需要的属性弄成PropertyInfo放到了一个集合里。如果fields是空的,说明需要所有属性,就把所有public和实例的property都放到集合里,否则,就把需要的属性放进去即可。

然后循环数据源,使用反射通过PropertyInfo获取该属性的值,最后组成一个ExpandoObject,再把这个ExpandoObject放到结果集合里面即可。

接下来修改参数类,因为这是个通用的东西,那就是为PaginationBase添加一个Fields属性吧:

640?wx_fmt=png

最后修改Action方法:

640?wx_fmt=png

测试:

640?wx_fmt=png

好用的。但是返回的数据并不是camelcase的,这是因为JSON.net串行化的ContractResolver并不适用于Dictionary。下面来处理这个问题。

打开Startup,在services.AddMvc()后边添加:

640?wx_fmt=png

这句话就是配置了JSON转化的ContractResolver。

在测试一下:

640?wx_fmt=png

现在Ok了。

处理异常

但如果API消费者在Fields里面提供了不存在的属性,那么就应该返回Bad Request。

原理上我也许可以使用ProperyMappingContainer里面的验证方法,但是数据塑形并不使用映射表。而且目的不同,一个是排序一个是数据塑形,所以因为关注分离吧(SoC)。

我们要做的就是给定一个Fields和一个类型,需要判断Fields里面包含的字段属性在这个类型里面都存在,所以还是做一个Service比较好,可以注入使用。

看代码:

640?wx_fmt=png

这个类比较简单不多讲了,别忘了在Startup里面注册。

然后在Controller里面注入并使用,别忘了还需要修改CreateCountryUri方法:

640?wx_fmt=png

测试:

640?wx_fmt=png

OK.

对单个资源塑形

这个跟集合的原理差不多,先建立一个扩展方法:

640?wx_fmt=png

再修改Action即可:

640?wx_fmt=png

测试:

 640?wx_fmt=png

是好用的,我就不多测试了。

 

针对数据塑形需要注意的是,尽量把Id带上,否则可能无法获取相关的链接了。

 

今天先写到这里,还有很多更深入一点的功能没有做,我就不做了。

到目前为止,这些Web API仍然称不上是RESTful的API,成熟度不够高,有些约束也没达到。下一篇文章会把升级这些API以便支持HATEOAS。

代码在这:https://github.com/solenovex/ASP.NET-Core-2.0-RESTful-API-Tutorial

项目有一些文件的拜访目录可能不对,暂时先不处理。

相关文章:

  • 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识

  • 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 (2) + 准备项目

  • 用ASP.NET Core 2.0 建立规范的 REST API -- GET 和 POST

  • 用ASP.NET Core 2.0 建立规范的 REST API -- DELETE, UPDATE, PATCH 和 Log

原文地址: http://www.cnblogs.com/cgzl/p/9117448.html


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

640?wx_fmt=jpeg

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

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

相关文章

用ASP.NET Core 2.1 建立规范的 REST API -- HATEOAS

本文所需的一些预备知识可以看这里: 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 和 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 (2) 准备项目建立Richardson成熟度2级的POST、GET、PUT、PATCH、DELETE的RESTful API请看这里&#xff1a;用ASP.NET Core …

学习手记(2020/8/19~2021/3/19)

文章目录所有集合子集数量和结论证明枚举子集的方法最大匹配模的次数线性基卡特兰数树形dpTipTipTip斯特林数斐波那契幂前缀和hallhallhall定理阿巴阿巴1狄利克雷卷积常用式子组合数学恒等式竞赛图性质一些博弈模型基础反演二项式反演莫比乌斯反演欧拉反演子集反演min-max\text…

奶牛的交叉路(jzoj 1756)

奶牛的交叉路 题目大意&#xff1a; 有两个数轴&#xff0c;之间有n条线分别连接着两个数轴的点各一个&#xff0c;这些线可能会相交&#xff0c;问有多少条线没有和其他点相交 样例输入 4 -3 4 7 8 10 16 3 9样例输出 2数据范围限制 1<N<100000&#xff0c;-1…

.Net Core 环境下构建强大且易用的规则引擎

1. 引言1.1 为什么需要规则引擎在业务的早期时代&#xff0c;也许使用硬编码或者逻辑判断就可以满足要求。但随着业务的发展&#xff0c;越来越多的问题会暴露出来&#xff1a;逻辑复杂度带来的编码挑战&#xff0c;需求变更时改变逻辑可能会引起灾难重复性的需求必须可重用&am…

【最短路】【SPFA】单源最短路径 (luogu 3371)

单源最短路径 luogu 3371 题目大意&#xff1a; 求出一个点到其他点的最短路 原题&#xff1a; 题目背景 本题测试数据为随机数据&#xff0c;在考试中可能会出现构造数据让SPFA不通过&#xff0c;如有需要请移步 P4779。 题目描述 如题&#xff0c;给出一个有向图&…

在Windows 下如何使用 AspNetCore Api 和 consul

一、概念&#xff1a;什么是consul:Consul 是有多个组件组成的一个整体&#xff0c;作用和Eureka,Zookeeper相当&#xff0c;都是用来做服务的发现与治理。 Consul的特性&#xff1a;1、 服务的发现&#xff1a;consul可以把注册到其中的服务提供给使用者&#xff0c;也可以主动…

网络流及建模专题(下)

前言 不断更新中… 专题的(下)篇将介绍网络流的一些奇奇怪怪的应用和费用流有关的一些套路。 本专题暂时包含三道题&#xff1a; 洛谷P1251 餐巾计划问题: 费用流的基本应用 Trade Gym - 100212I: 使用网络流对图论中的边进行调整 codeforces 818G - Four Melodies: 费用…

CentOS 7.4 下 如何部署 AspNetCore 结合 consul

上篇我们讲到consul的概念&#xff0c;以及在WIN下如何使用&#xff1a; 在Windows 下如何使用 AspNetCore Api 和 consul步骤如下&#xff1a;1、安装虚拟机VM 2、下载安装 CentOS 7.4&#xff08;地址就不提供了&#xff09;这是安装示例&#xff1a; VM虚拟机安装CentOS 示例…

【SPFA】最优贸易(luogu 1073)

最优贸易 luogu 1073 题目大意&#xff1a; 有n个城市和m条线路连接着这些城市&#xff08;当编号为1时是有向&#xff0c;2时是无向&#xff09;&#xff0c;从1城市出发到n城市&#xff0c;每个城市都有固定的水晶球价格&#xff08;进价和售价一样&#xff09;&#xff0…

Razor Page Library:开发独立通用RPL(内嵌wwwroot资源文件夹)

Demo路径&#xff1a;https://github.com/yanshengjie/RPL.Demo1. IntroductionRazor Page Library 是ASP.NET Core 2.1引入的新类库项目&#xff0c;属于新特性之一&#xff0c;用于创建通用页面公用类库。也就意味着可以将多个Web项目中通用的Web页面提取出来&#xff0c;封装…

Problem H Rock Paper Scissors,FFT

题目 题目链接 题意 给出两段石头剪刀布的顺序SS和T" role="presentation" style="position: relative;">TT&#xff0c;其中TT要短一些,现在让你把T" role="presentation" style="position: relative;">TT往SS的…

.NET Core微服务之基于Ocelot实现API网关服务

一、啥是API网关&#xff1f;API 网关一般放到微服务的最前端&#xff0c;并且要让API 网关变成由应用所发起的每个请求的入口。这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式。以前的话&#xff0c;客户端不得不去请求微服务A&#xff08;假设为Customers&am…

[译]RabbitMQ教程C#版 - 发布订阅

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

用ASP.NET Core 2.1 建立规范的 REST API -- 缓存和并发

本文所需的一些预备知识可以看这里: 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 和 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 (2) 准备项目建立Richardson成熟度2级的POST、GET、PUT、PATCH、DELETE的RESTful API请看这里&#xff1a;用ASP.NET Core …

2017 SEERC Divide and Conquer 树上差分

题目 题目大意&#xff1a;给出两颗树的复合图(即这张图是由两颗树拼起来的)&#xff0c;询问最小割掉多少条边&#xff0c;可以使得图不联通&#xff0c;并输出方案数。 分析 我觉得这是一道很难的题目&#xff0c;因为比较难想&#xff0c;前提结论比较多。 首先我们需要…

青蛙跳荷叶

青蛙跳荷叶 题目大意&#xff1a; 有n个点&#xff0c;从1开始到跳完这些点&#xff0c;且每次的距离不能相等&#xff0c;一个点不能到多次 原题&#xff1a; 题目描述 从前&#xff0c;有一个小青蛙决定去荷叶上练习跳跃.现在有n个荷叶排成一排&#xff0c;小青蛙一开始…

基于 Consul 实现 MagicOnion(GRpc) 服务注册与发现

0.简介0.1 什么是 ConsulConsul是HashiCorp公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置。这里所谓的服务&#xff0c;不仅仅包括常用的 Api 这些服务&#xff0c;也包括软件开发过程当中所需要的诸如 Rpc、Redis、Mysql 等需要调用的资源。简而言之 Con…

【DFS】排排坐

排排坐 题目大意&#xff1a; 有n个方块&#xff0c;有一些是黑色&#xff0c;有一些是白色&#xff0c;可以点击一个方块使它和它旁边的方块反转颜色&#xff08;黑变白&#xff0c;白变黑&#xff09;&#xff0c;问最少要点多少次才能将方块 们 变成目标的方块们&#xff…

用ASP.NET Core 2.1 建立规范的 REST API -- 保护API和其它

预备知识: 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 (2) 准备项目建立成熟度2级的 API请看这里&#xff1a;用ASP.NET Core 2.0 建立规范的 REST API -- GET 和 POST, 用ASP.NET Core 2.0 建立规范的 REST AP…

华为资深工程师:码农很多,但程序员并不多......

“春节假期&#xff0c;与几位友人小聚&#xff0c;大家互道工作顺利、平安健康云云......期间一位驰骋商界多年的老友问&#xff1a;“你现在在华为做什么工作呀?”我很骄傲地说&#xff1a;”系统架构师“&#xff0c;可是他却愣了很久。但当我老婆在旁边补上一句“码农“时…