第二节 实现配置MVC服务

第二节 实现配置MVC服务

使用.Net Core框架新建一个默认的Web程序时,其配置MVC服务的定义是存在于Startup.cs文件public void ConfigureServices(IServiceCollection services)方法中的

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);实现的,同时在上述方法中存在多行执行语句,但它们都可以被注释掉或删除,默认的Web程序的Home.Index页面依然会正常启动,但是如果把services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);语句注释掉或删除那么在程序调用时就会出现异常。从而可以得出这样的结论:在使用.Net Core框架所建立的默认MVC Web程序如果想正常运行,配置MVC服务的定义是其关键和核心。通过对默认的Web程序可以容易的找到MVC服务定义,对其调用的逻辑也相对的简单而直接。

想要对nopCommerce_4.10应用程序中进行反向开发,那么找出它对配置MVC服务的定义和调用是反向开发的第一步。在nopCommerce_4.10应用程序中对配置MVC服务的定义和调用是实现和调用逻辑是极其复杂的。下面我将这个复杂的实现和调用逻辑给出详细的描述。

一、重构默认程序

  1. 新建一个基于.Net Core框架的MVC Web程序见图1-1

图1-1

2、更改Startup.cs文件中的默认方法public void ConfigureServices(IServiceCollection services)方法为:

    /// <summary>

        /// 【配置服务】

        /// <param name="services">服务实例集合实例。</param>

        /// <remarks>

        /// 摘要:

        ///    添加服务实例集合到应用程序,并配置服务供应者。

        /// </remarks>

        /// </summary>

        public void ConfigureServices(IServiceCollection services)

        {

           services.AddMvc();

}

3、更改Startup.cs文件中的默认方法public void Configure(IApplicationBuilder app, IHostingEnvironment env)方法为:

        /// <summary>

        /// 【配置】

        /// <param name="app">用于配置应用程序请求管道的生成器实例。</param>

        /// <remarks>

        /// 摘要:

        ///    此方法由运行时调用,使用此方法配置HTTP请求管道。

        /// </remarks>

        /// </summary>

        public void Configure(IApplicationBuilder app)

        {

            app.UseMvc(routes =>

            {

                routes.MapRoute(

                    name: "default",

                    template: "{controller=Home}/{action=Index}/{id?}");

            });

     }

4、更改Program.cs文件中的默认Program类为:

public class Program

    {

        public static void Main(string[] args)

        {

            var host = WebHost.CreateDefaultBuilder(args)

                .UseKestrel(options => options.AddServerHeader = false)

                .UseStartup<Startup>()

                .Build();

 

            host.Run();

        }

  }

5、按F5发现依然能够正常启动默认的Home.Index页面,虽然它的样式大变。

6、删除文件夹:Controllers、Models;删除Home文件夹中除了Index.cshtml外的所有文件;删除Shared文件夹中的Error.cshtml文件;删除_ViewImports.cshtml文件中的“@using Web.Models

7、新建一个基于.Net Core框架的Controllers类库项目。为了整个应用程序的安全性考虑,一般情况下不要把Controllers和Models定义在Web项目中,这方面是我对nopCommerce应用程序所诟病的地方。

8、在Controllers类库项目使用NuGet引用最新稳定版的Microsoft.AspNetCore.Mvc.ViewFeatures,通过HomeController.cs文件添加HomeController类的定义如下:

 public class HomeController : Controller

    {

        public IActionResult Index()

        {

            return View();

        }

    }

9、Web项目引用Controllers类库项目后,按F5发现依然能够正常启动默认的Home.Index页面。

二、对配置MVC服务实现类和方法调用逻辑的剖析

    当我们打开nopCommerce_4.10应用程序的启动类Startup就会发现ConfigureServices方法调用了Framework项目ServiceCollectionExtensions类中的ConfigureApplicationServices方法,同时在该类中我们很容易的找到AddNopMvc方法,在此方法中定义了var mvcBuilder = services.AddMvc();语句实现了对配置MVC服务的定义。用于配置MVC服务的定义只有上述两个方法,为了明晰其调用逻辑在ServiceCollectionExtensions类中其它的方法下定义可以被注释掉或删除,即使在这两个方法中也有许多语句也要被被注释掉或删除

    AddNopMvc方法的调用却在NopMvcStartup类的ConfigureServices方法中,但是NopMvcStartup类是怎样与整个应用程序有机的关联,使用整个程序能够正常启动到默认的Home.Index页,则只提供了一个定义在Core项目中的INopStartup接口。很明显要想实现程序的有机调用,这些信息完全不够用。在原INopStartup接口和NopMvcStartup类中都有Configure方法的声明和实现,这是nopCommerce_4.10应用程序Startup类中的默认Configure方法的自定义实现,但是在1-3中我还使用了默认的Configure方法,所以声明在INopStartup接口和NopMvcStartup类中都有Configure方法都可以被注释掉或删除,这有助于我们更新容易集中精力观注于配置MVC服务定义这一个点是怎么实现的。

    我们回到ServiceCollectionExtensions类中的ConfigureApplicationServices方法把其定义为:

/// <summary>

        /// 【配置应用程序服务】

        /// <param name="services">服务集合实例集合。</param>

        /// <param name="configuration">应用程序配置实例。</param>

        /// <returns>

        /// 返回:

        ///     返回,服务提供者实例。

        /// </returns>

        /// <remarks>

        /// 摘要:

        ///     向应用程序添加服务并配置服务提供者实例。

        /// </remarks>

        /// </summary>

        public static IServiceProvider ConfigureApplicationServices(this IServiceCollection services, IConfiguration configuration)

        {

            var engine = EngineContext.Create();

            engine.Initialize(services);

            var serviceProvider = engine.ConfigureServices(services, configuration);

            return serviceProvider;

        }

通过该方法的定义,发现它与NopMvcStartup类都要调用定义在Core项目中的一些类和方法,同时结合原nopCommerce_4.10应用程序中也以很明显的看出Core项目只被其它项目引用或调用,而自身不引用或调用程序中的其它项目,这说明Core项目是实现整个应用程序的核心和基础(这点从项目的名称也可以看出)。我将新建Core项目并定义一些用于保证能够使用整个程序能够正常启动到默认的Home.Index页的类和方法及其实现和调用逻辑,在应用程序中添加Framework和Core项目,Framework项目通过NuGet引用FluentValidation.AspNetCore,Core项目NuGet引用Microsoft.AspNetCore.App 2.1.1版(因为使用VS2017所自动生成的基于.Net Core的Web项目中自带的Microsoft.AspNetCore.App的版本也为2.1.1)、Autofac.Extensions.DependencyInjection、AutoMapper.Extensions.Microsoft.DependencyInjection和System.IO.FileSystem.AccessControl见图1-2

图1-2

Framework项目中定义类:ServiceCollectionExtensions和NopMvcStartup,在Core项目所定义的类就多了,最后所形成的定义实现如图1-3

图1-3

从图1-3中可以看出Core项目所定义的多个类和方法,按照其所实现的功能大体上可分为两个类,一是为实现配置MVC服务专用的类和方法,这些类和方法不能直接移植到其它应用程序中使用,它们包含:EngineContext、IEngine、NopEngine和INopStartup。除了以上这些类其它的类的定义和实现都是为这些类提供支撑的,而这些提供支撑的类很容被易移植到其它应用程序中使用。我认为在这一点上nopCommerce_4.10应用程序项目做的不好,使用其调用逻辑显得有此复杂,所以EngineContext、IEngine、NopEngine和INopStartup这些定义实现可以下定义在Framework项目或把提供支撑的类定义在一个新的通用的项目中(例如:Common),这样可能使调用逻辑显的更加简单明了(注意:由于本人迄今为止并未对整个nopCommerce_4.10应用程序项目反射开发完成,如果有时间在对整个nopCommerce_4.10应用程序项目反射开发完成后,进行第二次重构看看是否能够达到上述效果)。

在Framework项目Core项目,在Web项目中同时引用Framework项目和Core项目,在Web项目Startup类中添加引用using Framework.Infrastructure.Extensions;,修改ConfigureServices方法为:

/// <summary>

        /// 【配置服务】

        /// <param name="services">服务实例集合实例。</param>

        /// <returns>

        /// 返回:

        ///     返回,服务供应者实例。

        /// </returns>

        /// <remarks>

        /// 摘要:

        ///    添加服务实例集合到应用程序,并配置服务供应者。

        /// </remarks>

        /// </summary>

        public IServiceProvider ConfigureServices(IServiceCollection services)

        {

            return services.ConfigureApplicationServices(Configuration);

    }

按F5发现Core.Infrastructure.AppDomainTypeFinder类中的LoadMatchingAssemblies方法在执行App.Load(an);语句时发生异常:System.IO.FileNotFoundException:“Could not load file or assembly 'Web.Views, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. 系统找不到指定的文件。。当我发现这个异常时,用三天的时间通过种种努力都没有找到nopCommerce_4.10应用程序与我的反向开发的程序有什么不同而此异常的原因。当我要放弃反向开发时发现通过默认所建立的Web项目在按F5生成后,在文件夹~\Web\bin\Debug\netcoreapp2.1中有“Web.Views.dll”文件,而在nopCommerce_4.10应用程序的此文件夹中没有此文件,是什么造成此原因的呢?我发现在在nopCommerce_4.10应用程序的Web项目中并未有任何关于NuGet的引用。对Microsoft.AspNetCore.App的引用是通过Web项目对Core项目的简接引用实现的(注意:此点是.Net Core框架与 .Net Framework框架的最大区别。通过对nopCommerce_4.10应用程序反向开发的不断进行,发现项目间的间接引用通过存在的而不是个例。而在.Net Framework框架中只能直接引用,否则会出现异常)。

解决上述异常的方案也相当简单即:删除Web项目中NuGet对Microsoft.AspNetCore.App的引用,在执行重新生成解决方案命令后,在文件夹~\Web\bin\Debug\netcoreapp2.1中“Web.Views.dll”文件没有了,按F5发现已经可以正常启动到默认的Home.Index页了。这时把Core项目中的对Microsoft.AspNetCore.App的引用更新到最新的稳定版后,后按F5发现依然可以正常启动到默认的Home.Index页。

到此为止我已经详细的剖析了nopCommerce_4.10应用程序对MVC服务实现的方法与逻辑,至于更新详细的信息请见我所上传代码“MyNopCommerce(不删,001_配置MVC服务)( https://download.csdn.net/download/zhoujian_911/10705234)”中的“日志”与“.vsdx”文件。

猜你喜欢

转载自blog.csdn.net/zhoujian_911/article/details/82970688