来一波C#.NET B/S开发方向的面试题。
祝好运连连
祝一面而就
GUID所占的内存大一些,而雪花算法所占的内存小一些
GUID可以通过设置方法来进行自增,如果没有方法,GUID不自增
雪花算法则是通过时间戳的方式生成,但不一定是全局递增的;另外如果时钟回拨,则有可能生成重复ID;
(1) Singleton单例模式:单例对象对于每个对象、每个请求都是一样的,对于不同的客户端、不同的请求可以说是一样的。
(2) Transient 瞬态模式:Transient对象总是不同的,每次都会创建一个新的实例,无论是同一个请求(同一个请求中的不同服务)还是同一个客户端。
(3) Scoped作用域模式:作用域对象在一个客户端请求中相同,但在多个客户端请求中不同。
在 .NET Core 中,过滤器是一种用于在应用程序中实现“横切关注点”的技术。
过滤器可以在应用程序处理请求和响应的不同阶段中执行代码,并允许您在每个阶段上执行自定义逻辑。以下是过滤器在 .NET Core 中的一些使用场景:
身份验证和授权:授权过滤器可以用于实现身份验证和授权逻辑,例如在请求到达控制器或操作之前验证用户的身份或权限。
日志记录:行为过滤器可以用于记录应用程序的日志,例如在请求到达控制器或操作时记录请求和响应的信息。
异常处理:异常过滤器可以用于捕获和处理应用程序中的异常,例如在操作执行时发生错误时返回自定义错误消息。
缓存:资源过滤器可以用于实现缓存逻辑,例如在操作执行前从缓存中获取数据或将数据添加到缓存中。
性能优化:行为过滤器可以用于优化应用程序的性能,例如在请求到达控制器或操作之前检查请求参数的有效性,以避免不必要的操作。
1.控制反转是一种在软件工程中解耦合的思想,调用类只依赖接口,而不依赖具体的实现类,减少了耦合。控制权交给了容器,在运行的时候才由容器决定将具体的实现动态的“注入”到调用类的对象中。
2.依赖注入是一种设计模式,可以作为控制反转的一种实现方式。依赖注入就是将实例变量传入到一个对象中去
控制反转思想可以指导我们如何设计出松耦合,更优良的程序,传统应用程序都是由于我们在类内部主动创建依赖对象 从而导致类与类之间 高耦合,难于测试,有了ioc容器以后我们可以把创建依赖对象的控制权交给了IOC容器,由容器注入组合对象,所以对象和对象之间是松耦合的;便于测试 ,最重要的是 使各个功能之间变得非常灵活。比如AutoFac,就是一个IOC容器
Map用来定义一个管道可以处理哪些请求。
Use和Run用来定义管道,一个管道由若干个Use和一个Run组成,每个Use引入一个中间件,而Run是用来执行最终的核心应用逻辑。
用Use将多个请求委托链接在一起。 next参数表示管道中的下一个委托。 可通过不调用next参数使管道短路。
Run 委托不会收到 next 参数。 第一个 Run 委托始终为终端,用于终止管道。 Run 是一种约定。 某些中间件组件可能会公开在管道末尾运行的 Run[Middleware]
Map*扩展用作分支管道的约定
UseAuthentication 身份验证中间件
UseCors 跨域中间件
UseSession 会话缓存中间件
UseStaticFiles 静态文件中间件
UseAuthorization 授权认证中间件
UseSwagger swagger测试中间件
UseRouting 路由中间件
1)协议不同:
WebApi用的是HTTP协议,WebService用的是SOAP协议;
2)数据格式
WebApi可以自定义格式(int,string,xml等,标准是json)
WebService是xml数据格式
3)WebApi无状态(http是无状态协议,断开数据就丢失),比WebService更轻量级。 WebApi支持如get,post等http操作
在ASP.NET Core中,中间件可以访问到的是HTTP请求和HTTP响应,所以可以用来:
通过生成一个HTTP响应来处理HTTP请求
处理并可以修改HTTP请求,然后将该HTTP请求传给管道上的下一个中间件
处理并可以修改HTTP响应,并将HTTP响应传递给管道上的下一个中间件或ASP.NET Core应用
使用 .NET Core 进行项目开发有以下几个优势:
跨平台支持:.NET Core 能够在 Windows、macOS 和 Linux 等多个操作系统上运行,可以大大降低开发人员的学习成本和开发成本,提高代码复用性。
高性能:.NET Core 相比传统 .NET Framework 具有更高的性能,主要得益于其采用的基于运行时编译的 JIT 技术,同时采用了更加轻量级的架构设计。
依赖性管理:.NET Core 提供了强大的依赖性管理功能,可以方便地管理和维护项目所依赖的各种包和库。
开放源代码:.NET Core 是一个开放源代码的框架,这意味着开发人员可以在其基础上进行二次开发和定制,也能够更好地与其他开源框架和工具进行集成。
支持微服务架构:.NET Core 支持微服务架构,可以方便地构建分布式应用程序。
总的来说,采用 .NET Core 进行项目开发可以提高开发效率,降低成本,同时也能够得到更好的性能和可维护性。
ASP.Net Core默认提供的跨平台的服务器是Kestrel服务器。Kestrel是ASP.Net Core的默认Web服务器,它是跨平台的,可以在Windows、Linux和macOS等操作系统上运行。
Kestrel是一个轻量级的服务器,专门为处理ASP.Net Core应用程序而设计。它负责处理HTTP请求和响应,支持HTTP/1.x和HTTP/2协议,并且具有异步处理请求的能力。Kestrel也可以与反向代理服务器(如Nginx或Apache)一起使用,以提高安全性和性能。
需要注意的是,虽然Kestrel是一个快速且可靠的服务器,但它并不适合直接暴露在公共网络上。在生产环境中,应该使用反向代理服务器(如Nginx或Apache)来保护Kestrel服务器。
CORS跨域服务
Authentication身份认证服务
Swagger的服务
Redis的服务
DbContext数据库上下文服务
控制器相关的服务(配置过滤器)
配置Autofac相关服务
还有自己项目的服务,如Service服务、Repository服务等
AOP(面向切面编程)是一种编程范式,它允许在程序运行时动态地横向增加新的行为,而无需修改现有代码。
AOP的核心思想是将应用程序分为多个关注点,每个关注点实现特定的功能,例如安全性、事务、日志记录、缓存等。
AOP的主要优势在于解耦和复用。通过使用AOP,可以将一些通用的功能集中在一个地方,而不是分散在整个应用程序中。这样,它可以让代码更加清晰易懂、易于维护,并且避免重复代码。
例如,假设您的应用程序需要记录每个方法的执行时间,您可以使用AOP创建一个切面,该切面在每次方法调用前记录开始时间,在方法调用后记录结束时间,并计算时间差。这样,您就可以将这个通用功能应用于整个应用程序,而无需在每个方法中重复代码。
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。
基本上有三种主流的解决方案:
1、使用JSONP的方式:JSONP是一种比较古老的解决方案,这种方案首先没有兼容性问题,基本都可以使用,但是它所解决的问题比较有限,且对服务端接口有一定的要求
2、使用反向代理:这种方式目前使用相当普遍,就是在目标服务器和浏览器中间架一层服务器,我们称该服务器为代理服务器
3、使用跨域资源共享:这是一种新的解决跨域的方式,主要是通过设置特殊的响应头,来达到解除跨域限制的目的。跨域资源共享简称CORS(我们现在用这个),需要浏览器和服务器同时支持,目前所有的浏览器都支持,ie必须不能低于ie10
EF(Entity Framework)是一个对象关系映射框架,可以用来简化与数据库交互的代码。在进行查询时,以下是一些优化EF查询效率的方法:
使用延迟加载:EF默认使用延迟加载(Lazy Loading)来获取导航属性的数据。延迟加载可以避免不必要的查询和数据加载,因此可以提高查询性能。你可以通过配置来启用或禁用延迟加载。
使用预先加载:预先加载(Eager Loading)是在查询时一次性获取所有相关数据的技术。它可以避免多次查询数据库,从而提高查询性能。你可以使用Include()方法来实现预先加载。
使用筛选:筛选是通过条件过滤数据以获取所需数据的技术。使用筛选可以减少从数据库中检索的数据量,从而提高查询性能。你可以使用Where()方法来实现筛选。
避免多层嵌套查询:多层嵌套查询会导致查询性能下降。你可以尝试使用联接(Join)操作来减少嵌套查询。
使用索引:索引可以加速数据检索和查询操作。如果你的数据库中有大量的数据,使用索引可以显著提高查询性能。
使用存储过程:存储过程可以在数据库中进行预处理,从而提高查询性能。你可以使用EF来执行存储过程。
调用AsNoTracking()方法 实现非跟踪式的只读查询
在之前的泛型仓储模式实现中,每个增删改都调用了SaveChanges方法,导致每次更新都提交了事务。
在实际开发过程中,我们经常遇到同时操作多张表数据,那么按照之前的写法,对数据库提交了多次操作,开启了多事务,不能保证数据的一致性,结合工作单元(UnitOfWork)是为了把多次操作放到同一事务中,要么都成功(Commit),要么都失败(Rollback),保证了数据的一致性。
在 .NET Core 中,过滤器和拦截器都是用于在 ASP.NET Core 应用程序处理请求和响应时提供预定义的功能的组件。以下是它们的一些常见应用场景:
过滤器:
认证和授权:在请求处理之前检查身份验证和授权状态
缓存:使用缓存来提高性能和减少响应时间
异常处理:捕获应用程序中的异常并采取相应措施
日志记录:记录请求和响应数据,用于调试和性能分析
压缩:压缩响应数据以减少传输时间和带宽
拦截器:
拦截和修改请求和响应数据
限制请求速率和并发连接数
实现缓存和本地存储
在请求处理前进行数据验证和格式化
在请求处理后进行数据处理和清理
数据库事务处理
过滤器和拦截器的区别:
过滤器和拦截器 底层实现方式大不相同,过滤器 是基于函数回调的,拦截器 则是基于C#的反射机制(动态代理)实现的。
工作流引擎,软件开发中不可避免的重要一环。.所谓 工作流引擎 ,是指workflow作为应用系统的一部分,并为之提供对各应用系统有决定作用的根据角色、分工和条件的不同 决定信息传递路由、内容等级等核心解决方案。工作流引擎包括流程的节点管理、流向管理、流程样例管理等重要功能。
泛型仓储主要是通过类型的参数化,将类型像方法的参数进行传递使得程序在后期有很强的扩展性,达到解耦业务逻辑层与数据访问层,降低耦合。
包含方法:CRUD方法。添加、批量添加;单删、批删,根据ID查询、根据条件查询、分页查询等
禁止使用延迟加载,使用贪婪加载,尽量的减少数据库的访问次数
使用AsNoTracking进行数据获取,这样省去了访问EF Context的时间,会大大降低数据获取所需的时间
使用IQueryable,IEnumerable进行查询,而不是用List
IQueryable返回的是查询表达式,也就是说生成了SQL查询语句但是却还没有与数据库进行交互。
IEnumerable则是已经执行查询数据库的操作且数据保存在了内存中
使用SqlQuery,使用sql查询语句,此方法获得的实体查询是在数据库上,实体不会被上下文跟踪。
使用Dto代替实体,需要哪些字段就查询哪些,而不是用select * 全部加载出来
EF数据加载三种方式:延迟加载、贪婪加载、显示加载(EF中默认是开启延迟加载)
延迟加载(Lazy Loading) 和淘宝的商品列表一样,下拉刷新,按需加载。
贪婪加载 (Eager Loading) 加载父对象时同时加载子对象。
显式加载 (Explicitly Loading)当我们禁用了延迟加载,仍然可以通过显式加载来延迟加载相关实体。
.NET Framework是Microsoft的一种平台,它能够用于构建、部署和管理从简单的窗体应用程序到复杂的企业级应用程序。
.NET Core是一个跨平台的、开源的、可扩展的框架,它可以用于构建应用程序和服务,使用任何编程语言。.NET Core提供了更多的可移植性和自定义性,并且比.NET Framework更加灵活。
.NET Core性能更快、生成的程序集更小适合容器化部署,更适合开发微服务
多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
如何避免线程死锁?
加锁顺序(线程按照一定的顺序加锁)
加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
死锁检测
进程定义:进程是具有一定功能的程序在一个数据结合上的运行过程,它是系统进行资源分配和调度管理的 一个可并发执行的基本单位
线程定义:线程是进程中实施调度和分派的基本单位。一般分为用户级线程和核心级线程。
1、一个进程可以有多个线程,但至少有一个线程;而一个线程只能在一个进程的地址空间内活动。
2、资源分配给进程,同一个进程的所有线程共享该进程所有资源。
3、CPU分配给线程,即真正在处理器运行的是线程。
4、线程在执行过程中需要协作同步,不同进程的线程间要利用消息通信的办法实现同步。
在 EF 中,跟踪和非跟踪机制是指在从数据库中查询实体数据时,EF 如何管理实体对象的状态和更改。
跟踪机制是 EF 默认使用的机制。当从数据库中查询实体对象时,EF 会将这些对象添加到一个内部的“对象上下文”中,并且会跟踪这些对象的所有更改。这意味着,当你修改实体对象时,EF 会自动跟踪这些更改,并在提交到数据库时进行保存。这种机制通常会导致内存占用增加,因为 EF 会一直跟踪实体对象,即使你不需要在应用程序中长时间保留这些对象。
非跟踪机制是一种不使用对象上下文的方式,EF 不会跟踪实体对象的更改。这种机制通常用于临时查询,只需要从数据库中读取一些数据,然后将其转换为实体对象,然后将这些对象用于只读操作。使用非跟踪机制可以减少内存占用,并提高性能。
在 EF 中,使用跟踪和非跟踪机制的方式取决于应用程序的需求和场景。如果需要更新实体对象并提交更改,则应使用跟踪机制。如果只需要从数据库中读取数据,而不需要跟踪更改,则应使用非跟踪机制。
在 .Net Core 项目中,可以通过 appsettings.json 文件来配置应用程序的不同环境。默认情况下,.Net Core 会读取 appsettings.json 文件中的配置,但是在不同环境中需要不同的配置,因此需要对 appsettings.json 文件进行不同的配置。
首先,可以创建 appsettings.json 文件,在其中添加应用程序需要的配置。然后,可以创建两个新的配置文件:appsettings.Development.json 和 appsettings.Production.json。
然后,在启动应用程序时,可以通过设置 ASPNETCORE_ENVIRONMENT 环境变量来指定当前环境。
如果不设置 ASPNETCORE_ENVIRONMENT 环境变量,则默认使用 appsettings.json 文件中的配置。
1、Database First:
数据库优先,就是你先建好数据库,然后再根据数据库生成Model。
这种方式唯一的缺点就是需要你去建实体对象的partial类,在partial类中设置特性等。
感觉还是这种方式是最好的,只是没有CodeFirst新潮啊,所以啊,很难留住那些花心的男人。
2、Code First:
代码优先,就是先建立实体类,然后根据实体类生成数据库。
这种方式不需要partial类,你在写实体类的时候,顺便也会把特性写上。
这种方式使用起来也不像微软说的那样容易,你既要懂数据库,又要懂Code First的各种约定、技巧,个人感觉比 Database First 入门更难。并且,操作不当的话,很有可能带来灾难性的后果,因为你一个错误的代码,就有可能导致数据库暴动。
3、Model First:模型优先,通过模型设计器,设计各个模型和ER关系,然后自动生成实体类cs文件
多线程是一种并发编程的技术,它允许程序在同一时间内执行多个线程,每个线程可以独立执行不同的任务。在多线程编程中,程序被设计成可以同时处理多个任务,从而提高程序的性能和响应能力。
在计算机中,线程是操作系统中的基本调度单位,它是轻量级的执行单元,它可以独立运行于程序中,与其他线程并发执行。线程共享进程的地址空间,因此可以访问相同的数据,不同的线程可以同时访问同一块内存空间,这种共享的机制使得线程之间的通信更加简单。
在 .NetCore 中
1. 以通过创建一个 Thread 对象并将其启动来启动一个线程。下面是启动线程的步骤:
创建一个 ThreadStart 委托,该委托将作为线程的入口点,指定线程将执行的方法。
创建一个 Thread 对象并将其实例化,将 ThreadStart 委托作为构造函数参数传递给 Thread 对象。
调用 Thread 对象的 Start() 方法来启动线程。线程将执行 ThreadStart 委托指定的方法
2. 也可以通过Task来创建、启动多线程
展示层、应用层、领域层、基础设施层
领域层和应用层要分开的原因?
领域驱动设计(DDD)的主要特点就是从业务领域出发,划分边界,把相关的功能在同一个领域范围内实现,所以说领域层是业务的核心,领域模型的核心逻辑代码一定要在领域层实现。
而应用层代码主要完成服务组合和编排,以及聚合之间的协作,它只是承上启下的作用,不应该有核心领域逻辑代码。如果将核心领域逻辑代码放到应用层,基于 DDD 分层架构模型的微服务实际上就会慢慢变成传统的三层架构模型了,那样的话代码逻辑混乱的情况早晚会出现,也就失去了使用DDD分层架构的初衷。
AutoMapper是基于对象到对象约定的映射工具,它可以把复杂的对象模型转为DTO,或者其他的--那些让设计更合理更适于序列化、通信、传递消息的简单对象 或者干脆就只是在领域层与应用层之间搭建一个简单的ACL防护层(就像DTO一样,用于代码的显示转换)来增加各自层的相互独立性。
写类型转换的映射代码是一件繁琐又枯燥的事情,所以使用AutoMapper能解决这些问题。
Autofac就是用来依赖注入的一个容器,用来解耦,并且由该容器来统一构建出对象。
Autofac传说是速度最快的一个,轻量级性能高;
(C#语言联系很紧密,许多框架如Abp都会有默认支持AutoFac,微软的Orchad开源程序使用的就是Autofac)
支持很多的注入方式,如批量注入整个程序集中的类,或者根据类名规则进行注入,也可以实现最基本的一条条地注入;也支持三种生命周期:单例、瞬态、域模式;
加密算法我们整体可以分为:可逆加密和不可逆加密,可逆加密又可以分为:对称加密和非对称加密。
不可逆加密算法有MD5,HMAC,SHA1,比较常用的场景就是用户密码加密,其验证过程就是通过比较两个加密后的字符串是否一样来确认身份的。
对称加密算法是应用比较早的算法,在数据加密和解密的时用的都是同一个密钥,这就造成了密钥管理困难的问题。常见的对称加密算法有DES、3DES、AES128、AES192、AES256;
非对称加密算法有两个密钥,这两个密钥完全不同但又完全匹配。只有使用匹配的一对公钥和私钥,才能完成对明文的加密和解密过程。常见的非对称加密有RSA、SM2等
反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外还可以直接创建对象,即使这个对象的类型在编译时还不知道。
1.反射 可以通过具体的程序集加载对应的类型,或者遍历类的成员,获取成员的类的值,具体使用场景(配合接口使用)
2.当功能点具有较多的变化需求时,将该变化需求都在一个类中维护会显得代码臃肿不堪,维护性比较低,这个时候如果可以知道具体加载的方法,就可以通过反射直接加载对应的程序集并创建实例,
3.通过反射遍历类成员,获取属性值,这个使用场景是在UI上,
ASP.NET SignalR 是为ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程。实时 Web功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。
实时通讯
什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端可以互相通知消息及调用方法,当然这是实时操作的。
以前用户需要刷新页面或使用Ajax轮询才能实现的实时显示数据,现在只要使用SignalR,就可以简单实现了。
最重要的是您无需重新建立项目,使用现有ASP .NET项目即可无缝使用SignalR。
在 LINQ 中,默认的连接方式是内连接(Inner Join),它只返回两个表中有匹配的行。内连接会根据两边表中的连接条件进行匹配,只返回匹配的结果。如果某个表中没有匹配的数据,则该表中的数据将不会被返回。内连接可以使用 join和on 关键字来实现。
如果需要实现左连接查询,可以使用DefaultIfEmpty() 方法和into关键字来实现
委托和Lambda表达式都是C#编程语言中的功能。
委托是一种类型,它可以用于封装一个或多个方法,并将它们作为参数传递给其他方法。委托定义了一个签名,该签名指定了方法可以接受的参数类型和返回类型。在委托类型的实例中,可以将一个或多个方法绑定到该委托实例,并且可以调用该委托实例以执行绑定的方法。
Lambda表达式是一种语法结构,它提供了一种简洁的方式来定义委托实例。Lambda表达式使用“=>”符号将输入参数与输出表达式分开。这个输出表达式可以是单个语句或代码块。Lambda表达式可以用于创建委托实例,该委托实例可以用于调用绑定的方法。
因此,Lambda表达式可以被视为是一种方便的语法,它允许您在不显式声明委托类型的情况下创建委托实例。委托类型是实际类型,而Lambda表达式是创建委托实例的语法。
使用场景:电商平台要搞促销活动,设定好活动开始时间,在到达开始时间的时候定时推一些促销信息到网站前台。用户购买商品后,未支付订单,支付时间过后,会执行取消订单
调度器:任务调度器,负责管理Quartz.NET引用运行时环境
触发器:描述执行任务的时间,告诉调度器什么时候执行任务
任务类:就是实现任务接口来定义我们需要操作的方法执行
责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者与接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止;
依赖注入模式: ABP 框架使用了依赖注入模式,以便实现应用程序中各个模块之间的解耦。
单例模式: ABP 框架中的某些组件 (如日志组件)是单例模式的,以便确保应用程序的性能和效率。
工厂模式: ABP 框架中使用工厂模式来创建一些对象,如仓储对象.
观察者模式: ABP 框架中使用观察者模式来实现事件处理,如事件总线模块中的事件处理器。
EF中的FirstOrDefault 和SingleOrDefault 都是用于查询序列(如数据库表)中的第一个匹配项,但它们在查询结果为空或者多于一个时有所不同。
FirstOrDefault :返回序列中满足指定条件的第一个元素,如果序列为空,则返回默认值(null或者指定的默认值)。如果序列中有多个匹配项,只返回第一个匹配项。
SingleOrDefault :返回序列中满足指定条件的唯一元素,如果序列为空,则返回默认值(null或者指定的默认值)。如果序列中有多个匹配项,将会抛出 InvalidOperationException 异常。
EF(Entity Framework)和Dapper都是.NET平台上的ORM(对象关系映射)框架,它们的主要作用都是简化应用程序与数据库之间的交互。虽然它们的目标是相同的,但是它们在实现方式和使用场景上有一些区别。
实现方式:EF是一种全面的ORM框架,它提供了许多功能,例如LINQ查询、跟踪变化和缓存等。Dapper则是一个轻量级的ORM框架,它的实现非常简单,几乎没有学习曲线,适合于小型项目。
性能:由于EF提供了许多功能,因此其性能可能比Dapper略低。然而,EF的查询优化器通常可以生成比手写的SQL更好的SQL语句,这可能会在某些情况下提高性能。而Dapper的性能则比较高,因为它几乎没有额外的开销。
学习曲线:EF需要学习的东西比Dapper多,它的API也比较复杂。而Dapper的API非常简单,只需要学习几个方法即可使用它。
适用场景:EF适用于大型企业级应用程序,因为它提供了更多的功能,可以更好地处理复杂的业务场景。Dapper适用于小型项目或需要高性能的项目,例如需要处理大量数据或需要快速读取数据的项目。
总之,EF和Dapper各有优缺点,选择哪个框架取决于项目的具体需求和开发人员的经验水平。
假设你有两个C#集合,分别命名为 collection1 和 collection2 。下面是使用LINQ进行交集、并集、差集和全集操作的代码示例:
//交集:
var intersection = collection1.Intersect(collection2);
//并集:
var union = collection1.Union(collection2);
//差集:
var difference = collection1.Except(collection2);
//全集:
var all = collection1.Concat(collection2).Distinct();
在这些代码中,LINQ的操作符被用来实现不同的集合操作。
.Intersect() 方法用于查找两个集合之间的交集,
.Union() 方法用于查找两个集合之间的并集,(重复的部分会去重,而Concat不去重)
.Except() 方法用于查找两个集合之间的差集,
.Concat() 和 .Distinct() 方法一起用于查找两个集合的全集。
ADO是ActiveX Data Objects的缩写,它是一个COM组件库,用于在Microsoft技术中访问数据。
简单来说,ADO.NET就是一种数据访问接口,可以让我们在程序中调用相应的类库对数据库
(通常为SQL Server,也可以是MySql等其他数据库)进行增删改查等操作。
ADO.NET由五大类库组成,分别是:
Connection(用于建立与 数据库的连接)
Command(用于执行SQL语句)
DataReader(用于读取数据)
DataAdapter(用于填充把数据填充到DataSet)
DataSet(数据集,用于程序中)
使用LINQ查询:在DbContext实例上使用LINQ查询语言,通过Where或者Any等方法对数据表进行筛选,然后使用Count或者Any等方法来判断是否有符合条件的数据
bool exists = dbContext.MyTable.Any(x => x.Id == myId);
这里的MyTable是数据表的名称,x是表中的每一行数据,Id是表中的某个字段名,myId是要查找的数据。如果有符合条件的数据,则返回true,否则返回false。
ABP(Asp.Net Boilerplate)是一个基于ASP.NET Core的开源应用程序框架。ABP框架为开发人员提供了一系列常用的功能和最佳实践,使开发人员能够更快地构建高质量的Web应用程序和微服务。
ABP框架采用模块化设计,可以将应用程序分解为一个个小的、独立的模块。每个模块都有自己的特定功能,可以在不同的应用程序中重用。ABP框架包含许多预置模块,例如身份验证、权限管理、本地化、缓存、通知等等,这些模块使开发人员能够更快地构建应用程序,并且可以根据需要进行自定义。
ABP框架还采用了领域驱动设计(DDD)的思想,将应用程序分解为不同的领域对象。这使得开发人员能够更好地组织和管理应用程序,并且更容易地进行单元测试和集成测试。
总之,ABP框架提供了一个全面的、可扩展的基础架构,使开发人员能够更轻松地构建高质量的Web应用程序和微服务。
使用场景:电商平台要搞促销活动,设定好活动开始时间,在到达开始时间的时候定时推一些促销信息到网站前台。用户购买商品后,未支付订单,支付时间过后,会执行取消订单
调度器:任务调度器,负责管理Quartz.NET引用运行时环境
触发器:描述执行任务的时间,告诉调度器什么时候执行任务
任务类:就是实现任务接口来定义我们需要操作的方法执行