Base solution for your next web application

Activities of "ivanosw1"

This seems to be a cleaner solution

[DependsOn(typeof(AbpQuartzModule))]
public class MyModule : AbpModule
{

    public MyModule()
    {
        // patch configuration before PreInitialize. 
        // Do not use IocManager property in the constructor as it is not populated 
        Abp.Dependency.IocManager.Instance.IocContainer.Register(
            Component
                .For<IAbpQuartzConfiguration, QuartzStartupConfiguration>()
                .LifestyleSingleton()
                .IsDefault());
    }

    // ..
}

Hi, this registration does work, but from the logs I can confirm the suspect that 2 different schedulers are initialized:

... 
INFO  2021-01-08 09:33:15,969 [1    ] Quartz.Impl.StdSchedulerFactory          - Default Quartz.NET properties loaded from embedded resource file
INFO  2021-01-08 09:33:16,021 [1    ] Quartz.Core.SchedulerSignalerImpl        - Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
INFO  2021-01-08 09:33:16,027 [1    ] Quartz.Core.QuartzScheduler              - Quartz Scheduler v.3.0.7.0 created.
INFO  2021-01-08 09:33:16,028 [1    ] Quartz.Simpl.RAMJobStore                 - RAMJobStore initialized.
INFO  2021-01-08 09:33:16,030 [1    ] Quartz.Core.QuartzScheduler              - Scheduler meta-data: Quartz Scheduler (v3.0.7.0) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 10 threads.
  Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.

INFO  2021-01-08 09:33:16,034 [1    ] Quartz.Impl.StdSchedulerFactory          - Quartz scheduler 'DefaultQuartzScheduler' initialized
INFO  2021-01-08 09:33:16,034 [1    ] Quartz.Impl.StdSchedulerFactory          - Quartz scheduler version: 3.0.7.0
INFO  2021-01-08 09:33:16,034 [1    ] Quartz.Core.QuartzScheduler              - JobFactory set to: Abp.Quartz.AbpQuartzJobFactory
WARN  2021-01-08 09:33:21,647 [1    ] tion.Repositories.EphemeralXmlRepository - Using an in-memory repository. Keys will not be persisted to storage.
WARN  2021-01-08 09:33:21,648 [1    ] taProtection.KeyManagement.XmlKeyManager - Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when application exits.
INFO  2021-01-08 09:33:24,436 [1    ] Quartz.Util.DBConnectionManager          - Registering datasource 'UnoInsDataSource' with db provider: 'Quartz.Impl.AdoJobStore.Common.DbProvider'
INFO  2021-01-08 09:33:24,440 [1    ] Quartz.Impl.StdSchedulerFactory          - Using object serializer: Quartz.Simpl.JsonObjectSerializer, Quartz.Serialization.Json
INFO  2021-01-08 09:33:25,304 [9    ] Quartz.Core.SchedulerSignalerImpl        - Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
INFO  2021-01-08 09:33:25,305 [9    ] Quartz.Core.QuartzScheduler              - Quartz Scheduler v.3.0.7.0 created.
INFO  2021-01-08 09:33:25,311 [9    ] Quartz.Impl.AdoJobStore.JobStoreTX       - Detected usage of SqlServerDelegate - defaulting 'selectWithLockSQL' to 'SELECT * FROM QRTZ_LOCKS WITH (UPDLOCK,ROWLOCK) WHERE SCHED_NAME = 'Framework Scheduler' AND LOCK_NAME = @lockName'.
INFO  2021-01-08 09:33:25,311 [9    ] Quartz.Impl.AdoJobStore.JobStoreTX       - Using db table-based data access locking (synchronization).
INFO  2021-01-08 09:33:25,314 [9    ] Quartz.Impl.AdoJobStore.JobStoreTX       - JobStoreTX initialized.
INFO  2021-01-08 09:33:25,314 [9    ] Quartz.Core.QuartzScheduler              - Scheduler meta-data: Quartz Scheduler (v3.0.7.0) 'Framework Scheduler' with instanceId 'DEV-N00015.637456916052992244'
  Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 10 threads.
  Using job-store 'Quartz.Impl.AdoJobStore.JobStoreTX' - which supports persistence. and is clustered.
  ...

The Abp.Quartz indeed creates a default scheduler regardless of what I do in my PreInitialize

    public class AbpQuartzModule : AbpModule
    {
        public override void PreInitialize()
        {
            IocManager.Register<IAbpQuartzConfiguration, AbpQuartzConfiguration>();
    
            // this line creates the default in-memory scheduler even if i replace the IAbpQuartzConfiguration in my PreInitialize
            Configuration.Modules.AbpQuartz().Scheduler.JobFactory = new AbpQuartzJobFactory(IocManager);
        }

For the moment I am going to shut the default one down before replacing it with my own.

Hi Zony, if I use the ReplaceService the registred type is still overwritten by Abp.Quartz

and thus the IScheduler is not properly configred. Am I missing something?

Furhermore, the Abp.Quartz.PreInitialize calls indirectly the StdSchedulerFactory.GetDefaultScheduler(), resulting in the creation of a default in-memory sheduler even before my custom PreInitialize gets called. In this way I will end up with 2 different scheduler instances.

We need to configure Quartz to use SQL storage, but we can not store the connection string in the static quartz.config file. In the AbpQuartzModule.PreInitialize() the AbpQuartzConfiguration is registred to resolve from the StdSchedulerFactory.GetDefaultScheduler(), but we would need to register our own implementation of IAbpQuartzConfiguration to create a scheduler with our configuration.

    class AbpCustomQuartzConfiguration : IAbpQuartzConfiguration
    {
        public IScheduler Scheduler
        {
            get
            {

                var builder = SchedulerBuilder.Create();
                builder.UsePersistentStore(options =>
                {
                    options.UseClustering();
                    options.UseSqlServer(sqlServerOptions =>
                    {
                        sqlServerOptions.ConnectionString = "...";
                    });
                    options.UseSerializer<JsonObjectSerializer>();
                });
                builder.SchedulerId = StdSchedulerFactory.AutoGenerateInstanceId;
                builder.MisfireThreshold = TimeSpan.FromMinutes(5);

                var scheduler = builder.BuildScheduler().Result;

                scheduler.JobFactory = new AbpQuartzJobFactory(IocManager.Instance);
                scheduler.ListenerManager.AddJobListener(IocManager.Instance.Resolve<IJobListener>());

                return scheduler;
            }
        }
    }

How can we accomplish this?

  • Version: Abp 5.14
  • Framework: .NET Core

Ok, I've created the issue

Thank you.

Hi @ismcagdas, I've made may attempts. After UseAbp is not possibile beacause the extension method AddMediatR(...) is on IServiceCollection that isn't available on Configure method.

After looking at the examples and what does this extesion https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection, I ended up with this results:

Scenario: Framework and 2 plugin modules:

  1. Startup -> ConfigureServices -> before the last return, add thie 3 line of code:
services.AddMediatR(typeof(Startup));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>));
            
  1. In every module, in the Initilize() register all RequestHandler and INotificationHandler
IocManager.RegisterAssemblyByConvention(typeof(MyModule).GetAssembly());
           
IocManager.Register<IRequestHandler<PingCommand, string>, PingHandler>(DependencyLifeStyle.Transient); //Request/Response
IocManager.Register<IRequestHandler<PingCommandOneWay,Unit>, PingHandlerOneWay>(DependencyLifeStyle.Transient); //Request
IocManager.Register<INotificationHandler<PingNotification>, Pong1>(DependencyLifeStyle.Transient); //Notification
IocManager.Register<INotificationHandler<PingNotification>, Pong2>(DependencyLifeStyle.Transient); //Notification

//Pipelines
IocManager.IocContainer.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(LoggingBehavior<,>)).LifestyleTransient());
IocManager.IocContainer.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(ValidationBehaviour<,>)));

//Pre-Post processor            IocManager.IocContainer.Register(Component.For(typeof(IRequestPreProcessor<>)).ImplementedBy(typeof(GenericPreProcessor<>)).LifestyleTransient());
IocManager.IocContainer.Register(Component.For(typeof(IRequestPostProcessor<,>)).ImplementedBy(typeof(GenericPostProcessor<,>)).LifestyleTransient());

//CatchAll notifications (See point  no.3 for this)
IocManager.Register<INotificationHandler<INotification>, PongAll>(DependencyLifeStyle.Transient);
            
  1. In order to intercept all notification, in only one module, add also this code:
IocManager.IocContaine.Kernel.AddHandlersFilter(new ContravariantFilter());

public class ContravariantFilter : IHandlersFilter
        {
            public bool HasOpinionAbout(Type service)
            {
                if (!service.IsGenericType)
                    return false;

                var genericType = service.GetGenericTypeDefinition();
                var genericArguments = genericType.GetGenericArguments();
                return genericArguments.Count() == 1
                       && genericArguments.Single().GenericParameterAttributes.HasFlag(GenericParameterAttributes.Contravariant);
            }

            public IHandler[] SelectHandlers(Type service, IHandler[] handlers)
            {
                return handlers;
            }
        }
        

All this seems to works as expected, but is only a sort of cut&paste of AddMediatR with some Abp behaviours. I would be appreciate if you can officially integrate MediatR on Abp or at least validate how manually do.

Thank you very much.

Prerequisites

  • What is your product version? 9.3.0
  • What is your product type (Angular or MVC)? Angular
  • What is product framework type (.net framework or .net core)? Core

If issue related with ABP Framework

  • What is ABP Framework version? 5.14.0

Hi, I need to user the MediatR library but I have a problem with the registration of interfaces. My code is loaded through plugins directory so I need to manually discover the assemblies because are not referenced directly. In the ConfigureServices, just after services.AddAbp<... I have this code:

var pluginTypes = AppDomain.CurrentDomain.GetAssemblies() .AsParallel() .Where(a =&gt; a.FullName.StartsWith("MyDll.")) .SelectMany(x => x.GetTypes()) .ToArray(); services.AddMediatR(pluginTypes);

But at this point, my plugins aren't not loaded yet and so AddMediatR fails.

I do the same with SignalR but it works because is after app.UseAbp in Configure method.

So, how can I register my plugins to MediatoR ?

Thank you.

Ok @ismcagdas

I'll look more deeply in Hangfire configuration.

I suppose your are interested too about this topic and I'll need your technical support to evaluate eventually changes to apply to AspNetZero in order to support multi instances.

It'll take some time and so for the moment I close the ticket.

Hi, some news about this topic? Is very important for a cloud based installation.

Thank you.

But, wait a moment. Hangfire is integrated in Aspnet zero, so, two instance of aspnet zero has two instance of hangfire. The problem is still alive.

Showing 11 to 20 of 178 entries