joseangelmt / AddRuntimeToDepsJson

Command line utility that adds "runtime" information to referenced NuGet packages containing only "Reference Assemblies".

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AddRuntimeToDepsJson

If your native application provides a mixed assembly (C++/CLI) so that your users can interact with it via .NET, you can provide such a mixed assembly via a NuGet package.

Example of the files section of the .nuspec file of the NuGet package publishing the assemblies in the lib folder.

<files>
  <file src="..\Digi21.DigiNG\bin\Release\net8.0\Digi21.DigiNG.dll" target="lib\net8.0\Digi21.DigiNG.dll" />
</files>

In the example above, since we provided the assemblies in the lib folder, when using this NuGet package, the .deps.json files of the dependent applications will provide information so that the .NET runtime knows the path to load the assembly....

{
  "runtimeTarget": {
    "name": ".NETCoreApp,Version=v8.0",
    "signature": ""
  },
  "compilationOptions": {},
  "targets": {
    ".NETCoreApp,Version=v8.0": {
      "cargabind/1.0.0": {
        "dependencies": {
          "Digi21.DigiNG": "24.0.0",
        },
        "runtime": {
          "cargabind.dll": {}
        }
      },
      "Digi21.DigiNG/24.0.0": {
        "runtime": {
          "lib/net8.0/Digi21.DigiNG.dll": {
            "assemblyVersion": "24.0.0.0",
            "fileVersion": "24.0.0.0"
          }
        }
      },

In this case, when your client runs its program, the loader will load your mixed assembly from the path: %userprofile%\.nuget\packages\digi21.diging\24.0.0\lib\net8.0\Digi21.DigiNG.dll.

If you publish a new version of your application, and in this new version some internal modification has been made to the mixed assembly, you will have to re-publish a new NuGet package, even if the public surface of the assembly has not changed, and you will have to apply publisher policies so that programs deployed by your users for previous versions of the NuGet package continue to run, or you will have to force your users to re-publish a new NuGet package, even if the public surface of the assembly has not changed.

To solve this, instead of publishing the mixed assemblies (which are runtime assemblies) in the NuGet package, you can publish Reference Assemblies (which you will have to implement in C# for example because you cannot create reference assemblies in C++/CLI projects).

Example of the files section of the .nuspec file of the NuGet package publishing the assemblies in the ref folder.

<files>
  <file src="..\Digi21.DigiNG\obj\Release\net8.0\ref\Digi21.DigiNG.dll" target="ref\net8.0\Digi21.DigiNG.dll" />
</files>

NuGet packages with Reference Assemblies are intended for cases where the NuGet package provides multiple runtime assemblies in the same package (one for each operating system or framework version) as explained in Multi-targeting for NuGet Packages, but because we are not including runtimes in our NuGet package, when you build an application using our NuGet package, the application's .deps.json file will not provide the name of the DLL to load, as we can see below:

{
  "runtimeTarget": {
    "name": ".NETCoreApp,Version=v8.0",
    "signature": ""
  },
  "compilationOptions": {},
  "targets": {
    ".NETCoreApp,Version=v8.0": {
      "cargabind/1.0.0": {
        "dependencies": {
          "Digi21.DigiNG": "24.0.0",
        },
        "runtime": {
          "cargabind.dll": {}
        }
      },
      "Digi21.DigiNG/24.0.0": {},

As you can see in the .deps.json file above, there is no reference to Digi21.DigiNG.dll, so the loader will not know which DLL the Digi21.DigiNG/24.0.0 assembly implements.

To solve this problem, we would have to manually add the name of the DLL that implements the assembly to the runtime attribute of our assembly:

{
  "runtimeTarget": {
    "name": ".NETCoreApp,Version=v8.0",
    "signature": ""
  },
  "compilationOptions": {},
  "targets": {
    ".NETCoreApp,Version=v8.0": {
      "cargabind/1.0.0": {
        "dependencies": {
          "Digi21.DigiNG": "24.0.0",
          "Digi21.DigiNG.IO.BinDouble": "24.0.0",
          "Newtonsoft.Json": "13.0.3"
        },
        "runtime": {
          "cargabind.dll": {}
        }
      },
      "Digi21.DigiNG/24.0.0": {
        "runtime": {
          "Digi21.DigiNG.dll": {}
        }

But we don't want the user to have to do this manually every time they build, so we can have our NuGet package provide a Post Build Event that runs a tool that parses the app's .deps.json file and adds this entry in case you don't have it, and this is the purpose of this repository.

The AddRutimeToDepsJson application is a console application that receives the following parameters:

  • Path of the .deps.json file to modify
  • SDK name
  • Assembly name
  • Path to the .DLL file that implements the assembly

For our example the parameters would be AddRutimeToDepsJson.exe "$(OutDir)$(TargetName).deps.json" ".NETCoreApp,Version=v8.0" "Digi21.DigiNG/24.0.0" Digi21.DigiNG.dll

To add a Post Build Event to our NuGet package we can follow the instructions explained in this Stack Overflow answer

We create the file Digi21.DigiNG.targets:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <BuildDependsOn>
			$(BuildDependsOn);
			Digi21DigiNGCustomTarget
		</BuildDependsOn>
	</PropertyGroup>

	<Target Name="Digi21DigiNGCustomTarget">
		<Exec Command="$(MSBuildThisFileDirectory)AddRuntimeToDepsJson.exe &quot;$(OutDir)$(TargetName).deps.json&quot; &quot;.NETCoreApp,Version=v8.0&quot; &quot;Digi21.DigiNG/24.0.0&quot; Digi21.DigiNG.dll" />
	</Target>
</Project>

...and finally, we add both the Digi21.DigiNG.targets file and the AddRuntimeToDepsJson program to the build folder of the NuGet package:

	<files>
		<file src="..\Digi21.DigiNG\obj\Release\net8.0\ref\Digi21.DigiNG.dll" target="ref\net8.0\Digi21.DigiNG.dll" />
		<file src="Digi21.DigiNG.targets" target="build\Digi21.DigiNG.targets" />
		<file src="C:\Users\josea\source\repos\AddRuntimeToDepsJson\AddRuntimeToDepsJson\bin\Release\net8.0\AddRuntimeToDepsJson.deps.json" target="build\AddRuntimeToDepsJson.deps.json" />
		<file src="C:\Users\josea\source\repos\AddRuntimeToDepsJson\AddRuntimeToDepsJson\bin\Release\net8.0\AddRuntimeToDepsJson.dll" target="build\AddRuntimeToDepsJson.dll" />
		<file src="C:\Users\josea\source\repos\AddRuntimeToDepsJson\AddRuntimeToDepsJson\bin\Release\net8.0\AddRuntimeToDepsJson.exe" target="build\AddRuntimeToDepsJson.exe" />
		<file src="C:\Users\josea\source\repos\AddRuntimeToDepsJson\AddRuntimeToDepsJson\bin\Release\net8.0\AddRuntimeToDepsJson.runtimeconfig.json" target="build\AddRuntimeToDepsJson.runtimeconfig.json" />
	</files>

And that's it: every time the application is built with our NuGet package, the runtime entry will automatically be added to the .deps.json file of the compiled project.

About

Command line utility that adds "runtime" information to referenced NuGet packages containing only "Reference Assemblies".


Languages

Language:C# 100.0%