.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 ...
随机推荐
- “GIS DICTIONARY A-Z” 查询页面开发(2)——INSERT INTO数据库
今日工作:数据库连接.数据写入 一.数据库连接:使用了pymysql库 from G2_dataClean import defList import pymysql db = pymysql.con ...
- 使用acme.sh申请&自动续期LetsEncrypt免费SSL证书(转)
一.简介 LetsEncrypt是一个免费.自动.开放的证书颁发机构.acme.sh 实现了 acme 协议, 可以从 LetsEncrypt 生成免费的证书. 本文介绍如何使用acme.sh来签发并 ...
- ansible自动化运维04
ansible playbook ansible-playbook命令格式: ansible-playbook [option] filename(剧本名字) ansible-playbook 命 ...
- 接口自动化--数据驱动(ddt)
上次我们提到了unittest单元测试框架,运用单元测试框架unittest进行编写测试用例 但是遇到了一个问题,就是难道我一个测试点中有多个测试用例,我要每一个都要去编写一条测试用例嘛?这实在是太复 ...
- WPF的依赖属性和附加属性(用法解释较全)
转:https://www.cnblogs.com/zhili/p/WPFDependencyProperty.html 一.引言 感觉最近都颓废了,好久没有学习写博文了,出于负罪感,今天强烈逼迫自己 ...
- 【oracle】ORA-12638
背景:换电脑时将旧电脑的ORACLE的登陆信息转到新电脑.其中有三个文件:listener.ora sqlnet.ora tnsnames.ora 解决办法:删了sqlnet.ora 原因:
- 知识点6 C++数据类型转换 string
一.int转string 1.c++11标准增加了全局函数std::to_string: string to_string (int val); string to_string (long val) ...
- vue自学小demo----前端
vue学习的小demo,实现简单的页面项目的增删 代码如下 <!DOCTYPE html> <html> <head> <meta charset=" ...
- 【BigData】Java基础_Eclipse配置自动补全new
需求描述 在使用Eclipse的时候,每次new一个对象,写起来比较麻烦,以下是配置Eclipse,然后使用快捷键补全new方法的步骤,此配置使用官方属于叫做:配置自动分配局部变量 配置步骤 打开Wi ...
- 亿级Web系统搭建 Web负载均衡的几种实现方式(阿里)
我还写了两篇详细的 参考:六大Web负载均衡原理与实现 参考:LVS(Linus Virtual Server):三种IP负载均衡方式比较+另三种Web负载均衡方式 其中LVS.HAProxy可以工作 ...