Tutorial: How to use NopCommerce data, core, services, framework in your external program

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
4 年 前
Hello All,

I am trying to utilize nopCommerce project to my console application.

I followed all steps mentioned for nopCommerce version 4.0.
But still I am getting error


None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Nop.Services.Orders.OrderService' can be invoked with the available services and parameters:
Cannot resolve parameter 'Nop.Core.Data.IRepository`1[Nop.Core.Domain.Orders.Order] orderRepository' of constructor 'Void .ctor(Nop.Core.Data.IRepository`1[Nop.Core.Domain.Orders.Order], Nop.Core.Data.IRepository`1[Nop.Core.Domain.Orders.OrderItem], Nop.Core.Data.IRepository`1[Nop.Core.Domain.Orders.OrderNote], Nop.Core.Data.IRepository`1[Nop.Core.Domain.Catalog.Product], Nop.Core.Data.IRepository`1[Nop.Core.Domain.Orders.RecurringPayment], Nop.Core.Data.IRepository`1[Nop.Core.Domain.Customers.Customer], Nop.Services.Events.IEventPublisher)'.



Here is my code snipped.

class Program
    {
        static void Main(string[] args)
        {

            try
            {
                EngineContextInitializer.Run();
                Console.WriteLine("Hello World!");

                var builder = new ContainerBuilder();
                builder.RegisterType<OrderService>().As<IOrderService>().SingleInstance();

                //Resolving inteface with autofac
                var container = builder.Build();
                var orderServiceService = container.Resolve<IOrderService>();

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

            }

            Console.ReadLine();
        }


Any help will be great help to me!
4 年 前
I'm not sure this is the "right" way to do it, but I was able to get past the DI problems in a console application. Here's what I did.

First, implement IDependencyRegistrar (I chose to do it in Program for simplicity):

    class Program : IDependencyRegistrar
    {


Next, create a member (static member, in my case) of type IContainer and a setter for said member:

        private static IContainer _container;

        static void SetContainer(IContainer container) {
            _container = container;
        }


Next, implement IDependencyRegistrar's methods. In the Register method register your SetContainer method as a build callback:

        public int Order => 0;

        public void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
        {
            builder.RegisterBuildCallback(SetContainer);
        }


That's it. Now, after EngineContextInitializer.Run() has finished you should be able to call _container.Resolve to resolve the services:

        static void Main(string[] args)
        {
            EngineContextInitializer.Run();

            var customerService = _container.Resolve<ICustomerService>();
            var orderService = _container.Resolve<IOrderService>();
            var productService = _container.Resolve<IProductService>();
4 年 前
One minor update. If you're planning on your application being long-lived remember to mind the scope of the DbContext. If you don't it can grow and grow and grow. For example, if you're inserting a bunch of customers in a loop you'll have to scope the services to each iteration of the loop, otherwise the DbContext will grow and performance will degrade over time as more and more objects are tracked. e.t.:

            for (...)
            {
                try
                {
                    using (var scope = _container.BeginLifetimeScope())
                    {

                        var customerService = scope.Resolve<ICustomerService>();
                        var orderService = scope.Resolve<IOrderService>();
3 年 前
Can you please provide sample source code?
3 年 前
Hello all,

I currently use 4.3 nopcommerce version and builder.RegisterBuildCallback doesn't seem to work anymore.

EngineContextInitializer has a new method : getConnection (replace run ?)

Does anyone have a working solution to access 4.3 version ?
3 年 前
Did anyone get this to work in 4.3?  

We can't migrate to 4.3 until we get all our console apps running.  We have around 30 jobs that sync dat to and from various other systems.

Thanks.
2 年 前
treesap wrote:
There are a few changes in the startup with nopcommerce 4.0

Does someone know how or have the same tutorial for nopcommerce 4.0?

Did you ever figure this out? I'm currently in the process of trying to do this on version 4.00.

The first change I made was to call
EngineContext.Create()
instead of
EngineContext.Initialize(false)
as this seems to be the correct replacement method.

Specifically, resolving a service triggers an exception in EngineContext.
IProductService ps = EngineContext.Current.Resolve<IProductService>();

The exception is System.ArgumentNullException occurred: 'Value cannot be null. Parameter name: provider'.

I've also tried to call the resolve method via the return from EngineService.Create():
var _engineInstance = EngineContext.Create();
IProductService ps = _engineInstance.Resolve<IProductService>();


Still, though, the same exception occurs. Any ideas?

Thanks

I have same problem
Do you find any solution?
2 年 前
I managed to get this working for version 4.3 in a console application after a struggle and thought this might be useful for someone.  Since Nop 4+ no longer provides a nuget, you have to manually create all the required version references.

The build folder requires some folders and files in specific locations
appsettings.json (direct copy of file from source with no modifications)
App_Data > dataSettings.json (with valid database connection)
wwwroot
wwwroot\db_backups
wwwroot\icons
wwwroot\images
wwwroot\images\uploaded
Themes
Plugins

I include the dataSettings.json and appsettings.json in the project to copy automatically on build.
Then I updated the csproj to create the required folders if missing.


<Target Name="CreateRequiredFolders" AfterTargets="Build">
  <MakeDir Directories="$(TargetDir)wwwroot" Condition="!Exists('$(TargetDir)wwwroot')" />
  <MakeDir Directories="$(TargetDir)wwwroot\db_backups" Condition="!Exists('$(TargetDir)wwwroot\db_backups')" />
  <MakeDir Directories="$(TargetDir)wwwroot\icons" Condition="!Exists('$(TargetDir)wwwroot\icons')" />
  <MakeDir Directories="$(TargetDir)wwwroot\images" Condition="!Exists('$(TargetDir)wwwroot\images')" />
  <MakeDir Directories="$(TargetDir)wwwroot\images\uploaded" Condition="!Exists('$(TargetDir)wwwroot\images\uploaded')" />
  <MakeDir Directories="$(TargetDir)Themes" Condition="!Exists('$(TargetDir)Themes')" />
  <MakeDir Directories="$(TargetDir)Themes" Condition="!Exists('$(TargetDir)Plugins')" />
</Target>


Here are the contents of my Program.cs file:

    class Program
    {
        static async Task Main(string[] args)
        {
            var host = await Startup(args);

            if(host != null)
            {
                using (host)
                {
      var productService = EngineContext.Current.Resolve<IProductService>();                  
                }
            }
        }

        public static async Task<IHost> Startup(string[] args)
        {
    var host = CreateHostBuilder(args).Build();
    await host.StartAsync();
    return host;
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder
                        .UseStartup<Startup>();
                }).UseConsoleLifetime();
        }
    }


Then the contents of my Startup.cs file:

    public class Startup
    {
        private readonly IConfiguration _configuration;
        private readonly IWebHostEnvironment _webHostEnvironment;
        private IEngine _engine;
        private NopConfig _nopConfig;

        public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
        {
            _configuration = configuration;
            _webHostEnvironment = webHostEnvironment;
        }
    
        public void ConfigureServices(IServiceCollection services)
        {
            (_engine, _nopConfig) = services.ConfigureApplicationServices(_configuration, _webHostEnvironment);
        }

        public void ConfigureContainer(ContainerBuilder builder)
        {
            _engine.RegisterDependencies(builder, _nopConfig);
        }
    
        public void Configure(IApplicationBuilder application)
        {
            EngineContext.Current.ConfigureRequestPipeline(application);
        }
    }
2 年 前
This post is thread is quite old by now, but since someone recently posted on it I figured it might be worth adding what we discovered in getting past this hurdle for 4.4.


The method described above does work, however it will spin up an active site, with default port binding.  This means that you can only run one of these at a time (we often have 5-10 running at once, so this did not work for us).  A work-around is to add the .UseUrls() method in some way (one example below) to specify the port.  If you don't do this, there will be an error when the second app tries to start up, complaining about the port already in use, or some such language that I don't remember off the top of my head.

  {
                    webBuilder
                        .UseStartup<Startup>()
                        .UseUrls("http://[::1]:0");
                })

Ultimately, we moved away from an Console style app completely and no longer use an approach similar to those mentioned in this thread.

Now, we have a custom dedicated plugin in our Nop instance that can execute the various jobs we need via a controller method that has access to all the Nop infrastructure.  This allows us to kick off a job by simply calling a URL, and avoids having multiple console Apps with duplicate copies of our Nop instance in various locations.  We also implemented System.Threading.Channels.Channel(s) along with Microsoft.Extensions.Hosting.BackgroundService(s) to queue up and run our jobs in the background as part of the Nop instance.  This was relatively complex and is a separate discussion completely, so I'll not dive into that any further.  There are some Microsoft videos and articles available if anyone has interest in that subject.
1 年 前
Has anyone made this work on 4.50?
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.