• Github 下载源代码 - 961 KB

介绍

3.0版开始,ASP.NET Core提供了一种使用Application Parts将应用程序拆分为模块的方法。

一个解决方案可能包含一个Web应用程序和任意数量的程序集库,其中可能包含控制器、视图、页面、静态文件(如 JavaScript CSS 文件)等。这些库称为Razor 类库 RCL

有人希望在解决方案中使用Razor库的原因有很多。

但最有价值的情况是动态加载库时,作为插件。想象一个电子商务解决方案,它提供了许多税收或运费计算插件或付款插件,供管理员选择。

不过也有一些困难。可以肯定的是,该文档未能提供完整的描述性示例。

但最令人沮丧的是,Application PartsRCL似乎不是为了与动态加载的库(即插件)一起使用而创建的。

特别是对于静态文件,即JavaScriptCSS文件,动态加载的RCL是失败的。

本练习的内容

在本文中,我们将研究这两个用例:

  • 主应用程序静态引用的RCL
  • 由主应用程序动态加载的RCL

两个RCL都包含静态文件,即JavaSriptCSS文件。

我们将使用一个ASP.NET Core MVC Web应用程序和两个RCL

首先,创建一个ASP.NET Core MVC Web应用程序并将其命名为WebApp.

引用RCL

按照文档提供的说明创建RCL

命名RCL StaticRCL。我们稍后会看到为什么这个名字很重要。

从项目中删除所有文件和文件夹,并添加三个新文件夹:ControllersViewswwwroot

Controllers文件夹中创建一个控制器类。

public class LibController : Controller
{[Route("/static")]public IActionResult Index(){return View();}
}

Views文件夹中创建一个Lib文件夹。添加一个Index.cshtml视图文件。

<script src="~/_content/StaticRCL/js/script.js"></script><div><strong>STATICALLY</strong> referenced Razor Class Library
</div><div><button onclick="StaticRCL_ShowMessage();">Click Me!</button>
</div>

wwwroot文件夹内创建一个js文件夹。添加一个script.js文件。

function StaticRCL_ShowMessage() {alert('Hi from Statically refernced Razor Class Library javascript');
}

可动态加载的RCL

使用与上述类似的结构和文件创建另一个RCL。命名为DynamicRCL

控制器

public class LibDynamicController : Controller
{[Route("/dynamic")]public IActionResult Index(){return View();}
}

视图

<script src="js/script.js"></script><div><strong>DYNAMICALLY</strong> loaded Razor Class Library
</div><div><button onclick="DynamicRCL_ShowMessage();">Click Me!</button>
</div>

JavaScript文件

function DynamicRCL_ShowMessage() {alert('Hi from Dynamically loaded Razor Class Library javascript');
}

我们还需要做到以下几点。

  • 在项目的程序集名称中添加一个rcl_前缀,即<AssemblyName>rcl_DynamicRCL</AssemblyName>
  • 添加一个GenerateEmbeddedFilesManifest,即<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  • 添加Microsoft.Extensions.FileProviders.Embedded NuGet包,即,<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.0" />
  • 设置输出路径到主Web Applicationbin文件夹,即<OutputPath>..\WebApp\bin\Debug\</OutputPath>
  • 指示项目使用wwwroot文件夹中的所有文件作为嵌入资源,即,<EmbeddedResource Include="wwwroot\**\*" />

这是整个项目的源文件:

<Project Sdk="Microsoft.NET.Sdk.Razor"><PropertyGroup><TargetFramework>netcoreapp3.1</TargetFramework><AddRazorSupportForMvc>true</AddRazorSupportForMvc><AssemblyName>rcl_DynamicRCL</AssemblyName><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>     <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest></PropertyGroup><PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"><OutputPath>..\WebApp\bin\Debug\</OutputPath></PropertyGroup><ItemGroup><FrameworkReference Include="Microsoft.AspNetCore.App" /><PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.0" /></ItemGroup> <ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup></Project>

处理引用的RCL

WebApp Web应用程序应该有一个对第一个RCLproject reference,即StaticRCL

HomeControllerIndex.cshtml如下:

@{ViewData["Title"] = "Home Page";
}<div class="text-center"><h1 class="display-4">Welcome</h1><div><a href="/static">Statically referenced Razor Class Library View</a></div><div><a href="/dynamic">Dynamically loaded Razor Class Library View</a></div>
</div>

如您所见,有两个锚元素调用相应的RCL路由。

Startup类的ConfigureServices()方法处理静态引用和动态加载的库。

public void ConfigureServices(IServiceCollection services)
{services.AddControllersWithViews().ConfigureApplicationPartManager((PartManager) => {ConfigureStaticLibraries(PartManager);  // static RCLsLoadDynamicLibraries(PartManager);      // dynamic RCLs});
}

ApplicationPartManager类管理部件和ASP.NET MVC的核心或Razor Pages应用程序的功能。

其逻辑是获取对已经被Web应用程序引用的Assembly的引用,为该Assembly创建一个AssemblyPart,然后调用ApplicationPartManager注册该AssemblyPart

void ConfigureStaticLibraries(ApplicationPartManager PartManager)
{Assembly Assembly = typeof(StaticRCL.Controllers.LibController).Assembly;ApplicationPart ApplicationPart = new AssemblyPart(Assembly);PartManager.ApplicationParts.Add(ApplicationPart);
}

以上适用于路由到Razor视图(和Razor页面)。随着扭曲,当涉及到静态文件,如JavaScriptCSS文件等。

以下是文档中的内容:

RCLwwwroot文件夹中包含的文件在前缀_content/{LIBRARY NAME}/下暴露给RCL或消费应用程序。例如,名为Razor.Class.Lib的库会生成_content/Razor.Class.Lib/处的静态内容路径。

以下是StaticRCL项目的Index.cshtml所做的,符合上述。

<script src="~/_content/StaticRCL/js/script.js"></script>

处理动态加载的RCL

根据相关文档,需要AssemblyLoadContext类的派生类才能加载插件库。

这里是:

public class LibraryLoadContext: AssemblyLoadContext
{private AssemblyDependencyResolver fResolver;public LibraryLoadContext(string BinFolder){fResolver = new AssemblyDependencyResolver(BinFolder);}protected override Assembly Load(AssemblyName assemblyName){string assemblyPath = fResolver.ResolveAssemblyToPath(assemblyName);if (assemblyPath != null){return LoadFromAssemblyPath(assemblyPath);}return null;}protected override IntPtr LoadUnmanagedDll(string unmanagedDllName){string FilePath = fResolver.ResolveUnmanagedDllToPath(unmanagedDllName);if (FilePath != null){return LoadUnmanagedDllFromPath(FilePath);}return IntPtr.Zero;}
}

我们在加载插件库时使用LibraryLoadContext

下面从ConfigureServices()调用的LoadDynamicLibraries()基于前缀(在本例中是rcl_)加载库,即插件程序集。这就是为什么我们将DynamicRCL项目的程序集名称更改为rcl_DynamicRCL的原因。

我希望代码易于理解。

void LoadDynamicLibraries(ApplicationPartManager PartManager)
{// get the output folder of this applicationstring BinFolder = this.GetType().Assembly.ManifestModule.FullyQualifiedName;BinFolder = Path.GetDirectoryName(BinFolder);// get the full filepath of any dll starting with the rcl_ prefixstring Prefix = "rcl_";string SearchPattern = $"{Prefix}*.dll";string[] LibraryPaths = Directory.GetFiles(BinFolder, SearchPattern);if (LibraryPaths != null && LibraryPaths.Length > 0){// create the load contextLibraryLoadContext LoadContext = new LibraryLoadContext(BinFolder);Assembly Assembly;ApplicationPart ApplicationPart;foreach (string LibraryPath in LibraryPaths){// load each assembly using its filepathAssembly = LoadContext.LoadFromAssemblyPath(LibraryPath);// create an application part for that assemblyApplicationPart = LibraryPath.EndsWith(".Views.dll") ?new CompiledRazorAssemblyPart(Assembly)as ApplicationPart : new AssemblyPart(Assembly);// register the application partPartManager.ApplicationParts.Add(ApplicationPart);// if it is NOT the *.Views.dll add it to a list for later useif (!LibraryPath.EndsWith(".Views.dll"))DynamicallyLoadedLibraries.Add(Assembly);}}
}

现在是棘手的部分。

我们已经将JavaScriptCSS 和其他static资源配置为嵌入DynamicRCL。此外,我们要求该库为这些嵌入文件创建一个清单

现在我们必须读取该清单,在该DynamicRCL程序集及其wwwroot文件夹上创建一个IFileProvider,然后向系统注册该文件提供程序。

void RegisterDynamicLibariesStaticFiles(IWebHostEnvironment env)
{IFileProvider FileProvider;foreach (Assembly A in DynamicallyLoadedLibraries){// create a "web root" file provider for the embedded static files// found on wwwroot folderFileProvider = new ManifestEmbeddedFileProvider(A, "wwwroot");// register a new composite provider containing// the old web root file provider// and the new one we just createdenv.WebRootFileProvider = new CompositeFileProvider(env.WebRootFileProvider, FileProvider);}
}

上面的方法在app.UseStaticFiles()调用之前被Startup类的Configure()方法调用。

app.UseHttpsRedirection();// register file providers for the dynamically loaded libraries
if (DynamicallyLoadedLibraries.Count > 0)RegisterDynamicLibariesStaticFiles(env);app.UseStaticFiles();

下面是DynamicRCL项目的Index.cshtml为了使用JavaScript文件所做的事情。

<script src="js/script.js"></script>

这里没有使用_content/{LIBRARY NAME}/方案。我们只使用该js文件夹,因为我们已将DynamicRCL程序集的wwwroot文件夹注册为Web 文件夹。

就这样。

测试于:

  • Windows 10
  • ASP.NET Core 3.1
  • Microsoft Visual Studio 2019 Preview, Version 16.9.0 Preview 5.0

https://www.codeproject.com/Articles/5296270/ASP-NET-Core-3-x-Dynamically-Loadable-Plugins-with

具有完整静态文件(JS、CSS)支持的 ASP.NET Core 3.x 动态可加载插件相关推荐

  1. 将 laravel 项目内静态文件,css、js、images 部署到七牛云 CDN

    项目升级,打算把 public 目录下的 css.js.image等文件,上传到七牛云,一直想搞来着,今天又想起来,正好 laravel 也从 5.2 升级到了 5.7,接下来把这边一搞,项目就更加优 ...

  2. python博客下载本地文件_解决django无法访问本地static文件(js,css,img)网页里js,cs都加载不了...

    1.今天网上下载一个博客项目,发现本地访问,js,css加载不了. 我想应该是项目上线的安全措施,但是我想调试项目.找到方法如下 在settings.py里面编辑 添加 STATICFILES_DIR ...

  3. 【Webpack5 配置分包加载 多文件js/css打包 】

    Webpack5 配置分包加载 多文件js/css打包 - 毛毛 - 毛大姑娘 的 后花园

  4. js如何动态的加载js文件

    在这个地方我说的动态的加载js文件是通过调用函数来加载js文件,我们在这个地方通过一个简单的小例子来实现 首先创建3个文件分别为:test1.html,test1.js,demo.js test1.j ...

  5. 将 ASP.NET Core 2.1 升级到最新的长期支持版本ASP.NET Core 3.1

    目录 前言 Microsoft.AspNetCore.Mvc.ViewFeatures.Internal 消失了 升级到 ASP.NET Core 3.1 项目文件(.csproj) Program. ...

  6. 支持64位系统的XOR加密后内存加载PE绕过杀毒软件

    http://bbs.pediy.com/showthread.php?t=203910 绝对自动支持32.64位的内存加载源码 无聊逛看雪时,看到了这个. 然后到github上找到了源.就是这里:h ...

  7. [译]使用LazZiya.ExpressLocalization开发多语言支持的ASP.NET Core 2.x项目

    介绍 开发多语言支持的ASP.NET Core 2.x Web应用程序需要大量的基础架构设置,并且耗费时间和精力.这篇文章,我们将使用LazZiya.ExpressLocalization nuget ...

  8. Three 之 three.js (webgl)基础 第二个入门案例之汽车模型加载和简单模型展示

    Three 之 three.js (webgl)基础 第二个入门案例之汽车模型加载和简单模型展示 目录 ​Three 之 three.js (webgl)基础 第二个入门案例之汽车模型加载和简单模型展 ...

  9. 【Android 逆向】Android 进程注入工具开发 ( 远程进程注入动态库文件操作 | 注入动态库 加载 业务动态库 | 业务动态库启动 | pthread_create 线程开发 )

    文章目录 前言 一.加载 libnattive.so 动态库 二. libnattive.so 动态库启动 三. pthread_create 线程开发 四. 线程执行函数 前言 libbridge. ...

最新文章

  1. Android性能优化常见问题,附架构师必备技术详解
  2. poj1190深搜 生日蛋糕
  3. 在斜坡上哪个物体滚的最快_人教版一年级上册 第十七课 会滚的玩具
  4. 记linux_centOS安装as86过程
  5. html5 写json 文件,HTML5实现本地JSON文件的读写
  6. Android CardView的基本使用
  7. sdl2 opengl d3d9的mipmap和各项异性过滤渲染
  8. python之获取标准时区的时间元组
  9. LeetCode 338. 比特位计数(动态规划)
  10. CoreJava Reading Note(3:Fundamental structure)
  11. LSF-SCNN:一种基于 CNN 的短文本表达模型及相似度计算的全新优化模型
  12. 【转】windows下GSL的配置
  13. 更新BLE的设备后,OSX LightBlue 不会更新扫描到Service
  14. html 组件化 编辑器,纯前端表格控件SpreadJS V14.0发布:组件化编辑器+数据透视表...
  15. 时间序列分析之ADF检验
  16. OSChina 周一乱弹 —— 大学老教授说你媳妇在幼儿园
  17. 两寸证件照的尺寸是多少?如何换两寸证件照的背景色?
  18. ThinkPad E550 安装 WIN7 的启动 U 盘制作
  19. Minicom安装和使用和lte调试方法
  20. pandas实现列转行

热门文章

  1. python interactive slider_python3----练习题(过滑块验证)
  2. python做算法分析_Python实现迪杰斯特拉算法过程解析
  3. python开发工具下所有软件都打不开_Python中pip/setup安装插件失败提示“pypi.python.org” 打不开的解决办法...
  4. 拦截器和过滤器区别_新手能看懂的(Interceptor)和(Filter)区别与使用!
  5. java 工厂模式详解_Java设计模式之工厂模式详解
  6. 没有日志 mysql 5.6主从同步_mysql之 mysql 5.6不停机主从搭建(一主一从基于日志点复制)...
  7. cesium three性能比较_硬金和千足金都是黄金,哪个比较好?为什么80%人都说硬金不好?...
  8. python2还是3好_学Python2还是python3 究竟哪个好
  9. linux 误删除mysql表能恢复吗_linux rm误删除数据库文件的恢复方法
  10. Linux内核内存管理(1):内存块 - memblock