{"id":37491255,"url":"https://github.com/simoncropp/packageshader","last_synced_at":"2026-01-25T02:00:30.590Z","repository":{"id":331229107,"uuid":"1124880096","full_name":"SimonCropp/PackageShader","owner":"SimonCropp","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-23T12:35:06.000Z","size":6431,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-23T21:58:33.872Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SimonCropp.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"License.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-29T19:22:16.000Z","updated_at":"2026-01-23T04:21:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SimonCropp/PackageShader","commit_stats":null,"previous_names":["simoncropp/packageshader"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SimonCropp/PackageShader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonCropp%2FPackageShader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonCropp%2FPackageShader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonCropp%2FPackageShader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonCropp%2FPackageShader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SimonCropp","download_url":"https://codeload.github.com/SimonCropp/PackageShader/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonCropp%2FPackageShader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28741621,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T01:40:51.112Z","status":"online","status_checked_at":"2026-01-25T02:00:06.841Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-16T07:38:16.256Z","updated_at":"2026-01-25T02:00:30.576Z","avatar_url":"https://github.com/SimonCropp.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src='/src/icon.png' height='30px'\u003e PackageShader\n\n[![Build status](https://img.shields.io/appveyor/build/SimonCropp/packageshader)](https://ci.appveyor.com/project/SimonCropp/packageshader)\n[![NuGet Status](https://img.shields.io/nuget/v/PackageShader.svg?label=PackageShader)](https://www.nuget.org/packages/PackageShader/)\n[![NuGet Status](https://img.shields.io/nuget/v/PackageShaderTool.svg?label=PackageShaderTool)](https://www.nuget.org/packages/PackageShaderTool/)\n[![NuGet Status](https://img.shields.io/nuget/v/PackageShader.MsBuild.svg?label=PackageShader.MsBuild)](https://www.nuget.org/packages/PackageShader.MsBuild/)\n\nAvoid dependency conflicts in assemblies changing the name of references. Designed as an alternative to [Costura](https://github.com/Fody/Costura), [ILMerge](https://github.com/dotnet/ILMerge), and [ILRepack](https://github.com/gluck/il-repack).\n\nThis project is a fork of [Alias](https://github.com/getsentry/dotnet-assembly-alias). Credit goes to [Sentry](https://sentry.io/) for producing the original Alias project. See their blog post [Alias: An approach to .NET assembly conflict resolution](https://blog.sentry.io/alias-an-approach-to-net-assembly-conflict-resolution/) for background on the approach.\n\n**See [Milestones](../../milestones?state=closed) for release notes.**\n\n\n## The Problem\n\nIn .NET plugin/extension based applications, all assemblies are loaded into a single shared context, making it impossible to load multiple versions of the same assembly simultaneously. When an assemblies depend on different versions of a library (like Newtonsoft.Json), conflicts arise based on load order - whichever version loads first is used by all subsequent assemblies, causing unexpected behavior or exceptions.\n\nThis is particularly common in:\n\n * **Unity extensions** - Unity Package Manager packages bundle System DLLs\n * **MSBuild tasks** - Tasks run in a shared AppDomain\n * **SharePoint/Office extensions** - Plugins share the host's assembly context\n * **Visual Studio extensions** - Extensions share the VS process\n\n\n## How It Works\n\nPackageShader resolves conflicts by:\n\n1. **Renaming assemblies** - Both the filename and IL assembly name are changed with a unique prefix/suffix\n2. **Patching references** - All assembly references are updated to point to the renamed assemblies\n3. **Fixing strong names** - Re-signs assemblies if a key is provided, or removes strong naming\n4. **Optionally internalizing** - Makes types internal and adds `InternalsVisibleTo` to maintain access\n\nThe result is a group of files that will not conflict with any assemblies loaded in the plugin context.\n\n\n## Alternatives\n\n| Tool | Approach | Limitation |\n|------|----------|------------|\n| [Costura](https://github.com/Fody/Costura) | Embeds dependencies as resources | Doesn't rename assemblies, conflicts persist |\n| [ILMerge](https://github.com/dotnet/ILMerge) | Merges IL into single assembly | Unmaintained, known bugs in .NET Core |\n| [ILRepack](https://github.com/gluck/il-repack) | Merges IL into single assembly | Not suitable for plugin deployment scenarios |\n| **PackageShader** | Renames and patches references | Produces multiple files (by design) |\n\n\n## Packages\n\n| Package | Description |\n|---------|-------------|\n| [PackageShader](https://www.nuget.org/packages/PackageShader/) | Core library for programmatic assembly shading |\n| [PackageShaderTool](https://www.nuget.org/packages/PackageShaderTool/) | .NET CLI tool for command-line usage |\n| [PackageShader.MsBuild](https://www.nuget.org/packages/PackageShader.MsBuild/) | MSBuild integration for automatic shading at build time |\n\n\n## PackageShader (Library)\n\nhttps://www.nuget.org/packages/PackageShader/\n\nThe core library provides programmatic access to assembly shading functionality.\n\n\n### Installation\n\n```\ndotnet add package PackageShader\n```\n\n\n### API\n\nThe main entry point is `Shader.Run()`:\n\n\u003c!-- snippet: ShaderUsage --\u003e\n\u003ca id='snippet-ShaderUsage'\u003e\u003c/a\u003e\n```cs\nvar assemblies = new List\u003cSourceTargetInfo\u003e\n{\n    new(\n        SourceName: \"Newtonsoft.Json\",\n        SourcePath: @\"C:\\libs\\Newtonsoft.Json.dll\",\n        TargetName: \"Newtonsoft.Json_Shaded\",\n        TargetPath: @\"C:\\output\\Newtonsoft.Json_Shaded.dll\",\n        IsShaded: true),\n    new(\n        SourceName: \"MyApp\",\n        SourcePath: @\"C:\\libs\\MyApp.dll\",\n        TargetName: \"MyApp\",\n        TargetPath: @\"C:\\output\\MyApp.dll\",\n        IsShaded: false)\n};\n\n// Optional: provide a strong name key\nvar key = StrongNameKey.FromFile(\"mykey.snk\");\n\nShader.Run(\n    infos: assemblies,\n    // Make shaded assembly types internal\n    internalize: true,\n    // null if strong naming is not required\n    key: key);\n```\n\u003csup\u003e\u003ca href='/src/Tests/UsageExamples.cs#L9-L35' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-ShaderUsage' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n### SourceTargetInfo\n\n\u003c!-- snippet: SourceTargetInfo --\u003e\n\u003ca id='snippet-SourceTargetInfo'\u003e\u003c/a\u003e\n```cs\npublic record SourceTargetInfo(\n    string SourceName,\n    string SourcePath,\n    string TargetName,\n    string TargetPath,\n    bool IsShaded,\n    bool IsRootAssembly = false);\n```\n\u003csup\u003e\u003ca href='/src/PackageShader/SourceTargetInfo.cs#L3-L11' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-SourceTargetInfo' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n### Low-Level API\n\nFor fine-grained control, use `StreamingAssemblyModifier` directly:\n\n\u003c!-- snippet: LowLevelUsage --\u003e\n\u003ca id='snippet-LowLevelUsage'\u003e\u003c/a\u003e\n```cs\nusing var modifier = StreamingAssemblyModifier.Open(\"MyAssembly.dll\");\n\nmodifier.SetAssemblyName(\"MyAssembly_Shaded\");\nmodifier.SetAssemblyPublicKey(key.PublicKey);\nmodifier.RedirectAssemblyRef(\"Newtonsoft.Json\", \"Newtonsoft.Json_Shaded\", key.PublicKeyToken);\nmodifier.MakeTypesInternal();\nmodifier.AddInternalsVisibleTo(\"MyApp\", key.PublicKey);\n\nmodifier.Save(\"MyAssembly_Shaded.dll\", key);\n```\n\u003csup\u003e\u003ca href='/src/Tests/UsageExamples.cs#L42-L52' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-LowLevelUsage' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n---\n\n\n## PackageShaderTool (CLI)\n\nhttps://www.nuget.org/packages/PackageShaderTool/\n\n**.NET  SDK 10 or higher is required to run this tool.**\n\nFor a given directory and a subset of assemblies:\n\n * Changes the assembly name of each \"shaded\" assembly.\n * Renames \"shaded\" assemblies on disk.\n * For all assemblies, fixes the references to point to the new shaded assemblies.\n\n\n### Installation\n\n```\ndotnet tool install --global PackageShaderTool\n```\n\n\n### Usage\n\n```\npackageshader --target-directory \"C:/Code/TargetDirectory\"\n              --suffix _Shaded\n              --assemblies-to-shade \"Microsoft*;System*;EmptyFiles\"\n```\n\n\n### Arguments\n\n| Argument | Short | Description |\n|----------|-------|-------------|\n| `--target-directory` | `-t` | Directory containing assemblies. Defaults to current directory. |\n| `--prefix` | `-p` | Prefix for renamed assemblies. |\n| `--suffix` | `-s` | Suffix for renamed assemblies. |\n| `--assemblies-to-shade` | `-a` | **Required.** Semi-colon separated list. Names ending in `*` are wildcards. |\n| `--assemblies-to-exclude` | `-e` | Semi-colon separated list of assemblies to exclude. |\n| `--internalize` | `-i` | Make all types in shaded assemblies internal. Defaults to false. |\n| `--key` | `-k` | Path to .snk file. If omitted, strong naming is removed. |\n\nEither `--prefix` or `--suffix` must be specified.\n\n\n### Examples\n\nShade all Microsoft and System assemblies with a suffix:\n\n```\npackageshader -t \"C:/MyApp/bin\" -s \"_Shaded\" -a \"Microsoft*;System*\"\n```\n\nShade specific assemblies with a prefix and internalize:\n\n```\npackageshader -t \"C:/MyApp/bin\" -p \"Shaded_\" -a \"Newtonsoft.Json;Serilog\" -i\n```\n\nShade with strong name signing:\n\n```\npackageshader -t \"C:/MyApp/bin\" -s \"_Shaded\" -a \"Newtonsoft*\" -k \"mykey.snk\"\n```\n\n\n---\n\n\n## PackageShader.MsBuild\n\nhttps://www.nuget.org/packages/PackageShader.MsBuild/\n\nAutomatically shade assemblies at build time via MSBuild integration.\n\n\n### Installation\n\n```\ndotnet add package PackageShader.MsBuild\n```\n\n\n### Configuration\n\nConfigure shading via MSBuild properties in the project file:\n\n\u003c!-- snippet: MsBuildConfig --\u003e\n\u003ca id='snippet-MsBuildConfig'\u003e\u003c/a\u003e\n```xml\n\u003c!-- Mark references to shade with Shade=\"true\" --\u003e\n\u003cItemGroup\u003e\n  \u003cPackageReference Include=\"Newtonsoft.Json\" Version=\"13.0.3\" Shade=\"true\" /\u003e\n  \u003cProjectReference Include=\"..\\MyLibrary\\MyLibrary.csproj\" Shade=\"true\" /\u003e\n\u003c/ItemGroup\u003e\n\n\u003c!-- Optional MSBuild properties --\u003e\n\u003cPropertyGroup\u003e\n  \u003c!-- Make shaded types internal (default: false) --\u003e\n  \u003cShader_Internalize\u003etrue\u003c/Shader_Internalize\u003e\n\u003c/PropertyGroup\u003e\n```\n\u003csup\u003e\u003ca href='/src/msbuild-config.include.xml#L1-L13' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-MsBuildConfig' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n### How It Works\n\nThe MSBuild package:\n\n1. Runs after the `AfterCompile` target\n2. Identifies `PackageReference` and `ProjectReference` items marked with `Shade=\"true\"`\n3. Matches those references to assemblies in `ReferenceCopyLocalPaths`\n4. Renames the matched assemblies with the specified prefix/suffix (default: `_Shaded`)\n5. Updates all assembly references to point to the renamed assemblies\n6. Optionally internalizes types and adds `InternalsVisibleTo` attributes\n7. Signs assemblies with the project's `AssemblyOriginatorKeyFile` if `SignAssembly` is true\n8. Excludes shaded dependencies from the NuGet package dependency list (sets `PrivateAssets=\"all\"`)\n9. Includes shaded assemblies in the NuGet package output, automatically co-located with the primary assembly\n\n\n### Full Example\n\n\u003c!-- snippet: MsBuildFull --\u003e\n\u003ca id='snippet-MsBuildFull'\u003e\u003c/a\u003e\n```xml\n\u003cProject Sdk=\"Microsoft.NET.Sdk\"\u003e\n  \u003cPropertyGroup\u003e\n    \u003cTargetFramework\u003enet8.0\u003c/TargetFramework\u003e\n    \u003cShader_Internalize\u003etrue\u003c/Shader_Internalize\u003e\n\n    \u003c!-- Optional: strong name signing --\u003e\n    \u003cSignAssembly\u003etrue\u003c/SignAssembly\u003e\n    \u003cAssemblyOriginatorKeyFile\u003emykey.snk\u003c/AssemblyOriginatorKeyFile\u003e\n  \u003c/PropertyGroup\u003e\n\n  \u003cItemGroup\u003e\n    \u003cPackageReference Include=\"PackageShader.MsBuild\" PrivateAssets=\"all\" /\u003e\n\n    \u003c!-- Mark dependencies to shade with Shade=\"true\" --\u003e\n    \u003cPackageReference Include=\"Newtonsoft.Json\" Version=\"13.0.3\" Shade=\"true\" /\u003e\n    \u003cPackageReference Include=\"Serilog\" Version=\"3.1.0\" Shade=\"true\" /\u003e\n\n    \u003c!-- Dependencies without Shade=\"true\" are not shaded --\u003e\n    \u003cPackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"8.0.0\" /\u003e\n  \u003c/ItemGroup\u003e\n\u003c/Project\u003e\n```\n\u003csup\u003e\u003ca href='/src/msbuild-full.include.xml#L1-L23' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-MsBuildFull' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThis configuration will:\n\n- Shade `Newtonsoft.Json` and `Serilog` (marked with `Shade=\"true\"`)\n- Leave `Microsoft.Extensions.Logging` unchanged\n- Make all types in shaded assemblies internal\n- Add `InternalsVisibleTo` attributes so the main assembly can access shaded types\n- Sign all assemblies with `mykey.snk`\n- Exclude shaded dependencies from the NuGet package dependency list\n\n\n### NuGet Package Path Behavior\n\nBy default, shaded assemblies are placed in `lib/$(TargetFramework)` in the NuGet package.\n\n**Automatic Co-location**: If the project uses custom `TfmSpecificPackageFile` entries to place the primary assembly in a non-standard location (e.g., `task/$(TargetFramework)` for MSBuild task packages), shaded assemblies are automatically co-located with the primary assembly.\n\nExample for MSBuild task package:\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003cIncludeBuildOutput\u003efalse\u003c/IncludeBuildOutput\u003e\n\u003c/PropertyGroup\u003e\n\n\u003cItemGroup\u003e\n  \u003c!-- Place primary DLL in task/ folder --\u003e\n  \u003cTfmSpecificPackageFile Include=\"$(OutputPath)$(TargetFileName)\"\u003e\n    \u003cPackagePath\u003etask/$(TargetFramework)\u003c/PackagePath\u003e\n    \u003cPack\u003etrue\u003c/Pack\u003e\n  \u003c/TfmSpecificPackageFile\u003e\n\n  \u003c!-- Shaded assemblies will automatically go to task/$(TargetFramework) --\u003e\n  \u003cPackageReference Include=\"Newtonsoft.Json\" Version=\"13.0.3\" Shade=\"true\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\n**Manual Override**: To explicitly specify the package path for shaded assemblies, use the `ShadedAssembliesPackagePath` property:\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003c!-- Manually specify where shaded assemblies should be placed --\u003e\n  \u003cShadedAssembliesPackagePath\u003etools/$(TargetFramework)\u003c/ShadedAssembliesPackagePath\u003e\n\u003c/PropertyGroup\u003e\n```\n\n\n## Icon\n\n[Shade](https://thenounproject.com/icon/shade-7850642/) designed by [Kim Naces](https://thenounproject.com/creator/kim2262/) from [The Noun Project](https://thenounproject.com).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimoncropp%2Fpackageshader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimoncropp%2Fpackageshader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimoncropp%2Fpackageshader/lists"}