Base solution for your next web application
Open Closed

Injection of CQRS library in ApplicationModule #8388


User avatar
0
BobIngham created

dotnet-core, angular 6.8.0 Hi Guys, I'm not the best with dependency injection and this one has me scratching my head. I have a CQRS class library used by Zero and also by an Azure function app for Azure Queue Storage. My communicator class looks as follows:

using Microsoft.WindowsAzure.Storage.Queue;
using Nuagecare.AzureQueueLibrary.Messages;
using Nuagecare.AzureQueueLibrary.MessageSerializer;
using System.Threading.Tasks;

namespace Nuagecare.AzureQueueLibrary.QueueConnection
{
    public interface IQueueCommunicator
    {
        T Read<T>(string message);
        Task CreateDefaultDocumentCollectionForTenantAsync<T>(T obj) where T : BaseQueueMessage;

    }
    public class QueueCommunicator : IQueueCommunicator
    {
        private readonly IMessageSerializer _messageSerializer;
        private readonly ICloudQueueClientFactory _cloudQueueClientFactory;

        public QueueCommunicator(IMessageSerializer messageSerializer,
            ICloudQueueClientFactory cloudQueueClientFactory)
        {
            _messageSerializer = messageSerializer;
            _cloudQueueClientFactory = cloudQueueClientFactory;
        }

        public IMessageSerializer MessageSerializer { get; }

        public T Read<T>(string message)
        {
            return _messageSerializer.Deserialize<T>(message);
        }

        public async Task CreateDefaultDocumentCollectionForTenantAsync<T>(T obj) where T : BaseQueueMessage
        {
            var queueReference = _cloudQueueClientFactory.GetClient().GetQueueReference(obj.Route);
            await queueReference.CreateIfNotExistsAsync();

            var serializedMessage = _messageSerializer.Serialize(obj);
            var queueMessage = new CloudQueueMessage(serializedMessage);

            await queueReference.AddMessageAsync(queueMessage);
        }
    }
}

I want to call the CreateDefaultDocumentCollectionForTenantAsync() method from within a Zero application service but I'm having problems injecting the IQueueCommunicator class in my Zero application module. Inside my CQRS AzureQueueLibrary I have a DependencyInjectionRegistry class as follows:

using Microsoft.Extensions.DependencyInjection;
using Nuagecare.AzureQueueLibrary.Infrastructure;
using Nuagecare.AzureQueueLibrary.MessageSerializer;
using Nuagecare.AzureQueueLibrary.QueueConnection;

namespace AzureQueueLibrary.Infrastructure
{
    public static class DependencyInjectionRegistry
    {
        public static IServiceCollection AddAzureQueueLibrary(this IServiceCollection service, string queueConnectionString)
        {
            service.AddSingleton(new QueueConfig(queueConnectionString));
            service.AddSingleton<ICloudQueueClientFactory, CloudQueueClientFactory>();
            service.AddSingleton<IMessageSerializer, JsonMessageSerializer>();
            service.AddTransient<IQueueCommunicator, QueueCommunicator>();
            return service;
        }

    }
}

How do I register this class library in Zero? I thought maybe I could inject into Web.Host Startup.cs:

services.AddAzureQueueLibrary(_appConfiguration["ConnectionStrings:AzureStorage"]);

But AddAzureQueueLibrary is not part of IServiceCollection even after the class library has been added as a dependency. Normally with a class library I would inject to my ApplicationModule as follows:

            Configuration.ReplaceService(typeof(IDocumentProcessor), () =>
            {
                IocManager.IocContainer.Register(
                    Component.For<IDocumentProcessor>()
                        .ImplementedBy<DocumentProcessor>()
                        .LifestyleTransient()
                    );
            });

But this is different not least because it needs _ appConfiguration["ConnectionStrings:AzureStorage"] to be passed along to it when it is injected.

Any help gratefully received!!!!


4 Answer(s)
  • User Avatar
    0
    aaron created
    Support Team

    But AddAzureQueueLibrary is not part of IServiceCollection even after the class library has been added as a dependency.

    You need to add the appropriate using directive based on the namespace of the extension method:

    using AzureQueueLibrary.Infrastructure;
    
  • User Avatar
    0
    BobIngham created

    Hi Aaron, The using statement is one thing but the other is how to call the method. To do that i need t oinject the service. Let's say:

    using AzureQueueLibrary.Infrastructure;
    ...
    
    private readonly IQueueCommunicator _queueCommunicator;
    
    public TenantAppService(IQueueCommunicator, queueCommunicator)
    {
        _queueCommunicator = queueCommunicator;
    }
    ...
    

    I can't invoke my _ queueCommunicator because it hasn't been injected.... Sorry for my poor coding and lack of knowledge, it's one reason why i use Zero in the first place.... Any sample code would be most appreciated.

  • User Avatar
    0
    aaron created
    Support Team

    Did you register the service by successfully calling services.AddAzureQueueLibrary in Startup.ConfigureServices?

  • User Avatar
    0
    BobIngham created

    Hi Aaron, As always you were correct. After I had properly registered by service in Startup.cs by using the namespace evenything worked. Fantastic, I have been looking for a way of implementing CQRS with Zero for a long time and this will definitely help with Azure function apps. If anyone is interested in the SQRS model for Azure Queue Storage I can recommend the following three videos on YouTube: Azure functions with Queue Storage Aaron, thanks again for stepping me through. Always a pleasure and good to see you working in Zero fold again!