1, 启用 ShadowCopy
如何启用, 参见:
What's new in ASP.NET Core 6.0 | Microsoft Learn
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- To customize the asp.net core module uncomment and edit the following section.
For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
<system.webServer>
<handlers>
<remove name="aspNetCore"/>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout">
<handlerSettings>
<handlerSetting name="experimentalEnableShadowCopy" value="true" />
<handlerSetting name="shadowCopyDirectory" value="../ShadowCopyDirectory/" />
<!-- Only enable handler logging if you encounter issues-->
<!--<handlerSetting name="debugFile" value=".\logs\aspnetcore-debug.log" />-->
<!--<handlerSetting name="debugLevel" value="FILE,TRACE" />-->
</handlerSettings>
</aspNetCore>
</system.webServer>
</configuration>
需要注意的是:
processPath
arguments
这两个参数要替换掉, 否则站点启动不了:
processPath="dotnet" arguments="CPS_SUP.WebApi.N5.dll"
arguments
这个参数要替换成自己的项目启动项。
2, 在 Plugin 模式下的问题
- 如果子项目是用
输出目录
的方式将 DLL 输出到主项目的Debug|Release
下,主项目启动的时候,扫描DLL 并进行加载的话 (简单的Plugin
模式),上面的设置对子项目无效,仍然会提示文件被占用。
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<OutputPath>..\CPS_SUP.WebApi.N5\bin\Debug\net6.0\</OutputPath>
<!--移除输出目录中的 net6.0 子文件夹, 直接输出到 debug, release 目录中-->
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<!--将引用的相关DLL一并输出, 否则, 不会输出-->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<OutputPath>..\CPS_SUP.WebApi.N5\bin\Release\net6.0\</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
- 除非主项目直接引用这个子项目。
- 如果直接引用子项目, 会在
{app}.deps.json
里面把相关的子项目信息都列出来。但是Plugin
的目的, 就是了和主项目脱离关系, 况且几十个Plugin
,每个Plugin
都是单独编译,所以不考虑这种方式。 - 我试着安装
.NET 7 RC2
的Hosting bundle
, (windows 2008 R2
), 但是 目录:C:\Program Files\IIS\Asp.Net Core Module\V2
下面对应的版本仍然是16.xxx
而不是最新的17.xxx
, 不知道咋回事。.NET 7
的尝试到此为止, 况且目前还只是RC
版。
好像陷入了无解的境地。。。
但是。。。
把 主项目的 {appp}.deps.json
文件删掉。。。(参见: sdk/runtime-configuration-file.md at main · dotnet/sdk (github.com) )
MyApp.deps.json - A list of dependencies, compilation dependencies and version information used to address assembly conflicts. Not technically required, but required to use the servicing or package cache/shared package install features, and to assist during roll-forward scenarios to select the newest version of any assembly that exists more than once in the application and framework(s). If the file is not present, all assemblies in the current folder are used instead.
Not technically required
明确了这个文件不是必须的.
尝试把这个文件移除/改名之后, 就不会在提示文件被占用了。这说明:当前版本的 shadowCopy
只是是监控了 {app}.deps.json
中列出的文件
对 EF 的影响
上面把 {app}.deps.json
文件删掉之后, 执行带有 EF 查询的方法, 报了这么一个异常:
System.PlatformNotSupportedException: Strings.PlatformNotSupported_DataSqlClient
at Microsoft.Data.SqlClient.SqlConnectionStringBuilder..ctor(String connectionString)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.<>c.<get_IsMultipleActiveResultSetsEnabled>b__7_0(String cs)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.get_IsMultipleActiveResultSetsEnabled()
at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerCompiledQueryCacheKeyGenerator.GenerateCacheKey(Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
为解决这个问题, 把发布选项的目标运行时 从 可移植
改为 win-x64
, 然后发布, EF 执行正常了..
指定 --additional-deps
上面的步骤,太麻烦, 一不小心就会把服务搞成 503
即然上面证实了 shadowCopy
只是监控了 {app}.deps.json
中列出的文件, 那能不能让它多监控一些文件呢?
要实现这个目的有两个方法:
- 把每个 Plugin 都引用进主项目里去, 这和 Plugin 模式冲突。
- 用 --additional-deps ,把目录下面所有的 xxx.deps.json 都列出来。
- 不要忘了原来的那个
%LAUNCHER_ARGS%
(CPS_SUP.WebApi.N5.dll)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- To customize the asp.net core module uncomment and edit the following section.
For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
<system.webServer>
<handlers>
<remove name="aspNetCore"/>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
</handlers>
<aspNetCore
processPath="dotnet"
arguments="--additional-deps CPS_SUP.Biz.AXin.deps.json;CPS_SUP.Biz.Ctrip.deps.json;CPS_SUP.Biz.DC.deps.json;CPS_SUP.Biz.DDS.deps.json CPS_SUP.WebApi.N5.dll"
stdoutLogEnabled="false"
stdoutLogFile="logs\stdout"
hostingModel="InProcess">
<handlerSettings>
<handlerSetting name="experimentalEnableShadowCopy" value="true" />
<handlerSetting name="shadowCopyDirectory" value="../ShadowCopyDirectory/" />
<!-- Only enable handler logging if you encounter issues-->
<!-- <handlerSetting name="debugFile" value="logs\aspnetcore-debug.log" /> -->
<!-- <handlerSetting name="debugLevel" value="FILE,TRACE" /> -->
</handlerSettings>
</aspNetCore>
</system.webServer>
</configuration>
--additional-deps 参数的说明
这个参数有个缺点,就是不能用通配符。。。导致每新加一个 Plugin 都需要重新修改一下这个参数。所有的都要加上, 不在这个列表里面的相关 dll 还是会被锁定的。
这个参数的分隔符在 windows 下是 ;
还有一点注意:为避免无意中把 web.config
给覆盖了, 应该把这个文件设置为只读。
日志文件
最后一个问题,日志文件也被复制到了 ShadowCopy 文件夹中去了...
要解决这个问题,只能把所有日志目录指定站点文件外了。
不然真成扫地机器人扫狗屎,糊一地了。。。
.NET 7 中的 ShadowCopy
参见:Advanced configuration | Microsoft Learn
.NET 7 把这个功能从实验功能升级成正式功能了。
对应的, 把experimentalEnableShadowCopy
改成了 enableShadowCopy
。