Dataverse: Ways to Generating NuGet Package to be used in Dependant Assembly plug-ins

With all the crazy changes happening in Power Platform technologies, especially Dataverse/Model-Driven-Apps. We must admit, that the plugin development has not really changed. So I believe most organizations still use plugin projects that created so long time ago and when the Dependant Assembly plug-ins (preview) come to GA. Then they will start to migrate the old plugin project to the new version so we can make use of the Dependant Assembly plug-ins.

Before we go to the demonstration, you need to make sure to install the Power Platform CLI. This tool is updated regularly by Microsoft and they keep adding more and more features, especially for Developers to do their work! If you already installed it, make sure to update the version using the command “pac install latest“.

Create New Project + Copy All the files

The easiest way to do it in my opinion is to create a new project with the same name as the targeted project. For example, I have the below .csproj file:

Old plugin csproj

For demonstration purposes, I put the directory of SampleOldPlugin and create a new empty directory with the name of New. Once we set that, we only need to open command prompt > CD to the targeted folder (inside New folder) > then execute command “pac plugin init -o SampleOldPlugin” (for the detail command you can check here):

Create the same plugin project name

We need to pass the parameter -o SampleOldPlugin. When the CLI creates the plugin project, it will create the correct project name as what you want (in my case, I named it SampleOldPlugin). Once we did it, the next step we need to open both projects’ directories > copy the files that you need from the old project to the new one > paste to the new project’s directory:

Copy the files you needed from the old project to the new project

Once we copy all the necessary files into the new project, the next steps are to remove the generated files.

Delete unnecessary files

For your project, if you have a NuGet package/external DLL, you can add to the reference and you can build (and when you got the build error, you need to fix it) and deploy it.

Deploy the NuGet package

You also can verify your NuGet package using NuGet Package Explorer:

Verify your NuGet Package

Build Manually your NuGet Package + Edit Using NuGet Package Explorer

Before you scroll down, this is not worth it. 🤣 But I do it for observation + learning purposes. The first step is to make sure that you use .NET Framework 4.7.1 for the project. Then if your project is still dependent on the local files (especially Microsoft.Xrm.Sdk.dll/Microsoft.Crm.Sdk.dll), you need to remove that dependency + install Microsoft.CrmSdk.CoreAssemblies NuGet package (just to be safe). For this demonstration, I created a simple throw error where I used Newtonsoft as the third-party library:

using System;
using Microsoft.Xrm.Sdk;
using Newtonsoft.Json;

namespace SampleOldPlugin
{
    public class Test
    {
        public string Message { get; set; }
    }

    public class DemoPlugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            var test = JsonConvert.DeserializeObject<Test>("{'Message': 'Hello Temmy!'}");
            throw new InvalidPluginExecutionException("ERROR FROM DemoPlugin: " + test.Message);
        }
    }
}

While this is my .csproj file to show you this is the old project:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{42AE02ED-E8AC-4554-9E41-1CC46947A980}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>SampleOldPlugin</RootNamespace>
    <AssemblyName>SampleOldPlugin</AssemblyName>
    <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <TargetFrameworkProfile />
    <NuGetPackageImportStamp>
    </NuGetPackageImportStamp>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup>
    <SignAssembly>true</SignAssembly>
  </PropertyGroup>
  <PropertyGroup>
    <AssemblyOriginatorKeyFile>StrongSignKey.snk</AssemblyOriginatorKeyFile>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.Crm.Sdk.Proxy, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.45\lib\net462\Microsoft.Crm.Sdk.Proxy.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.Xrm.Sdk, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.45\lib\net462\Microsoft.Xrm.Sdk.dll</HintPath>
    </Reference>
    <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
      <HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
    </Reference>
    <Reference Include="System.Core" />
    <Reference Include="System.DirectoryServices" />
    <Reference Include="System.DirectoryServices.AccountManagement" />
    <Reference Include="System.IdentityModel" />
    <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
    </Reference>
    <Reference Include="System.Numerics" />
    <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
    </Reference>
    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
    </Reference>
    <Reference Include="System.Runtime.Serialization" />
    <Reference Include="System.Security" />
    <Reference Include="System.ServiceModel" />
    <Reference Include="System.ServiceModel.Web" />
    <Reference Include="System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll</HintPath>
    </Reference>
    <Reference Include="System.Text.Json, Version=6.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Text.Json.6.0.2\lib\net461\System.Text.Json.dll</HintPath>
    </Reference>
    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
    </Reference>
    <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
    </Reference>
    <Reference Include="System.Web" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="DemoPlugin.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="DemoPluginHelper.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="app.config" />
    <None Include="packages.config" />
    <None Include="StrongSignKey.snk" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets" Condition="Exists('..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets')" />
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
    <PropertyGroup>
      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets'))" />
  </Target>
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>

Next, open the Developer Command Prompt (from Visual Studio) > cd to the .csproj file > execute command “nuget spec“:

Generated .nuspec file

You can open and update the .nuspec file. Below is a sample of my changes:

<?xml version="1.0"?>
<package >
  <metadata>
    <id>$title$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <owners>$author$</owners>
    <description>$description$</description>
    <releaseNotes>Temmy updates</releaseNotes>
    <copyright>Copyright 2022</copyright>

  </metadata>
</package>

Then if you want to make all the setup correctly, you can open your Visual Studio > right click on the project > Properties > Assembly Information (on the Application tab) > Update all the properties necessary for you:

Update the Assembly Information

After you make sure you can build the project successfully, the next step is to open your Developer Command Prompt again and execute the command “nuget pack” (make sure you are in the .csproj folder):

Create the NuGet Package

If you go to the .csproj directory, you will see that we got SampleOldPlugin.1.0.0.0.nupkg. But, if you sneak peak the NuGet package using NuGet Package Explorer, you will see that there are some dependencies that not needed + missing dependency (Newtonsoft.Json.dll) that supposed included in the Package contents (right side):

Checking the NuGet Package generated

To remove those packages that we don’t need, you can open the packages.config in your project (by default if using an old project) and add the property developmentDependency=”true” to all the packages that you don’t want to include:

Left is the original, Right is with the changes

With this, when you execute the command “nuget pack” > open the NuGet Package using NuGet Package Explorer > in the Package contents, under net471 > right click > add existing file > add Newtonsoft.Json.dll in your debug folder. After added, click File > Save, and this package is ready to be deployed (I know this part still needs a manual way).

Adding the Newtonsoft.Json.dll manually

Once you deploy it, the package is ready to be used. For the demonstration purpose, I add a plugin step in the Message=Update + Entity=’Contact‘:

Result

Happy CRM-ing!

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.