经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
深入解析ASP.NET Core MVC的模块化设计[下篇]
来源:cnblogs  作者:Artech  时间:2024/3/7 9:15:11  对本文有异议

ASP.NET Core MVC的“模块化”设计使我们可以构成应用的基本单元Controller定义在任意的模块(程序集)中,并在运行时动态加载和卸载。《设计篇》介绍了这种为“飞行中的飞机加油”的方案的实现原理?本篇我们将演示将介绍“分散定义Controller”的N种实现方案。源代码从这里下载。

一、标注ApplicationPartAttribute特性
二、标注RelatedAssemblyAttribute特性
三、注册ApplicationPartManager
四、添加ApplicationPart到现有ApplicationPartManager

一、标注ApplicationPartAttribute特性

接下来我们就通过几个简单的实例来演示如何将Controller类型定义在非入口应用所在的项目中。我们创建如图1所示的解决方案,其中App是一个MVC应用类型的项目,而Foo则是一个普通的类库项目,App具有针对Foo的项目引用。我们希望将部分Controller类型定义在Foo这个类库项目中。

image_thumb[12]
图1 将部分Controller类型定义在Foo项目中

我们在App项目中定义了如下这个HomeController。如代码片段所示,我们在构造函数中注入了ApplicationPartManager对象,并利用它得到当前应用范围内所有有效Controller类型。在执行应用根路径的Action方法Index中,我们将得到的有效Controller类型名称呈现出来。如下所示的FooController类型是我们在Foo项目中定义的Controller类型。

  1. public class HomeController : Controller
  2. {
  3. private readonly IEnumerable<Type> _controllerTypes;
  4. public HomeController(ApplicationPartManager manager)
  5. {
  6. var feature = new ControllerFeature();
  7. manager.PopulateFeature(feature);
  8. _controllerTypes = feature.Controllers;
  9. }
  10.  
  11. [HttpGet("/")]
  12. public string Index()
  13. {
  14. var lines = _controllerTypes.Select(it => it.Name);
  15. return string.Join(Environment.NewLine, lines.ToArray());
  16. }
  17. }
  18.  
  1. public class FooController
  2. {
  3. public void Index() => throw new NotImplementedException();
  4. }

在启动这个演示程序后,如果利用浏览器通过根路径访问定义在HomeController类型中的Action方法Index,我们会得到如图2所示的输出结果。从输出结果可以看出,定义在非MVC应用项目Foo中的Controller类型在默认情况下是不会被解析的。

image_thumb[14]
图2 默认只解析MVC应用所在项目定义的Controller

如果希望MVC应用在进行Controller类型解析的时候将项目Foo编译后的程序集(默认为Foo.dll)包括进来,我们可以在应用所在项目中标注ApplicationPartAttribute特性将程序集Foo作为应用的组成部分。所以我们在Program.cs中针对ApplicationPartAttribute特性进行了如下的标记。

  1. [assembly:ApplicationPart("Foo")]

修改后的程序集启动之后,再次利用浏览器按照按照相同的路径对它发起请求,我们将得到如图3所示的输出结果。由于程序集Foo成为了当前应用的有效组成部分,定义在它里面的BarController自然也成为了当前应用有效的Controller类型。

image_thumb[16]
图3 解析ApplicationPartAttribute特性指向程序集中的Controller类型

二、标注RelatedAssemblyAttribute特性

除了在入口程序集上标注ApplicationPartAttribute特性将某个程序集作为当前应用的有效组成部分之外,我们也可以通过标注RelatedAssemblyAttribute达到相同的目的。根据前面的介绍,我们知道RelatedAssemblyAttribute特性只能标注到入口程序集或者ApplicationPartAttribute特性指向的程序集中,所以我们可以将RelatedAssemblyAttribute特性标注到Foo项目中将另一个程序集包含进行。为此我们在解决方案中添加了另一个类库项目Bar(如图4所示),并为App添加针对Bar的项目引用,然后在Bar项目中定义一个类似于FooController的BarController类型。

image_thumb[19]
图4 将部分Controller类型定义在Foo和Bar项目中

为了将项目Bar编译后生成的程序集(默认为Bar.dll)作为当前应用的组成部分,我们可以选择在App或者Foo项目中标注一个指向它的RelatedAssemblyAttribute特性。对于我们演示的实例来说,我们选择在FooController.cs中以如下形式标注一个指向程序集Bar的RelatedAssemblyAttribute特性。

  1. [assembly: RelatedAssembly("Bar")]

修改后的程序集启动之后,再次利用浏览器按照按照相同的路径对它发起请求,我们将得到如图5所示的输出结果。由于程序集Bar成为了当前应用的有效组成部分,定义在它里面的BazController自然也成为了当前应用有效的Controller类型。

image_thumb[21]
图5 解析RelatedAssemblyAttribute特性指向程序集中的Controller类型

三、注册ApplicationPartManager

由于针对有效Controller类型的解析是利用注册的ApplicationPartManager对象实现的,所以我们完全可以通过注册一个ApplicationPartManager对象的方式达到相同的目的。接下来我们将上一个演示实例中标注的ApplicationPartAttribute和RelatedAssemblyAttribute特性删除,并将承载程序修改为如下的形式。

  1. var manager = new ApplicationPartManager();
  2. var entry = Assembly.GetEntryAssembly()!;
  3. var foo = Assembly.Load(new AssemblyName("Foo"));
  4. var bar = Assembly.Load(new AssemblyName("Bar"));
  5.  
  6. manager.ApplicationParts.Add(new AssemblyPart(entry));
  7. manager.ApplicationParts.Add(new AssemblyPart(foo));
  8. manager.ApplicationParts.Add(new AssemblyPart(bar));
  9. manager.FeatureProviders.Add(new ControllerFeatureProvider());
  10.  
  11.  
  12. var builder = WebApplication.CreateBuilder(args);
  13. builder.Services
  14. .AddSingleton(manager)
  15. .AddControllers();
  16. var app = builder.Build();
  17. app.MapControllers();
  18. app.Run();

如上面的代码片段所示,我们创建了一个ApplicationPartManager对象,并在其ApplicationParts属性中显式添加了指向入口程序集以及Foo和Bar程序集的AssemblyPart对象。为了能够让这个ApplicationPartManager对象具有解析Controller类型的能力,我们在其FeatureProviders中添加了一个ControllerFeatureProvider对象。在后续的应用承载程序中,我们将这个ApplicationPartManager对象作为服务注册到依赖注入框架中。修改后的程序集启动之后,再次利用浏览器按照按照相同的路径对它发起请求,我们依然会得到如图5所示的输出结果。

四、添加ApplicationPart到现有ApplicationPartManager

其实我们没有必要注册一个新的,按照如下的方式将Foo、Bar程序集转换成AssemblyPart并将其添加到现有的ApplicationPartManager之中也可以达到相同的目的。

  1. var builder = WebApplication.CreateBuilder(args);
  2. builder.Services
  3. .AddControllers()
  4. .AddApplicationPart(Assembly.Load(new AssemblyName("Foo")))
  5. .AddApplicationPart(Assembly.Load(new AssemblyName("Bar")));
  6. var app = builder.Build();
  7. app.MapControllers();
  8. app.Run();

深入解析ASP.NET Core MVC的模块化设计[上篇]
深入解析ASP.NET Core MVC的模块化设计[下篇]
如何实现运行时动态定义Controller类型?

原文链接:https://www.cnblogs.com/artech/p/18052365

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号