.net core mvc启动顺序以及主要部件3-Startup
前面分享了.net core Program类的启动过程已经源代码介绍,这里将继续讲Startup类中的两个约定方法,一个是ConfigureServices,这个方法是用来写我们应用程序所依赖的组件。另一个Configure,它是我们MVC请求的中间件方法,也就是我们每个请求来要执行的过程都可以写在这个方法里面。
为什么说Startup类中的两个方法是基于约定的呢?其实是这样的,在.net core Program类Main方法中有个调用了Run方法这个方法从IServiceCollection容器中拿到一个IStartup类型的实例然后调用了IStartup中定义的两个方法法,如果我们的Startup类是实现了这个接口的类 那么就不是基于约定了,直接就可以使用,但是我们发现在vs给我们生成的Startup类并没有实现任何接口,所以就不会是IStartup类型,那么内部是如何去做的呢? 其实是这样的,在注册Startup实例的时候还有个类型叫做ConventionBasedStartup从名称上解读这个类就是转换为基础的Startup,其实却是也是这样的,这个类中是实现了IStartup接口,它的两个方法中分别调用了各自的对用委托,这些委托实际执行的就是我们Startup类中定义的两个方法,请看源代码:
public class ConventionBasedStartup : IStartup
{
private readonly StartupMethods _methods; public ConventionBasedStartup(StartupMethods methods)
{
_methods = methods;
} public void Configure(IApplicationBuilder app)
{
try
{
_methods.ConfigureDelegate(app);
}
catch (Exception ex)
{
if (ex is TargetInvocationException)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}
throw;
}
} public IServiceProvider ConfigureServices(IServiceCollection services)
{
try
{
return _methods.ConfigureServicesDelegate(services);
}
catch (Exception ex)
{
if (ex is TargetInvocationException)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}
throw;
}
}
}
现在Startup类的方法说清楚了,我们具体来说说方法中的内容,首先说ConfigureServices(IServiceCollection services),这个方法的参数是约定好的,不能随意改变,里面的IServiceCollection接口其实就是我们依赖注入的容器,说的再直白一点就是我们整个MVC所需要的实例都由IServiceCollection所管理,IServiceCollection有几个重要的扩展方法,他们都是定义在ServiceCollectionServiceExtensions静态类中,AddTransient方法,表示用这个方法添加到IServiceCollection容器的实例在需要注入的实例中都是一个全新的实例,AddScoped方法,这个方法表示在一次请求的生命周期内共用一个实例,AddSingleton方法,这个方法表示整个程序共用一个实例,例如日志服务,IConfiguration服务等都属于典型Singleton。请看例子:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<TransientService>();
services.AddTransient<ServiceDemo1>();
services.AddTransient<ServiceDemo2>();
} public void Configure(IApplicationBuilder app, ServiceDemo1 demo1, ServiceDemo2 demo2 )
{
demo1.Test();
demo2.Test();
app.Run(async (HttpContext context) =>
{
await context.Response.WriteAsync("test successd");
});
}
}
public class TransientService
{
private int _updateCount;
public int GetUpdateCount()
{
this._updateCount = this._updateCount + 1;
return this._updateCount;
}
}
public class ServiceDemo1
{
private readonly TransientService _service;
public ServiceDemo1(TransientService service)
{
_service = service;
}
public void Test()
{
Console.WriteLine($"我是demo1的计数:{this._service.GetUpdateCount()}");
}
}
public class ServiceDemo2
{
private readonly TransientService _service;
public ServiceDemo2(TransientService service)
{
_service = service;
}
public void Test()
{
Console.WriteLine($"我是demo2的计数:{this._service.GetUpdateCount()}");
}
}
上面的例子中会产生一下结果,可以看得出来这两个注入的TransientService都是全新的实例
如果我们稍微改变一下注入的方法,将原本的 services.AddTransient<TransientService>();改成services.AddScoped<TransientService>();就会产生如下结果:
这个能说明什么呢,我们有两次注入 这个就表示TransientService保持了之前demo1的状态 demo1和demo2是可以共用这个实例来传输数据的,AddSingleton方法理解起来比较简单就不过多絮叨了,上面已经说明。
接下来再来说说Startup类中的Configure方法,Configure方法中的参数是可以变化的,也就是说你可以用依赖注入的方法在参数中注入你想要注入的实例,前面说了 这个方法是我们请求的中间件方法,这个方法中会整合我们注入的IApplicationBuilder 中调用的各种Use方法中定义的中间件 并不是说这里面定义的代码每次请求都会被执行,这个概念一定要搞清楚,Configure方法只会在启动的时候执行一次,后面就不会再执行了,Configure方法只是让我们可以定义整个MVC的处理请求的执行顺序,具体的可以看看官方的文档https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.2
其实中间件都是由IApplicationBuilder 所管理的ApplicationBuilder类实现了IApplicationBuilder 接口中的方法,看到ApplicationBuilder中的源代码中有个属性_components 它是一个IList<Func<RequestDelegate, RequestDelegate>>类型的委托容器,容器中的委托就是请求过来需要执行的中间件委托,当你在Configure方法中调用app.UseXXX的时候就会被注册到这个容器中去,然后请求过来就按照顺序执行容器中的每一个委托,所以这里就解释了前面说的Configure方法只会被执行一次的说法。下面也贴一下ApplicationBuilder类的源代码:
public class ApplicationBuilder : IApplicationBuilder
{
private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>(); public IServiceProvider ApplicationServices
{
get
{
return GetProperty<IServiceProvider>(Constants.BuilderProperties.ApplicationServices);
}
set
{
SetProperty(Constants.BuilderProperties.ApplicationServices, value);
}
} public IFeatureCollection ServerFeatures => GetProperty<IFeatureCollection>(Constants.BuilderProperties.ServerFeatures); public IDictionary<string, object> Properties
{
get;
} public ApplicationBuilder(IServiceProvider serviceProvider)
{
Properties = new Dictionary<string, object>(StringComparer.Ordinal);
ApplicationServices = serviceProvider;
} public ApplicationBuilder(IServiceProvider serviceProvider, object server)
: this(serviceProvider)
{
SetProperty(Constants.BuilderProperties.ServerFeatures, server);
} private ApplicationBuilder(ApplicationBuilder builder)
{
Properties = new CopyOnWriteDictionary<string, object>(builder.Properties, StringComparer.Ordinal);
} private T GetProperty<T>(string key)
{
if (!Properties.TryGetValue(key, out object value))
{
return default(T);
}
return (T)value;
} private void SetProperty<T>(string key, T value)
{
Properties[key] = value;
} public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_components.Add(middleware);
return this;
} public IApplicationBuilder New()
{
return new ApplicationBuilder(this);
} public RequestDelegate Build()
{
RequestDelegate requestDelegate = delegate (HttpContext context)
{
context.Response.StatusCode = 404;
return Task.CompletedTask;
};
foreach (Func<RequestDelegate, RequestDelegate> item in _components.Reverse())
{
requestDelegate = item(requestDelegate);
}
return requestDelegate;
}
}
好啦,这篇关于Startup类就算介绍完成了,下篇开始正式介绍MVC
.net core mvc启动顺序以及主要部件3-Startup的更多相关文章
- .net core mvc启动顺序以及主要部件2
原文:.net core mvc启动顺序以及主要部件2 前一篇提到WebHost.CreateDefaultBuilder(args)方法创建了WebHostBuilder实例,WebHostBuil ...
- .net core mvc启动顺序以及主要部件1
原文:.net core mvc启动顺序以及主要部件1 首先我是新人一个写这些东西也是为了增加记忆,有不对的地方请多多指教. 说回正题,打开Program.cs文件,看到在有个CrateWebHost ...
- .net core mvc启动顺序以及主要部件4-MVC
前面三章已经把MVC启动过程以及源代码做了讲解,本章开始正式MVC,mvc全称叫model view controller,也就是把表现层又细分三层,官网的图片描述: 默认创建了一个.net core ...
- PCB MVC启动顺序与各层之间数据传递对象关系
准备着手基于MVC模式写一套Web端流程指示查看,先着手开发WebAPI打通数据接口,后续可扩展手机端 这里将MVC基本关系整理如下: 一.MVC启动顺序 二.MVC各层之间数据传递对象关系
- ASP.NET Core MVC 源码学习:MVC 启动流程详解
前言 在 上一篇 文章中,我们学习了 ASP.NET Core MVC 的路由模块,那么在本篇文章中,主要是对 ASP.NET Core MVC 启动流程的一个学习. ASP.NET Core 是新一 ...
- 第二十一节:Asp.Net Core MVC和WebApi路由规则的总结和对比
一. Core Mvc 1.传统路由 Core MVC中,默认会在 Startup类→Configure方法→UseMvc方法中,会有默认路由:routes.MapRoute("defaul ...
- asp.net core mvc剖析:启动流程
asp.net core mvc是微软开源的跨平台的mvc框架,首先它跟原有的MVC相比,最大的不同就是跨平台,然后又增加了一些非常实用的新功能,比如taghelper,viewcomponent,D ...
- 解说asp.net core MVC 过滤器的执行顺序
asp.net core MVC 过滤器会在请求管道的各个阶段触发.同一阶段又可以注册多个范围的过滤器,例如Global范围,controller范围等.以ActionFilter为例,我们来看看过滤 ...
- linux下使用supervisor启动.net core mvc website的配置
发布好的asp.net core mvc项目, 如果想在window或linux下的以控制台程序启动的话,可以用下面的命令 dotnet MyProject.dll --urls="http ...
随机推荐
- windows设置多个JDK环境
1.查看jdk版本 java -version 2.查看JAVA_HOME和PATH的变量值 echo %JAVA_HOME% set path 3.临时修改环境变量JAVA_HOME和PATH的变量 ...
- mysql 常用 sql 语句 - 快速查询
Mysql 常用 sql 语句 - 快速查询 1.mysql 基础 1.1 mysql 交互 1.1.1 mysql 连接 mysql.exe -hPup ...
- PCI_PCIe_miniPCIe规格说明
PCI PCI是一种本地总线(并行),规格书名称:PCI Local Bus Specification.并行总线,插槽规格统一. PCI stands for Peripheral Componen ...
- Mysql数据库之备份还原(mysqldump,LVM快照,select备份,xtrabackup)
备份类型: 热备份:读写不受影响 温备份:仅可执行读备份 冷备份:离线备份,读写均不能执行,关机备份 物理备份和逻辑备份 物理备份:复制数据文件,速度快. 逻辑备份:将数据导出之文本文件中,必要时候, ...
- UGUI:技能冷却效果
版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...
- Comet OJ - Contest #10 C.鱼跃龙门
传送门 题意: 求最小的\(x\),满足\(\frac{x(x+1)}{2}\% n=0,n\leq 10^{12}\). 多组数据,\(T\leq 100\). 思路: 直接考虑模运算似乎涉及到二次 ...
- 如何用<dl>标签做表格而不用table标签
我们都知道很多的内容编辑器(TinyMCE编辑器.fck)都有插入表格功能,快速方便,但是这些表格用到的<table>标签,可以查看html源代码就能发现,table标签对搜索引擎不是很友 ...
- 16-C#笔记-枚举
枚举同C++ using System; namespace EnumApplication { class EnumProgram { enum Days { Sun, Mon, tue, Wed, ...
- 13-cmake语法-路径设置
路径设置: 包括头文件路径.库文件路径.库文件名等 INCLUDE_DIRECTORIES 向工程添加多个特定的头文件搜索路径,路径之间用空格分隔,如果路径包含空格,可以使用双引号将它括起来,默认的行 ...
- 排序算法-冒泡排序(Java)
package com.rao.sort; import java.util.Arrays; /** * @author Srao * @className BubbleSort * @date 20 ...