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

什么是REST

REST 是 Representational State Transfer 的缩写. 它是一种架构的风格, 这种风格基于一套预定义的规则, 这些规则描述了网络资源是如何定义和寻址的.

一个实现了REST这些规则的服务就叫做RESTful的服务.

最早是由Roy Fielding提出的.

RPC 风格

/getUsers/getUser?id=1/createUser/deleteUser?id=4/updateUser?name=dave

 

上面这些节点是针对User的CRUD操作. 

这种样式风格的web服务更倾向于叫做RPC风格的服务.

在RPC的世界里, 节点仅仅就是可以在远程被触发的函数, 而在REST的世界里, 节点就是实体, 也叫做资源.

REST的原则/约束

REST有6大原则/约束, 每一个原则都是对API有正面或负面影响的设计决定.

RESTful API 最关心的有这几方面: 性能, 可扩展性, 简洁性, 互操作性, 通讯可见性, 组件便携性和可靠性.

这些方面被封装在REST的6个原则里, 它们是: 

1. 客服端-服务端约束: 客户端和服务端是分离的, 它们可以独自的进化.

2. 无状态: 客户端和服务段的通信必须是无状态的, 状态应包含在请求里的. 也就是说请求里要包含服务端需要的所有的信息, 以便服务端可以理解请求并可以创造上下文.

3. 分层系统: 就像其它的软件架构一样, REST也需要分层结构, 但是不允许某层直接访问不相邻的层. 

4. 统一接口: 这里分为4点, 他们是: 资源标识符(URI), 资源的操作(也就是方法Method, HTTP动词), 自描述的响应(可以认为是媒体类型Media-Type), 以及状态管理(超媒体作为应用状态的引擎 HATEOAS, Hypermedia as the Engine of Application State).

5. 缓存: 缓存约束派生于无状态约束, 它要求从服务端返回的响应必须明确表明是可缓存的还是不可缓存的.

6. 按需编码: 这允许客户端可以从服务端访问特定的资源而无须知晓如何处理它们. 服务端可以扩展或自定义客户端的功能.

只有满足了这6个原则的系统才可以真正称得上是RESTful的, 其实大部分系统的RESTful API并不是RESTful的, 但这样并不代表这些API就不好, 利弊需要开发人员去衡量.

Richardson 成熟度模型

Richardson 成熟度模型代表着你的API是否足够成熟, 分为4个级别, 0代表最差, 3代表最好.

0级, 天花沼泽:

这里HTTP协议只是被用来进行远程交互, 协议的其余部分都用错了, 都是RPC风格的实现(例如SOAP, 尤其是使用WCF的时候).

例如:

POST (查询数据信息)
http://host/myapiPOST (创建数据)
http://host/myapi

 

1级, 资源:

这级里, 每个资源都映射到一个URI上了, 但是HTTP方法并没有正确的使用, 结果的复杂度不算太高.

例如这两个查询:

POST
http://host/api/authorsPOST
http://host/api/authors/{id}

 

2级, 动词:

正确使用了HTTP动词, 状态码也正确的使用了, 同时也去掉了不必要的变种.

例如:

GET
http://host/api/authors200 Ok (authors)
POST (author representation)
http://host/api/authors201 Created (author)


3级, 超媒体:

API支持超媒体作为应用状态的引擎 HATEOAS, Hypermedia as the Engine of Application State, 引入了可发现性.

例如:

GET
http://host/api/authors200 Ok (返回了authors 和 驱动应用程序的超链接)

 

介绍ASP.NET Core

略.

但是, 你需要知道以下概念: .NET Core, .NET Standard.

还需要会使用下列工具: .NET Core CLI, Visual Studio 2017/Visual Studio Code/Visual Studio for Mac

ASP.NET Core 支持创建Web API, 但并不是直接支持RESTful的 Web API.

 

ASP.NET Core的基本知识

这部分还是需要简单的介绍下, 如果已经会了, 请略过本文其余部分.

创建ASP.NET Core项目

打开VS2017, 选择ASP.NET Core Web Application项目模板, 写好名字, OK.

640?wx_fmt=png

 

选择空模板, OK:

640?wx_fmt=png

 

项目建立好了, 结果如下:

640?wx_fmt=png

然后我们看一下项目文件, 右键编辑MyRestful.Api:

640?wx_fmt=png

这里, SDK属性表示了我们使用的是哪个SDK, 而目标框架是.NET Core 2.0.

(提示: 如果需要指向多个目标框架的话可以使用TargetFrameworks元素, 注意多了个s)

 

看一下Program.cs:

640?wx_fmt=png

Main方法是程序的入口. 而Web的宿主是通过BuildWebHost函数来实例化的, 它调用了WebHost.CreateDefaultBuilder方法, 很明显这是一个建造者模式, 它最终会构建出一个web宿主.

调用WebHost.CreateDefaultBuilder会返回一个IWebHostBuilder, 它允许我们进行一些配置动作.

程序启动

UseStartup方法会注册一个类, 这个类负责配置整个程序的启动过程. 这里默认用的是Startup类.

Startup类有两个方法 ConfigureServices (这个可以没有) 和 Configure (这个必须有):

640?wx_fmt=png

在Configure方法里, 配置应该遵循Add/Use的风格样式, 首先定义需要什么, 然后定义如何使用它.

而在ConfigureServices方法里, 所有程序级的依赖项都可以在这里注册到默认的IoC容器里, 把它们添加到IServiceCollection即可.

Configure方法才是真正负责配置HTTP请求管道的方法, 并且运行时也需要它.

IApplicationBuilder的扩展方法Run会传递一个RequestDelegate, 其内部功能就是回写Hello World.

 

ASP.NET Core还允许我们按约定为指定环境建立单独的启动配置. 启动类可以通过这个函数定义UseStartup(startupAssemblyName: xxx); 运行时会在这个指定的组件查找叫做Startup, Startup[环境名]的类, 其中[环境名]就是ASPNETCORE_ENVIRONMENT这个环境变量的值. 如果能找到指定环境的类, 那么它将覆盖默认的启动类. 

例如 环境变量值如果是Developmen的话, 那么运行时就会尝试寻找Startup和StartupDevelopment类, 该约定在启动类里面的方法名上也有效, 环境特定的启动类里的两个方法分别是 Configure[环境名]和Configure[环境名]Services.

 

除了之前讲的Run方法外, IApplicationBuilder还有一个Use扩展方法.

Use扩展方法接受RequestDelegate作为参数来提供HttpContext, 同时接受也为下一层准备的RequestDelegate参数.

640?wx_fmt=png

需要注意的是, Run方法和Use方法定义的顺序非常重要, 运行时将会精确的按照创建的顺序来执行.

 

服务器

ASP.NET Core 服务器的作用是响应客户端发过来的请求, 这些请求会作为HttpContext传递进来. ASP.NET Core 内置两种服务器:

Kestrel, 它是跨平台的服务器, 基于Libuv.

HTTP.sys, 它是仅限Windows系统的服务器, 基于HTTP.sys内核驱动.

下面就是从客户端发请求到应用程序的流图:

640?wx_fmt=png

其中Kestrel可以作为一个独立进程自行托管, 也可以在IIS里. 但是还是建议使用IIS或Nginx等作为反向代理服务器. 在构建API或微服务时, 这些服务器可以作为网关使用, 因为它们会限制对外暴露的东西也可以更好的与现有系统集成, 所以它们会提供额外的防御层, 

使用反向代理服务器(IIS)之后的流图如下:

640?wx_fmt=png

让web宿主工作于IIS之后需要使用IWebHostBuilder的UseIISIntegration这个扩展方法.

除了内置的两种服务器, 您还可以使用自定义的服务器, 使用IWebHostBuilder的UserServer扩展方法, 它接受一个实现了IServer接口的实例, 您的自定义服务器需要实现该接口. 这里就不讲了.

 

中间件

在应用程序请求管道内装配的组件就是中间件, 它们负责处理通过管道的请求和响应.

在HTTP请求管道的上下文里, 中间件可以叫做请求委托, 它们是由Run, Map 和 Use 扩展方法共同组建而成的.

每个中间件可以在它被调用之前和之后执行可选的逻辑, 同时也可以决定该请求是否可以被送到管道的下一个中间件那里.

请求在中间件里的流图如下:

640?wx_fmt=png

看一下这个例子:

640?wx_fmt=png

如果我在浏览器地址输入 http://localhost:5000/return, 那么结果就是Returned!

如果输入 http://localhost:5000/end, 那么是The End.

如果输入 http://localhost:5000/xxx?value=1234, 结果是 the number is 1234

如果输入 http://localhost:5000/xxx?value=abcde, 结果是 Hello, the value is abcde!

 

注意: 应用程序管道里的请求委托(中间件)定义的顺序是非常重要的, 请求的时候按定义的顺序执行, 而响应的顺序正好相反.

 

中间件最好不要像上面一样写在Startup类里, 每个中间件应该放在单独的类里. 

我把上例中检查是否为数字的中间件写在一个单独的类里:

640?wx_fmt=png

这种中间件没有实现特定的接口或者继承特定类, 它更像是Duck Typing (你走起路来像个鸭子, 叫起来像个鸭子, 那么你就是个鸭子).

然后在Startup的Configure方法里调用app.UseMiddleware<NumberMiddleware>()即可:

640?wx_fmt=png

 

路由

在ASP.NET Core里,使用路由中间件RouterMiddleware来处理路由.

想要使用路由, 同样也是遵循 Add/Use 这个模式. 

首先在ConfigureServices方法里添加(Add):

640?wx_fmt=png

然后在Configure方法里使用(Use):

640?wx_fmt=png

UseRouter这个扩展方法可以接受IRouter或者Action<IRouterBuilder>作为参数.

例如:

640?wx_fmt=png

当发送 http://localhost:5000/ GET请求的时候, 返回 Default route.

当 GET http://localhost:5000/user/dave的时候, 返回 Hi dave

当 POST http://localhost:5000/user/dave的时候, 返回 Hi, posted name is dave

其中{name}, 是名为name的参数.

如果写成"user/{name}/{age:number}", 那么age这个参数的必须可以被解析为数值型.

而"user/{name}/{gender?}", 这里的gender参数可以没有.

 

Controller

HTTP请求通过管道最终到达Action并返回的流图如下:

640?wx_fmt=png

默认情况下Controller放在ASP.NET Core项目的Controllers目录下。

在ASP.NET Core项目里可以通过多种方式来创建Controller,当然最建议的方式还是通过继承AspNetCore.Mvc.Controller这个抽象类来建立Controller。

例如:

640?wx_fmt=png

上例中类名可以不是以Controller结尾。

 

还有其它的方式创建Controller,按约定类名以Controller结尾的POCO类也会被认为是Controller,例如:

640?wx_fmt=png

 

针对POCO类, 即使名称不是以Controller结尾,仍然可以把它作为Controller,这就需要在类上面添加 [Controller] 这个属性:

640?wx_fmt=png

 

如果某个类的名字以Controller结尾, 但是你不想把它当作Controller,那么就应该为该类标注 [NonController] 这个属性:

640?wx_fmt=png

 

实际上, 看源码就可以知道 Controller 继承于 ControllerBase:

640?wx_fmt=png

 

 而ControllerBase上面标注着 [Controller] 属性。

 

Action

在Controller里面,可以使用public修饰符来定义Action,通常会带有参数,可以返回任何类型,但是大多数情况下应该返回IActionResultAction的方法名要么是以HTTP的动词开头,要么是使用HTTP动词属性标签,包括:[HttpGet], [HttpPut], [HttpPost], [HttpDelete], [HttpHead], [HttpOptions], [HttpPatch].

例如:

640?wx_fmt=png

其中某个方法名如果恰好是以HTTP的动词开头,那么可以通过标注 [NonAction] 属性来表示这个方法不是Action。

通过继承Controller基类的方法来创建Controller还是有很多好处的,因为它提供了很多帮助方法,例如:Ok, NotFound, BadRequest等,它们分别对应HTTP的状态码 200, 404, 400;此外还有Redirect,LocalRedirect,RedirectToRoute,Json,File,Content等方法。

 

为MVC定义路由有两种方式:使用IRouteBuilder或者使用基于属性标签的路由。针对Rest,最好还是使用基于属性标签的方式。

路由属性标签可以标注在Controller或者Action方法上,例如:

640?wx_fmt=png

Controller类上标注的路由“api/[controller]”,其中[controller] 就代表该类的名字去掉结尾Controller的部分,也就是“api/person”。

在Controller上使用[Route]属性就定义了该Controller下所有Action的路由基地址,每个Action可以包含一个或者多个相对的路由模板(地址),这些路由模板可以在[Http...]中定义。但是如果使用 ~ 这个符号的话,该Action的地址将会是绝对路由地址,也就是覆盖了Controller定义的基路由。

 

实体绑定

传入的请求会映射到Action方法的参数,可以实原始数据类型也可以是复杂的类型例如Dto(data transfer object)或ViewModel。这个把Http请求绑定到参数的过程叫做实体绑定。

例如:

640?wx_fmt=png

 

其中id参数是定义在路由里的,而name参数在路由里没有,但是仍然可以从查询参数中把name参数映射出来。

注意路由参数和查询参数的区别,下面这个URL里val1和val2是查询参数,它们是在url的后边使用?和&分隔:

/product?val1=2&val2=10

 

而针对上面的Action,下面这个URL的路由参数id就是123:

/api/first/123

 

 

针对下面这个POST Action:

640?wx_fmt=png

我们可以通过几种方式为其传递类型为Person的参数。

可以使用查询参数:/api/people?id=1&name=Dave

如果POST Json数据:

640?wx_fmt=png

640?wx_fmt=png

那么在Action里面得到的参数person的属性值都是null。这是因为这样的原始数据是包含在请求的Body里面,为了解决这个问题,你需要告诉Action从哪里获取参数,针对这个例子就应该使用 [FromBody] 属性标签:

640?wx_fmt=png

如果提交的是表单数据,那么就应该使用[FromForm]:

640?wx_fmt=png

640?wx_fmt=png

其它的出处还有 [FromHeader], [FromRoute], [FromServices]等。

再看一个FromHeader的例子:

640?wx_fmt=png

 

640?wx_fmt=png

如果使用复杂类型Person来获取person参数好像不行,只能使用原始类型的吧?

 

实体验证

ASP.NET Core内置的实体验证是通过验证属性标签来实现的,大多数情况下这样会很方便。

例如:

640?wx_fmt=png

其中Display不是验证标签,但是通过它可以自定义属性的显式名称,在其它错误信息里可以使用{0}来引用该名称。

 

判断实体参数是否符合要求,可以检查ModelState.IsValid属性,这个属性也是由ControllerBase提供的,例如:

640?wx_fmt=png

发送一个请求:

640?wx_fmt=png

这是个不合理的参数,返回的是400 BadRequest,带着验证结果:

640?wx_fmt=png

 

尽管大多数情况西,验证属性标签都满足要求,但是有时候还是需要进行一些灵活的验证,你可以使用像FluentValidation这样的第三方库,也可以使用内置的方式来实现自定义验证。

ASP.NET Core内置支持两种方式来进行自定义验证:通过继承ValidationAttribute来创建自定义验证属性标签,或者让实体实现IValidatebleObject接口。

使用自定义验证属性标签:

640?wx_fmt=png

把该标签放到name属性上

640?wx_fmt=png

使用刚才的请求,其结果是:

640?wx_fmt=png

 

另一种方式,在Person类实现IValidatableObject接口

640?wx_fmt=png

但是我使用这种方法并不好用,不知道我哪里用错了!

 

过滤器

640?wx_fmt=png

和中间件一样,ASP.NET Core MVC的过滤器也可以在请求管道的特定阶段的之前或之后执行某些代码。过滤器还可以有子管道,子管道里面包含着其它过滤器。

过滤器和中间件的区别:中间件是应用程序级别的,它可以处理每个发送过来的请求;而过滤器是针对MVC的,它只会处理发往MVC的请求。

ASP.NET Core MVC的过滤器分为5类:

  • 授权过滤器,它是第一个运行的,它的作用就是判断HTTP Context中的用户是否拥有当前请求的权限,如果用户没有权限,那么它就会“短路”管道。

  • 资源过滤器,在授权过滤器后运行,在管道其它动作之前,和管道动作都结束后运行。它可以实现缓存或由于性能原因执行短路操作。它在实体绑定之前运行,所以它也可以对影响实体绑定。

  • Action过滤器,它在Action方法调用之前和之后立即执行,它可以操作传进Action的参数和返回的结果。

  • 异常过滤器,针对在写入响应Body之前发生的未处理的异常,它可以应用全局的策略,

  • 结果过滤器,它可以在每个Action结果执行之前和之后运行代码,但也只是在Action方法无错误的成功完成后才可以执行。

下图标明了这些过滤器在管道中是如何交互的:

640?wx_fmt=png

过滤器可以作为属性标签使用,或者也可以在Startup类里面进行全局注册。

例子:

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc.Filters;


namespace MyRestful.Api.Filters

{

    public class DefaultNameFilter: IActionFilter, IAsyncActionFilter

    {

        public void OnActionExecuting(ActionExecutingContext context)

        {

            context.ActionDescriptor.RouteValues["name"] = "Anonymous";

        }


        public void OnActionExecuted(ActionExecutedContext context)

        {

            context.HttpContext.Response.Headers["X-Name"] = context.ActionDescriptor.RouteValues["name"];

        }


        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

        {

            OnActionExecuting(context);

            var result = await next();

            OnActionExecuted(result);

        }

    }

}

全局注册,在Startup里:

public void ConfigureServices(IServiceCollection services)

        {

            services.AddMvc(options =>

            {

                options.Filters.Add<DefaultNameFilter>();

            });

        }

或者自定义一个属性标签,内部的代码是一样的:

using System;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc.Filters;


namespace MyRestful.Api.Filters

{

    public class DefaultUserNameFilterAttribute: Attribute, IActionFilter, IAsyncActionFilter

    {

        public void OnActionExecuting(ActionExecutingContext context)

        {

            context.ActionDescriptor.RouteValues["name"] = "Anonymous";

        }


        public void OnActionExecuted(ActionExecutedContext context)

        {

            context.HttpContext.Response.Headers["X-Name"] = context.ActionDescriptor.RouteValues["name"];

        }


        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

        {

            OnActionExecuting(context);

            var result = await next();

            OnActionExecuted(result);

        }

    }

}

然后把该标签用在Action方法上即可:

[DefaultUserNameFilter]

        [HttpGet("first/{id}")]

        public IActionResult FindFirstPerson(int id, string name)

        {

            return null;

        }


640?wx_fmt=png 

格式化响应结果

Action的结果最好使用IActionResult, 但也可以使用其他类型,例如IEnumerable<T>等。强制结果输出为特定的类型可以通过调用特定的方法来实现,例如JsonResponse就是输出JSON,ContentResponse就是输出文本。另外也可以使用[Produces(xxx)] 这个过滤器,它可以应用于全局,controller或者Action。

在REST服务里,有个词叫内容协商,它表示客户端通过Accept Header里的media-type来指定所需的结果格式。

ASP.NET Core MVC 默认实现并使用JSON格式化,但也支持其它格式,这需要在startup里面注册。

客户端浏览器可能在请求的Accept Headers里提供了多种的格式,但是ASP.NET Core MVC 默认是忽略浏览器的Accept Header的,并使用标准的输出格式。但是修改MvcOptions的RespectBrowserAcceptHeader值为true,可以改变这个行为:

640?wx_fmt=png

ASP.NET Core还提供了 XML 格式,可以在MvcOptions里面添加:

640?wx_fmt=png

 

今天先写到这,还没有切入正题。

原文地址: https://www.cnblogs.com/cgzl/p/9010978.html


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

640?wx_fmt=jpeg

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

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

相关文章

【图论】【最短路】【Dijkstra】最小花费(ssl 2206/luogu 1576)

最小花费 ssl 2206 luogu 1576 题目大意&#xff1a; 有n个人&#xff0c;他们之间有m对人可以相互{\color{red}相互}相互转账&#xff0c;但要收一定的税&#xff0c;求第x个人转给第y个人至少要多少钱 Description 在n个人中&#xff0c;某些人的银行账号之间可以互相转…

codeforces 939C Convenient For Everybody 简直羞耻

题解 这是一道大水题&#xff0c;然而我卡了1个半小时都没做出来&#xff0c;就是因为我搞反了时区的概念&#xff0c;必须挂出来&#xff0c;警示自己&#xff01;&#xff01;&#xff01; 首先明确时区的概念&#xff0c;如果一区为1时的时候&#xff0c;i区的本地时间为i时…

P2824-[HEOI2016/TJOI2016]排序【线段树,二分】

正题 题目链接:https://www.luogu.com.cn/problem/P2824 题目大意 nnn个数&#xff0c;每次将一个区间正序或者倒序排序&#xff0c;求最后位置ppp的数。 解题思路 思路确实巧妙 二分答案&#xff0c;定义大于midmidmid的数为1&#xff0c;小于midmidmid的数为2&#xff0c;…

【快速幂】小明解密码 (jzoj 2146)

小明解密码 题目大意 让你计算n^m的个位&#xff08;有t组数据&#xff09; 样例输入 2 3 4 4 5 样例输出 1 4 数据范围限制 对于30&#xff05;的数据&#xff0c;1≤t≤20&#xff0c;1≤n,m≤8 对于100&#xff05;的数据&#xff0c;1≤t≤1000&#xff0c;1≤…

使用ML.NET预测纽约出租车费

有了上一篇《.NET Core玩转机器学习》打基础&#xff0c;这一次我们以纽约出租车费的预测做为新的场景案例&#xff0c;来体验一下回归模型。场景概述我们的目标是预测纽约的出租车费&#xff0c;乍一看似乎仅仅取决于行程的距离和时长&#xff0c;然而纽约的出租车供应商对其他…

codeforces 932D Tree 倍增法+二分搜索

题面叙述 题目给出两种操作&#xff1a; 操作1是将一个权重为W的点加到树的某个节点下。 操作2是询问一个从R开始的序列的最长可能长度。 其中这个序列要这样找&#xff1a;从R开始&#xff0c;沿着祖先方向往上找&#xff0c;凡是权重大于等于当前序列最后一个点的要被选上…

P4430-小猴打架【perfer序列】

正题 题目链接:https://www.luogu.com.cn/problem/P4430 题目大意 nnn个点&#xff0c;每次不同联通块之间连边直到成为一颗树&#xff0c;求连边方式 解题思路 根据perferperferperfer序列&#xff0c;可以将一颗无根树变为一个长度n−2n-2n−2的序列&#xff0c;所以数量是…

【DP】小明在边塞(jzoj 2147)

小明在边塞 题目大意&#xff1a; 小明在&#xff08;1,1&#xff09;&#xff0c;他要去到&#xff08;n,m&#xff09;&#xff0c;当此点为1时&#xff0c;他的体力值-1&#xff0c;当此点为2时&#xff0c;他的体力值1&#xff0c;他只会向下或向右走&#xff08;就是往终…

使用ML.NET实现情感分析[新手篇]

在发出《.NET Core玩转机器学习》和《使用ML.NET预测纽约出租车费》两文后&#xff0c;相信读者朋友们即使在不明就里的情况下&#xff0c;也能按照内容顺利跑完代码运行出结果&#xff0c;对使用.NET Core和ML.NET&#xff0c;以及机器学习的效果有了初步感知。得到这些体验后…

codeforces 932E Team Work 高等数学求导、dp

题解 这是一道纯粹的数学求导题目。 首先我们先写出要求的公式。 ans∑r1nCnrrkans \sum_{r1}^{n} C_n^{r}r^kans∑r1n​Cnr​rk 乍一看&#xff0c;雾草好吓人&#xff0c;但是学过高等数学且稍有常识的人&#xff08;不是我&#xff09;可以看出&#xff0c;这个可以由某个…

【背包】小明逛超市(jzoj 2148)

小明逛超市 题目大意&#xff1a; 有一个大小为n的背包&#xff0c;和m件物品&#xff0c;每件物品都有自己的价格和价值还有个数&#xff0c;当个数为0时则为无限件&#xff0c;为1实则为1件&#xff0c;求最大的价值 样例输入 4 5 5 3 0 5 3 1 4 4 0 2 3 0 3 2 1 样…

P4093-[HEOI2016/TJOI2016]序列【CDQ分治,树状数组】

正题 题目链接:https://www.luogu.com.cn/problem/P4093 题目大意 nnn个数字&#xff0c;每次有一个数字可能和原序列不同&#xff0c;但最多只有一个不同。 求所有情况下都满足的最长不降子序列 解题思路 定义maximax_imaxi​表示位置iii的最大数&#xff0c;minimin_imini…

潘正磊:再过三五年 AI会变成开发人员的基本概念

在微软Build 2018开发者大会上&#xff0c;微软公司全球开发平台事业部的资深副总裁潘正磊&#xff08;Julia Liuson&#xff09;接受了界面记者在内的采访。潘正磊在微软西雅图总部带领一千多人组成的团队&#xff0c;微软的开发工具&#xff0c;包括Visual Studio&#xff0c…

codeforces 938D Buy a Ticket 有初值的Dijkstra、有趣的题目

题意 给出一些城市电影票的价格&#xff0c;以及城市之间交通的路费&#xff0c;询问每一个城市怎样才能花最少的钱看到电影&#xff08;看完电影还要再回来&#xff09;。 题解 这是一道不太难但是挺有趣的题目。 我们这样想&#xff0c;每个城市只需要查看票价比他更便宜的城…

P2480-[SDOI2010]古代猪文【中国剩余定理,Lucas定理】

大早上起来写题有助于醒脑&#xff08;其实是昨晚没睡好/kk 正题 题目链接:https://www.luogu.com.cn/problem/P2480 题目大意 给出nnn和ggg&#xff0c;求g∑d∣nCnd%999911659g^{\sum_{d|n}C_{n}^d}\% 999911659g∑d∣n​Cnd​%999911659 解题思路 因为999911659999911659…

qMISPlat入门级使用问题解答一

qMISPlat 2.0(业务配置开发平台) 自2018-4-18号正式开源以来&#xff0c;得到了众多.net core爱好者的关注&#xff0c;现将近半个月以来&#xff0c;大家反馈的一些使用配置方面的问题统一作如下解答。如你对qMISPlat不了解&#xff0c;请查看文章qMISPlat产品介绍。一、从码云…

【DP】小明游天界(zjoj 2149)

小明游天界 题目大意&#xff1a; 有 m个单位时间&#xff0c;让你从1走到n&#xff08;不能早到&#xff0c;不能晚到&#xff09;&#xff0c;要使经过的城市最多&#xff0c;若无法用m个单位时间到达n就输出-1 样例输入 5 12 4 1 2 5 1 4 3 4 2 4 2 5 5 样例输出 …

codeforces 935E Fafa and Ancient Mathematics 语法树、动态规划

题解 一道很有意思的题目&#xff0c;同时把动态规划和语法树结合起来&#xff0c;很有新意&#xff0c;思路我是想出来了&#xff0c;但是我的写法较为麻烦&#xff0c;从别人的submission中找了一个写起来简介的代码分享给大家。 看到表达式的形式&#xff0c;我们可以想到使…

P1429-平面最近点对(加强版)【分治】

正题 题目链接:https://www.luogu.com.cn/problem/P1429 题目大意 平面上nnn个点&#xff0c;求最近点对 解题思路 考虑分治求最近点对&#xff0c;首先将平行于yyy轴将平面穿过xxx左边的中位数分割成两半&#xff0c;现在最近点对有三种可能&#xff0c; 在分割线左边在分…

夏季(8 ~9)月 在深圳举办线下dotnet 大会 调查

随着微软 Build 2018的落幕&#xff0c;微软为.NET Core的应用规划了七大场景&#xff1a;计划今年夏季&#xff08;8 ~9&#xff09;月 在深圳举办线下dotnet 大会 &#xff0c;特此向大家做个调查。请大家抽出5分钟做下投票&#xff1a;顺便送大家一个福利&#xff1a;.NET社…