DLL-файлы ILMerge/ILRepack не могут быть зарегистрированы с помощью инструмента регистрации подключаемого модуля Dynamics 365

Я пытаюсь создать плагин для D365. У меня есть зависимости пакета, включая

  • Azure.DigitalTwins.Core
  • Azure.Core
  • Azure.Identity

Эти зависимости .dll должны быть объединены в одну .dll для регистрации подключаемого модуля. Я использую пакетный файл ILMerge. скрипт для объединения этих DLL в один вывод merged.dll.

Вот сценарий, который я использую:

@echo off
:: this script needs https://www.nuget.org/packages/ilmerge

:: Set build, used for directory. Typically Release or Debug
SET ILMERGE_BUILD=bin\Debug\ilmerge

:: set your NuGet ILMerge Version, this is the number from the package manager install, for example:
:: PM> Install-Package ilmerge -Version 3.0.29
:: to confirm it is installed for a given project, see the packages.config file
SET ILMERGE_VERSION=3.0.41

:: the full ILMerge should be found here:
SET ILMERGE_PATH=%USERPROFILE%\.nuget\packages\ilmerge\%ILMERGE_VERSION%\tools\net452
:: dir "%ILMERGE_PATH%"\ILMerge.exe

SET PROJECT_ROOT=%CD%
SET ASSEMBLY_DIR=%PROJECT_ROOT%\bin\Debug\net462

::/targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0" ^
::/target:library ^
::/copyattrs ^
::/closed ^
::/allowDup ^

echo Merging adtplugin...
:: add project DLL's starting with replacing the FirstLib with this project's DLL
"%ILMERGE_PATH%"\ILMerge.exe ^
/keyfile:%PROJECT_ROOT%\adtplugin.snk ^
/out:%ILMERGE_BUILD%\merged.dll ^
/target:library ^
/nDebug ^
/closed ^
/allowDup ^
/copyattrs ^
/targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2" ^
%ASSEMBLY_DIR%\adtplugin.dll ^
%ASSEMBLY_DIR%\Azure.Core.dll ^
%ASSEMBLY_DIR%\Azure.DigitalTwins.Core.dll ^
%ASSEMBLY_DIR%\Azure.Identity.dll ^
%ASSEMBLY_DIR%\Microsoft.Bcl.AsyncInterfaces.dll ^
%ASSEMBLY_DIR%\Microsoft.Identity.Client.dll ^
%ASSEMBLY_DIR%\Microsoft.Identity.Client.Extensions.Msal.dll ^
%ASSEMBLY_DIR%\Microsoft.Win32.Primitives.dll ^
%ASSEMBLY_DIR%\netstandard.dll ^
%ASSEMBLY_DIR%\System.Memory.dll ^
%ASSEMBLY_DIR%\System.Threading.Tasks.Extensions.dll 

pause
:Done

Я немного поиграл с флагами /option, переданными в ILMerge.exe. В настоящее время с показанной конфигурацией я могу объединить перечисленные .dll в один вывод merged.dll.

Затем я пытаюсь использовать инструмент регистрации подключаемых модулей, чтобы зарегистрировать новую сборку, используя выходной файл merged.dll. Когда я пытаюсь зарегистрировать плагин, я получаю ошибки:

Инструмент регистрации плагинов

Вот дамп ошибки:

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Unable to load plug-in assembly.
Detail: <OrganizationServiceFault xmlns="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <ActivityId>9e6ed737-8374-464e-956a-d70b46a2c686</ActivityId>
  <ErrorCode>-2147204719</ErrorCode>
  <ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
    <KeyValuePairOfstringanyType>
      <a:key>ApiExceptionSourceKey</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">Plugin/Microsoft.Crm.ObjectModel.PluginAssemblyService</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiSourceActivityKey</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">Microsoft.Crm.Extensibility.PipelineStep</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiExceptionOwnerKey</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">COMMONDATASERVICECDS\CDSAPI-Reliability</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiOriginalExceptionKey</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">Microsoft.Crm.CrmException: Unable to load plug-in assembly. ---&gt; Microsoft.Crm.CrmException: Unable to load plug-in assembly.
   at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.LoadCrmPluginAssemblyMetadata(IBusinessEntity pluginAssembly, IExecutionContext context, Boolean loadAllMetadata)
   at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.RetrieveAssemblyMetadata(IBusinessEntity pluginAssembly, ExecutionContext context, Boolean retrieveFromExisting, Boolean forSystemAssembly)
   at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.ValidateOperation(String operationName, IBusinessEntity entity, ExecutionContext context)
   at Microsoft.Crm.ObjectModel.SdkEntityServiceBase.CreateInternal(IBusinessEntity entity, ExecutionContext context, Boolean verifyAction)
   --- End of inner exception stack trace ---
   at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action, PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.Pipeline.&lt;&gt;c__DisplayClass7_0.&lt;RunStep&gt;b__0()</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiStepKey</a:key>
      <a:value i:type="b:guid" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/">3ecabb1b-ea3e-db11-86a7-000a3a5473e8</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiDepthKey</a:key>
      <a:value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiActivityIdKey</a:key>
      <a:value i:type="b:guid" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/">9e6ed737-8374-464e-956a-d70b46a2c686</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiPluginSolutionNameKey</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">System</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiStepSolutionNameKey</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">System</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiExceptionCategory</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">SystemFailure</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiExceptionMessageName</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">UnableToLoadPluginAssembly</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>ApiExceptionHttpStatusCode</a:key>
      <a:value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">500</a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>0</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">Failed to load plugin assembly with exception Microsoft.Crm.CrmException: GetAssemblyMetadata: expected mdtAssemblyRef or mdtAssembly
   at Microsoft.Crm.CrmException.Assert(Boolean condition, String message)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.GetAssemblyMetadata(UInt32 token)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessTypeRef(UInt32 typeRef)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessType(UInt32 token)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessTypeDef(UInt32 typeDef)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessType(UInt32 token)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.LoadMetadata()
   at Microsoft.Crm.CrmPluginAssemblyMetadata.LoadMetadataFromAssemblyContent(ArraySegment`1 assemblyContents, Boolean loadAllMetadata)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.LoadMetadataFromAssemblyContent(String content, Boolean loadAllMetadata)
   at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.LoadCrmPluginAssemblyMetadata(IBusinessEntity pluginAssembly, IExecutionContext context, Boolean loadAllMetadata). PluginInfo =&gt; Crm plugin assembly info : sourcetype = 0, description = , ismanaged = False, pluginassemblyid = b77380cb-8676-45b6-9e5c-63a5960ed2ac, ispasswordset = False, publickeytoken = 7F66FA42F6885FDC, name = merged, culture = neutral, isolationmode = 2, version = 1.0.0.0, </a:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <a:key>1</a:key>
      <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">Microsoft.Crm.CrmException: GetAssemblyMetadata: expected mdtAssemblyRef or mdtAssembly
   at Microsoft.Crm.CrmException.Assert(Boolean condition, String message)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.GetAssemblyMetadata(UInt32 token)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessTypeRef(UInt32 typeRef)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessType(UInt32 token)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessTypeDef(UInt32 typeDef)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.ProcessType(UInt32 token)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.LoadMetadata()
   at Microsoft.Crm.CrmPluginAssemblyMetadata.LoadMetadataFromAssemblyContent(ArraySegment`1 assemblyContents, Boolean loadAllMetadata)
   at Microsoft.Crm.CrmPluginAssemblyMetadata.LoadMetadataFromAssemblyContent(String content, Boolean loadAllMetadata)
   at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.LoadCrmPluginAssemblyMetadata(IBusinessEntity pluginAssembly, IExecutionContext context, Boolean loadAllMetadata)</a:value>
    </KeyValuePairOfstringanyType>
  </ErrorDetails>
  <HelpLink>http://go.microsoft.com/fwlink/?LinkID=398563&amp;error=Microsoft.Crm.CrmException%3a80044191&amp;client=platform</HelpLink>
  <Message>Unable to load plug-in assembly.</Message>
  <Timestamp>2021-04-29T17:46:08.9958593Z</Timestamp>
  <ExceptionRetriable>false</ExceptionRetriable>
  <ExceptionSource i:nil="true" />
  <InnerFault>
    <ActivityId>9e6ed737-8374-464e-956a-d70b46a2c686</ActivityId>
    <ErrorCode>-2147204719</ErrorCode>
    <ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
    <HelpLink i:nil="true" />
    <Message>Unable to load plug-in assembly.</Message>
    <Timestamp>2021-04-29T17:46:08.9958593Z</Timestamp>
    <ExceptionRetriable>false</ExceptionRetriable>
    <ExceptionSource i:nil="true" />
    <InnerFault i:nil="true" />
    <OriginalException i:nil="true" />
    <TraceText i:nil="true" />
  </InnerFault>
  <OriginalException i:nil="true" />
  <TraceText i:nil="true" />
</OrganizationServiceFault>

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at Microsoft.Crm.Tools.Libraries.RegistrationHelper.RegisterAssembly(CrmOrganization org, String pathToAssembly, CrmPluginAssembly assembly) in D:\a\1\s\src\GeneralTools\PluginRegistrationV3\PluginRegistration\CrmLibraries\RegistrationHelper.cs:line 723
   at Microsoft.Crm.Tools.AssemblyRegistration.PluginRegistrationViewModel.RegisterAssembly() in D:\a\1\s\src\GeneralTools\PluginRegistrationV3\RegistrationTools\AssemblyRegistration\ViewModels\PluginRegistrationViewModel.cs:line 649

Если кто-то успешно использовал сценарий .bat для запуска ILMerge, объединения файлов .dll и использования выходных данных для регистрации подключаемого модуля D365, сообщите мне! (чрезвычайно конкретно... я знаю, ха-ха)

Обновлять

Теперь я переключился на ILRepack и ILRepack.Lib.MSBuild.Task. Я использую следующую конфигурацию в файле ILRepack.targets:

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="ILRepacker" AfterTargets="Build">
    <ItemGroup>
      <InputAssemblies Include="$(OutputPath)$(TargetName)$(TargetExt)" />
      <!--<InputAssemblies Include="$(OutputPath)\*.dll" />-->
      <InputAssemblies Include="$(OutputPath)adtplugin.dll" />
      <InputAssemblies Include="$(OutputPath)Azure.Core.dll" />
      <InputAssemblies Include="$(OutputPath)Azure.DigitalTwins.Core.dll"/>
      <InputAssemblies Include="$(OutputPath)Azure.Identity.dll"/>
      <InputAssemblies Include="$(OutputPath)Microsoft.Bcl.AsyncInterfaces.dll"/>
      <InputAssemblies Include="$(OutputPath)System.Memory.dll"/>
      <InputAssemblies Include="$(OutputPath)System.Threading.Tasks.Extensions.dll"/>
      <!--<InputAssemblies Include="$(OutputPath)Microsoft.Identity.Client.dll"/>
      <InputAssemblies Include="$(OutputPath)Microsoft.Identity.Client.Extensions.Msal.dll"/>
      <InputAssemblies Include="$(OutputPath)Microsoft.Win32.Primitives.dll"/>
      <InputAssemblies Include="$(OutputPath)netstandard.dll"/>-->
      
    </ItemGroup>

    <ILRepack
        Parallel="true"
        Internalize="false"
        InternalizeExclude="@(DoNotInternalizeAssemblies)"
        InputAssemblies="@(InputAssemblies)"
        LibraryPath="$(OutputPath)"
        Wildcards="false"
        TargetKind="SameAsPrimaryAssembly"
        DebugInfo="false"
        KeyFile="adtplugin.snk"
        OutputFile="$(OutputPath)Merged\$(AssemblyName).dll"
        LogFile="$(OutputPath)Merged\ILRepack.log"
    />
  </Target>
</Project>

Слияние прошло успешно, но регистрация плагина по-прежнему не удалась с тем же дампом ошибки, что и выше.


person Cory Crowley    schedule 29.04.2021    source источник
comment
Мой совет: прекратите использовать ILMerge. Вместо этого используйте ILRepack, теперь его легко добавить в ваш проект. См. эту статью о SO.   -  person Henk van Boeijen    schedule 30.04.2021
comment
Я переключил ILRepack (и обновил информацию о своем вопросе), но все равно получаю ту же ошибку регистрации плагина: /   -  person Cory Crowley    schedule 30.04.2021
comment
Вы объединяете сборки .NET Core? Сборки должны быть основаны на .NET Framework 4 и не могут быть из пространства имен System.   -  person Henk van Boeijen    schedule 30.04.2021
comment
Глядя на ваши сборки, я думаю, что вариант может заключаться в создании компонента Azure (например, веб-API) и вызове его из вашего плагина с помощью простого HttpClient.   -  person Henk van Boeijen    schedule 30.04.2021


Ответы (2)


Возможно, вы захотите избежать слияния всего, что является частью .NET Framework (я предполагаю, что такие библиотеки, как System.Memory и System.Threading.Tasks, являются).

При этом, исходя из объединяемых вами DLL, даже если вы зарегистрируете их, в зависимости от того, что на самом деле делает код, ограничения песочница может помешать запуску подключаемого модуля.

Если это так, вы можете изучить Подключаемый модуль Azure Aware.

Когда-то у меня был плагин, в котором мне приходилось выполнять проверку подписи RSA. Я пытался использовать библиотеки .NET, но песочница запрещала выполнение кода, связанного с RSA. В итоге мне пришлось собрать свою собственную, используя библиотеку RSA с открытым исходным кодом, которую я нашел под названием EZ-RSA.

Спасибо за обновление. Я еще немного изучил сообщение об ошибке. Я нашел эта статья и этот вопрос, в котором разработчик, кажется, пришел к выводу, что ILMerging Identity library является тупиком.

Что касается пути слияния/переупаковки, вы можете использовать пустой проект и объединять библиотеки DLL одну за другой, проверяя регистрацию плагина после каждого, чтобы увидеть, какая библиотека или библиотеки нарушают регистрацию.

Последнее, что я слышал, даже когда это работает, ILMerge технически не поддерживается. Поддерживается подключаемый модуль Azure Aware.

Вы можете зарегистрировать свой подключаемый модуль для обращения к конечной точке службы или веб-перехватчику при его срабатывании:
reg1

Для конечной точки службы он может обращаться к различным типам прослушивателей в очереди служебной шины Azure (через строку подключения или это диалоговое окно конфигурации). конечная точка службы

Возможен также вызов Webhook: webhook

person Aron    schedule 30.04.2021
comment
Как ни странно, когда я явно не включаю System.Memory и System.Threading.Tasks, регистрация плагина завершается с ошибкой, говорящей о том, что эти пакеты не найдены. Вот почему они в этом списке, но я согласен. Их не нужно включать, поэтому я не уверен, почему это происходит. - person Cory Crowley; 30.04.2021
comment
Я переключился на ILRepack и обновил свой вопрос, но регистрация плагина по-прежнему не работает с тем же дампом ошибки. - person Cory Crowley; 30.04.2021
comment
Спасибо за обновление. Я расширил свой ответ. - person Aron; 30.04.2021

Попробуйте использовать пакет Fody для объединения ваших .dll-файлов после сборки. Сначала вам необходимо установить Fody и Costura.Fody через nuget. Он добавит некоторые ссылки и файл FodyWeavers.xml, который вы можете заполнить таким образом.

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura />
</Weavers>

Затем в Обозревателе решений выберите ссылки для сборок, которые вы хотите объединить, и в окне свойств измените Копировать локально< /em> на True. Для тех сборок, которые вы не хотите включать в процесс слияния, выберите Копировать локально – False.

Перестройте свое решение, и на выходе вы получите объединенную dll.

person Arsen    schedule 30.04.2021