前面分享了.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的更多相关文章

  1. .net core mvc启动顺序以及主要部件2

    原文:.net core mvc启动顺序以及主要部件2 前一篇提到WebHost.CreateDefaultBuilder(args)方法创建了WebHostBuilder实例,WebHostBuil ...

  2. .net core mvc启动顺序以及主要部件1

    原文:.net core mvc启动顺序以及主要部件1 首先我是新人一个写这些东西也是为了增加记忆,有不对的地方请多多指教. 说回正题,打开Program.cs文件,看到在有个CrateWebHost ...

  3. .net core mvc启动顺序以及主要部件4-MVC

    前面三章已经把MVC启动过程以及源代码做了讲解,本章开始正式MVC,mvc全称叫model view controller,也就是把表现层又细分三层,官网的图片描述: 默认创建了一个.net core ...

  4. PCB MVC启动顺序与各层之间数据传递对象关系

    准备着手基于MVC模式写一套Web端流程指示查看,先着手开发WebAPI打通数据接口,后续可扩展手机端 这里将MVC基本关系整理如下: 一.MVC启动顺序 二.MVC各层之间数据传递对象关系

  5. ASP.NET Core MVC 源码学习:MVC 启动流程详解

    前言 在 上一篇 文章中,我们学习了 ASP.NET Core MVC 的路由模块,那么在本篇文章中,主要是对 ASP.NET Core MVC 启动流程的一个学习. ASP.NET Core 是新一 ...

  6. 第二十一节:Asp.Net Core MVC和WebApi路由规则的总结和对比

    一. Core Mvc 1.传统路由 Core MVC中,默认会在 Startup类→Configure方法→UseMvc方法中,会有默认路由:routes.MapRoute("defaul ...

  7. asp.net core mvc剖析:启动流程

    asp.net core mvc是微软开源的跨平台的mvc框架,首先它跟原有的MVC相比,最大的不同就是跨平台,然后又增加了一些非常实用的新功能,比如taghelper,viewcomponent,D ...

  8. 解说asp.net core MVC 过滤器的执行顺序

    asp.net core MVC 过滤器会在请求管道的各个阶段触发.同一阶段又可以注册多个范围的过滤器,例如Global范围,controller范围等.以ActionFilter为例,我们来看看过滤 ...

  9. linux下使用supervisor启动.net core mvc website的配置

    发布好的asp.net core mvc项目, 如果想在window或linux下的以控制台程序启动的话,可以用下面的命令 dotnet MyProject.dll --urls="http ...

随机推荐

  1. Linux操作系统安全-OpenSSL工具常用命令介绍

    Linux操作系统安全-OpenSSL工具常用命令介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.OpenSSL开源项目有三个组件 openssl: 多用途的命令行工具,包 ...

  2. vue - 基础(3)

    1.数据的双向绑定 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  3. Winform----自定义控件之半透明遮罩(蒙版遮盖指定控件)

    先贴运行效果图,源码点击这里下载 1.新建自定义控件 2.实现功能   namespace UserControlLib   {   [ToolboxBitmap(typeof(ZhLoading)) ...

  4. 循环递减算法 [a,b,c] 求 ab,ac,bc

    有数组 lineList=[a,b,c] 求所有不同的两两组合 ,结果:ab,ac,bc lineList.forEach((lineA,lineIndex)=>{ ==len){ return ...

  5. ubunt 文件permission denied问题的解决

    在linux系统使用过程中,升级python到3.6以后,执行pip命令,遇到permission denied问题,系统显示如下: -bash: /home/www/my_flask/venv/bi ...

  6. NOIP2013-2014提高组题目浅析

    1.前言 迎接NOIP的到来...在这段闲暇时间,决定刷刷水题.这里只是作非常简单的一些总结. 2.NOIP2014 <1> 生活大爆炸之石头剪刀布(模拟) 这是一道考你会不会编程的题目. ...

  7. PATB1006换个格式输出整数

    参考代码: #include<cstdio> int main() { int n;//接收输入的数字 int a = 0, b = 0, c = 0;//分别记录百位十位个位上的数 sc ...

  8. 在非gnome系桌面环境下运行deepin-wine tim的错误解决

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/deepin_wine_run_in_not_gnome_desk ...

  9. Docker环境下的前后端分离项目部署与运维(八)使用Docker部署RabbitMQ集群

    下载RabbitMQ镜像 镜像地址RabbitMQ Docker官方认证镜像地址:https://hub.docker.com/_/rabbitmq 安装命令安装之前,切记把Docker Hub设置为 ...

  10. Spring Boot进阶系列四

    这边文章主要实战如何使用Mybatis以及整合Redis缓存,数据第一次读取从数据库,后续的访问则从缓存中读取数据. 1.0 Mybatis MyBatis 是支持定制化 SQL.存储过程以及高级映射 ...