说明:
本人为了尽快完成对整个nopCommerce_4.40.4程序的实现的详解,在本章只讲述通过MSBuild的怎样的定义流程来相互组合插件项与启动项,而探究其实现原理,即只其所以然而不知其然,如果有时时间本人会深入探究其实现原理。
准备工作:
1、重构整个示例程序,使用整个程序的目录结构与nopCommerce_4.40.4相同,因为“MSBuild”预生成,需要使用“\Build\src\ClearPluginAssemblies\ClearPluginAssemblies.csproj”,ClearPluginAssemblies则是根据nopCommerce_4.40.4程序特有的目录结构而特定定义的,示例程序的目录结构与nopCommerce_4.40.4不同,“MSBuild”预生成就会与预期结果大相径庭。如果要想“MSBuild”预生成脱离nopCommerce_4.40.4目录结构,必须对“\Build\src\ClearPluginAssemblies\ClearPluginAssemblies.csproj”进行深入理解并重构,但现在我还没有这个时间,其后本人会单独把“MSBuild”预生成作为1个专题进行深入探讨和理解。
2、插件与nopCommerce程序的组合必须匹配以特定的版本,在程序的定义中是大于2.0以上的nopCommerce程序才能与插件进行匹配,在当插件所匹配nopCommerce程序的版本号为:“4.40”,所以必须把除插件项以外的其它项的版本号定义为:“4.40”,插件将会因版本不匹配而不能与nopCommerce程序相组合。(nopCommerce程序的这种功能有此与Windows的程序安装与卸载功能和此相似,即对程序有管理功能)
ClearPluginAssemblies的功能实现:
1、把“Nop.Plugin.ExternalAuth.Facebook”插件项中“Content”、“Views”目录及其所有文件和“logo.jpg”文件在执行预生成后(Ctrl+Shift+B),会把这些文件专自动复制到“\Presentation\Nop.Web\Plugins\ExternalAuth.Facebook” 目录中。
2、自动删除“\Presentation\Nop.Web\Plugins\ExternalAuth.Facebook” 目录中,一些公有的静态文件和dll文件,只保留与Nop.Plugin.ExternalAuth.Facebook”插件相关的静态文件和dll文件。
通过MSBuild定义Nop.Plugin.ExternalAuth.Facebook和Nop.Web:
- 通过MSBuild定义Nop.Plugin.ExternalAuth.Facebook,双击Nop.Plugin.ExternalAuth.Facebook项目打开Nop.Plugin.ExternalAuth.Facebook.csproj文件,定义该文件为:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<!--设置预生成目录的相对路径字符串-->
<OutputPath>..\..\Presentation\Nop.Web\Plugins\ExternalAuth.Facebook</OutputPath>
<!--定义预生成目录的属性变量-->
<OutDir>$(OutputPath)</OutDir>
<!--该属性的参数值为:true时,如果当前项目(这里特指:Nop.Plugin.ExternalAuth.Facebook)中存在NuGet引用,则保证在执行了预生成操作后把NuGet所引用的dll文件复制到目标项目(这里特指:Nop.Web)的指定目录中。-->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<!--当通过“ClearPluginAssemblies”删除复制到目标项目(这里特指:Nop.Web)的指定目录中的文件时,排除对下面所定义文件的删除操作。-->
<ItemGroup>
<None Remove="Content\facebookstyles.css" />
<None Remove="Content\Images\facebook_logo.png" />
<None Remove="logo.jpg" />
<None Remove="plugin.json" />
<None Remove="Views\Configure.cshtml" />
<None Remove="Views\PublicInfo.cshtml" />
<None Remove="Views\_ViewImports.cshtml" />
</ItemGroup>
<!--通过“ClearPluginAssemblies”和下载的定义,把当前项目(这里特指:Nop.Plugin.ExternalAuth.Facebook)中指定文件,复制到目标项目(这里特指:Nop.Web)的指定目录中。-->
<!--CopyToPublishDirectory 的值,Never:从不复制;PreserveNewest:复制最新的-->
<ItemGroup>
<Content Include="Content\facebookstyles.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\Images\facebook_logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="logo.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Views\Configure.cshtml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Views\PublicInfo.cshtml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Views\_ViewImports.cshtml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="5.0.15" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Presentation\Nop.Web.Framework\Nop.Web.Framework.csproj" />
<!-- 引用“ClearPluginAssemblies”程序-->
<ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
</ItemGroup>
<!-- 在执行预生成操作后,通过“ClearPluginAssemblies”程序,用于在执行预生成操作后,自动把指定的文件复制到目标项目(这里特指:Nop.Web)的指定目录中,同时删除一些语言包和公有dll文件,只保留当前插件项一些特有的dll文件。-->
<Target Name="NopTarget" AfterTargets="Build">
<!--删除目标项目(这里特指:Nop.Web)的指定目录中,一些语言包和公有dll文件,只保留当前插件项一些特有的dll文件-->
<MSBuild Projects="@(ClearPluginAssemblies)" Properties="PluginPath=$(MSBuildProjectDirectory)\$(OutDir)" Targets="NopClear" />
</Target>
</Project>
2、通过MSBuild定义Nop.Web,双击Nop.Webk项目打开Nop.Web.csproj文件,定义该文件为:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Version>4.4.0.0</Version>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\Nop.Core\Nop.Core.csproj" />
<ProjectReference Include="..\..\Libraries\Nop.Data\Nop.Data.csproj" />
<ProjectReference Include="..\..\Libraries\Nop.Services\Nop.Services.csproj" />
<ProjectReference Include="..\Nop.Web.Framework\Nop.Web.Framework.csproj" />
</ItemGroup>
<!-- 设置插件项在执行预生成操作后,所要复制到的目标项目(这里特指:Nop.Web)的指定目录。 -->
<!-- 在执行预生成操作后,通过“ClearPluginAssemblies”程序,用于在执行预生成操作后,自动把指定的文件复制到目标项目(这里特指:Nop.Web)的指定目录中,同时删除一些语言包和公有dll文件,只保留当前插件项一些特有的dll文件。 -->
<Target Name="NopTarget" AfterTargets="Build">
<ItemGroup>
<!-- 设置插件项静态描述文件所要被复制到的路径。-->
<PluginsDescription Include="$(MSBuildProjectDirectory)\Plugins\**\plugin.json;" />
<!-- 把插件项静态描述文件复制到指定的目录中。-->
<PluginsFolders Include="@(PluginsDescription->'%(relativedir)')" />
<!--拷贝文件夹中获取所有库并删除它们,因为根据设置,这可能不会在应用程序启动时发生,但这可能会在项目调试期间导致不可预知的结果。 -->
<ShadowCopiesLibraries Include="$(MSBuildProjectDirectory)\Plugins\bin\*.*" Exclude="$(MSBuildProjectDirectory)\Plugins\bin\placeholder.txt" />
<!-- 引用“ClearPluginAssemblies”程序-->
<ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
</ItemGroup>
<PropertyGroup>
<PluginsFolders>@(PluginsFolders)</PluginsFolders>
</PropertyGroup>
<!-- 从拷贝文件夹中删除库。-->
<Delete Files="@(ShadowCopiesLibraries)" />
<!--当.net Core构建一个项目时,它将所有引用的库复制到输出文件夹中。对于插件,它会创建太多不必要的文件,只会占用空间。目前您不能禁用此行为。这就是为什么我们必须手动删除插件输出目录中所有不必要的库。
当前程序却是通过“ClearPluginAssemblies”程序,来自动删除这些不太有用的文件。-->
<MSBuild Projects="@(ClearPluginAssemblies)" Properties="PluginPath=$(PluginsFolders)" Targets="NopClear" />
</Target>
</Project>
按Ctrl+Shift+B,执行预生成操作后,“Nop.Plugin.ExternalAuth.Facebook”插件项的副本已经自动被复制在了Nop.Web项目的“Plugins”目录中。
105 NopEditorTagHelper、NopLabelTagHelper、AdminMapperConfiguration
NopEditorTagHelper类,管理区域自定义HTML编辑控件。
NopLabelTagHelper类,管理区域自定义HTML标号标签。
AdminMapperConfiguration类,该类为定义在管理区域中的一些模型纪录的接口及其类,通过“AutoMapper”中间件定义一些相应的映射规则;同时把这些模型纪录的接口及其类通过“AutoMapper”中间件,注入到.NetCore框架的内置依赖注入容器中,为这些类的实例化做好提前的准备工作。
注意:
- 按F5执行程序,会出现语法异常,并会出现错误警告弹出窗口:
在该窗口中选择“不再显示此对话框”,并点击“是”
造成该语法错误异常的原因是,“Nop.Plugin.ExternalAuth.Facebook”插件项的dll库并未直接被引用到“Nop.Web”项中,而是间接的被复制到了“Nop.Web”项,在程序执行被中,“Nop.Plugin.ExternalAuth.Facebook”插件项的dll库,会被动态的加载到“Nop.Web”项中,从而正常的被执行和显示,但是在按F5预执行程序时,“Nop.Plugin.ExternalAuth.Facebook”插件项的dll库,还没有被加载到“Nop.Web”项中,所以产生语法错误,只要忽略这类错误就可解决这些问题,实际上通过查看nopCommerce_4.40.4程序的代码也是这样解决该问题的。
但是这种操作也造成了nopCommerce_4.40.4程序在按F5第1次被执行时会产生各种不确定的异常,但再次在按F5第2次执行程序时这些异常诡异的不见了,程序也能够正常被执行了,这也是本人建议如非十分必须就不要使用插件来增加程序的功能,更好的解决方案是通过版本的迭代来增加程序的功能的根本原因。
2、重构[HttpPost] Nop.Web.Controllers.InstallController.Index方法,添加以下语句:
//初始化当前程序中所需的插件,即把当前程序中所有内置插件的相关信息持久化到“\Presentation\Nop.Web\App_Data\plugins.json”静态文件中。
var pluginService = EngineContext.Current.Resolve<IPluginService>();
pluginService.ClearInstalledPluginsList();
var pluginsIgnoredDuringInstallation = new List<string>();
if (!string.IsNullOrEmpty(_appSettings.InstallationConfig.DisabledPlugins))
{
pluginsIgnoredDuringInstallation = _appSettings.InstallationConfig.DisabledPlugins
.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(pluginName => pluginName.Trim()).ToList();
}
var plugins = (await pluginService.GetPluginDescriptorsAsync<IPlugin>(LoadPluginsMode.All))
.Where(pluginDescriptor => !pluginsIgnoredDuringInstallation.Contains(pluginDescriptor.SystemName))
.OrderBy(pluginDescriptor => pluginDescriptor.Group).ThenBy(pluginDescriptor => pluginDescriptor.DisplayOrder)
.ToList();
//把所有内置插件的相关数据信息持久化到“\Presentation\Nop.Web\App_Data\plugins.json”静态文件中。
foreach (var plugin in plugins)
{
await pluginService.PreparePluginToInstallAsync(plugin.SystemName, checkDependencies: false);
}
3、必须在执行“清理解决方案”后,再执行“重新生成解决方案”,否则“EngineContext.Current.Resolve<IPluginService>();”,将不会对IpluginService接口进行实例化,上述这些语句的作用是自动新建“\Presentation\Nop.Web\App_Data\plugins.json”静态文件,并反下面的数据持久化到该文件中:
{
"InstalledPlugins": [],
"PluginNamesToUninstall": [],
"PluginNamesToDelete": [],
"PluginNamesToInstall": [
{
"Item1": "ExternalAuth.Facebook",
"Item2": null
}
],
"InstalledPluginNames": [
"过时的字段,仅为兼容性而使用。"
]
}
4、在数据库安装操作完成后,再次按F5执行程序,在执行了登录操作后,输入“https://localhost:44303/Admin/Authentication/ExternalMethods”,这时外部身份认证插件相关的数据已经被载入到当前页面的表格组件中,这时“\Presentation\Nop.Web\App_Data\plugins.json”静态文件中所持久化存储的数据已经变更为:
{
"InstalledPlugins": [
{
"SystemName": "ExternalAuth.Facebook",
"Version": "1.68"
}
],
"PluginNamesToUninstall": [],
"PluginNamesToDelete": [],
"PluginNamesToInstall": [],
"InstalledPluginNames": [
"过时的字段,仅为兼容性而使用。"
]
点击表格组件中的“配置”按钮(“https://localhost:44303/Admin/FacebookAuthentication/Configure”),外部身份认证插件的配置管理页面也正常被显示出来了。
对以上功能更为具体实现和注释:22-03-18-034_Nop_4.40.4(通过MSBuild相互组合插件项与启动项)