Nopcommerce: Copy References to Output Directory in PlugIns with Nuget Packages

Created on 3 Aug 2018  路  7Comments  路  Source: nopSolutions/nopCommerce

nopCommerce version: 4.10

Steps to reproduce the problem:

  1. Add new .net core project with all nopCommerce project changes, eg PostBuild step & update output directory to nop.web/plugins
  2. Add Nuget reference to IdentityServer4 2.2.0
  3. Build and notice the plugins// dir contains the plugin assembly but not the IdentityServer4.dll, this assembly however is in the package store c:\users\.nuget\packages\IdentityServer4...
  4. Run the app and you will receive an assembly not found error page.

If I copy the dll from the nuget package into the root of my project and mark it as content and copy things work as long as I copy all its dependencies too.

If I use true this works too but a ton of assemblies get dumped into my plugin directory.

The ClearPluginAssemblies.proj does not really work other than to remove a few nop assemblies as all the package references come from the user's package store.

Basically I need to understand the best workflow to develop a plugin with a Nuget package reference and then understand how to properly deploy such plugin on nopCommerce 4.10.

functionality / feature

Most helpful comment

Hi,

If you want your NuGet .dlls to be copied to plugin output, you need to make sure your .csproj looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <OutputPath>..\..\Presentation\Nop.Web\Plugins\SamplePlugin\</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <OutputPath>..\..\Presentation\Nop.Web\Plugins\SamplePlugin\</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="IdentityServer4" Version="2.2.0" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\Libraries\Nop.Core\Nop.Core.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Libraries\Nop.Data\Nop.Data.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Libraries\Nop.Services\Nop.Services.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Presentation\Nop.Web.Framework\Nop.Web.Framework.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Presentation\Nop.Web\Nop.Web.csproj">
      <Private>false</Private>
    </ProjectReference>
  </ItemGroup>

  <Target Name="FilterCopyLocalItems" AfterTargets="ResolveLockFileCopyLocalProjectDeps">
    <ItemGroup>
      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)' != 'IdentityServer4'" />
    </ItemGroup>
  </Target>
</Project>

Important parts are "CopyLocalLockFileAssemblies" set to true and "FilterCopyLocalItems" part, other than that everything is default for nopCommerce plugins.

If your library has many dependencies you need to specify them all, for instance here is what we did for Microsoft.AspNetCore.OData:

  <Target Name="FilterCopyLocalItems" AfterTargets="ResolveLockFileCopyLocalProjectDeps">
    <ItemGroup>
      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)' != 'Microsoft.AspNetCore.Authentication.JwtBearer' AND '%(Filename)' != 'Microsoft.AspNetCore.OData' AND '%(Filename)' != 'Microsoft.IdentityModel.Protocols.OpenIdConnect' AND '%(Filename)' != 'Microsoft.IdentityModel.Logging' AND '%(Filename)' != 'Microsoft.IdentityModel.Protocols' AND '%(Filename)' != 'Microsoft.IdentityModel.Tokens' AND '%(Filename)' != 'Microsoft.OData.Core' AND '%(Filename)' != 'Microsoft.OData.Edm' AND '%(Filename)' != 'System.IdentityModel.Tokens.Jwt' AND '%(Filename)' != 'Microsoft.Spatial'" />
    </ItemGroup>
  </Target>

Hope it helps,
John,
GrandNode Team

All 7 comments

Hi,

If you want your NuGet .dlls to be copied to plugin output, you need to make sure your .csproj looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <OutputPath>..\..\Presentation\Nop.Web\Plugins\SamplePlugin\</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <OutputPath>..\..\Presentation\Nop.Web\Plugins\SamplePlugin\</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="IdentityServer4" Version="2.2.0" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\Libraries\Nop.Core\Nop.Core.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Libraries\Nop.Data\Nop.Data.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Libraries\Nop.Services\Nop.Services.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Presentation\Nop.Web.Framework\Nop.Web.Framework.csproj">
      <Private>false</Private>
    </ProjectReference>
    <ProjectReference Include="..\..\Presentation\Nop.Web\Nop.Web.csproj">
      <Private>false</Private>
    </ProjectReference>
  </ItemGroup>

  <Target Name="FilterCopyLocalItems" AfterTargets="ResolveLockFileCopyLocalProjectDeps">
    <ItemGroup>
      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)' != 'IdentityServer4'" />
    </ItemGroup>
  </Target>
</Project>

Important parts are "CopyLocalLockFileAssemblies" set to true and "FilterCopyLocalItems" part, other than that everything is default for nopCommerce plugins.

If your library has many dependencies you need to specify them all, for instance here is what we did for Microsoft.AspNetCore.OData:

  <Target Name="FilterCopyLocalItems" AfterTargets="ResolveLockFileCopyLocalProjectDeps">
    <ItemGroup>
      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)' != 'Microsoft.AspNetCore.Authentication.JwtBearer' AND '%(Filename)' != 'Microsoft.AspNetCore.OData' AND '%(Filename)' != 'Microsoft.IdentityModel.Protocols.OpenIdConnect' AND '%(Filename)' != 'Microsoft.IdentityModel.Logging' AND '%(Filename)' != 'Microsoft.IdentityModel.Protocols' AND '%(Filename)' != 'Microsoft.IdentityModel.Tokens' AND '%(Filename)' != 'Microsoft.OData.Core' AND '%(Filename)' != 'Microsoft.OData.Edm' AND '%(Filename)' != 'System.IdentityModel.Tokens.Jwt' AND '%(Filename)' != 'Microsoft.Spatial'" />
    </ItemGroup>
  </Target>

Hope it helps,
John,
GrandNode Team

Thanks @JanKonopka for a great detailed answer. So during dev how do you get around the dependent assemblies from being deleted when nop.web project runs ClearPluginAssemblies.proj. I can get my direct referenced assemblies to stick however any nuget package dependencies for my project get cleared out by the ClearPluginAssemblies project when nop.web is built/run/executed.

I don't use this "Target" in my .csproj when creating plugins and recommend same thing to you. Use .csproj analogous to the one I provided and you don't need nopCommerce's mechanism of clearing assemblies.

Hi @toddca. This isn't problem of nopCommerce and ClearPluginAssemblies.proj(it delete only references wich loaded by Nop.Web project, we do it for prevent problem with different versions of the same library)

For more details you can watch those links
https://github.com/dotnet/sdk/issues/2235
https://github.com/dotnet/sdk/issues/933

https://github.com/NuGet/Home/issues/4837

https://stackoverflow.com/questions/42862739/how-to-copy-files-to-ouptut-directory-from-a-referenced-nuget-package-in-net-co
https://stackoverflow.com/questions/43837638/how-to-get-net-core-projects-to-copy-nuget-references-to-build-output

But we configure our project to more conveniently use the CopyLocalLockFileAssemblies parameter

Closed #3208

Isn't this going to cause a performance issue since it adds all the dlls. This will increase the plugin size a lot and add every single nuget package installed even the ones not installed in plugin.

Hello @bulutkartal. Yes, this produce a little bit problem with build performance, but after build all unused packages in plugins will delete by ClearPluginAssemblies project and on runtime won't be any problem

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AndreiMaz picture AndreiMaz  路  4Comments

mariannk picture mariannk  路  4Comments

mariannk picture mariannk  路  5Comments

AndreiMaz picture AndreiMaz  路  4Comments

a-patel picture a-patel  路  5Comments