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

时间:2015-10-14 13:27:25

标签: c# middleware asp.net-core-mvc

我正在尝试理解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>();

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

3 个答案:

答案 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)

构建管道有两个阶段:

  • 为DI注册服务
  • 将中间件添加到管道

AddMvc注册MVC所需的服务(例如,视图引擎,JSON格式化程序等),但不向管道添加任何内容。

UseMiddleware<T>是将中间件添加到管道的通用方法。此方法将使用DI系统通过中间件类的构造函数执行注入依赖项。

UseMvc等是扩展方法,可以更轻松地传递配置选项。如果您编写自定义中间件,则可以调用UseMiddleware<T>或提供扩展方法,具体取决于您需要如何设置中间件。

您可以在此处找到更多信息:https://docs.asp.net/en/latest/fundamentals/middleware.html