.NET 6 迁移到 Minimal API

.NET 6 迁移到 Minimal API

Intro

上次写了一篇 Minimal API Todo Sample,有些童鞋觉得 Minimal API 有些鸡肋,有一些功能的支持都不太好,但是其实 Host 之前支持的功能 Minimal API 大部分都是支持的,上次的 Todo Sample 完全没有使用 Controller 来使用 API,但也是可以使用 Controller 的,这一点从新的项目模板就能看的出来

New Template

使用 dotnet new webapi -n Net6TestApi 新的 ASP.NET Core Web API 模板项目结构如下创建新的项目,结构如下:

07a47e206dacb64525edb5b73fbbe350.png

主要变化的结构如下:

  • 默认启用了可空引用类型(<Nullable>enable</Nullable>)和隐式命名空间引用(<ImplicitUsings>enable</ImplicitUsings>)(可以参考项目文件的变化)

  • Program.cs

    • 和之前项目的相比,新的项目模板没有了 Startup,服务都在 Program.cs 中注册

    • Program 使用了 C# 9 中引入的顶级应用程序以及依赖 C# 10 带来的 Global Usings 的隐式命名空间引用

  • WeatherForecast/WeatherForecastController 使用 C# 10 的 File Scoped Namespace 新特性以及上述的隐式命名空间引用

    namespace Net6TestApi;public class WeatherForecast
    {public DateTime Date { get; set; }public int TemperatureC { get; set; }public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);public string? Summary { get; set; }
    }

如果想和之前的模板对比一下,可以使用 dotnet new webapi -o Net5TestApi -f net5.0 可以创建 .NET 5.0 的一个 API,因为 .NET 5.0 默认不支持 C# 10 新特性所以还是之前的项目模板

72271733b737044751550115fbb6fdfc.png

Migration

上面是一个模板的变化,对于已有的项目如何做项目升级呢?

以之前的一个 TodoApp 为例,升级到 .NET 6 之后向 Minimal API 做迁移的一个示例:

修改之前的代码是这样的:

Program.cs,比默认模板多了 Runtime metrics 的注册和数据库和默认用户的初始化

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Prometheus.DotNetRuntime;
using SparkTodo.API;
using SparkTodo.Models;DotNetRuntimeStatsBuilder.Customize().WithContentionStats().WithGcStats().WithThreadPoolStats().StartCollecting();var host = Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webHostBuilder =>{webHostBuilder.UseStartup<Startup>();}).ConfigureLogging(loggingBuilder =>{loggingBuilder.AddJsonConsole();}).Build();using (var serviceScope = host.Services.CreateScope())
{var dbContext = serviceScope.ServiceProvider.GetRequiredService<SparkTodoDbContext>();await dbContext.Database.EnsureCreatedAsync();//init Database,you can add your init data herevar userManager = serviceScope.ServiceProvider.GetRequiredService<UserManager<UserAccount>>();var email = "weihanli@outlook.com";if (await userManager.FindByEmailAsync(email) == null){await userManager.CreateAsync(new UserAccount{UserName = email,Email = email}, "Test1234");}
}await host.RunAsync();

Startup 代码如下:

using System;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Prometheus;
using SparkTodo.API.Services;
using SparkTodo.API.Swagger;
using SparkTodo.DataAccess;
using Swashbuckle.AspNetCore.SwaggerGen;namespace SparkTodo.API
{/// <summary>/// StartUp/// </summary>public class Startup{public Startup(IConfiguration configuration){Configuration = configuration.ReplacePlaceholders();}public IConfiguration Configuration { get; }public void ConfigureServices(IServiceCollection services){// Add framework services.services.AddDbContextPool<SparkTodo.Models.SparkTodoDbContext>(options => options.UseInMemoryDatabase("SparkTodo"));//services.AddIdentity<SparkTodo.Models.UserAccount, SparkTodo.Models.UserRole>(options =>{options.Password.RequireLowercase = false;options.Password.RequireUppercase = false;options.Password.RequireNonAlphanumeric = false;options.Password.RequiredUniqueChars = 0;options.User.RequireUniqueEmail = true;}).AddEntityFrameworkStores<SparkTodo.Models.SparkTodoDbContext>().AddDefaultTokenProviders();// Add JWT token validationvar secretKey = Configuration.GetAppSetting("SecretKey");var signingKey = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(secretKey));var tokenAudience = Configuration.GetAppSetting("TokenAudience");var tokenIssuer = Configuration.GetAppSetting("TokenIssuer");services.Configure<JWT.TokenOptions>(options =>{options.Audience = tokenAudience;options.Issuer = tokenIssuer;options.ValidFor = TimeSpan.FromHours(2);options.SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);});services.AddAuthentication(options =>{options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>{options.TokenValidationParameters = new TokenValidationParameters{// The signing key must match!ValidateIssuerSigningKey = true,IssuerSigningKey = signingKey,// Validate the JWT Issuer (iss) claimValidateIssuer = true,ValidIssuer = tokenIssuer,// Validate the JWT Audience (aud) claimValidateAudience = true,ValidAudience = tokenAudience,// Validate the token expiryValidateLifetime = true,// If you want to allow a certain amount of clock drift, set that here:ClockSkew = System.TimeSpan.FromMinutes(2)};});// Add MvcFrameworkservices.AddControllers();// Add api version// https://www.hanselman.com/blog/ASPNETCoreRESTfulWebAPIVersioningMadeEasy.aspxservices.AddApiVersioning(options =>{options.AssumeDefaultVersionWhenUnspecified = true;options.DefaultApiVersion = ApiVersion.Default;options.ReportApiVersions = true;});// swagger// https://stackoverflow.com/questions/58197244/swaggerui-with-netcore-3-0-bearer-token-authorizationservices.AddSwaggerGen(option =>{option.SwaggerDoc("spark todo", new OpenApiInfo{Version = "v1",Title = "SparkTodo API",Description = "API for SparkTodo",Contact = new OpenApiContact() { Name = "WeihanLi", Email = "weihanli@outlook.com" }});option.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "API V1" });option.SwaggerDoc("v2", new OpenApiInfo { Version = "v2", Title = "API V2" });option.DocInclusionPredicate((docName, apiDesc) =>{var versions = apiDesc.CustomAttributes().OfType<ApiVersionAttribute>().SelectMany(attr => attr.Versions);return versions.Any(v => $"v{v}" == docName);});option.OperationFilter<RemoveVersionParameterOperationFilter>();option.DocumentFilter<SetVersionInPathDocumentFilter>();// include document fileoption.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"), true);option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme(){Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",Name = "Authorization",In = ParameterLocation.Header,Type = SecuritySchemeType.ApiKey,});option.AddSecurityRequirement(new OpenApiSecurityRequirement{{ new OpenApiSecurityScheme{Reference = new OpenApiReference(){Id = "Bearer",Type = ReferenceType.SecurityScheme}}, Array.Empty<string>() }});});services.AddHealthChecks();// Add application services.services.AddSingleton<ITokenGenerator, TokenGenerator>();//Repositoryservices.RegisterAssemblyTypesAsImplementedInterfaces(t => t.Name.EndsWith("Repository"),ServiceLifetime.Scoped, typeof(IUserAccountRepository).Assembly);}public void Configure(IApplicationBuilder app){// Disable claimType transform, see details here https://stackoverflow.com/questions/39141310/jwttoken-claim-name-jwttokentypes-subject-resolved-to-claimtypes-nameidentifieJwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();// Emit dotnet runtime version to response headerapp.Use(async (context, next) =>{context.Response.Headers["DotNetVersion"] = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription;await next();});//Enable middleware to serve generated Swagger as a JSON endpoint.app.UseSwagger();//Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpointapp.UseSwaggerUI(option =>{option.SwaggerEndpoint("/swagger/v2/swagger.json", "V2 Docs");option.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs");option.RoutePrefix = string.Empty;option.DocumentTitle = "SparkTodo API";});app.UseRouting();app.UseCors(builder=>{builder.AllowAnyHeader().AllowAnyMethod().AllowCredentials().SetIsOriginAllowed(_=>true);});app.UseHttpMetrics();app.UseAuthentication();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapHealthChecks("/health");endpoints.MapMetrics();endpoints.MapControllers();});}}
}

使用 Minimal API 改造后是下面这样的:

DotNetRuntimeStatsBuilder.Customize().WithContentionStats().WithGcStats().WithThreadPoolStats().StartCollecting();var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddJsonConsole();// Add framework services.
builder.Services.AddDbContextPool<SparkTodo.Models.SparkTodoDbContext>(options => options.UseInMemoryDatabase("SparkTodo"));
//
builder.Services.AddIdentity<SparkTodo.Models.UserAccount, SparkTodo.Models.UserRole>(options =>
{options.Password.RequireLowercase = false;options.Password.RequireUppercase = false;options.Password.RequireNonAlphanumeric = false;options.Password.RequiredUniqueChars = 0;options.User.RequireUniqueEmail = true;
}).AddEntityFrameworkStores<SparkTodo.Models.SparkTodoDbContext>().AddDefaultTokenProviders();// Add JWT token validation
var secretKey = builder.Configuration.GetAppSetting("SecretKey");
var signingKey = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(secretKey));var tokenAudience = builder.Configuration.GetAppSetting("TokenAudience");
var tokenIssuer = builder.Configuration.GetAppSetting("TokenIssuer");
builder.Services.Configure<SparkTodo.API.JWT.TokenOptions>(options =>
{options.Audience = tokenAudience;options.Issuer = tokenIssuer;options.ValidFor = TimeSpan.FromHours(2);options.SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
});builder.Services.AddAuthentication(options =>
{options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>{options.TokenValidationParameters = new TokenValidationParameters{// The signing key must match!ValidateIssuerSigningKey = true,IssuerSigningKey = signingKey,// Validate the JWT Issuer (iss) claimValidateIssuer = true,ValidIssuer = tokenIssuer,// Validate the JWT Audience (aud) claimValidateAudience = true,ValidAudience = tokenAudience,// Validate the token expiryValidateLifetime = true,// If you want to allow a certain amount of clock drift, set that here:ClockSkew = System.TimeSpan.FromMinutes(2)};});// Add MvcFramework
builder.Services.AddControllers();
// Add api version
// https://www.hanselman.com/blog/ASPNETCoreRESTfulWebAPIVersioningMadeEasy.aspx
builder.Services.AddApiVersioning(options =>
{options.AssumeDefaultVersionWhenUnspecified = true;options.DefaultApiVersion = ApiVersion.Default;options.ReportApiVersions = true;
});
// swagger
// https://stackoverflow.com/questions/58197244/swaggerui-with-netcore-3-0-bearer-token-authorization
builder.Services.AddSwaggerGen(option =>
{option.SwaggerDoc("spark todo", new OpenApiInfo{Version = "v1",Title = "SparkTodo API",Description = "API for SparkTodo",Contact = new OpenApiContact() { Name = "WeihanLi", Email = "weihanli@outlook.com" }});option.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "API V1" });option.SwaggerDoc("v2", new OpenApiInfo { Version = "v2", Title = "API V2" });option.DocInclusionPredicate((docName, apiDesc) =>{var versions = apiDesc.CustomAttributes().OfType<ApiVersionAttribute>().SelectMany(attr => attr.Versions);return versions.Any(v => $"v{v}" == docName);});option.OperationFilter<RemoveVersionParameterOperationFilter>();option.DocumentFilter<SetVersionInPathDocumentFilter>();// include document fileoption.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"), true);option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme(){Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",Name = "Authorization",In = ParameterLocation.Header,Type = SecuritySchemeType.ApiKey,});option.AddSecurityRequirement(new OpenApiSecurityRequirement{{ new OpenApiSecurityScheme{Reference = new OpenApiReference(){Id = "Bearer",Type = ReferenceType.SecurityScheme}}, Array.Empty<string>() }});
});
builder.Services.AddHealthChecks();
// Add application services.
builder.Services.AddSingleton<ITokenGenerator, TokenGenerator>();
//Repository
builder.Services.RegisterAssemblyTypesAsImplementedInterfaces(t => t.Name.EndsWith("Repository"),ServiceLifetime.Scoped, typeof(IUserAccountRepository).Assembly);var app = builder.Build();// Disable claimType transform, see details here https://stackoverflow.com/questions/39141310/jwttoken-claim-name-jwttokentypes-subject-resolved-to-claimtypes-nameidentifie
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();// Emit dotnet runtime version to response header
app.Use(async (context, next) =>
{context.Response.Headers["DotNetVersion"] = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription;await next();
});//Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
//Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint
app.UseSwaggerUI(option =>
{option.SwaggerEndpoint("/swagger/v2/swagger.json", "V2 Docs");option.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs");option.RoutePrefix = string.Empty;option.DocumentTitle = "SparkTodo API";
});app.UseRouting();
app.UseCors(builder =>
{builder.AllowAnyHeader().AllowAnyMethod().AllowCredentials().SetIsOriginAllowed(_ => true);
});app.UseHttpMetrics();app.UseAuthentication();
app.UseAuthorization();app.MapHealthChecks("/health");
app.MapMetrics();
app.MapControllers();using (var serviceScope = app.Services.CreateScope())
{var dbContext = serviceScope.ServiceProvider.GetRequiredService<SparkTodoDbContext>();await dbContext.Database.EnsureCreatedAsync();//init Database,you can add your init data herevar userManager = serviceScope.ServiceProvider.GetRequiredService<UserManager<UserAccount>>();var email = "weihanli@outlook.com";if (await userManager.FindByEmailAsync(email) == null){await userManager.CreateAsync(new UserAccount{UserName = email,Email = email}, "Test1234");}
}
await app.RunAsync();

改造方法:

  • 原来 Program 里的 Host.CreateDefaultBuilder(args) 使用新的 var builder = WebApplication.CreateBuilder(args); 来代替

  • 原来 Program 里的 ConfigureLogging 使用 builder.Logging 来配置 builder.Logging.AddJsonConsole();

  • 原来 Program 里的 ConfigureAppConfiguration 使用 builder.Configuration.AddXxx 来配置 builder.Configuration.AddJsonFile("");

  • 原来 Startup 里的服务注册使用 builder.Services 来注册

  • 原来 Startup 里的配置是从构造器注入的,需要使用配置的话用 builder.Configuration 来代替

  • 原来 Startup 里中间件的配置,通过 var app = builder.Build(); 构建出来的 WebApplication 来注册

  • 原来 Program 里的 host.Run/host.RunAsync 需要改成 app.Run/app.RunAsync

More

Minimal API 会有一些限制,比如

  • 不能通过 builder.WebHost.UseStartup<Startup>() 通过 Startup 来注册服务和中间件的配置的

  • 不能通过 builder.Host.UseEnvironment/builder.Host.UseContentRoot/builder.WebHost.UseContentRoot/builder.WebHost.UseEnvironment/builder.WebHost.UseSetting 来配置 host 的一些配置

  • 现在的 WebApplication 实现了 IEndpointRouteBuilder,可以不用 UseEndpoints 来注册,比如可以直接使用 app.MapController() 代替 app.UseEndpoints(endpoints => endpoints.MapController())

更多可以参考 David 总结的一个迁移指南 https://gist.github.com/davidfowl/0e0372c3c1d895c3ce195ba983b1e03d

Minimal API 结合了原来的 Startup,不再有 Startup,但是原来的应用也可以不必迁移到 Minimal API,根据自己的需要进行选择

References

  • https://github.com/WeihanLi/SparkTodo/commit/d3e327405c0f151e89378e9c01acde4648a7812f

  • https://github.com/WeihanLi/SparkTodo

  • https://gist.github.com/davidfowl/0e0372c3c1d895c3ce195ba983b1e03d

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

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

相关文章

教你透彻了解红黑树

教你透彻了解红黑树 作者&#xff1a;July、saturnman 2010年12月29日本文参考&#xff1a;Google、算法导论、STL源码剖析、计算机程序设计艺术。本人声明&#xff1a;个人原创&#xff0c;转载请注明出处。推荐阅读&#xff1a;Left-Leaning Red-Black Trees, Dagstuhl Wor…

cass字体_不动产 准备工作 第一步: 管理CASS码

管理CASS码https://www.zhihu.com/video/1063850168960647168管理CASS码 功能概述&#xff1a;通过管理CASS码将不动产基础矢量数据分为房屋、房屋附属、其他设施三类&#xff0c;同时通过管理CASS码可以对建筑物面积计算规则进行自定义和统设、以及设置建筑物注记文本(和数据入…

lol修改服务器域名,LOL历史转区用户解冻大区官网自助系统地址 新版申请解冻账号网址...

原标题&#xff1a;LOL历史转区用户解冻大区官网自助系统地址 新版申请解冻账号网址英雄联盟在9月1日正式上线了历史转区用户解冻服务&#xff0c;因转区导致冻结账号的玩家可以在这边申请解冻了&#xff0c;很多玩家还不清楚申请的地址在哪&#xff0c;下面就来为大家详细的介…

c语言浮点型常量表示平均数_小白基础知识必备|| 整型常量与进制间的转换

一、C语言关键字C语言的关键字共有32个&#xff0c;根据关键字的作用&#xff0c;可分为数据类型关键字、控制语句关键字、存储类型关键字和其它关键字四类。数值类型关键字(12个)void、char、short、int、long、float、double、signed、unsigned、struct、enum、union控制语句…

中国代工厂的困惑:把大牌t恤卖到99块3件,还会有人买吗?

▲ 点击查看“很多人都知道大牌有溢价但是不知道大牌溢价逼近900%打个比方一件1000块的T恤&#xff0c;T恤成本如果是100那么剩下的900&#xff0c;算是买了个大牌logo”这是我们上个月去到的一家中国代工厂工厂内部人员向我们透露的他说&#xff0c;其实无论是纪梵希、爱马仕、…

.NET 排序 Array.SortT 实现分析

System.Array.Sort<T> 是.NET内置的排序方法, 灵活且高效, 大家都学过一些排序算法&#xff0c;比如冒泡排序,插入排序,堆排序等&#xff0c;不过你知道这个方法背后使用了什么排序算法吗?先说结果, 实际上 Array.Sort 不止使用了一种排序算法, 为了保证不同的数据量的排…

联想电脑如何添加无线网络连接服务器,安装英特尔MYWIFI的操作步骤

适用范围:(1)操作系统&#xff1a;仅支持VISTA /WINDOWS 7&#xff0c;不支持WINDOWS XP/2003/2000&#xff1b;(2)硬件&#xff1a;INTEL MY WIFI支持INTEL 5100以及以上无线网卡&#xff0c;非INTEL无线网卡不支持。知识点分析:英特尔的MY WIFI技术是一项针对笔记本电脑无线网…

假如把女生比作一种水果

1 和睡相不好的人一起睡觉是什么体验&#xff1f;2 箱子里的是我方输出&#xff0c;外面的是对方打野3 女儿问爸爸小时候都玩什么&#xff0c;于是爸爸给她做了这个。。4 推上一网友随手拍到的照片&#xff0c;就好像是三张图片拼起来的一样。5 一位台湾艺用解剖学老师的硬核授…

ai怎么调界面大小_科研论文作图系列-从PPT到AI (一)

这是“投必得学术”推送的第44篇文章&#xff0c;专注科研技能和资讯分享&#xff01;关注“投必得学术”&#xff0c;可以看到我们所有干货和资讯&#xff01;导语&#xff1a;之前的推送中&#xff0c;小编给大家介绍过几款科研作图软件&#xff0c;包括统计分析软件Origin和…

讲师征集| .NET Conf China 2021正式启动!

去年年初疫情突袭武汉&#xff0c;打得我们措手不及在众多 .NET 开发者们的殷切期盼声中一场轰动极客圈的技术狂欢趴毅然在苏州盛大开启、圆满落幕&#xff01;我们坚信&#xff0c;你还记忆犹新……▽因为&#xff0c;TA 是 .NET 5.0 发布的”里程碑“线上线下轮番轰炸的技术干…

【Android游戏开发十一】手把手让你爱上Android sdk自带“9妹”

本站文章均为 李华明Himi 原创,转载务必在明显处注明&#xff1a; 转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/321.html 前几天群成员讨论过关于9patch的工具【我比较喜欢喊它9妹子&#xff0c;西西(*^_^*)】、然后研究了一下&#xff0c;比较…

为什么PostgreSQL比MongoDB还快之完结篇(深挖单点索引查询)

之前两篇测试中发现&#xff1a;单点索引查询中PostgreSQL的速度是MongoDB(WiredTiger引擎)的4倍。http://blog.chinaunix.net/xmlrpc.php?rblog/article&uid20726500&id4960138http://blog.chinaunix.net/xmlrpc.php?rblog/article&uid20726500&id4981629虽…

ajax和spa的区别,在XX团上消费过一次不正规的Spa,现在过来两个月公安局打电话叫我过去...

咨询我帮助人数&#xff1a;36021721.公安局打电话来的原因比较多&#xff0c;具体需要根据电话的内容进行分析。而且公安局的范围比较大&#xff0c;涉及到的部门比较多&#xff0c;每个部门负责处理各自的工作问题&#xff0c;有民事的&#xff0c;也有刑事的。有派出所的&am…

centos7 iptables 端口转发 保存_iptables 防火墙

目录&#xff1a;yum 在线安装yum卸载安装包rpm 卸载yum安装rpm离线安装利用 Downloadonly 插件下载 RPM 软件包及其所有依赖包使用 Yumdownloader 工具来下载 RPM 软件包及其所有依赖包yum 在线安装CentOS7默认的防火墙不是iptables,而是firewalle.yum卸载安装包yum remove to…

日本惊现神操作!偷偷研究飞刀方程致使厕所爆炸......

欢快如厕为何大声惨叫前几天&#xff0c;竟然有模友私信超模君&#xff0c;说这是不是真的。网友私信截图WTF&#xff01;数学史上就有一道“奇葩的”难题&#xff0c;是历代数学家们在厕所里解决的。厕所冥想1917年&#xff0c;为了给日本武士增添生活趣味&#xff0c;数学家挂…

抓取手机https_python爬虫入门02:教你通过 Fiddler 进行手机抓包

哟~哟~哟~hi起来everybody今天要说说怎么在我们的手机抓包通过python爬虫入门01&#xff1a;教你在 Chrome 浏览器轻松抓包我们知道了 HTTP 的请求方式以及在 Chrome 中摸清了一些套路但是除了对数据进行解析之外有时候我们想对请求的数据或者响应的数据进行篡改怎么做呢&#…

BeetleX进程服务管理组件应用

有些时候需要在程序中启动和管理其他应用进程&#xff0c;当碰到这样的需求的时候可以通过Process对象来完成&#xff1b;为了让使用和管理更方便在这基础上封装 了BeetleX.ServicesProcess组件&#xff0c;通过组件的管理中心让进程操作更方便&#xff0c;同时还集成了Web套件…

升级总代分享思路_桃生企业至尊七郎瓷砖新展厅全新升级惊艳亮相

桃生企业至尊七郎瓷砖新展厅惊艳亮相&#xff0c;将艺术和时尚完美融合&#xff0c;即将成为晋江天工建材城的新地标&#xff01;2020年桃生企业逆流升级进行中&#xff0c;全新展厅即将揭幕&#xff01;全新空间 对话年轻轻奢于行&#xff0c;优雅于里&#xff0c;全新一楼的…

烧脑又过瘾!关于c²= b² + a²,你不知道的N个事实

全世界只有3.14 % 的人关注了爆炸吧知识勾股定理你真的懂吗一般人看来&#xff0c;勾股定理只存在于特定的三角形或几何图形中。但实际上&#xff0c;绝大多数人都小看了这条有2600年历史的公式&#xff0c;很多看似不可能的图形&#xff0c;只要涉及到了平方数&#xff0c;勾股…

[snmp++]读取cisco路由交换机信息[一] - 环境搭建

首先从网上下载gn3这个摸拟器以及cisco路由器的bin. 如图&#xff0c;下面的clouds里添加本地连接&#xff0c;这样表示路由器与本机的网卡桥接。即在R2里的接口设置一个与本机的IP地址同一网段。这样局域网的机就可以与R2通信 R2的配置如下 snmp-server community public RO 读…