mvc6中的应用程序,服务和中间件之间的区别

Viv*_*ndi 19 c# middleware asp.net-core-mvc

我试图理解MVC6中的中间件概念.它对我来说仍然含糊不清.我没有真正看到你在Startup课堂上得到的一些"标准"变量之间的差异.

据我所知,有三种不同的方法告诉应用程序它应该使用特定的中间件?

您可以使用服务调用中间件.但这似乎只是为了"添加"中间件?

services.AddMvc();

// Add other services
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
Run Code Online (Sandbox Code Playgroud)

那你有IApplicationBuilder app.这是实际使用服务中加载的中间件吗?所以你可以这样称呼:

app.UseMvc();
app.UseErrorPage(...);
app.UseIdentity(); // cookie authentication 
Run Code Online (Sandbox Code Playgroud)

然后有一种方法来加载和使用这样的中间件:

app.UseMiddleware<MyCustomMiddleware>();
Run Code Online (Sandbox Code Playgroud)

有三种类型的注册/使用中间件有什么好处?它们之间的确切差异是什么?

Dan*_*.G. 16

我会区分添加服务和添加中间件.

添加服务

这基本上是将您的功能所需的类注册到ASP .Net 5中构建的依赖注入容器中.(IServiceCollection接口)

您可以做的最简单的事情是逐个手动添加它们,如下所示:

services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
Run Code Online (Sandbox Code Playgroud)

如果要构建更复杂的应用程序或自包含框架,则可能需要创建一个注册所需服务的函数.这样做的好方法是创建一个扩展方法:

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();
Run Code Online (Sandbox Code Playgroud)

这正是services.AddMvc();在做什么.

以更灵活的方式,它允许您传递lambda以进一步自定义默认服务,如模型绑定器(Like services.AddMvc(opts => opts.ModelBinders ...)),并返回一个IMvcBuilder,您可以使用它来进一步自定义它,如视图引擎(Like services.AddMvc().AddViewOptions(opts => opts.ViewEngines ...)).

添加中间件

ASP .Net 5不是基于HTTP模块和处理程序,而是基于OWIN中间件的概念.有一个不错的博客条目安德烈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();
});
Run Code Online (Sandbox Code Playgroud)

您还可以创建自己的中间件类并注册它:

app.UseMiddleware<MyMiddleware>();
Run Code Online (Sandbox Code Playgroud)

最后,您可以再次定义扩展方法以封装复杂的设置逻辑.

这是做什么的app.UseMvc().它允许您定义路由,然后通过调用添加路由中间件app.UseRouter().正如您所看到的,执行app.UseRouterRouterMiddleware调用添加到管道中builder.UseMiddleware<RouterMiddleware>(router);

您的中间件所需的任何服务以前都已注册.这意味着它们将通过内置的DI容器提供给中间件.


最终结果是,框架使您更容易基本混合和匹配应用程序所需的组件(服务)和行为(中间件),包括您需要的位.


Bar*_*xto 8

我想在丹尼尔回答一个实际的例子.(他的答案非常详细和正确,请先检查一下).

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);

});
Run Code Online (Sandbox Code Playgroud)

如果您想在各种应用程序或其他人共享中间件,您可能需要创建一个中间件并使用它更像:

app.UseMiddleware<HtmlMinifierMiddleware>(); 
Run Code Online (Sandbox Code Playgroud)

这将通过configure方法中的单行代码为您完成所有工作.通常的做法是发布扩展方法,app.UseHtmlMinifier()并返回可以链接以进行配置或支持配置参数的特定对象.使用扩展提供了很多灵活性,可读性和api可发现性:D

现在想象你的中间件是这样的:

public class HtmlMinifierMiddleware {
    public HtmlMinifier(IHtmlMinifier minifier) {
        // ...
    }
    public string Minify(string content) {
        return minifier.Minify(content);
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,您需要传递IHtmlMinifer,因此您需要为DI注册它.

这在ConfigureService上完成,如:

services.AddScoped<IHtmlMinifier, MyCoolHtmlMinifier>();
Run Code Online (Sandbox Code Playgroud)

现在假设您不需要1,但需要很多依赖项,中间件的开发人员/使用者需要知道需要注册的每个依赖项.

中间件的作者通常会附带一个扩展来简化开发人员的使用,例如:services.AddHtmlMinifier()这就是注册服务进入DI容器的扩展方法.

即使您没有使用中间件,也可以使用相同的模式利用自己应用程序的依赖关系.

例如,如果您的应用程序是一个电子商务,您可以创建注册你的依赖扩展方法:services.AddProductManagement(),services.AddPriceCalculator(),services.AddSearching(),等,或只services.AddMyCoolApplication()提供添加(注册)您的服务(依赖)的清洁方式由DI容器的发现你的申请.