我正在尝试理解MVC6中的中间件概念。它对我来说仍然含糊不清。我没有看到你在Startup
类中获得的一些“标准”变量之间的差异。
据我所知,有三种不同的方法可以告诉应用程序它应该使用特定的中间件吗?
您可以使用服务通过服务调用中间件。但这似乎只是为了“添加”中间件?
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>();
使用中间件进行三种注册 / 有什么好处?它们之间的确切差异是什么?
答案 0 :(得分:15)
我会区分添加服务和添加中间件。
添加服务
这基本上是将您的功能所需的类注册到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 ...)
)。
添加中间件
ASP .Net 5不是基于HTTP模块和处理程序,而是基于OWIN中间件的想法。有一个nice blog entry由 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();
});
您也可以create your own middleware class注册:
app.UseMiddleware<MyMiddleware>();
最后,您可以再次定义扩展方法来封装复杂的设置逻辑。
这是
将app.UseMvc()
的作用。它允许您定义路由,然后通过调用app.UseRouter()
添加路由中间件。如您所见,app.UseRouter
的实施通过调用RouterMiddleware
builder.UseMiddleware<RouterMiddleware>(router);
添加到管道中
您的中间件所需的任何服务以前都已注册。这意味着它们将通过内置的DI容器提供给中间件。
最终结果是框架使您更容易基本混合和匹配应用程序所需的组件(服务)和行为(中间件),包括您需要的位。
答案 1 :(得分:7)
我想在丹尼尔回答一个实际的例子。 (他的回答非常详细和正确,请先检查一下)。
<强> TL; DR:强>
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容器为您的应用程序找到的服务(依赖关系)。
答案 2 :(得分:2)
构建管道有两个阶段:
AddMvc
注册MVC所需的服务(例如,视图引擎,JSON格式化程序等),但不向管道添加任何内容。
UseMiddleware<T>
是将中间件添加到管道的通用方法。此方法将使用DI系统通过中间件类的构造函数执行注入依赖项。
UseMvc
等是扩展方法,可以更轻松地传递配置选项。如果您编写自定义中间件,则可以调用UseMiddleware<T>
或提供扩展方法,具体取决于您需要如何设置中间件。
您可以在此处找到更多信息:https://docs.asp.net/en/latest/fundamentals/middleware.html