lucabriguglia/OpenCQRS

Having problems to integrate into owin ASP.NET application

Closed this issue · 4 comments

Hello,

as far as I understand, there is nothing fancy about IDispatcher that it could not work outside asp.net core, it would just need an extra step as I show below.

I have an older base code which I cannot upgrade to .net core for now.
What I'm trying to do is manually create a ServiceCollection and IConfigurationProvider to build the dispatcher. It works, but I am having an issue integrating with Unity.

On my Startup.cs I have:

        public IDispatcher ConfigureKledex()
        {

            var configurationProviders = new List<IConfigurationProvider>
            {
                new MemoryConfigurationProvider(new MemoryConfigurationSource()
                {
                    InitialData = new List<KeyValuePair<string, string>>()
                    {
                        new KeyValuePair<string, string>("DomainDbConfiguration:ConnectionString",
                            WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)
                    }
                })
            };
            IConfiguration configuration = new ConfigurationRoot(configurationProviders);
            
            var services = new ServiceCollection();
            
            services.AddOptions();

            services.AddKledex(typeof(DeactivateCompany))
                    .AddOptions(options =>
                    {
                        options.PublishEvents   = false;
                        options.SaveCommandData = false;
                    })
                    .AddSqlServerProvider(configuration)
                    .AddServiceBusProvider(configuration)
                ;

            var serviceProvider = services.BuildServiceProvider();

            var dispatcher = serviceProvider.GetService<IDispatcher>();

            return dispatcher;
        }

then on my Startup.cs I call it like this and it works!

            //just for testing! IT WORKS <--
            var command = DeactivateCompany.Create(1);
            ConfigureKledex().SendAsync(command);

Naturally, I just needed now to register IDispatcher on my Unity container to inject into my controllers.

The gotcha is: For past constraints, I had to initialize my IUnityContainer using WebActivatorEx.

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnityWebActivator), "Start")]
namespace AMZ.MVC {
  public class MvcApplication : HttpApplication {
    ...
  }
}
    public static class UnityWebActivator
    {
        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start()
        {

            IUnityContainer container = UnityConfig.GetConfiguredWebContainer();

            // MVC resolver.
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));

            // Web API resolver
            GlobalConfiguration.Configuration.DependencyResolver = new Unity.AspNet.WebApi.UnityDependencyResolver(container);
        }
    }

When now I try using my previously mentioned ConfigureKledex method, say, as a factory,

IUnityContainer container = UnityConfig.GetConfiguredWebContainer();
            container.RegisterFactory<IDispatcher>(container => ConfigureKledex());

it executes alike, but for some reason once moving into the static method of UnityMvcActivator, this similar code line which would work just fine now stops working throwing an exception saying it could not find the command handler.

            //this worked on Startup.cs but now it throws an exception
            //saying the handler could not be found
            var command = DeactivateCompany.Create(1);
            ConfigureKledex().SendAsync(command);

The thing is: The same code which worked on Startup (after container registration), simply after moving to the static method of WebActivator it started throwing the exception.

Would you have an idea of what is going on, on an alternative way to solve this issue?

What I understand is that I have to register IDispatcher into Unity and everything would work just as normal, despite being on an ASP.NET project. I would inject it into my controllers and it would just redirect the command to the appropriate handler.

Could it have something to do when webactivator executes and Scrutor? Maybe WebActivator runs somehow in a way that is have not loaded assemblies or what yet?

Hello, updating the issue with my progress, so hopefully it can help someone in the future.
I have a question at the end.

Apparently I can get rid of WebActivator. I moved the initialization of my Unity container to Global.asax.cs file. It somehow fixes the problem I was having. I don't know why though.

Also, I'm using Unity.Microsoft.DependecyInjection package so I can use my Unity container together with ServiceCollection class. Thus, I can inject anything I'm already using on my MVC application inside my commands just like normal; say, my dbcontext.

Here is my new factory method so far:

        static IDispatcher ConfigureKledex(IUnityContainer container)
        {

            var configurationProviders = new List<IConfigurationProvider>
            {
                new MemoryConfigurationProvider(new MemoryConfigurationSource()
                {
                    InitialData = new List<KeyValuePair<string, string>>()
                    {
                        new KeyValuePair<string, string>("DomainDbConfiguration:ConnectionString",
                            WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)
                    }
                })
            };
            IConfiguration configuration = new ConfigurationRoot(configurationProviders);
            
            
            ServiceCollection services = new ServiceCollection();
            
            services.AddOptions();

            services.AddKledex(typeof(DeactivateCompany))
                    .AddOptions(options =>
                    {
                        options.PublishEvents   = false;
                        options.SaveCommandData = false;
                    })
                    .AddSqlServerProvider(configuration)
                    .AddServiceBusProvider(configuration)
                ;

            var serviceProvider = services.BuildServiceProvider(container);

            var dispatcher = serviceProvider.GetService<IDispatcher>();

            return dispatcher;
        }

And the code which was on the WebActivator class now is the first thing on Global.asax.cs Application_Start method.

        protected void Application_Start()
        {
            var container = UnityConfig.GetConfiguredWebContainer();
            container.RegisterFactory<IDispatcher>(ConfigureKledex);

            // MVC resolver.
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));

            // Web API resolver
            GlobalConfiguration.Configuration.DependencyResolver = new Unity.AspNet.WebApi.UnityDependencyResolver(container);
        //...
        }

By using the RegisterFactory method without an explicit lifetime manager, it uses Transient by default. I guess it will work; otherwise, I post an update here.

I guess what I'm doing is correct so far. I run your wiki configuration code to configure the ServiceCollection Kledex uses internally, and I'm resolving the IDispatcher from it and using as the result of the Unity factory.

Would you have any observations to make on how I'm handling it? Any misconception I've not spotted?

I'm not a Unity expert but I'm assuming that what you are doing is correct and thanks for sharing your solution, it could help someone else :-)

Closing as I'm assuming it is resolved.