NopCommerce Plugins built within custom plugin

1.1k Views Asked by At

I am using Nopcommerce 4.2 and trying to create a custom Plugin.

At runtime I get the error:

System.Exception: 'A plugin with 'DiscountRequirement.MustBeAssignedToCustomerRole' system name is already defined

When I go to Nop.Web/Plugins, I can see all the plugins that have been built - including mine. When I look in my custom plugin, I can see a folder folder called Plugins, this contains all the other plugins that have been built.

I have looked at my csproj and compared it against nop default plugins and cannot work out why mine builds all the plugins again.

to be clear the structure that is being created is:

Nop.Web

  • Plugins/

    --DiscountRules.CustomerRoles

    --ExchangeRate.EcbExchange

    --...Other plugins...

    --My.Plugin/

    ----App_Data

    ----Areas

    ----Plugins/

    -----DiscountRules.CustomerRoles

    -----ExchangeRate.EcbExchange

    -----...Other plugins...

my project file

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

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
      <OutputPath>..\..\Presentation\Nop.Web\Plugins\Widgets.MostViewedProducts</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
    <EnableDefaultContentItems>false</EnableDefaultContentItems>
    <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <ItemGroup>
    <Compile Remove="Domain\**" />
    <Content Remove="Domain\**" />
    <EmbeddedResource Remove="Domain\**" />
    <None Remove="Domain\**" />
  </ItemGroup>

  <ItemGroup>
    <None Remove="logo.jpg" />
    <None Remove="plugin.json" />
  </ItemGroup>

  <PropertyGroup>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="logo.jpg">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="plugin.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <Content Update="Areas\Admin\Views\BuilderProductAttribute\Create.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProductAttribute\Edit.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProductAttribute\List.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProductAttribute\_CreateOrUpdate.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\Create.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\Edit.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\List.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\ProductAttributeCatalogCreatePopup.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\ProductAttributeMappingCreate.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\ProductAttributeMappingEdit.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\_CreateOrUpdate.Attributes.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\_CreateOrUpdate.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\_CreateOrUpdate.Info.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\_CreateOrUpdate.SEO.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\_CreateOrUpdateProductAttributeMapping.Catalog.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\_CreateOrUpdateProductAttributeMapping.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\BuilderProduct\_CreateOrUpdateProductAttributeMapping.Info.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\ProductBuilder\Configure.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
    <Content Update="Areas\Admin\Views\_ViewImports.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Views\BuilderProduct\AttributeMappingProduct.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Views\BuilderProduct\Details.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Views\BuilderProduct\ProductDetails.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Views\BuilderProduct\_CatalogSelectors.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Views\BuilderProduct\_ProductBox.ProductBuilder.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Update="Views\_ViewImports.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Pack>$(IncludeRazorContentInPack)</Pack>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <Folder Include="Areas\Admin\Controllers\" />
    <Folder Include="Areas\Admin\Extensions\" />
    <Folder Include="Areas\Admin\Factories\" />
    <Folder Include="Areas\Admin\Infrastructure\" />
    <Folder Include="Areas\Admin\Models\" />
    <Folder Include="Areas\Admin\Views\" />
    <Folder Include="Controllers\" />
    <Folder Include="Extensions\" />
    <Folder Include="Factories\" />
    <Folder Include="Models\" />
  </ItemGroup>


  <ItemGroup>
    <ProjectReference Include="..\..\Presentation\Nop.Web.Framework\Nop.Web.Framework.csproj" />
    <ProjectReference Include="..\..\Presentation\Nop.Web\Nop.Web.csproj" />
    <ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
  </ItemGroup>


  <ItemGroup>
    <None Update="Views\Shared\Components\Default.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="Views\_ViewImports.cshtml">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

  <!-- This target execute after "Build" target -->
  <Target Name="NopTarget" AfterTargets="Build">
    <!-- Delete unnecessary libraries from plugins path -->
    <MSBuild Projects="@(ClearPluginAssemblies)" Properties="PluginPath=$(MSBuildProjectDirectory)\$(OutDir)" Targets="NopClear" />
  </Target>
</Project>

EDIT

Plugin.json

    {
  "InstalledPluginNames": [
    "Widgets.GoogleAnalytics",
    "Widgets.NivoSlider",
    "ExternalAuth.Facebook",
    "Misc.Cards",
    "Payments.PayPalSmartPaymentButtons",
    "Payments.PayPalStandard",
    "Catalog.SkipToProduct"
  ],
  "PluginNamesToUninstall": [],
  "PluginNamesToDelete": [
    "DiscountRequirement.MustBeAssignedToCustomerRole",
    "CurrencyExchange.ECB",
    "Misc.SendinBlue",
    "Payments.CheckMoneyOrder",
    "Payments.Manual",
    "Payments.Qualpay",
    "Payments.Square",
    "Pickup.PickupInStore",
    "Shipping.FixedByWeightByTotal",
    "Shipping.UPS",
    "Tax.Avalara",
    "Tax.FixedOrByCountryStateZip"
  ],
  "PluginNamesToInstall": []
}
3

There are 3 best solutions below

0
On

the problem might be a reference, because when you add the reference DiscountRequirement.MustBeAssignedToCustomerRole to another plugin you need to put in the property Copylocal = false.

0
On

Please clear your bin and delete all of the plugin under this "Nop.Web -> Plugins" folder once. This works for me. Thanks

0
On

There are a few places that are having the error. Can't give an answer without checking such as plugin.json, dependencyregister.cs, plugin.cs,etc..

But when you familiar with it you can find your own way to speed up your developments.

tip: This is the easiest way if you are still getting any issue with your plugin.

  1. Just take a copy of small original plugin such as 'Nop.Plugin.Payments.Qualpay,Square,SendinBlue' and rename then edit .proj file set output folder.
  2. remove all the unnecessary classes, files, and folders except 'DependencyRegistrar.cs,RouteProvider.cs,plugin.json,StartUpPlugin.cs'
  3. change the namespaces of remaining files and remove unnecessary codes.
  4. In plugin.json "SupportedVersions": [ "4.20" ] is a must value
  5. build and clear all the errors.
  6. It should appear on 'Configuration > Local Configuration'

tip: This is the my project building best practice when I'm getting references errors

  1. Clean the solution
  2. go to ~/API/Presentation/Nop.Web/Plugins folder and remove all the build folders.
  3. Right-click on 'Libraries' folder and build it.
  4. Right-click on 'Presentation' folder and build it.
  5. Right-click on 'Plugins' folder and build it.
  6. Good luck..!!

you can refer below as a template

plugin.json ("SupportedVersions": [ "4.20" ] is a must value) otherwise plugin service won't pick your plugin

{
  "Group": "Plugin group name",
  "FriendlyName": "Elastic Search",
  "SystemName": "Custom.Plugin.ElasticSearch",
  "Version": "1.56",
  "SupportedVersions": [ "4.20" ],
  "Author": "Isanka Thalagala",
  "DisplayOrder": 27,
  "FileName": "Custom.Plugin.ElasticSearch.dll",
  "Description": "This plugin provice ilastic search"
}

DependencyRegistrar.cs class

public class DependencyRegistrar : IDependencyRegistrar
{
   /// <summary>
   /// Register services and interfaces
   /// </summary>
   /// <param name="builder">Container builder</param>
   /// <param name="typeFinder">Type finder</param>
   /// <param name="config">Config</param>
   public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
   {
      //register service manager
      builder.RegisterType<SearchFilterService>().As<ISearchFilterService>().InstancePerLifetimeScope();
      builder.RegisterType<ElasticSearchService>().As<IElasticSearchService>().InstancePerLifetimeScope();          
   }

   /// <summary>
   /// Gets order of this dependency registrar implementation
   /// </summary>
   public int Order => 1;
}

ElasticSearchPlugin.cs

public class ElasticSearchPlugin : BasePlugin
    {
        #region Ctor
        public ElasticSearchPlugin()
        {
        }

        #endregion

        #region Methods
        /// <summary>
        /// Install the plugin
        /// </summary>
        public override void Install()
        {
            base.Install();
        }

        /// <summary>
        /// Uninstall the plugin
        /// </summary>
        public override void Uninstall()
        {
            base.Uninstall();
        }

        #endregion

        /// <summary>
        /// Gets a value indicating whether to hide this plugin on the widget list page in the admin area
        /// </summary>
        public bool HideInWidgetList => true;
    }