NET Core面试题
说说显示实现接口和隐式实现接口的区别。
隐式接口实现: 如果类或者结构要实现的是单个接口,可以使用隐式实现。
显式接口实现: 如果类或者结构继承了多个接口,那么接口中相同名称成员就要显式实现。显示实现是
通过使用接口的完全限定名来实现接口成员的。
使用显式接口成员执行体通常有两个目的:
1、显式接口成员执行体不能通过类的实例进行访问,这就 可以从公有接口中把接口的实现部分单
独分离开。如果一个类只在内部使用该接口,而类的使用者不会直接使用到该接口,这种显式接口成员
执行体就可以起到作用。
2、 显式接口成员执行体避免了接口成员之间因为同名而发生混淆。如果一个类希望对名称和返回类型
相同的接口成员采用不同的实现方式,这就必须要使用到显式接口成员执行体。 如果没有显式接口成员
执行体,那么对于名称和返回类型不同的接口成员,类也无法进行实现。
//约定接口
interface ISkill
{
void Flying();
}
//隐式实现ISkill接口
public class Bird: ISkill
{
public void Flying()
{
}
}
//第一种调用方式
Bird bird = new Bird();
bird.Flying();
//第二种调用方式
ISkill secondBrid = new Bird();
secondBrid.Flying();
//用类和接口都可以调用Flying方法
//约定两个接口
interface InterfaceA
{
void Say();
}
interface InterfaceB
{
void Say();
}
//继承
class Person:InterfaceA, InterfaceB
{
void InterfaceA.Say()
{
Console.WriteLine("helloA");
}
void InterfaceB.Say()
{
Console.WriteLine("helloB");
}
}
//访问形式
class Program
{
static void Main(string[] args)
{
InterfaceA p = new Person();
p.Say();
InterfaceB p2 = new Person();
p2.Say();
}
}
// 显示实现只能通过对应的接口访问对应的接口内的方法。用实现类去访问时访问不到的。
说说file访问修饰的作用。
.NET7到来时,C#11中添加了file访问修饰符。就是文件的意思,file是只能用来定义类型的访问修饰 符,不能定义类型中的类成员,即使嵌套类也不可以。file是用来定义使用范围最小的类型访问修饰符, 只限于在当前文件中,其他类型的成员内访问。
file基本的使用场景是,当需要一个类型时,但又不想这个类型的使用范围延伸到外部,所以就在当 前.cs文件定义一个file访问修饰符的类型,仅限于当前文件中的类型成员内部封装并访问。
public class Product {
public string ? Name {
get;
set;
}
public decimal PurchasePrice {
get;
set;
}
public void PrintSalesProduct() {
var salesPrice = new SalesPrice {
RetailPrice = PurchasePrice * 1.5 m, WholesalePrice = PurchasePrice * 1.2 m
};
Console.WriteLine($ "Name:{Name},{salesPrice}");
}
}
file record SalesPrice {
public decimal RetailPrice {
get;
set;
}
public decimal WholesalePrice {
get;
set;
}
}
说说什么是原始字符串。
C# 11 引入了原始字符串特性,允许用户利用原始字符串在代码中插入大量的无需转移的文本,方便开发者在代码中以字符串的方式塞入代码文本等。
原始字符串需要被至少三个 " 包裹,例如 """ 和 """"" 等等,前后的引号数量要相等。
另外,原始字符串的缩进由后面引号的位置来确定
例如:
此时 str 是:带有换行符的字符串
{
string str = """
hello
world
""";
Console.WriteLine(str);
}
此时 str 是:带有换行符,且第二行有空格的字符串
{
var str = """"
hello
world
"""";
Console.WriteLine(str);
}
可以直接定义JSON格式
{
//可以直接定义JSON格式
var json = """"
{
"a": 1,
"b": {
"c": "hello",
"d": "world"
},
"c": [1, 2, 3, 4, 5]
}
"""";
Console.WriteLine(json);
object obj= Newtonsoft.Json.JsonConvert.DeserializeObject<object>(json);
Hashtable tb = Newtonsoft.Json.JsonConvert.DeserializeObject<Hashtable>(json);
}
可以直接定义JSON格式
{
int age= 37;
string? jsonResult= $$"""
{
"Id":123,
"Name":"Richard",
"Age":"{{age}}"
}
""";
}
C#10 中struct有什么改进?
主要在于支持了无参数构造函数的改进,在C# 10之前,约束了不能有无参数的构造函数,现在在C#10 方法了这一约束;
public struct Teaach
{
public Teaach(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
说说C#10中Lambda表达式的新特点
在之前的版本中我们是需要显式声明委托类型,如上述被注释的代码,在 C# 10 就可以直接使用 var 来声明由编译器去推断委托的类型
// Func<int> func = () => 1;
var func = () => 1;
// Func<string> func2 = ()=>"Hello";
var func2 = () => "Hello";
我们可以在指定输入参数类型的时候,可以设置 ref / out / int 来表示一个值类型的引用传递,示例如
下
var refFunc = (ref int x) => { x++; };
var outFunc = (out int x) => { x = -1; };
var inFunc = (in int x) => { };
var num = 1;
refFunc(ref num);
Console.WriteLine(num);
outFunc(out num);
Console.WriteLine(num);
C# 10 的委托可以指定返回类型,如下:
// return type
var lambdaWithReturnValue0 = int? () => null;
// return type and input type
var lambdaWithReturnValue1 = int? (string s)
=> string.IsNullOrEmpty(s) ? 1 : null;
// Func<bool, object>
var choose = object (bool b) => b ? 1 : "two";
对于能够推断出类型的方法,我们也可以使用 var 来声明委托,示例如下
// Action<string> func3 = LocalMethod;
var func3 = LocalMethod;
void LocalMethod(string a)
{
Console.WriteLine(a);
}
var checkFunc = string.IsNullOrEmpty;
var read = Console.Read;
Action<string> write = Console.Write;
现在我们可以在 Lambda 表达式中指定 Attribute
var parse3 =[Description("Lambda attribute")](string s) => int.Parse(s);
var choose3 =[Description("Lambda attribute1")]object (bool b) => b ? 1 : "two";
说说对于泛型特性的理解。
泛型:不确定的类型,声明时不确定类型,调用时确定类型。可以支持一个类、方法、委托、接口等 类 支持不同类型的需求;那么对于泛型的支持;
C# 10 推广了特性,使得特性可以用泛型,如下例:
public sealed class SomeAttribute<T> : Attribute
{
}
在使用的时候:
[SomeAttribute<int>]
class A { }
[SomeAttribute<string>]
class B { }
说说在ASP.NET Core7中,依赖注入中的方法注入需要注意什么?
在MinimalAPI 或者是控制器中的方法中,如果需要支持注入,因为注入的对象和方法的参数是写在一起 的。会出现系统无法识别这里写的参数究竟是要注入,还是调用方传入的参数。那么如果明确那个参数 是要通过注入(也就是说通过IOC容器来创建),就需要给这个参数标记一个特性【FromServices】,指 定当前这个参数是来自于IOC容器,也就是注入进来的。
说说ASP.NET Core7 限流中间件。
实操如下:
安装.NET 7.0 SDK
通过nuget包安装Microsoft.AspNetCore.RateLimiting
创建.NET7网站应用,注册中间件
可以根据不同资源不同限制并发数,/api前缀的资源租约数2,等待队列长度为2,其他默认租约数1,队列长度1。
app.UseRateLimiter(new RateLimiterOptions()
{
// 触发限流的响应码
DefaultRejectionStatusCode = 500,
OnRejected = async (ctx, rateLimitLease) =>
{
// 触发限流回调处理
},
Limiter = PartitionedRateLimiter.Create<HttpContext, string>(resource =>
{
if (resource.Request.Path.StartsWithSegments("/api"))
{
return RateLimitPartition.CreateConcurrencyLimiter("WebApiLimiter", _ => new ConcurrencyLimiterOptions(2,QueueProcessingOrder.NewestFirst, 2));
}
else
{
return RateLimitPartition.CreateConcurrencyLimiter("DefaultLimiter",
_ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1));
}
})
});
说说Record关键字的用法
可以用来简单声明一个类:
record People
{
public string Name { get; init; }
public int Age { get; init; }
}
上面是声明一个类
下面的声明也是声明一个类,和上面的一样;不需要使用大括号来执行属性;
record People2(string Name, int Age);
这里的示例,用 record 声明了两个 实体,第二个 实体 声明的时候使用了简化的写法,record People2(string Name, int Age); 这样的声明意味着,构造方法有两个参数,分别是 string Name 和 int Age,并对应着两个属性,属性的声明方式和 People 一样 public string Name { get; init; } 都是一个get 一个 init,对于 record 支持一个 with 表达式,来修改某几个属性的值,这对于有很多属性都相同的场景来说是及其方便的;
说说 Minimal API的特点,和普通API有什么区别?
Minimal API翻译过来:极简Api或者最小Api,从名字上就可以理解。 Minimal API意在去掉过多的流 程。相比于普通的Webapi,在HttpContext的处理流程中,减少了处理的步骤,没有MVC的流程,在中间 件的位置处理了请求;减少了处理的步骤,减少了计算机的资源消耗,提高性能。当然在功能的支持上 也有部分是少于普通 的.NET Core WebApi的。
说说你知道的ORM框架?
EntityFramework6
EntityFrameworkCore
SqlSugar
FreeSql
Dapper
DosORM
等等~~
说说对SaveChanges的理解。
SaveChanges是以Context为维度的一次提交,对于数据库操作的一切动作,只要是在同一个Context实 例,所有的操作,在调用SaveChanges方法后,统一体现到数据库中去;
说说对EFCore中EntityState的理解?
因为EFCore对于数据库的所有操作都是通过上下文DbContext来完成的,且是通过SaveChanges方法统 一落实到数据库中去的;
EntityState是EFCore 在对数据库操作增删改的时候,记录当前被操作的数据对 象和Context的关系,针对与不同的操作,对应的一个状态信息,一共五种状态; 一共五种:
Detached = 0, 当前对象和context没有任何关系,没有被上下文跟踪
Unchanged=1, 当前对象被context跟踪,数据没有做任何修改
Deleted=2, 当前对象被context跟踪,且标记是数据删除,调用SaveChanges后将会从数据中删 除;
Modified=3, 当前对象被context跟踪,且有属性数据被修改过,调用SaveChanges后将会从数据中 修改;
Added=4 当前对象被context跟踪,且数据并没有存在数据库中,调用SaveChanges后将会新增 到数据库中去;
说说什么是导航属性和引用属性?
实体框架 中的导航属性提供了一种在两个实体类型之间导航关联的方法。 导航属性在概念模型中由 NavigationProperty 元素 (CSDL) 定义。 针对对象参与到其中的每个关系,各对象均可以具有导航属性。 使用导航属性,您可以在两个方向上导航和管理关系,如果重数为一或者零或一,则返回 EntityReference,或者如果重数为多个,则返回 EntityCollection。 也可以选择单向导航,这种情况下 可以删除导航属性。
说说EFCore7 中有哪些新功能?
JSON资料行
查询JSON资料行
ExecuteUpdate 和 ExecuteDelete (大量更新)
更快速的 SaveChanges
EFCore有几种配置映射方式?
两种:
1.特性映射
2.通过DbContext中的 OnModelCreating 方法来配置映射;
ASP.NET Core管道里面的Map拓展有什么作用?
可以针对不同的路径添加不同的中间件。
如何从.NET Framewok升级到ASP.NET Core7?
没有办法直接升级,因为是两个完全不相同的平台,但是C#语法差不多。
如果要升级,需要考虑的要点如下:
1、平台更换
2、依赖框架的变化,需要和之前的框架做对比。
3、新平台对于一些新写法尝试Option模式等等
说说.NET7中 _ViewImports文件的作用?
在.NET7中可以支持组件化编程,定义的各种组件,在项目中使用的时候,需要在_ViewImports文件中引入进来。
什么是Razor页面?
是ASP.NET Core中支持ASP网页表格的一种开发模型。@page 作为页面的起始标志。。 Stringbulider的使用, 好制定合适的容量值,否则优于默认值容量不足而频繁的进行内存分
说说.NET5中 __ViewStart文件的作用?
在控制器在返回视图的时候,开始替换视图引擎的时候,从_ViewStart.cshtml 开始,来初始化展示的视图界面;
如何在Razor页面中实现数据模型绑定?
如何在Controller中注入service?
在Config services方法中配置这个service。 在controller的构造函数中,添加这个依赖注入。
描述一下依赖注入后的服务生命周期?
在ASP.NET Core中,我们不需要关心如何释放这些服务, 因为系统会帮我们释放掉。有三种服务的生命周期。
单实例服务, 通过add singleton方法来添加。在注册时即创建服务, 在随后的请求中都使用这一个服务。
短暂服务, 通过add transient方法来添加。是一种轻量级的服务,用于无状态服务的操作。
作用域服务,一个新的请求会创建一个服务实例。使用add scoped方法来添加。
ASP.NET Core跟ASP.NET比较有哪些更好的地方?
第一是跨平台,它可以运行在三大操作系统上面,windows, Linux和MAC。
第二是对架构本身安装没有依赖,因为所有的依赖都跟程序本身在一起。
第三是ASP.NET Core处理请求的效率更高,能够处理更多的请求。
第四是ASP.NET Core有更多的安装配置方法。
说说ASP.NET Core内置容器的特点?
ASP.NET Core内置容器IServiceCollection,只支持构造函数注入;支持三种声明周期:单例、瞬时、 Scoped三种声明周期管理;
ASP.NET Core中如何读取静态文件?
可以通过中间件UseStaticFiles来配置读取静态文件;
//示例:要访问D盘的MyStaticFiles文件夹下的images文件夹下的banner1.svg问件该如何呢?
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider("D:/MyStaticFiles"),
RequestPath = "/StaticFiles"
});
}
//html文件
<img src="~/StaticFiles/images/banner1.svg" alt="pic"/>
ASP.NET Core项目如何设置IP地址和端口号?
可以使用Properties文件夹下的launchSettings配置文件来配置不同的启动方式的时候,分别配置IP和端口号。
//launchSettings.json
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:8088/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Hx.USORST.CustomerStock.WebApi": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:8088"
}
}
}
ASP.NET Core项目中,wwwroot文件夹内包含什么内容?
包含了css、js、js库、字体文件
如何理解C#10 中全局的using?
using 指令简化了您使用命名空间的方式。C# 10 包括一个新的全局 using 指令和隐式 usings,以减少您需要在每个文件顶部指定的 usings 数量。
全局 using 指令:如果关键字 global 出现在 using 指令之前,则 using 适用于整个项目。
隐式 usings:隐式 usings 功能会自动为您正在构建的项目类型添加通用的全局 using 指令。要启用隐式 usings,请在 .csproj 文件中设置 ImplicitUsings 属性
NET6 中中间件的底层实现和.NET5中间件的区别?
从底层实现没有太大的区别,都是委托的多层嵌套,实现中间件的组装,在.NET6中提供了更多的重载可以来调用;都是基于底层还是转换成委托的多层嵌套式。
谈谈对ASP.NET Core kestrel的理解?
A、初识Kestrel
首先,Kestrel是一个跨平台的Web服务器,支持运行在Windows、macOS、Linux等操作系统中。Kestrel支持一下使用场景:
HTTPS
Opaque upgrade used to enable WebSockets(启用WebSocket情况下的不透明升级)
Unix sockets for high performance behind Nginx(Nginx高性能模式下的Unix套接字)
HTTP2(不支持macOS)
Kestrel支持运行在所有.NET 支持的平台和版本之上。
B、Kestrel主要有两种使用模式:
- Kestrel直接作为Web服务器,直接接收并处理各类Http请求:
- 与各类反向代理服务器(例如Nginx、Apache、IIS)配合使用,反向代理服务器接收Http请求,将这些请求转发到Kestrel Web服务器
C、使用反向代理服务器的好处有哪些呢?
对外暴露有限的HTTP服务
更加安全,反向代理服务器做了一层过滤、防护和转发
通过反向代理服务器实现负载均衡和动态请求分发路由
减少域名使用,降低WAF防火墙防护成本
安全通信 (HTTPS) 配置,HTTPS转HTTP,仅反向代理服务器需要 X.509 证书,并且该服务器可使用普通 HTTP 协议与内部网络的应用服务器通信。
//Kestrel配置项
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
//修改服务器侦听的IP地址、主机地址以及使用的端口号
webBuilder.UseUrls("http://*:5000;http://localhost:5001;https://hostname: 5002");
webBuilder.ConfigureKestrel((hostingContext, options) => {
//是否每个HTTP响应都要有Header
//默认为true
options.AddServerHeader = false;
//设置监听的地址和端口
options.Listen(IPAddress.Loopback, 6000);
options.Listen(IPAddress.Loopback, 6001);
//设置启用HTTPS并设置SSL证书
options.Listen(IPAddress.Loopback, 6002, listenOptions => {
listenOptions.UseHttps("ssl证书文件.pfx", "ssl证书文件密码");
});
});
})
.ConfigureKestrel(options =>
{
//设置监听配置
options.Listen(IPAddress.Any, 5002,listenOptions =>
{
//设置HTTP协议,启用HTTP2
listenOptions.Protocols = HttpProtocols.Http2;
});
});
}
谈谈对Autofac的理解?
Autofac是一个IOC容器,支持三种类型的DI依赖注入,配置文件配置映射关系,支持AOP扩展定制; 在ASP.NET Core的使用步骤如下:
1.Nuget引入Autofac程序集
2.在Program类中的CreateHostBuilder方法中,通过.UseServiceProviderFactory(new AutofacServiceProviderFactory())替换容器工厂,把容器替换到框架中;
3.在StartUp中增加ConfigureContainer方法,用来配置映射关系
public void ConfigureContainer(ContainerBuilder builder)
{
}
//使用了Autofac以后,在IServiceCollection中注入的服务,也能生效;因为Autofac是先接受了所有的来自于IServiceCollection的服务映射后,再去读取ConfigureContainer方法中配置的映射;
4.就可以在控制器中配置构造函数注入了
说说在Linux系统部署ASP.NET Core项目的步骤。
a. 准备Linux系统
b.安装ASP.NET Core 的运行时环境(类似于人类生存需要空气和水,那么ASP.NET Core程序运行也需要符合它运行的的环境)
c.发布ASP.NET Core 项目(可以直接发布到Linux上去,也可以发布成文件系统,然后上传)
d.上传到Linux系统
e. 进入到发布程序的根目录,执行命令:
dotnet run --urls=http://Linux系统的Ip:端口号
说说热重载是什么。
热重载由“编辑并继续”,在不需要停止在代码断点或者重启应用程序的情况下,就可以对代码进行修 改,并可以立即看到代码修改的效果。修改代码后,点击Vs 上的红色火苗按钮即可。
如何理解鉴权和授权两个词。
鉴权:确定来来访者是谁,解析来访者携带的信息,记录来访着的信息;
授权:鉴权以后,通过来访者的信息内容来分辨是否允许本次返回本次要访问的资源;如果在鉴权步骤 没有解析到用户信息,在授权阶段就会返回401,如果解析到了用户信息,在授权阶段通过用户信息来 判断的时候。用户不具备访问资源的权限,返回403.
说说.NET7包含了几大方向的开发?
共8大方向:
- WEB:网站开发
- Mobile:手机端开发
- Desktop:桌面开发
- Microservices:微服务
- Cloud:云原生开发
- Machin Learning:人工智能
- Game Development:游戏开发
- Internet of Things:物联网开发
如何理解云原生?
云原生最大的价值和愿景,就是认为未来的软件,会从诞生起就生长在云服务器上,并且遵循一种新的软件开发、发布和运维模式,从而使得软件能够最大化地发挥云的能力。
- 第一部分是云应用定义与开发流程。这包括应用定义与镜像制作、配置 CI/CD、消息和 Streaming 以及数据库等。
- 第二部分是云应用的编排与管理流程。这也是 Kubernetes 比较关注的一部分,包括了应用编排与调 度、服务发现治理、远程调用、API 网关以及 Service Mesh。
- 第三部分是监控与可观测性。这部分所强调的是云上应用如何进行监控、日志收集、Tracing 以及在云 上如何实现破坏性测试,也就是混沌工程的概念。
- 第四部分就是云原生的底层技术,比如容器运行时、云原生存储技术、云原生网络技术等。
- 第五部分是云原生工具集,在前面的这些核心技术点之上,还有很多配套的生态或者周边的工具需要使 用,比如流程自动化与配置管理、容器镜像仓库、云原生安全技术以及云端密码管理等。
最后则是 Serverless。Serverless 是一种 PaaS 的特殊形态,它定义了一种更为“极端抽象”的应用编写方 式,包含了 FaaS 和 BaaS 这样的概念。而无论是 FaaS 还是 BaaS,其最为典型的特点就是按实际使用 计费(Pay as you go),因此 Serverless 计费也是重要的知识和概念
ASP.NET Core应用程序部署IIS,需要准备什么?
需要安装AspNetCoreMoudleV2
如何理解MVC5的管道和ASP.NET Core的管道?
在.NET Framework中MVC的管道是通过事件驱动,观察者模式来完成。在HttpContext处理的过程中, 定义好事件,然后通过给事件注册行为;请求来了以后,执行事件,从而执行行为,达到扩展目的;
在ASP.NET Core中,管道是通过委托来完成的,通过委托的多层嵌套装配,形成一个俄罗斯套娃;请求
来了以后,穿过整个俄罗斯套娃的全部过程;
在ASP.NET Core设计中,为什么要把把ResourceFilter放在授权Filter之后,而在其他Filter之前。
ResourceFilter是用来做缓存的,请求来了以后,如果能取出缓存,也必须是在授权桌,有权限才能取 数据;也是ResourceFilter是用来做缓存的,如果有缓存,授权后就可以直接取缓存,就没有必要再去 执行其他的逻辑;如果放在其他Filter之后,在执行了其他的Filter后取缓存,那么其他的Filter执行就没 有价值了。
如何理解MAUI?
.NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于创建使用 C# 和 XAML 的本机移动和桌面应 用。 .NET多平台应用 UI( .NETMAUI) 使你可以使用面向 Android、iOS、macOS、Windows 和 Tizen 的移动 和桌面外形规格的 .NET 跨平台 UI 工具包生成本机应用
如何在ASP.NET Core中激活Session功能?
首先要添加session包. 其次要在configservice方法里面添加session。然后又在configure方法里面调用 usesession。
什么是中间件?
中间件在这里是指注入到应用中处理请求和响应的组件。是通过多个委托来嵌套形成的一个俄罗斯套 娃!
Applicationbuilder的Use和Run方法有什么区别?
这两个方法都在StartUp 类的configure方法里面调用。都是用来向应用请求管道里面添加中间件的。 Use方法可以调用下一个中间件的添加,而run不会。run是终结式的;
publicvoidConfigure(IApplicationBuilder app, IHostingEnvironment env)
{ //可以看到通过匿名函数实现的中间件是内嵌在启动类文件中的,因此通常也叫做内联中间件。
app.Use(async(context, next) =>
{
awaitcontext.Response.WriteAsync("One Holle Word 1!\r\n");
awaitnext; //传递到下一个中间件,而不是先执行下面的
awaitcontext.Response.WriteAsync("One Holle Word 2!\r\n");
});
app.Run(async(context) =>
{
awaitcontext.Response.WriteAsync("Two Holle Word 1!\r\n");
awaitcontext.Response.WriteAsync("Two Holle Word 2!\r\n");
});
}
什么是ASP.NET Core里面的taghelper ?
Taghelper用来在服务器端使用Razor视图引擎创建Html元素的。
什么是ASP.NET Core?
首先ASP.NET Core可以说是ASP.NET的升级版本。它遵循了.NET的标准架构,是一个基于.NET Core的 Web开发框架,可以运行于多个操作系统上。它更快,更容易配置,更加模块化,可扩展性更强
ASP.NET Core 中AOP的支持有哪些?
通过Filter来支持;分别有IResourceFilter AuthorizeFilter ActionFilter ExceptionFilter ResultFilter, Filter也被称为拦截器!
ASP.NET Core Filter的注册方式有哪些?
方法注册:只对方法生效
控制器注册:对控制器中的所有方法生效
全局注册:对整个项目生效;
ASP.NET Core Filter如何支持依赖注入?
可以通过全局注册,支持依赖注入
通过TypeFilter(typeof(Filter)) 标记在方法,标记在控制器
通过ServiceType(typeof(Filter))标记在方法,标记在控制器,必须要注册Filter这类;
TypeFilter和ServiceType的本质是实现了一个IFilterFactory接口
ASP.NET Core 如何和读取配置文件中的内容?
可以有两种方式,可以通过IConfiguration接口来读取;
有可以定义根据配置文件结构一致的实体对象,来绑定到对象中去;或者通过1写入,2注入读取
必须保证:DBConnectionOption和配置文件的内容结构一致;
1. services.Configure<DBConnectionOption>
(Configuration.GetSection("ConnectionStrings"));//注入多个链接
2.private DBConnectionOption dBConnections = null;
private DbContext _Context = null;
public DbContextFactory(DbContext context, IOptions<DBConnectionOption>
options)
{
_Context = context;
dBConnections = options.Value;
}
ASP.NET Core有哪些好的功能?
第一是依赖注入。
第二是日志系统架构。
第三是引入了一个跨平台的网络服务器,kestrel。可以没有iis, apache和nginx就可以单独运行。
第四是可以使用命令行创建应用。
第五是使用appsettings来配置工程。
第六是使用StartUp来注册服务。
第七是更好的支持异步编程。
第八是支持web socket和signal IR。
第九是对于跨网站的请求的预防和保护机制。
ASP.NET Core跟ASP.NET比较有哪些更好的地方?
第一是跨平台,它可以运行在三大操作系统上面,windows, Linux和MAC。
第二是对架构本身安装没有依赖,因为所有的依赖都跟程序本身在一起。
第三是ASP.NET Core处理请求的效率更高,能够处理更多的请求。
第四是ASP.NET Core有更多的安装配置方法。
什么是meta packages?
Meta packages是指包含所有ASP dot net code依赖的一个包。叫做Microsoft.AspNetCore
ASP.NET Core应用能够跟ASP.NET4.x架构一起工作吗?
可以。ASP.NET Core应用可以跟标准的dot net 库一起工作
什么是ASP.NET Core的StartUp 类?
StartUp 类是ASP.NET Core应用的入口。所有的ASP.NET Core应用必须有这个类。这个类用来配置应 用。这个类的调用是在program main函数里面进行配置的。类的名字可以自己定义。
StartUp 类的configservice方法和configure方法各有什么作用?
configservice : 在这个方法里我们可以添加一些service进入依赖注入容器。
configure : 这个方法来定义整个应用如何响应HTTP请求。它有几个比较重要的参数,applicationbuilder,Hosting,environment ,logfactory, 在这里我们可以配置一些中间件用来处理路径,验证和session等等。
ASP.NET Core里面的路径是如何处理的?
路径处理是用来为进入的请求寻找处理函数的机制。所有的路径在函数运行开始时进行注册。 主要有两种路径处理方式, 常规路径处理和属性路径处理。常规路径处理就是用MapRoute的方式设定 调用路径,属性路径处理是指在调用函数的上方设定一个路径属性。
ASP.NET Core工程里面有多少个工程文件?
launchsetting,appsettings,Program, StartUp
如何使taghelper在元素这一层上失效?
使用叹号。
Applicationbuilder的Use和Run方法有什么异同?
首先这两个方法都是在 startup
类的 configure
方法里面调用的,并且都是用来向应用请求管道里面添加中间件的。但是 Use
方法可以调用下一个中间件,Run
方法则不能,它是终结式的。
ASP.NET Core 是什么?
ASP.NET Core 可以说是 ASP.NET 的升级版本,它遵循 .NET 标准框架,是基于 .NET Core
的 Web 开发框架,可运行于多种操作系统,相比 ASP.NET 来说更快、更易于配置、更加模块化,并且扩展性更加强。
ASP.NET Core 中 AOP是通过什么来支持的?分别有哪些?
AOP 是通过 Filter
来支持的,分别有 IResourceFile、AuthorizeFilter、ActionFilter、ExceptionFilter、ResultFilter
。
ASP.NET Core Filter 注册方式有哪几种?它们的有效范围
有三种,分别是:
- 方法注册:只对方法生效;
- 控制器注册:只对控制器中的方法生效;
- 全局注册:对整个项目生效;
ASP.NET Core Filter 如何支持依赖注入?
- 通过全局注册的方式支持依赖注入:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<TestActionFilterAttribute>();
services.AddControllersWithViews(options =>
{
options.Filters.Add<TestActionFilterAttribute>();
});
}
12345678
- 通过
TypeFilter(typeof(Filter))
注入( 标记在方法、控制器):
[TypeFilter(typeof(Filter))]
public IActionResult Index()
{
return View();
}
- 通过
ServiceType(typof(Filter))
注入( 标记在方法、控制器,必须要注册Filter
这个类):
[ServiceFilter(typeof(Filter))]
public IActionResult Index()
{
return View();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<TestActionFilterAttribute>();
services.AddControllersWithViews();
}
ASP.NET Core 读取配置文件内容的方法?
读取配置文件的方法有两种,一种是通过 IConfiguration
接口读取,一种是根据配置文件结构定义出结构一致的实体对象去绑定。
请列举出你所知道的 ASP.NET Core 的优秀功能。
- 依赖注入;
- 日志系统架构;
- 具有跨平台网络服务器
kestrel
,可以在没有IIS、Apache
和Nginx
的情况下单独运行; - 可以使用命令行来创建应用;
- 使用
json(appsettings)
配置工程; - 使用
startup
注册服务; - 提升了对异步编程的支持性;
- 完全支持
web socket
和signalR
; - 具有对跨站请求的预防和保护机制。
ASP.NET Core跟ASP.NET比较有哪些更好的地方?
- 第一是跨平台,它可以运行在三大操作系统上面,windows, Linux和MAC。
- 第二是对架构本身安装没有依赖,因为所有的依赖都跟程序本身在一起。
- 第三是ASP.NET Core处理请求的效率更高,能够处理更多的请求。
- 第四是ASP.NET Core有更多的安装配置方法。
什么是meta packages?
Meta packages`是指包含所有ASP dot net code依赖的一个包。叫做`Microsoft.AspNetCore
ASP.NET Core应用能够跟ASP.NET4.x架构一起工作吗?
可以。ASP.NET Core应用可以跟标准的dot net 库一起工作。
什么是ASP.NET Core的startup 类?
startup 类是ASP.NET Core应用的入口。所有的ASP.NET Core应用必须有这个类。这个类用来配置应
用。这个类的调用是在program main函数里面进行配置的。类的名字可以自己定义。
startup 类的configservice方法有什么作用?
在这个方法里我们可以添加一些service进入依赖注入容器。
startup 类的configure方法有什么作用?
这个方法来定义整个应用如何响应HTTP请求。它有几个比较重要的参数,applicationbuilder,Hosting environment, log factory, 在这里我们可以配置一些中间件用来处理路径,验证和session等等。
ASP.NET Core里面的路径是如何处理的?
路径处理是用来为进入的请求寻找处理函数的机制。所有的路径在函数运行开始时进行注册。
主要有两种路径处理方式, 常规路径处理和属性路径处理。常规路径处理就是用MapRoute的方式设定
调用路径,属性路径处理是指在调用函数的上方设定一个路径属性。
什么是ASP.NET Core里面的taghelper
Taghelper用来在服务器端使用Razor视图引擎创建html元素的。
说说.NET5中 _ViewImports文件的作用。
在.NET5中可以支持组件化编程,定义的各种组件,在项目中使用的时候,需要在_ViewImports文件中引入进来。
什么是Razor页面?
是ASP.NET Core中支持ASP网页表格的一种开发模型。@page 作为页面的起始标志。。
Stringbulider的使用,最好制定合适的容量值,否则优于默认值容量不足而频繁的进行内存分
说说.NET5中 __ViewStart文件的作用
在控制器在返回视图的时候,开始替换视图引擎的时候,从_ViewStart.cshtml 开始,来初始化展示的视图界面;
如何在Razor页面中实现数据模型绑定?
使用bindproperty属性。
如何在Controller中注入service?
在config services方法中配置这个service。
在controller的构造函数中,添加这个依赖注入。
描述一下依赖注入后的服务生命周期?
在ASP.NET Core中,我们不需要关心如何释放这些服务, 因为系统会帮我们释放掉。有三种服务的生命周期。
单实例服务, 通过add singleton方法来添加。在注册时即创建服务, 在随后的请求中都使用这一个服务。
短暂服务, 通过add transient方法来添加。是一种轻量级的服务,用于无状态服务的操作。
作用域服务,一个新的请求会创建一个服务实例。使用add scoped方法来添加。
说说ASP.NET Core内置容器的特点;
ASP.NET Core内置容器IServiceCollection,只支持构造函数注入;支持三种声明周期:单例、瞬时、Scoped三种声明周期管理;
ASP.NET Core中如何读取静态文件?
可以通过中间件UseStaticFiles来配置读取静态文件;
ASP.NET Core项目如何设置IP地址和端口号?
可以使用Properties文件夹下的launchSettings配置文件来配置不同的启动方式的时候,分别配置IP和端口号。
ASP.NET Core项目中,wwwroot文件夹内包含什么内容?
包含了css、js、js库、字体文件
ASP.NET Core 如何支持Log4Net扩展?
就是一个日志组件的集成使用,大概分为以下步骤:
- nuget引入log4net程序集;Microsoft.Extensions.Logging.Log4Net.AspNetCore程序集合
- 增加配置文件,配置文件内容如下
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<!-- Define some output appenders -->
<appender name="rollingAppender" type="log4net.Appender.RollingFileAppender">
<file value="..\log\Customlog.txt"/>
<!--追加日志内容-->
<appendToFile value="true"/>
<!--防止多线程时不能写Log,官方说线程非安全-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<!--可以为:Once|Size|Date|Composite-->
<!--Composite为Size和Date的组合-->
<rollingStyle value="Composite"/>
<!--当备份文件时,为文件名加的后缀-->
<datePattern value="yyyyMMdd.TXT"/>
<!--日志最大个数,都是最新的-->
<!--rollingStyle节点为Size时,只能有value个日志-->
<!--rollingStyle节点为Composite时,每天有value个日志-->
<maxSizeRollBackups value="20"/>
<!--可用的单位:KB|MB|GB-->
<maximumFileSize value="3MB"/>
<!--置为true,当前最新日志文件名永远为file节中的名字-->
<staticLogFileName value="true"/>
<!--输出级别在INFO和ERROR之间的日志-->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ALL"/>
<param name="LevelMax" value="FATAL"/>
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</appender>
</log4net>
123456789101112131415161718192021222324252627282930313233
- 使用Log4net配置
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args) //创建默认主机的建造者;
.ConfigureLogging(loggbuild =>
{
loggbuild = loggbuild.AddLog4Net("CfgFile/log4net.Config");
}) ///配置logging(指定使用Log4net)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup> (); //如何配置? 配置全交给Startup来完成;
}).UseServiceProviderFactory(new AutofacServiceProviderFactory());
}
123456789101112
就可以支持注入了,可以在控制器中使用了
说说脚本启动ASP.NET Core Web项目
介绍两种方式:
第一种:定位到Web项目的编译地址下,就是bin文件夹下的.NET5文件夹,然后在当前文件夹下打开命令提示窗口;dotnet dll文件 ---urls=http://ip地址:端口号 回车即可;
第二种:定位到Web项目的根目录下,然后在当前文件夹下打开命令提示窗口;dotnet run ---urls=http://ip地址:端口号 回车即可;
推按第二种,第二种方式,在启动的时候,会自动编译项目,然后启动dll文件;
说说Core WebApi的Swagger。
Swagger是一个Api说明文档,支持Api测试;现在CoreWebApi开发使用swagger还挺多的;
在.NET5中已经内置了Core WebApi;配置流程如下:
- Nuget引入程序集:Swashbuckle.AspNetCore.SwaggerGen
- 配置服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "WebApplication1", Version = "v1"
});
});
}
- 配置使用中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication1 v1"));
}
说说Core WebApi特性路由。
在Core WebApi中,每一个Api必须指定特性路由,即在Api或者控制器上标记特性Route("api/[Controller]/Api");访问Api,就按照这个格式访问;
说说RESTful是什么。
在传统的服务中,比方说WebService,WCF,Remouting,都是通过调用方法来做到一个进程去调用另外一个进程的服务,在Core WebApi中是把要调用的服务资源化,比方说有图书资源,Books,学生资源Studentlist,每一个资源对应一个控制器,然后对外提供增删改查等操作;对外提供统一的Uri, 可以对资源Books,资源Studentlist做增删改查的操作;访问的是资源,可以根据不同的访问方式,做不同的事儿;
说说脚本在请求Web CoreApi的时候,为什么会发生跨域问题?
跨域问题:本质是浏览器的行为,浏览器有一个同源策略,同源策略:协议、IP地址相同就认为是同源;否则就非同源;同源策略限定脚本请求只能请求同源的服务器返回的内容才给正常的使用;否则就会报跨域问题;其实我们在请求Core WebApi的时候,浏览器直接访问Api没有问题,如果是脚本请求,就会出现跨域问题;
如何解决跨域问题?
三种方式:
- 后台模拟Http请求,既然是浏览器的行为,就避开浏览器,先来一个同源的服务器去请求,然后由服务器模拟http请求去请求到Core WebApi的资源,然后响应给前端;
- JSONP,思路:通过html部分标签发起请求,比方说 等等,发起请求是可以避开同源策略的,使用这些标签发起请求,然后带有一个回调函数,然后得到请求后,把回调函数之心一次,把数据解析后使用;
- 服务端允许跨域,多种方式,可以自己定义中间件支持跨域,只要把响应的Response的头信息Header中写入“Access-Control-Allow-Origin” 即可支持跨域;如果需要让所有的Api都支持跨域,就可以写一个中间件从管道处理模型中去支持跨域,如果要选择性的支持跨域,可以使用ActionFilter来完成,也可以通过Cors(ASP.NET Core中提供的中间件,可以支持配置不同的跨域规则)来配置支持跨域;
说说你了解到的鉴权授权技术。
- 传统的授权技术:通过Session、Cookie完成授权;实现特点: 让无状态的http请求,变的有状态,让第一次请求和第二次请求之间产生联系,第一次请求进入服务器,在服务器写入一组session,然后返回sessionId给客户端存在Cookie,第二次请求,从cookie中渠道SessionId,传递给服务器,服务器鉴别SessionId,如果是上一次来的SessionId,就认为之前来请求过;就认为有权限;
- 流行鉴权授权方式:Token授权,在Core WebApi中主要就是JWT和IdentityServer4;都是独立的授权中心,授权后办法token,然后客户端带着token去请求Api,Api方验证Token,验证通过就有权限,验证不通过就没有权限;
请问对gRPC有了解吗,说说gRPC。
有了解,说gRPC可以先说RPC,PRC:所谓RPC(remote procedure call远程过程调用) 框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。
所谓gRPC 是由谷歌开发的一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python,Ruby, Objective-C, PHP 和 C# 支持.
gRPC有几种模式?
四种模式:
1,简单模式:简单模式只是使用参数和返回值作为服务器与客户端传递数据的方式,最简单。
2,客户端流模式:即从客户端往服务器端发送数据使用的是流,即服务器端的参数为流类型,然而在服务器相应后返还数据给客户端,使用的也是流的send方法。一般在服务器端的代码,需要先recv再send,而客户端与此相反。但是在后面的双向模式中可以使用go的协程协作。
3,服务器端流模式:即服务器端返回结果的时候使用的是流模式,即传入的数据是通过参数形式传入的。但是在往客户端发送数据时使用send方法,与客户端返回数据的方式大同小异。
4,双向模式:客户端如果不适用协程,那么发送必须在接收之前。如果使用协程,发送与接收并没有先后顺序。为了保证协程的同步,可以使用互斥量进行约束。
说说如何使用C#实现简单模式gRPC
分为客户端和服务端;
服务端:
通过vs新建一个gRPC服务,会内置一proto文件;内容如下,可以理解成是一个模板,通过这个模板可以生成对应的类文件。
syntax = "proto3"; //规范---标准---工具生成C#
option csharp_namespace = "Zhaoxi.gRPCDemo.DefaultServer";
package greet;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
需要让这个文件生效,就必须要在项目文件中配置使用这个文件;GrpcServices=“Server”,这是服务端的配置;
<ItemGroup>
<Protobuf Include="Protos\CustomMath.proto" GrpcServices="Server" />
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
编译,就可以通过这个模板生成一些类,包含这些类的方法;
客户端:
- Vs新建一个控制台,作为客户端
- 把服务端的那个proto文件,连同文件一起Copy到客户端来。
- 配置客户端的项目文件,如下。请注意 GrpcServices=“Client”
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
<Protobuf Include="Protos\CustomMath.proto" GrpcServices="Client" />
</ItemGroup>
编译后,编写调用gRPC的方法如下:
private static async Task TestHello()
{
using(var channel = GrpcChannel.ForAddress("https://localhost:5001"))
{
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest
{
Name = "hello"
});
Console.WriteLine("Greeter 服务返回数据: " + reply.Message);
}
}
说说gRPC的拦截器有哪些?
分为客户端拦截器,和服务端拦截器,是AOP的编程思想的体现。
分别有:
- BlockingUnaryCall:拦截阻塞调用
- AsyncUnaryCall: 拦截异步调用
- AsyncServerStreamingCall 拦截异步服务端流调用
- AsyncClientStreamingCall 拦截异步客户端流调用
- AsyncDuplexStreamingCall 拦截异步双向流调用
- UnaryServerHandler 用于拦截和传入普通调用服务器端处理程序
- ClientStreamingServerHandler 用户拦截客户端流调用的服务端处理程序
- ServerStreamingServerHandler 用于拦截服务端流调用的服务器端处理程序
- DuplexStreamingServerHandler 用于拦截双向流调用的服务器端处理程序
gPRC作为一种被调用的服务,有什么保护安全的措施吗?
有的,可以使用JWT,无论是对称可逆加密还是非对称可逆加密,都是可以支持的;
请问对EFCore有了解吗?
有了解。
Entity Framework Core是适用于.NET的新式物件资料库对应程式。其支援LINQ查询、变更追踪、更新以及结构描述移转。
EF Core透过[资料库提供者外挂程式模型]来搭配使用SQL Server/SQL Azure、SQLite、Azure Cosmos DB、MySQL、PostgreSQL及更多资料库。。、
说说EFCore查询的性能调优小技巧。
如果说查询出来的数据,只是做展示,不做增删改查,可以在查询的时候,增加AsNoTracking()方法,可以提高性能,可以避免在内存中存在副本;
建议在查询的时候,多使用Find()方法,会有限走内存缓存,如果内存已经存在,就不会去数据库中查询数据;
EFCore 如何通过数据生成实体和DbContext?
步骤如下:
- Nuget引入 如下程序集
Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
- 在Vs中打开工具–nuget包管理器–程序包管理器控制台:命令执行:
Scaffold-DbContext "Data Source=DESKTOP-63QE7M1;Initial Catalog=ZhaoxiEduDataBase;User ID=sa;Password=sa123" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entity -Force - Context ZhaoxiDbContext -ContextDir
注:命令参数应用如下:
命令参数:
-OutputDir *** 实体文件所存放的文件目录
-ContextDir *** DbContext文件存放的目录
-Context *** DbContext文件名
-Schemas *** 需要生成实体数据的数据表所在的模式
-Tables *** 需要生成实体数据的数据表的集合
-DataAnnotations
-UseDatabaseNames 直接使用数据库中的表名和列名(某些版本不支持)
-Force 强制执行,重写已经存在的实体文件
123456789101112131415
说说什么是导航属性和引用属性。
实体框架中的导航属性提供了一种在两个实体类型之间导航关联的方法。
导航属性在概念模型中由NavigationProperty元素 (CSDL) 定义。针对对象参与到其中的每个关系,各对象均可以具有导航属性。使用导航属性,您可以在两个方向上导航和管理关系,如果重数为一或者零或一,则返回EntityReference,或者如果重数为多个,则返回 EntityCollection。 也可以选择单向导航,这种情况下可以删除导航属性。
垃圾回收机制
简述一下一个引用对象的生命周期?
-
new创建对象并分配内存
-
对象初始化
-
对象操作、使用
-
资源清理(非托管资源)
-
GC垃圾回收
创建下面对象实例,需要申请多少内存空间?
public class User
{
public int Age { get; set; }
public string Name { get; set; }
public string _Name = "123" + "abc";
public List<string> _Names;
}
40字节内存空间。
什么是垃圾?
一个变量如果在其生存期内的某一时刻已经不再被引用,那么,这个对象就有可能成为垃圾。
GC是什么,简述一下GC的工作方式?
在公共语言运行时 (CLR) 中,垃圾回收器 (GC) 用作自动内存管理器。 垃圾回收器管理应用程序的内存分配和释放。
她的基本工作原理就是遍历托管堆中的对象,标记哪些被使用对象(哪些没人使用的就是所谓的垃圾),然后把可达对象转移到一个连续的地址空间(也叫压缩),其余的所有没用的对象内存被回收掉。
GC进行垃圾回收时的主要流程是?
(1)标记 ,找到并创建所有活动对象的列表。
(2)重定位 ,用于更新对将要压缩的对象的引用。
(3)压缩 ,用于回收由死对象占用的空间,并压缩幸存的对象。 压缩阶段将垃圾回收中幸存下来的对象移至段中时间较早的一端。
GC在哪些情况下回进行回收工作?
(1)系统具有低的物理内存。 这是通过 OS 的内存不足通知或主机指示的内存不足检测出来。
(2)由托管堆上已分配的对象使用的内存超出了可接受的阈值。 随着进程的运行,此阈值会不断地进行调整。
(3)调用 GC.Collect 方法。 几乎在所有情况下,你都不必调用此方法,因为垃圾回收器会持续运行。 此方法主要用于特殊情况和测试。
using() 语法是如何确保对象资源被释放的?如果内部出现异常依然会释放资源吗?
using() 只是一种语法形式,其本质还是try…finally的结构,可以保证Dispose始终会被执行。
解释一下C#里的析构函数?为什么有些编程建议里不推荐使用析构函数呢?
C#里的析构函数其实就是终结器Finalize,因为长得像C++里的析构函数而已。
有些编程建议里不推荐使用析构函数要原因在于:第一是Finalize本身性能并不好;其次很多人搞不清楚Finalize的原理,可能会滥用,导致内存泄露,因此就干脆别用了
Finalize() 和 Dispose() 之间的区别?
Finalize() 和 Dispose()都是.NET中提供释放非托管资源的方式,他们的主要区别在于执行者和执行时间不同:
finalize由垃圾回收器调用;dispose由对象调用。
finalize无需担心因为没有调用finalize而使非托管资源得不到释放,而dispose必须手动调用。
finalize不能保证立即释放非托管资源,Finalizer被执行的时间是在对象不再被引用后的某个不确定的时间;而dispose一调用便释放非托管资源。
只有class类型才能重写finalize,而结构不能;类和结构都能实现IDispose。
另外一个重点区别就是终结器会导致对象复活一次,也就说会被GC回收两次才最终完成回收工作,这也是有些人不建议开发人员使用终结器的主要原因。
Dispose和Finalize方法在何时被调用?
Dispose一调用便释放非托管资源;
Finalize不能保证立即释放非托管资源,Finalizer被执行的时间是在对象不再被引用后的某个不确定的时间;
.NET中的托管堆中是否可能出现内存泄露的现象?
是的,可能会。比如:
不正确的使用静态字段,导致大量数据无法被GC释放;
没有正确执行Dispose(),非托管资源没有得到释放;
不正确的使用终结器Finalize(),导致无法正常释放资源;
其他不正确的引用,导致大量托管对象无法被GC释放;
在托管堆上创建新对象有哪几种常见方式?
new一个对象;
字符串赋值,如string s1=”abc”;
值类型装箱;
什么是多态?
通过继承实现的不同对象,调用相同的方法,产生不同的执行结果。C#支持两种类型的多态,编译时的多态和运行时的多态。
编译时的多态:
编译时的多态是通过重载来实现的,对于非虚的成员来说,系统在编译时,根据传递的参数类型,个数以及返回类型的不同决定实现不同的操作.
重载:
public int Sum(int x,int y)
public int Sum(int x,int y,int z)
public double Sum (Double x,Double y)
重载特点:
方法名称必须相同
参数列表必须不同
返回值类型可以不同
运行时的多态:
运行时的多态是指系统直到运行时,才根据实际情况实现何种操作.
运行时的多态可以通过virtual-override(虚成员覆盖实现)以及abstract-override(抽象方法覆盖实现)两种方式来实现.
通过override实现覆写注意的几点
只有虚方法和抽象方法才能被覆写
子类和基类中的方法必须具有相同的方法名称,参数个数,参数类型以及返回值类型.
总结:
编译时的多态使运行速度更快,就像const编译时解析.
运行时的多态带来了高度灵活以及抽象的特点.
锁,除了lock还有哪些锁?
基元线程同步构造分为:基元用户模式构造和基元内核模式构造,两种同步构造方式各有优缺点,而混合构造(如lock)就是综合两种构造模式的优点。
用户模式构造
(1) System.Threading.Interlocked:易失构造,它在包含一个简单数据类型的变量上执行原子性的读或写操作。
(2)Thread.VolatileRead 和 Thread.VolatileWrite:互锁构造,它在包含一个简单数据类型的变量上执行原子性的读和写操作。
内核模式构造的主要有两种方式,以及基于这两种方式的常见的锁:
基于事件:如AutoResetEvent、ManualResetEvent
基于信号量:如Semaphore
EF如何处理并发?
什么叫并发:当多个用户同时更新同一数据的时候,由于更新可能导致数据的不一致性,使得程序的业务数据发生错误,这种情况可以称之为并发。
并发又分为两种:乐观并发 与 悲观并发
乐观并发:即系统允许多个用户同时修改同一条记录,系统会预先定义由数据并发所引起的并发异常处理模式,去处理修改后可能发生的冲突
当出现乐观并发时应该怎么处理呢,通常有如下三种处理方法
a 保留最后一次对象修改的值
b 保留最初的修改值
c 合并修改值
悲观并发:在同一时刻只允许一个用户修改相同数据,直接用Lock 与 unLock就可以处理.
事务的四大特性:
1 、原子性 (atomicity):强调事务的不可分割.
事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做
2 、一致性 (consistency):事务的执行的前后数据的完整性保持一致.
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
3 、隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
4 、持续性 (durability) :事务一旦结束,数据就持久到数据库
也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
那么在没有对事务进行隔离时会发生哪些危害了?
脏读:当一个事务读取数据修改后以经SaveChange但事务还没有提交,此时另外一个事务就读取了该数据,此时的数据就是脏数据,这一过程就是脏读
不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的这一过程就是不可重复读
幻读:一个事务针对一张表的所有数据进行读取修改,而此时另一个事务向表中插入了一条数据,则第一个事务数据不包含新数据,像出现幻觉一样,这一过程就是幻读。
避免不可重复读需要锁行。
避免幻影读则需要锁表。
EF四种隔离级别
01:Read uncommitted(读未提交):最低级别,任何情况都会发生。
02:Read Committed(读已提交):可避免脏读的发生。
03:Repeatable read(可重复读):可避免脏读、不可重复读的发生。
04:Serializable(串行化):避免脏读、不可重复读,幻读的发生。
四种隔离级别:Seralizable 级别最高,最低的是 Read uncommitted 级别,级别越高,执行效率就越低,隔离级别的设置只对当前链接有效,对.NET 操作数据库来说,一个 Connection 对象相当于一个链接。
01:MySQL 数据库的默认隔离级别是Repeatable read 级别。
02:Oracle数据库中,只支持 Seralizable 和 Read committed级别,默认的是 Read committed 级别。
03:SQL Server 数据库中,默认的是Read committed 级别。
efcore事务的几种方法?
默认事务(SaveChanges)
默认情况下,如果数据库提供程序支持事务,单个 SaveChanges() 调用中的所有变更都会在一个事务中被提交。如果其中任何一个变更失败了, 那么事务就会回滚,没有任何变更会被应用到数据库。这意味着 SaveChanges() 能够确保要么成功保存,要么在发生错误时不对数据库做任何修改。
关闭默认事务:context.Database.AutoTransactionsEnabled = false;
DbContextTransaction
使用方式
BeginTransaction开启事务、Commit提交事务、Rollback回滚事务、Dispose销毁,如果用Using包裹的话,不再需要手动Rollback,走完Using会自动回滚。如果不用Using包裹事务,就需要在Catch中手动RollBack回滚,并且最好最后手动的Dispose一下。(如SameDbContext文件夹中的Test1和Test2方法)
使用场景
同一个上下文多个SaveChanges的方法(如:自增主键后续要用到)、SaveChanges和EF调用SQL语句混用
环境事务 TransactionScope
使用方式
new TransactionScope创建事务、Complete提交事务、 Transaction.Current.Rollback();回滚事务、Dispose销毁对象。如果用Using包裹的话,不再需要手动Rollback,走完Using会自动回滚。如果不用Using包裹事务,就需要在Catch中手动RollBack回滚,并且最好最后手动的Dispose一下。TransactionScope有三个属性:IsolationLevel(隔离等级),Timeout(超时),TransactionScopeOption(选项)
用途
A. 同一个上下文的事务。(多个SaveChanges(自增主键后续用到的情况)、SaveChanges和EF调用SQL语句混用)(如Test1方法)
B. 多种数据库技术访问同一个数据库的事务 (如Test2方法)
C. 同一个数据库多个不同的上下文是支持的(如Test3方法)
D. 不同数据库的上下文是不支持的,(如Test4方法,开启msdtc服务的步骤: cmd命令→ net start msdtc ,然后发现报错:This platform does not support distributed transactions.说明目前Core平台下不支持分布式事务)
使用EF update 怎么保证在并发时数据正确?
1、RowVersion ( TimeStamp ) 时间戳
EF实现Rowversion 并发控制 需要借助 TimeStamp 标示 ,并且一个类只能有 一个此标示,标示的必须是byte[]类型。使用Rowversion会对整行数据进行并发检测。
2、 ConcurrencyCheck
有些时候并不需要控制针对整条记录的并发,只需要控制某个列的数据不会出现脏操作就ok,这个时候 就使用ConcurrencyCheck 。你必须将ConcurrencyCheck特性添加到实体需要控制并发的非主键属性上,使实体框架可以将所有标记的列包含到更新语句的Where子句中。
3、 DbUpdateConcurrencyException
您可以通过EF实体框架引发的DbUpdateConcurrencyException异常处理来解决冲突。
jwt的组成有那几部分?
样式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分组成.
(1).Header头部:{"alg":"HS256","typ":"JWT"}基本组成,也可以自己添加别的内容,然后对最后的内容进行Base64编码.
(2).Payload负载:iss、sub、aud、exp、nbf、iat、jti基本参数,也可以自己添加别的内容,然后对最后的内容进行Base64编码.
(3).Signature签名:将Base64后的Header和Payload通过.组合起来,然后利用Hmacsha256+密钥进行加密。
jwt的安全性有哪些建议?
1、SecurityKey一定要保管好;
2、签名一定要有,校验签名并且不接受非法的签名;( 签名解决了数据传输过程中参数被篡改的风险)
3、payload增加时间戳减少重放攻击;
4、payload里不存放敏感信息,若有请用临时票据token形式的;
5、接口传输采用https协议;
什么是面向对象?面向对象的三大特性和五大原则是什么?
面向对象的方法主要是把事物给对象化,包括其属性和行为。面向对象编程更贴近实际生活的思想。总体来说面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象(万物皆对象)。
三大基本特性
封装
封装,就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
继承
继承,指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过 “继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用 基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。
多态
通过继承实现的不同对象,调用相同的方法,产生不同的执行结果.。
五大基本原则:SPR, OCP, LSP, DIP, ISP
单一职责原则SRP(Single Responsibility Principle)
是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。
开放封闭原则OCP(Open-Close Principle)
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。
里式替换原则LSP(the Liskov Substitution Principle LSP)
子类应当可以替换父类并出现在父类能够出现的任何地方。
依赖倒置原则DIP(the Dependency Inversion Principle DIP)
高层模块不应该依赖低层模块,二者都应该依赖其抽象。
接口分离原则ISP(the Interface Segregation Principle ISP)
模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来
sqlserver的触发器是什么?怎么使用触发器?
触发器是数据库中由一定时间触发的特殊的存储过程,他不是由程序掉用也不是手工启动的。触发器的执行可以由对一个表的insert,delete, update等操作来触发,触发器经常用于加强数据的完整性约束和业务规则等等。
索引的作用?和它的优点缺点是什么?
索引就一种特殊的查询表,数据库的搜索引擎可以利用它加速对数据的检索。索引很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小。
介绍存储过程基本概念和 她的优缺点
存储过程是一个预编译的SQL语句,他的优点是允许模块化的设计,也就是说只需创建一次,在该程序中就可以调用多次。例如某次操作需要执行多次SQL,就可以把这个SQL做一个存储过程,因为存储过程是预编译的,所以使用存储过程比单纯SQL语句执行要快。缺点是可移植性差,交互性差。
使用索引有哪些需要注意的地方?
创建索引的的字段尽量小,最好是数值,比如整形int等;
对于频繁修改的字段,尽量不要创建索引,维护索引的成本很高,而且更容易产生索引碎片;
定期的索引维护,如索引碎片的修复等;
不要建立或维护不必要的重复索引,会增加修改数据(新增、修改、删除数据)的成本;
使用唯一性高的字段创建索引,切不可在性别这样的低唯一性的字段上创建索引;
在SQL语句中,尽量不要在Where条件中使用函数、运算符或表达式计算,会造成索引无法正常使用;
应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描;
应尽量避免在 where 子句中使用!=或<>操作符,否则将导致引擎放弃使用索引而进行全表扫描;
索引碎片是如何产生的?有什么危害?又该如何处理?
索引在使用一段时间后(主要是新增、修改、删除数据,如果该页已经存储满了,就要进行页的拆分,频繁的拆分,会产生较多的索引碎片)会产生索引碎片。
索引碎片会严重印象数据的查询效率,如果碎片太多,索引可能不会被使用。
碎片的处理方式主要有两种:
第一种是预防:设置页的填充因子
意思就是在页上设置一段空白区域,在新增数据的时候,可以使用这段空白区域,可以一定的避免页的拆分,从而减少索引碎片的产生。
填充因子就是用来描述这种页中填充数据的一个比例,一般默认是100%填充的。如果我们修改填充因子为80%,那么页在存储数据时,就会剩余20%的剩余空间,这样在下次插入的时候就不会拆分页了。 那么是不是我们可以把填充因子设置低一点,留更多的剩余空间,不是很好嘛?当然也不好,填充因子设置的低,会需要分配更多的存储空间,叶子节点的深度会增加,这样是会影响查询效率的,因此,这是要根据实际情况而定的。
那么一般我们是怎么设置填充因子的呢,主要根据表的读写比例而定的。如果读的多,填充因子可以设置高一点,如100%,读写各一半,可以8090%;修改多可以设置5070%。
第二种是索引修复:定期对索引进行检查、维护,写一段SQL检查索引的碎片比例,如果碎片过多,进行碎片修复或重建,定期执行即可。具体可以参考本文末尾的相关参考资料。
锁的目的是什么?
主要解决多个用户同时对数据库的并发操作时会带来以下数据不一致的问题:
丢失更新,同时修改一条数据
读脏,A修改了数据后,B读取后A又取消了修改,B读脏
不可重复读,A用户读取数据,随后B用户读取该数据并修改,此时A用户再读取数据时发现前后两次的值不一致
还有一种是幻读,这个情况好像不多。
并发控制的主要方法是封锁,锁就是在一段时间内禁止用户做某些操作以避免产生数据不一致
锁的粒度有哪些?
数据库锁:锁定整个数据库,这通常发生在整个数据库模式改变的时候。
表锁:锁定整个表,这包含了与该表相关联的所有数据相关的对象,包括实际的数据行(每一行)以及与该表相关联的所有索引中的键。
区段锁:锁定整个区段,因为一个区段由8页组成,所以区段锁定是指锁定控制了区段、控制了该区段内8个数据或索引页以及这8页中的所有数据行。
页锁:锁定该页中的所有数据或索引键。
行或行标识符:虽然从技术上将,锁是放在行标识符上的,但是本质上,它锁定了整个数据行。
什么是事务?什么是锁?
事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上个节点。为了确保要么执行,要么不执行,就可以使用事务。要将所有组语句作为事务考虑,就需要通过ACID测试,即原子性,一致性,隔离性和持久性。
锁是实现事务的关键,锁可以保证事务的完整性和并发性。
视图的作用,视图可以更改么?
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的sql操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。
视图的目的在于简化检索,保护数据,并不用于更新。
150什么是触发器(trigger)? 触发器有什么作用?
触发器是数据库中由一定时间触发的特殊的存储过程,他不是由程序掉用也不是手工启动的。触发器的执行可以由对一个表的insert,delete, update等操作来触发,触发器经常用于加强数据的完整性约束和业务规则等等。
SQL里面IN比较快还是EXISTS比较快?
这个题不能一概而论,要根据具体情况来看。IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。
如果查询语句使用了not in,那么对内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in 要快。
维护数据库的完整性和一致性,你喜欢用触发器还是自写业务逻辑?为什么?
尽可能使用约束,如check、主键、外键、非空字段等来约束。这样做效率最高,也最方便。其次是使用触发器,这种方法可以保证,无论什么业务系统访问数据库都可以保证数据的完整新和一致性。最后考虑的是自写业务逻辑,但这样做麻烦,编程复杂,效率低下。
oauth是什么?有哪些方式?
oauth是开发授权协议。主要用来颁发令牌(token)。有四种授权方式。
授权码(authorization-code)
隐藏式(implicit)
密码式(password):
客户端凭证(client credentials)
授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
decimal的精度为什么比double高?
float 单精度浮点 32bit,
double 双精度浮点64bit,
decimal是高精度 128bit,浮点型。
float double 是 基本类型(primitive type),decimal不是。
float 有效数字7位,范围 ±1.5 × 10E−45 to ±3.4 × 10E38
double 有效数字15/16 位,范围 ±5.0 × 10 E−324 to ±1.7 × 10E308
decimal 有效数字 28/29 位,范围 ±1.0 × 10E−28 to ±7.9 × 10E28
decimal的有效位数很大,达到了28位,但是表示的数据范围却比float和double类型小。使用的时候会对计算时的性能有影响。
数值存储范围越小的精度越高,存储数值范围越大,精度就越不准确,如果存储正常金额的情况下,使用money,好处在于可以存储不指定的小数点位数的数值,比较真实。如果对于既要求精度,又固定小数点位数的数值存储,采用decimal(numeric),优点在于可以自定义小数点位数,精度高。如特殊情况,如数值范围巨大只能用float(real)类型了,此类型一般不提倡使用。
ASP.NET Core 比 ASP.NET 的优势在哪?
跨平台,ASP.NET Core 可以在 Windows、Linux 和 Mac 系统运行;
开源,ASP.NET Core 在 Github 上是开源的,意味着更安全以及更好的服务;
部署灵活,ASP.NET Core 运行时可以作为应用的一部分进行部署,也可以集中安装在Web 服务器上。另外,也适配 Docker 容器;
性能更强,ASP.NET Core 处理请求的性能更好,从而能处理更多的请求;
ASP.NET Core 的特性有哪些?
支持依赖注入,ASP.NET Core 内置的依赖项注入;
内置日志框架,并且可以扩展;
可以通过命令来创建、运行应用程序;
对异步编程更好的支持;
引入新的、快速跨平台的 Web 服务器 — Kestrel;
支持 SignalR ;
可基于环境进行配置 ,appSettings.json
ASP.NET Core Filter如何⽀持依赖注⼊?
全局注册
public void ConfigureServices(IServiceCollection services)
{
//全局注册异常过滤器
services.AddControllersWithViews(option =>
{
option.Filters.Add<ExecptionFilter>();
});
}
TypeFilter 方式注册
[TypeFilter(typeof(ExecptionFilter))]
public IActionFilter Index()
{
return View();
}
ServiceFilter 方式注册
使用 ServiceFilter 必须要注册Filter这类,可以标记在控制器和方法里
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<ExecptionFilter>();
}
[ServiceFilter(typeof(ExecptionFilter))]
public IActionFilter Index()
{
return View();
}
ASP.NET Core Filter 的注册方式有哪些?
方法注册:只对标记的方法有效
控制器注册:对控制器中的所有方法有效
全局注册:对整个项目生效
ASP.NET Core 的 Startup 类是什么?
Startup 类是 ASP.NET Core 应用程序的入口,ASP.NET Core 应用不可以缺少,这个类主要用来配置应用程序。类名不一定叫 "Startup" 该类在 Program Main方法里进行调用。
Startup 类有两个方法
ConfigService 方法可以添加 Service 到依赖注入容器
Cofnigure 方法定义整个应用如何响应 HTTP 请求。可配置中间件,一些常用的中间件要熟悉和了解并配置。
ApplicationBuilder Map 有什么用?
可以针对不同的路径添加不同的中间件。
ASP.NET Core 工程文件有哪些?
launchSetting,appSettings,Program,Startup
ASP.NET Core 中服务的生命周期有哪些?
Singleton 单例模式,只有一个服务实例被创建,这个实例存储在内存,可以在整个应用程序中使用。
services.AddSingleton<ITaskService, TaskService>();
Scoped 作用域,会在每个请求都创建一个服务的实例,请求的过程用的是同一实例。
services.AddScoped<ITaskService, TaskService>();
Transient 瞬态,服务每次被调用的时候会创建一个服务实例,这种比较适合轻量级、无状态的服务。
services.AddTransient<ITaskService, TaskService>();
中间件的应用场景有哪些?列举一些常用的中间件。
开发环境的异常处理:UseDeveloperExceptionPage();
⽣产环境的异常处理:UseExceptionHandler();
HTTP 严格传输安全协议:UseHsts();添加 Strict-Transport-Security 标头
HTTPS 重定向:UseHttpsRedirection();将 HTTP 重定向到 HTTPS
启用静态文件:UseStaticFiles();
启用 Cookie 策略:UseCookiePolicy();
路由请求:UseRouting();
身份验证:UseAuthentication(); 对用户进行身份验证,通过后才可心访问安全资源
授权:UseAuthorization(); 授权用户访问安全资源
会话中间件:UseSession();
终节点路由:UseEndpoints();
就列这些,注意它们的执行顺序。
ASP.NET Core 项目如何设置 IP 地址和端口号?
打开 Properties 文件夹下的 launchSettings 文件进行配置。
ASP.NET Core 异常处理有哪些方案?
创建一个 YldController 继承 Controller,重写 OnActionExecuted。后面创建的 Controller 都继承 YldController
namespace FirstWebApp.Controllers
{
public class YldController : Controller
{
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception != null)
{
//处理异常,记录异常信息等
}
base.OnActionExecuted(context);
}
}
//创建 HomeController ,继承 YldController
public class HomeController : YldController
{
public IActionResult Index()
{
return View();
}
}
继承 ActionFilterAttribute 类
public class ExceptionActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception != null)
{
//处理异常,记录异常信息等
}
base.OnActionExecuted(context);
}
}
public override void OnResultExecuted(ResultExecutedContext context)
{
if (context.Exception != null)
{
//处理异常,记录异常信息等
}
base.OnResultExecuted(context);
}
继承 IExceptionFilter 接口
public class YldExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.Exception != null)
{
//省略...
}
}
}
使用 ExceptionHandler
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
自定义中间件
public class ErrorMiddleware
{
private readonly RequestDelegate next;
public ErrorMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await next(context);
}
catch (Exception ex)
{
//处理异常
}
}
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
//启用自定义中间件
app.UseMiddleware(typeof(ErrorMiddleware));
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
什么是XSRF 或 CSFR?如何防止ASP.NET Core 中的跨站点请求伪造(XSRF/CSFR)攻击?
跨站点请求伪造 (也称为 XSRF 或 CSRF) 是对 web 托管应用程序的攻击,恶意 web 应用可能会影响客户端浏览器和信任该浏览器的 web 应用之间的交互。这些攻击是可能的,因为 web 浏览器会自动向网站发送每个请求的身份验证令牌。这种形式的攻击也称为 一键式攻击 或 会话 riding ,因为攻击利用用户以前的经过身份验证的会话。
标签:Core,面试题,ASP,使用,NET,方法,public From: https://www.cnblogs.com/rsg-zxh/p/17168786.html