Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/Dataverse/Plugin/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# TALXIS.DevKit.Build.Dataverse.Plugin

MSBuild integration for Dataverse plugin assembly projects. Configures Visual Studio project type GUIDs for CRM plugin development, brings in `Microsoft.CrmSdk.CoreAssemblies` and `Microsoft.PowerApps.MSBuild.Plugin`, applies automatic Git-based versioning, and exposes metadata targets that allow Solution projects to discover and integrate plugin assemblies during build.
MSBuild integration for Dataverse plugin assembly projects. Configures Visual Studio project type GUIDs for CRM plugin development, brings in `Microsoft.CrmSdk.CoreAssemblies` and `Microsoft.PowerApps.MSBuild.Plugin`, applies automatic Git-based versioning, merges referenced managed dependencies into the output DLL via ILRepack so the Dataverse sandbox can load all required types from a single assembly, and exposes metadata targets that allow Solution projects to discover and integrate plugin assemblies during build.

## Installation

Expand All @@ -25,6 +25,7 @@ The package sets `ProjectType` to `Plugin` and configures `ProjectTypeGuids` for
### Build-time targets

- **TalxisBeforeBuild** (runs before `BeforeBuild`) -- executes `GenerateVersionNumber` followed by `ApplyPluginVersionNumber` to set `AssemblyVersion`, `FileVersion`, `Version`, and `PackageVersion` from Git.
- **TalxisMergePluginDependencies** (runs after `Build`) -- uses [ILRepack](https://github.com/gluck/il-repack) to merge every managed DLL that landed in `$(OutDir)` into the main plugin assembly, so the Dataverse sandbox (which loads a single assembly) can resolve all referenced types without sibling DLLs. Sandbox-provided assemblies are skipped: `Microsoft.Xrm.Sdk*`, `Microsoft.Crm.Sdk.Proxy`, `Newtonsoft.Json`, `System.*`, `mscorlib`, `netstandard`. Idempotent — always reads the raw compiler output from `$(IntermediateOutputPath)` so the target can safely re-run within the same Solution build. Merged types keep their original public names (`Internalize=false`) to preserve Dataverse's reflection-based plugin type detection. Disable per-project with `<TalxisMergePluginDependencies>false</TalxisMergePluginDependencies>`.
Comment thread
zekelinAlex marked this conversation as resolved.

### Integration targets

Expand All @@ -44,10 +45,11 @@ These targets are called by `TALXIS.DevKit.Build.Dataverse.Solution` when it dis
| `PluginTargetFramework` | `$(TargetFramework)` or `net462` | Target framework used to locate the compiled plugin DLL. |
| `PluginPublishFolderName` | `publish` | Publish folder name under `bin\<Configuration>\<TFM>\`. |
| `PluginAssemblyId` | _(auto-generated)_ | Explicit GUID for the plugin assembly metadata; a new GUID is generated if empty. |
| `TalxisMergePluginDependencies` | `true` | When `true`, runs `TalxisMergePluginDependencies` after `Build` to ILRepack referenced DLLs into the plugin assembly. Set to `false` to opt out. |

## Related Packages

- **Depends on**: `TALXIS.DevKit.Build.Dataverse.Tasks`, `Microsoft.PowerApps.MSBuild.Plugin`, `Microsoft.CrmSdk.CoreAssemblies`
- **Depends on**: `TALXIS.DevKit.Build.Dataverse.Tasks`, `Microsoft.PowerApps.MSBuild.Plugin`, `Microsoft.CrmSdk.CoreAssemblies`, `ILRepack.Lib.MSBuild.Task`
- **Consumed by**: `TALXIS.DevKit.Build.Dataverse.Solution` projects via `ProjectReference`


Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<dependency id="Microsoft.PowerApps.MSBuild.Plugin" version="$MicrosoftPowerAppsTargetsVersion$" />
<dependency id="Microsoft.CrmSdk.CoreAssemblies" version="[9.0.2.60]" />
<dependency id="Microsoft.NETFramework.ReferenceAssemblies" version="[1.0.3]" />
<dependency id="ILRepack.Lib.MSBuild.Task" version="[2.0.44.2]" />
<dependency id="TALXIS.DevKit.Build.Dataverse.Tasks" version="$Version$" />
</dependencies>
</metadata>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
<PackageReference Include="Microsoft.CrmSdk.CoreAssemblies" Version="9.0.2.*" PrivateAssets="All" />
<PackageReference Include="Microsoft.PowerApps.MSBuild.Plugin" Version="1.*" PrivateAssets="All" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.*" PrivateAssets="All" />
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.44.2" PrivateAssets="All" />
</ItemGroup>
</Project>
10 changes: 10 additions & 0 deletions src/Dataverse/Tasks/msbuild/tasks/StubForILRepack.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
No-op stub. MergePluginDependencies.targets sets $(ILRepackTargetsFile)
to point at this file so that ILRepack.Lib.MSBuild.Task's auto-merge
target is suppressed (its condition is `!Exists($(ILRepackTargetsFile))`).
Lives outside the Targets/ wildcard folder so it is NOT auto-imported
(re-importing it via $(ILRepackTargetsFile) would otherwise raise MSB4011).
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<!--
Merge managed dependencies into the plugin/workflow-activity DLL so the
Dataverse sandbox (which loads a single assembly) can resolve all types
without sibling DLLs.

Runs AfterTargets="Build" for projects with <ProjectType>Plugin</ProjectType>
or <ProjectType>WorkflowActivity</ProjectType>. Picks every DLL that ended
up in $(OutDir) (bin/<Config>/<TF>/) and merges them into the main DLL,
EXCEPT assemblies the Dataverse sandbox already provides (Microsoft.Xrm.Sdk*,
Microsoft.Crm.Sdk.Proxy, System.*, mscorlib, Newtonsoft.Json).

Idempotent: always reads the raw compiler output from
$(IntermediateOutputPath) as the primary, never the already-merged bin file.
This lets the target safely re-run multiple times in the same Solution build
(SDK invokes Build on the plugin project from two different chains) without
duplicate-type errors.

Disable for a specific project with:
<PropertyGroup>
<TalxisMergePluginDependencies>false</TalxisMergePluginDependencies>
</PropertyGroup>
-->

<PropertyGroup>
<TalxisMergePluginDependencies Condition="'$(TalxisMergePluginDependencies)' == ''">true</TalxisMergePluginDependencies>
<!-- Suppress the auto-merge target shipped with ILRepack.Lib.MSBuild.Task
(which runs AfterTargets="Build" in Release config and would conflict
with our target). The package skips its auto-target when
$(ILRepackTargetsFile) points at an existing file — point it at a
dedicated no-op stub that lives OUTSIDE the Targets/ wildcard folder
(so it is not auto-imported; re-importing it via $(ILRepackTargetsFile)
would otherwise raise MSB4011). -->
<ILRepackTargetsFile Condition="'$(ILRepackTargetsFile)' == ''">$(MSBuildThisFileDirectory)..\StubForILRepack.targets</ILRepackTargetsFile>
</PropertyGroup>

<Target Name="TalxisMergePluginDependencies"
AfterTargets="Build"
Condition=" '$(TalxisMergePluginDependencies)' == 'true'
and ('$(ProjectType)' == 'Plugin' or '$(ProjectType)' == 'WorkflowActivity') ">
<PropertyGroup>
<_TalxisMergePrimaryRaw>$(IntermediateOutputPath)$(AssemblyName).dll</_TalxisMergePrimaryRaw>
<_TalxisMergeOutputDll>$(OutDir)$(AssemblyName).dll</_TalxisMergeOutputDll>
</PropertyGroup>
<ItemGroup>
<_TalxisMergeAll Include="$(OutDir)*.dll" />
<_TalxisMergePrimary Include="@(_TalxisMergeAll)"
Condition=" '%(Filename)%(Extension)' == '$(AssemblyName).dll' " />
<_TalxisMergeDeps Include="@(_TalxisMergeAll)" Exclude="@(_TalxisMergePrimary)" />
<!-- Drop sandbox-provided assemblies; merging them would clash with the
platform-supplied versions at runtime inside the sandbox. -->
<_TalxisMergeDeps Remove="@(_TalxisMergeDeps)"
Condition=" '%(Filename)' == 'mscorlib'
Or '%(Filename)' == 'netstandard'
Or '%(Filename)' == 'Newtonsoft.Json'
Or '%(Filename)' == 'Microsoft.Xrm.Sdk'
Or '%(Filename)' == 'Microsoft.Xrm.Sdk.Deployment'
Or '%(Filename)' == 'Microsoft.Xrm.Sdk.Workflow'
Comment thread
zekelinAlex marked this conversation as resolved.
Outdated
Or '%(Filename)' == 'Microsoft.Crm.Sdk.Proxy'
Or $([System.String]::Copy('%(Filename)').StartsWith('System.')) " />
</ItemGroup>

<Message Importance="high"
Text="TalxisMergePluginDependencies: merging into $(AssemblyName).dll -> @(_TalxisMergeDeps->'%(Filename)', ', ')"
Condition=" '@(_TalxisMergeDeps)' != '' " />
<Message Importance="high"
Text="TalxisMergePluginDependencies: nothing to merge"
Condition=" '@(_TalxisMergeDeps)' == '' " />

<!-- Internalize=false: keep merged types with their original public names.
With Internalize=true ILRepack prepends a GUID to type names
(e.g. <abc-def>WorkflowActivityBase), breaking Dataverse's
reflection-based detection of plugin / workflow-activity types via
IsSubclassOf(typeof(CodeActivity)) / interface lookup. -->
<ILRepack Condition=" '@(_TalxisMergeDeps)' != '' "
Parallel="true"
Internalize="false"
InputAssemblies="$(_TalxisMergePrimaryRaw);@(_TalxisMergeDeps)"
OutputFile="$(_TalxisMergeOutputDll)"
KeyFile="$(AssemblyOriginatorKeyFile)"
LibraryPath="$(OutDir)" />
</Target>

</Project>
6 changes: 4 additions & 2 deletions src/Dataverse/WorkflowActivity/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# TALXIS.DevKit.Build.Dataverse.WorkflowActivity

MSBuild integration for Dynamics 365 custom workflow activity assembly projects. Mirrors the Plugin package pattern: configures Visual Studio project type GUIDs, applies automatic Git-based versioning, and exposes metadata targets that allow Solution projects to discover and integrate workflow activity assemblies during build.
MSBuild integration for Dynamics 365 custom workflow activity assembly projects. Mirrors the Plugin package pattern: configures Visual Studio project type GUIDs, applies automatic Git-based versioning, merges referenced managed dependencies into the output DLL via ILRepack so the Dataverse sandbox can load all required types from a single assembly, and exposes metadata targets that allow Solution projects to discover and integrate workflow activity assemblies during build.

## Installation

Expand All @@ -25,6 +25,7 @@ The package sets `ProjectType` to `WorkflowActivity` and configures `ProjectType
### Build-time targets

- **TalxisBeforeBuild** (runs before `BeforeBuild`) -- executes `GenerateVersionNumber` followed by `ApplyPluginVersionNumber` to set `AssemblyVersion`, `FileVersion`, `Version`, and `PackageVersion` from Git.
- **TalxisMergePluginDependencies** (runs after `Build`) -- uses [ILRepack](https://github.com/gluck/il-repack) to merge every managed DLL that landed in `$(OutDir)` into the main workflow activity assembly, so the Dataverse sandbox (which loads a single assembly) can resolve all referenced types without sibling DLLs. Sandbox-provided assemblies are skipped: `Microsoft.Xrm.Sdk*`, `Microsoft.Crm.Sdk.Proxy`, `Newtonsoft.Json`, `System.*`, `mscorlib`, `netstandard`. Idempotent — always reads the raw compiler output from `$(IntermediateOutputPath)` so the target can safely re-run within the same Solution build. Merged types keep their original public names (`Internalize=false`) to preserve Dataverse's reflection-based detection of `CodeActivity` subclasses. Disable per-project with `<TalxisMergePluginDependencies>false</TalxisMergePluginDependencies>`.
Comment thread
zekelinAlex marked this conversation as resolved.

### Integration targets

Expand All @@ -44,10 +45,11 @@ These targets are called by `TALXIS.DevKit.Build.Dataverse.Solution` when it dis
| `WorkflowActivityTargetFramework` | `$(TargetFramework)` or `net462` | Target framework used to locate the compiled workflow activity DLL. |
| `WorkflowActivityPublishFolderName` | `publish` | Publish folder name under `bin\<Configuration>\<TFM>\`. |
| `WorkflowActivityAssemblyId` | _(auto-generated)_ | Explicit GUID for the workflow activity assembly metadata; a new GUID is generated if empty. |
| `TalxisMergePluginDependencies` | `true` | When `true`, runs `TalxisMergePluginDependencies` after `Build` to ILRepack referenced DLLs into the workflow activity assembly. Set to `false` to opt out. |

## Related Packages

- **Depends on**: `TALXIS.DevKit.Build.Dataverse.Tasks`, `Microsoft.PowerApps.MSBuild.Plugin`, `Microsoft.CrmSdk.CoreAssemblies`
- **Depends on**: `TALXIS.DevKit.Build.Dataverse.Tasks`, `Microsoft.PowerApps.MSBuild.Plugin`, `Microsoft.CrmSdk.CoreAssemblies`, `ILRepack.Lib.MSBuild.Task`
- **Consumed by**: `TALXIS.DevKit.Build.Dataverse.Solution` projects via `ProjectReference`


Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<dependency id="Microsoft.PowerApps.MSBuild.Plugin" version="$MicrosoftPowerAppsTargetsVersion$" />
<dependency id="Microsoft.CrmSdk.CoreAssemblies" version="[9.0.2.60]" />
<dependency id="Microsoft.NETFramework.ReferenceAssemblies" version="[1.0.3]" />
<dependency id="ILRepack.Lib.MSBuild.Task" version="[2.0.44.2]" />
<dependency id="TALXIS.DevKit.Build.Dataverse.Tasks" version="$Version$" />
</dependencies>
</metadata>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
<Import Project="$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.WorkflowActivity.props" Condition="Exists('$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.WorkflowActivity.props')" />

<ItemGroup>
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.44.2" PrivateAssets="All" />
</ItemGroup>
</Project>