Asp.net core 是一个开源和跨平台的框架,用于构建如WEB应用,物联网(IoT)应用和移动后端应用等连接到互联网的基于云的现代应用程序。asp.net core 应用可运行.net和。netframework之上。
它由最小开销的模块化的组件构成,因此在构建解决方案的同时可以保持灵活性。Asp.net Core不再基于System.Web.dll。当前它基于一系列颗粒化的,并且有良好构建的NuGet包。
1.Asp.net Core应用
Asp.net Core应用实际上是一个在Main方法中创建一个Web服务器的简单控制台应用程序。
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Main方法调用WebHost.CreateDefaultBuilder,后者按照生成器的模式来创建Web应用程序主机。生成器提供定义Web服务器(如UseKestrel)和启动类的方法(UseStartup)。上面的代码,自动分配了Kestrel Web服务器。Asp.Net Core的web服务器(如Http.sys),可通过调用相应的扩展方法使用。
IWebHostBuilde是WebHost.CreateDefaultBuilde调用的返回类型,它提供了许多可选方法,包括用于在Http.sys中托管应用的UseHttpSys,以及用于指定根内容目录UseConyenRoot。Build和Run方法生成IWebHost对象,该对象托管应用并开始侦听HTTP请求。
2.Startup
(1)Startup 类
如上面代码,IWebHostBuilder的UseStartup方法为应用指定Startup类。
ASP.NET Core为应用程序提供了处理每个请求的完整控制。Startup类是应用程序的入口,这个类可以设置配置,可用来定义请求处理管道(该管道将用于处理应用程序的所以请求)和配置应用需要的服务(并且将应用程序将要使用的服务连接起来)。
Startup类必须是公开的,并且必须包含下面的方法:
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,)
{
}
ConfigureServices方法用于定义应用所使用的服务(如MVC,EF,以及自定义的服务),Configure方法用于定义你的请求管道中的中间件。
所有的应用程序中都有Startup类,可能会存在特定环境的启动类和方法,但无论如何,Startup类都将被充当为应用程序的启动点。ASP.NET会在主程序集中搜索名为Startup的类(在任何命名空间下)。你也可以指定一个其他程序集用于检索,只需使用
Hosting:Application配置键。
Startup类能够选择性地在构造函数中接受通过依赖注入提供的依赖项。一般而言,将要被配置的应用程序的方法应定义于Startup类的构造函数中,如Configuration。Startup类必须定义Configure方法,可选择定义一个ConfigureServices方法,
这些方法在应用程序启动时被调用。
(2)Configure 方法
Configure方法用于指定ASP.NET应用程序将如何响应每一个HTTP请求。简单来说,你可以配置每个请求都接受相同的响应。但是,大多数应用程序都需要更多的功能。更复杂的管道配置可以封装在中间件(middleware)中,并通过扩展方法添加到IApplicationBuilder上。
Configure方法必须接受一个IApplicationBuilder参数。一些额外服务,比如IHostingEnviroment或ILoggerFactory也可以被指定,在他们可用的情况下,这些服务将会被服务器注入。下面是默认的Web站点模板,多个扩展方法被用于配置管道,以支持BrowserLink,错误页,静态文件,MVC.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
每个Use扩展方法都会把一个中间件加入请求管道。例如,UseMvc扩展方法增加了路由中间件请求管道,并配置MVC为默认处理程序。
(3)ConfigureServices方法
像Configure一样,可以在IServicesCollection上使用扩展方法来包装需要大量配置细节的ConfigureServices。例如下面默认的Web模板代码,使用几个Add[Something]扩展方法用于应用程序,用来使用Session,MVC。
public void ConfigureServices(IServiceCollection services)
{
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(10);
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
通过依赖注入可将服务以及自定义服务加入服务容器,使其在应用程序中使用。就像Startup类能够将指定依赖项作为其方法参数,而不是硬编码来实例化,中间件,控制器类以及其他类都可以做到。
(4)一些服务
ASP.NET Core在应用程序启动时提供了一些应用服务和对象。只要在Startup类的构造函数中包含适合的接口,或者在它的Configure方法,ConfigureServices方法中包含合适的接口即可。
IApplicationBuilder:
被用于构建应用程序的请求管道。只能在Startup中的Configure方法中使用。
IApplicationEnvironment:
提供了访问应用程序属性,类似于ApplicationName,ApplicationVersion以及ApplicationBasePath。可以在Startup的构造函数和Configure方法中使用。
ILoggerFactory:
提供了创建日志的机制。可以在Startup的构造函数或Configure方法中使用。
IServiceCollection:
当前容器中各服务的配置集合。只能在ConfigureServices方法中使用。只用在ConfigureServices方法中配置后,此服务在应用程序中才能使用。
3.服务
服务是应用中用于通用调用的组件。服务必须通过依赖注入(DI)获取并使用。ASP.NET Core内置了一个简单的控制反转(IoC)容器,它默认支持构造函数注入,同时也可以替换成别的IoC容器。
4.中间件
在ASP.NET Core中,可以使用中间件构建自己的请求处理管道。ASP.NET Core中间件为一个HttpContext执行异步逻辑,然后按顺序调用下一个中间件或直接终止请求。一般情况,要想使用一个中间件,只需在Configure方法里调用IApplicationBuilder
上一个对应的UseXYZ扩展方法即可。比如,内置的中间件:
静态文件(Static files)
路由(Route)
身份验证(Authentication)
当然也可以创建自定义的中间件,以及在ASP.NET Core中使用基于任何OWIN的中间件。
中间件是用于组成应用程序管道来处理请求和响应的组件。管道内的每一个组件都可以选择是否将请求交给下一个组件,并在管道中调用下一个组件之前和之后执行一些操作。请求委托被用来建立请求管道,请求委托处理每一个HTTP请求。
请求委托通过使用IApplicationBuilder类型的Run,Map以及Use扩展方法来配置,并在Startup类中传给Congigure方法。每个单独的请求委托可以编写为一个内嵌的方法,或定义在一个可重用的类中。这些可重用的类就叫作“中间件"或“中间组件“。每个位于请求管道内的中间件负责执行某些操作以及调用管道中下一个组件,或适时短路。
ASP.NET请求管道由一系列的请求委托构成:
每一个委托在下一个委托之前和之后都有机会执行操作,任何委托都能选择停止传递到下一个委托,转而自己处理该请求,这就是请求管道的短路,而且是一种有意义的设计,因为这样可以避免不必要的工作。比如,一个授权中间件只有在通过身份验证之后才能调用下一个委托,否则就短路。
异常处理委托需要在管道的早期被调用,这样它们就能够捕捉到发生在管道内所有的异常。
下面是Web项目默认模板代码:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
上面的代码在非开发环境下,UseExceptionHandler是第一个被加入到管道中的中间件,因此将会捕获之后代码中出现的任何异常,然后跳转到设置的异常页。
接着是静态文件中间件,静态文件中间件不提供授权检查,由它提供的任何文件,包括那些位于wwwroot下的文件都是公开可被访问的。
如果想基于授权来提供这些文件:
首先将文件放置到wwwroot外面以及任何静态文件中间件都可以访问到的目录,在控制器中判断授权是否允许访问,如果允许则通过FileResult来提供文件。
然后被静态文件中间件处理的请求会在管道中被短路。如果请求不是由静态文件模块处理,就会传给洗一个中间件Identity模块执行身份验证。如果未通过身份验证,则管道短路。否则,执行后面的MVC框架。
最简单的ASP.NET应用程序可以使用单个请求委托来处理请求。在这种情况下,并不存在所谓的管道,调用单个匿名函数以应对每个HTTP请求。
app.Run(async context=>
{
await context.Response.WriteAsync("Hello World!");
});
短路示例:第一个Run委托短路管道,只有第一个委托会返回”Hello,World!“
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Run(async context=>
{
await context.Response.WriteAsync("Hello,World!");
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello,World,Again!");
});
}
多个请求委托链接示例:next参数表示管道内下一个请求委托。在管道中可以通过不调用next参数来短路。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context,next)=>
{
await context.Response.WriteAsync("Hello,World!\n");
await next.Invoke();
await context.Response.WriteAsync("Hello,World,End!\n");
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello,World,Again!\n");
});
}
Run,Map与Use方法
可以使用Run,Map,和Use方法配置HTTP管道。Run方法会短路管道,因为它不会调用next请求委托。因此Run方法一般只在管道底部被调用。Run方法是一种惯例,有些中间件组件可能会暴露自己的Run[Middleware]方法,而这些方法只能在管道末尾运行。
Use方法前面已经介绍,Use方法中没有使用next参数和Run方法是等价的:
app.Use(async (context,next)=>
{
await context.Response.WriteAsync("Hello,World!");
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello,World!");
});
ASP.NET Core中约定Map*扩展方法被用于分支管道。当前的实现支持基于请求路径或使用谓词来进入分支。Map扩展方法用于匹配基于请求路径的请求委托。Map只接受路径,并配置单独的中间件管道功能。
下面的例子,任何基于/maptest的请求都会被管道中所配置的HandleMapTest方法处理:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Map("/maptest", HandleMapTest);
}
private static void HandleMapTest(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map test");
});
}
除了基于路径的映射外,MapWhen方法还支持基于谓词的中间件分支,允许构建单独的管道。任何Func<HttpContext,bool>类型的谓语都可被用于将请求映射到新的管道分支。
示例:检测查询字符串中变量branch是否存在
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.MapWhen(context=>
{
return context.Request.Query.ContainsKey("branch");
}, HandleBranch);
}
private static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context=>
{
await context.Response.WriteAsync("Branch used.");
});
}
在Map方法中需要短路管道,因为会进入分支。
在map中还可以嵌套。
自定义中间件
中间件遵循显示依赖原则,并在其构造函数中暴露所有依赖项。中间件能够利用UseMiddleware<T>扩展方法的优势,直接通过他们的构造函数注入服务。依赖注入服务是自动填充的,扩展所用到的params参数数组被用于非注入参数。
自定义日志中间件
5.服务器
ASP.NET Core托管模式并不直接监听请求,而是依赖于一个HTTP Sever实现来转发请求到应用程序。这个转发的请求会以一组feature接口的形式被包装,然后被应用程序组合到一个HttpContext中去。
ASP.NET Core包含一个托管的跨平台Web服务器:Kestrel,它往往会被运行在一个如IIS或者Nginx的生产Web服务器之后。
6.内容根目录
内容根目录是应用程序所用到的所有内容的根路径,比如views和web内容。默认情况下,内容根目录与宿主应用的可执行程序的应用根目录相同;其他位置可以通过WebHostBuilder来设置。
7.网站根目录
应用程序的Web根目录是项目中类似于CSS,JS和图片文件公开,静态的资源的目录。静态文件中间件将默认只读取Web根目录和其子目录中的文件。Web根目录默认为<contentroot>/wwwwroot,但是可以通过WebHostBuilder来指定另一个地址。
8.静态文件
静态文件中间件
9.配置
ASP.NET Core使用一个新的配置模型,用来处理简单的键值对。新的配置模型不是基于System.Configuration或者web.config;它是一个有序拉取数据的配置providers。内置的构造提供支持多种不同的文件格式,XML,JSON,INI和用于支持基于环境的
配置环境变量。同样也可以编写自定义的配置providers。
配置文件
9.环境
环境