mvc6中应用、服务和中间件的区别
本文关键字:中间件 区别 服务 应用 mvc6 | 更新日期: 2023-09-27 18:17:44
我试图理解MVC6中的中间件概念。对我来说还是有点模糊。我真的看不出你在Startup
类中得到的几个"标准"变量之间的区别。
据我所知,有3种不同的方法告诉应用程序它应该使用特定的中间件?
你可以通过使用。但这似乎只是为了"添加"中间件?
services.AddMvc();
// Add other services
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
然后是IApplicationBuilder app
。这是实际使用中间件加载的服务吗?所以你可以这样命名它:
app.UseMvc();
app.UseErrorPage(...);
app.UseIdentity(); // cookie authentication
然后有一种方法来加载和使用中间件,像这样:
app.UseMiddleware<MyCustomMiddleware>();
使用中间件注册/三种类型的有什么好处?它们之间的确切区别是什么?
我会区分添加服务和添加中间件。
添加业务
这基本上是将特性所需的类注册到asp.net 5中构建的依赖注入容器中。(IServiceCollection
接口)
你能做的最简单的事情就是手动一个一个地添加它们,如:
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
如果你正在构建一个更复杂的应用程序,或者一个自包含的框架,你可能想要创建一个函数来注册所需的所有服务。一个很好的方法是创建一个扩展方法:
public static void AddMyServices(this IServiceCollection services)
{
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
...
}
//register all your services just by running the ext method:
services.AddMyServices();
这正是services.AddMvc();
正在做的。
添加中间件以更灵活的方式,因为它允许你传递一个lambda来进一步自定义默认服务,如模型绑定器(如
services.AddMvc(opts => opts.ModelBinders ...)
),并返回一个IMvcBuilder,你可以使用它来进一步自定义它的东西,如视图引擎(如services.AddMvc().AddViewOptions(opts => opts.ViewEngines ...)
)。
- 检查
MvcServiceCollectionExtensions
和MvcCoreServiceCollectionExtensions
的执行情况
asp.net 5不是基于HTTP模块和处理程序,而是基于中间件的OWIN思想。Andrei Dzimchuk有一篇很好的博客文章描述了中间件,很好地总结了它:
中间件—通过在服务器和应用程序之间形成管道的组件来检查、路由或修改特定目的的请求和响应消息。
这个定义适用于ASP。NET 5也是如此。中间件可以被认为是我们在经典ASP.NET中拥有的HTTP模块和处理程序。一些中间件将在处理请求时实现各种中间任务,如身份验证、会话状态检索和持久化、日志记录等。其中一些将是生成响应的最终请求处理程序。
那么现在你想把你自己的行为添加到ASP管道中。
最简单的是定义一个内联中间件:
app.Use(async (context, next) =>
{
//do something before passing the request to the next middleware
await next.Invoke();
});
您也可以创建自己的中间件类并注册它:
app.UseMiddleware<MyMiddleware>();
最后,您可以再次定义扩展方法来封装复杂的设置逻辑。
这就是
将app.UseMvc()
所做的。它允许您定义路由,然后通过调用app.UseRouter()
添加路由中间件。可以看到,app.UseRouter
的实现通过调用builder.UseMiddleware<RouterMiddleware>(router);
RouterMiddleware
添加到管道中。
您的中间件所需的任何服务先前都已注册。这意味着它们可以通过内置的DI容器提供给中间件。
最终结果是,框架使您更容易混合和匹配应用程序所需的组件(服务)和行为(中间件),只包括您需要的部分。
我想给丹尼尔的回答加上一个实际的例子。(他的回答非常详细和正确,先看看这个)。
TL;博士:
services.Add
与中间件没有直接关系。它是关于在依赖注入容器中注册依赖项。
app.Use
是关于挑选哪些代码将在管道中运行(执行逻辑),以何种顺序,以及是否允许管道继续处理。想象力是这里的限制,一个例子是编写一个中间件,根据IP地址,你可以显示一个页面,说:'对不起,服务在你的国家不可用')
app.UseMiddleware
它与app.Use
相同,但不是声明内联代码,而是指定一个类,该类将具有Invoke方法,该方法将为您调用。
假设您希望应用程序处理您的输出或部分输出,例如缩小HTML。
您可以添加一个中间件,在将响应写入输出之前拦截响应并将其最小化。
所以你可以用:
app.Use(async (context, next) =>
{
await next(context);
context.Response // will have the response as processed by all the previous middleswares like mvc.
if IsMinifiable(context.Response)
MinifyResponse(context.Response);
});
如果您希望在各种应用程序中或由其他人共享您的中间件,您可能希望创建一个中间件并更像以下方式使用它:
app.UseMiddleware<HtmlMinifierMiddleware>();
将在configure方法中使用一行代码为您完成所有工作。通常的做法是发布像app.UseHtmlMinifier()
这样的扩展方法,并返回可以链接用于配置或支持配置参数的特定对象。使用扩展提供了很大的灵活性、可读性和api可发现性:D
现在假设您的中间件是这样声明的:
public class HtmlMinifierMiddleware {
public HtmlMinifier(IHtmlMinifier minifier) {
// ...
}
public string Minify(string content) {
return minifier.Minify(content);
}
// ...
}
如你所见,你需要传递一个IHtmlMinifer,所以你需要为DI注册它。
这是在ConfigureService上完成的,像
services.AddScoped<IHtmlMinifier, MyCoolHtmlMinifier>();
现在假设你需要的不是1个,而是很多依赖项,中间件的开发者/消费者将知道需要注册的每一个依赖项。
中间件的作者通常会附带一个扩展来方便开发者使用,比如:services.AddHtmlMinifier()
,它就是这样一个扩展方法,用于将服务注册到DI容器中。
即使您没有使用中间件,您也可以使用相同的模式来利用您自己的应用程序的依赖性。
例如,如果你的应用是一个电子商务,你可以创建扩展方法来注册你的依赖项:services.AddProductManagement()
, services.AddPriceCalculator()
, services.AddSearching()
等,或者只是services.AddMyCoolApplication()
,以提供一种干净的方式来添加(注册)你的服务(依赖项),以便在你的应用的DI容器中找到。
构建管道分为两个阶段:
- 为DI注册服务
- 将中间件添加到管道
AddMvc
注册了MVC需要的服务(例如,视图引擎,JSON格式化器等),但不向管道添加任何东西。
UseMiddleware<T>
是向管道中添加中间件的通用方法。该方法将使用DI系统通过中间件类的构造函数注入依赖项。
UseMvc
和类似的扩展方法使它更容易传入配置选项。如果您编写自定义中间件,则只需调用UseMiddleware<T>
或提供扩展方法,这取决于您需要如何设置中间件。
您可以在这里找到更多信息:https://docs.asp.net/en/latest/fundamentals/middleware.html