Search code examples
autofacazure-service-fabric

Service Fabric Autofac how to?


I'm trying to configure IoC (concept I'm not very familiar with yet) in my SF in a stateful service as explained here : https://www.codeproject.com/Articles/1217885/Azure-Service-Fabric-demo and here : https://alexmg.com/posts/introducing-the-autofac-integration-for-service-fabric.

in program.cs - main:

var builder = new ContainerBuilder();
builder.RegisterModule(new GlobalAutofacModule());
builder.RegisterServiceFabricSupport();
builder.RegisterStatefulService<Payment>("PaymentType");

using (builder.Build())
{
    ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Payment).Name);
    Thread.Sleep(Timeout.Infinite);
}

GlobalAutofacModule :

public class GlobalAutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<ChargeRepository>().As<IChargeRepository>().SingleInstance();
        builder.RegisterType<CustomerRepository>().As<ICustomerRepository>().SingleInstance();
        builder.RegisterType<InvoiceItemRepository>().As<IInvoiceItemRepository>().SingleInstance();
        builder.RegisterType<PlanRepository>().As<IPlanRepository>().SingleInstance();
        builder.RegisterType<ProductRepository>().As<IProductRepository>().SingleInstance();
        builder.RegisterType<SourceRepository>().As<ISourceRepository>().SingleInstance();
        builder.RegisterType<SubscriptionRepository>().As<ISubscriptionRepository>().SingleInstance();
        builder.RegisterType<TokenRepository>().As<ITokenRepository>().SingleInstance();
    }
}

the service is called without problems

        public Payment(StatefulServiceContext context, 
        IChargeRepository chargeRepo, 
        ICustomerRepository customerRepo,
        IInvoiceItemRepository invoiceItemRepo,
        IPlanRepository planRepository,
        IProductRepository productRepo,
        ISourceRepository sourceRepo,
        ISubscriptionRepository subscriptionRepo,
        ITokenRepository tokenRepo)
        : base(context)
    { ... }

in one of it's methodes it needs to call a custom mapper (error on missing params)

var test = new Mapper().GetProductsDto(false, false);

the class is defined like this :

    private readonly IChargeRepository _chargeRepo;
    private readonly ICustomerRepository _customerRepo;
    private readonly IInvoiceItemRepository _invoiceItemRepo;
    private readonly IPlanRepository _planRepo;
    private readonly IProductRepository _productRepo;
    private readonly ISourceRepository _sourceRepo;
    private readonly ISubscriptionRepository _subscriptionRepo;
    private readonly ITokenRepository _tokenRepo;

    public Mapper(IChargeRepository chargeRepo,
        ICustomerRepository customerRepo,
        IInvoiceItemRepository invoiceItemRepo,
        IPlanRepository planRepository,
        IProductRepository productRepo,
        ISourceRepository sourceRepo,
        ISubscriptionRepository subscriptionRepo,
        ITokenRepository tokenRepo)
    {
        _chargeRepo = chargeRepo;
        _customerRepo = customerRepo;
        _invoiceItemRepo = invoiceItemRepo;
        _planRepo = planRepository;
        _productRepo = productRepo;
        _sourceRepo = sourceRepo;
        _subscriptionRepo = subscriptionRepo;
        _tokenRepo = tokenRepo;
    }
public IEnumerable<ProductListDto> GetStripeProductsDto(bool isLogged, bool isSubscriber) {...}

So how do I instantiate the mapper and call the method without passing every repo as params ?

EDIT: tmp solution until approuved/disapprouved

    private static void Main()
    {
        try
        {
            using (ContainerOperations.Container)
            {
                ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Payment).Name);
                Thread.Sleep(Timeout.Infinite);
            }
        }
        catch (Exception e)
        {
            ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
            throw;
        }
    }
}

public class ContainerOperations
{
    private static readonly Lazy<IContainer> _containerSingleton =
        new Lazy<IContainer>(CreateContainer);

    public static IContainer Container => _containerSingleton.Value;

    private static IContainer CreateContainer()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule(new GlobalAutofacModule());
        builder.RegisterServiceFabricSupport();
        builder.RegisterStatefulService<Payment>("Inovatic.SF.Windows.PaymentType");
        return builder.Build();
    }
}


public class GlobalAutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        //builder.RegisterType<Mapper>();

        builder.RegisterType<ChargeRepository>().As<IChargeRepository>().SingleInstance();
        builder.RegisterType<CustomerRepository>().As<ICustomerRepository>().SingleInstance();
        builder.RegisterType<InvoiceItemRepository>().As<IInvoiceItemRepository>().SingleInstance();
        builder.RegisterType<PlanRepository>().As<IPlanRepository>().SingleInstance();
        builder.RegisterType<ProductRepository>().As<IProductRepository>().SingleInstance();
        builder.RegisterType<SourceRepository>().As<ISourceRepository>().SingleInstance();
        builder.RegisterType<SubscriptionRepository>().As<ISubscriptionRepository>().SingleInstance();
        builder.RegisterType<TokenRepository>().As<ITokenRepository>().SingleInstance();

    }
}

call is now like this : var productListDto = Mapper.GetStripeProductsDto(isLogged, false); mapper:

    private static IProductRepository _productRepo => ContainerOperations.Container.Resolve<IProductRepository>();

    public static IEnumerable<ProductListDto> GetStripeProductsDto(bool isLogged, bool isSubscriber)
    {
        var productList = _productRepo.GetAllStripeProducts().ToList();

Solution

  • I think you should also register Mapper class in IoC container and add it to Payment's constructor, then container will create Mapper with all required params for you. You can do it calling something like builder.RegisterType<Mapper>().SingleInstance();