.NET与.NETCore
在5.0版本之前,.NET代表.NETFramework,在5.O版本之后Framework被抛弃,与Core合并为.NET5.0
.NETCore从哪开始
毫无疑问,C#程序都是以Program.cs文件中的Main方法开始。
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>();
});
}
可以看到,程序先创建了个IHostBuilder,将args参数传入Host.CreateDefaultBuilder
方法中。在此方法中才调用大名鼎鼎的Startup类。
可以不使用Startup类,其作用只是配置host,甚至可以根据控制台指令执行不同的TStartup类。
自定义TStartup:(TStartup可以是任意类,没有接口限制。)
public class ClassOne
{
public ClassOne(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var conn = Configuration["ConnectionString:DefaultConn"];
services.AddDbContext<ApplicationDbContext>(option => option.UseSqlServer(conn));
services.AddIdentity<Useraccount, IdentityRole>(
options => options.SignIn.RequireConfirmedAccount = true
).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews(
config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}
);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
必须要的几点:
1.带IConfiguration
参数的构造函数。
2.public IConfiguration Configuration { get; }
3.public void ConfigureServices(IServiceCollection services)
因为要使用MVC必须先注册服务。
4.public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
参数自己看着加,IApplicationBuilder是设置中间件,IWebHostEnvironment是文件环境(可以取根目录等等)。
服务的依赖注入
依赖注入DI和控制反转IoC
-
依赖注入
首先理解依赖:public class MyClass { List<int> _list; public void Change() { _list.Count; } }
在MyClass中有一个_list属性,就说明其存在一个依赖。并且可以发现_list没有初始化,并且Change方法希望访问其Count参数。按上述代码是不会编译通过的。所以需要从外部注入_list实例。这就是依赖注入的含义。
public class MyClass
{
List<int> _list;
public void Change(List<int> list)
{
_list.Count;
}
}
-
控制反转
学习了接口之后,我们得以充分了解面向对象的特点——多态。多态的特性是实现控制反转的基础。在没有多态之前,每个函数都必须接受精确的、数量相同的参数。这说明控制权掌握在函数。将参数类型调整为基类(如Object)时,函数可接受范围变大,函数是处于被动接受的状态——给什么参数都要收。这就叫控制反转。
但是有时候会发现使用Object太广泛了,所以接口的作用就凸显出来了。在C#中,接口就是对类的特点的集合。例如有许许多多不同种类的鸟,但是他们都有共同的特点——会飞、长有两只翅膀。那么就可以使用IBird接口抽象形容它。使用接口做参数相对于用Object同样是控制反转,只是范围缩小了。public class MyClass { IList<int> _list; public void Change(IList<int> list) { _list.Count; } }
回到Core中
services.AddScoped<IAccountProfileService, AccountProfileService>();
注入方法与只用接口注入不同。可以看到ConfigureServices(IServiceCollection services)
的参数是一个service集合,服务就是注入到这个动态集合里。AddScoped<T1,T2>()
方法中T2是服务类,T1是服务接口。所以每一个需要注入的服务都要有一个接口。
- 使用Add方法注入服务后怎么实例化服务?
有三种服务类型
1.Transient:每一次GetService都会创建一个新的实例。
什么时候是getservice呢?
public class AccountController : Controller
{
private readonly UserManager<Useraccount> _userManager;
private readonly SignInManager<Useraccount> _signInManager;
private readonly IAccountProfileService _profileService1;
private readonly IAccountProfileService _profileService2;
public AccountController(UserManager<Useraccount> userManager,SignInManager<Useraccount> siginManager
, IAccountProfileService profileService1,IAccountProfileService profileService2)
{
_userManager = userManager;
_signInManager = siginManager;
_profileService1 = profileService1;
_profileService2 = profileService2;
}
}
假设用户发送一个请求,AccountController响应了。通过构造器生成两个服务,如果是Transient那么两个服务不同。如果是Scoped,在下一次http服务发送来之前两个服务相同。Singleton都是同一服务。
2.Scoped:在同一个Scope内只初始化一个实例 。
3.Singleton:整个应用程序生命周期内只创建一个实例。
Core的优点在哪
可扩展性强:framework程序开始时选框架,之后添加框架麻烦。core采用服务注入的方式添加框架,灵活性更强。服务之间相互独立,减少耦合。
中间件
https://www.cnblogs.com/liujiabing/p/11498163.html
-
什么是中间件:
出于安全性考虑,前端发送来的请求都不能直接输入后端。需要管道对信息预处理,管道中的组件就是中间件。
主要功能:信息安全、对数据预处理、调度分配 -
中间件执行顺序:
-
.netcore终端中间件:
-
Run
app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); });
执行该函数后会直接跳到管道末尾,后续中间件不会执行。
-
Map
app.Map("map1", app => { app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); });
第一个参数:匹配条件是HttpContext.Request.Path和预设值。
第二个参数:自定义管道。
可以根据这个函数设计多个管道分支。 -
MapWhen
map加约束版本app.MapWhen(context => context.Request.Query.ContainsKey("nihao"), app => { app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } );
-
路径设置:
.netcore中MVC会默认设置有终端模式:
设置默认路由,就是设置终端路由。app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });
老方法
app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
老方法需要吧mvc设置为无终端模式。
services.AddControllersWithViews( config => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); config.Filters.Add(new AuthorizeFilter(policy)); config.EnableEndpointRouting = false;//设置 } );