0

I would like to use Assembly Scanner Pattern and register class with Attribute from another assembly

Project: AssemblyScanner

using System;

namespace AssemblyScanner
{
    public class RegisterScope : Attribute
    {
        public RegisterScope()
        {

        }
    }
}

Project: Domian.Service

namespace Domain.Service.Test
{
    [RegisterScope]
    public class CarService
    {
    }
}

Project: UnitTests

using AssemblyScanner;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Domain.Service.Test;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Xunit;

namespace UnitTests
{
    public class AssemblyScannerTests
    {
        [Fact]
        public void AssemblyScannerTest()
        {
            var t = AssemblyScannerPattern().GetService<CarService>();

            //AssemblyScannerPattern -> https://stackoverflow.com/questions/33811015/autofac-how-to-load-assemblies-that-are-referenced-but-not-directly-used
            //Other Example -> https://www.codeproject.com/Articles/1201502/Dependency-Injection-in-ASP-NET-Web-API-using-Auto
        }

        public AutofacServiceProvider AssemblyScannerPattern()
        {
            var serviceCollection = new ServiceCollection();

            ContainerBuilder builder = new ContainerBuilder();

            string[] assemblyScanerPattern = new[] { @"Domain.Service*.dll" };

            // Make sure process paths are sane...
            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

            //  begin setup of autofac >>

            // 1. Scan for assemblies containing autofac modules in the bin folder
            List<Assembly> assemblies = new List<Assembly>();
            assemblies.AddRange(
                Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.dll", SearchOption.AllDirectories)
                         .Where(filename => assemblyScanerPattern.Any(pattern => Regex.IsMatch(filename, pattern)))
                         .Select(Assembly.LoadFrom)
                );

            foreach (var assembly in assemblies)
            {
                builder.RegisterAssemblyTypes(assembly)
                    .AsImplementedInterfaces();
            }

            foreach (var assembly in assemblies)
            {
                foreach (var attributeClass in assembly.ExportedTypes)
                {
                    foreach (var registerScope in attributeClass.CustomAttributes.Where(s => s.AttributeType.Name.Contains("RegisterScope")))
                    {
                          var importedClassFromAssembly = GetInstance(attributeClass.Namespace + "." + attributeClass.Name);

                          //builder.RegisterType<importedClassFromAssembly.GetType>().As(importedClassFromAssembly);
                    }
                }

            }

            var container = builder.Build();

            var serviceProvider = new AutofacServiceProvider(container);

            return serviceProvider;
        }

        public object GetInstance(string strFullyQualifiedName)
        {
            Type type = Type.GetType(strFullyQualifiedName);
            if (type != null)
                return Activator.CreateInstance(type);
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = asm.GetType(strFullyQualifiedName);
                if (type != null)
                    return Activator.CreateInstance(type);
            }
            return null;
        }
    }
}

I found class with Attribute "RegisterScope" but I have got problem with builder.RegisterType

enter image description here

And here I get null but I would like to get instance class

enter image description here

Update

It`s better situation I get now correct object when I write this

builder.RegisterInstance(importedClassFromAssembly).As<CarService>();

but I would like to something like this - Error

builder.RegisterInstance(importedClassFromAssembly).As<importedClassFromAssembly.GetType>();

I try also this (but this give me null in GetService();)

builder.RegisterInstance(importedClassFromAssembly).As<dynamic>();

Current Code with Last small problem

using AssemblyScanner;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Domain.Service.Test;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Xunit;

namespace UnitTests
{
    public class AssemblyScannerTests
    {
        [Fact]
        public void AssemblyScannerTest()
        {
            var t = AssemblyScannerPattern().GetService<CarService>();

            //AssemblyScannerPattern -> https://stackoverflow.com/questions/33811015/autofac-how-to-load-assemblies-that-are-referenced-but-not-directly-used
            //Other Example -> https://www.codeproject.com/Articles/1201502/Dependency-Injection-in-ASP-NET-Web-API-using-Auto
        }

        public AutofacServiceProvider AssemblyScannerPattern()
        {
            var serviceCollection = new ServiceCollection();

            ContainerBuilder builder = new ContainerBuilder();

            string[] assemblyScanerPattern = new[] { @"Domain.Service*.dll" };

            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

            List<Assembly> assemblies = new List<Assembly>();
            assemblies.AddRange(
                Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.dll", SearchOption.AllDirectories)
                         .Where(filename => assemblyScanerPattern.Any(pattern => Regex.IsMatch(filename, pattern)))
                         .Select(Assembly.LoadFrom)
                );

            foreach (var assembly in assemblies)
            {
                foreach (var attributeClass in assembly.ExportedTypes)
                {
                    if(attributeClass.CustomAttributes.Where(s => s.AttributeType.Name.Contains("RegisterScope")).Any())
                    {
                        var importedClassFromAssembly = GetInstance(attributeClass.FullName);

                        builder.RegisterInstance(importedClassFromAssembly).As<CarService>();
                    }
                }
            }

            var container = builder.Build();

            var serviceProvider = new AutofacServiceProvider(container);

            return serviceProvider;
        }

        public object GetInstance(string strFullyQualifiedName)
        {
            Type type = Type.GetType(strFullyQualifiedName);
            if (type != null)
                return Activator.CreateInstance(type);
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = asm.GetType(strFullyQualifiedName);
                if (type != null)
                    return Activator.CreateInstance(type);
            }
            return null;
        }
    }
}
Rafał Developer
  • 2,135
  • 9
  • 40
  • 72

1 Answers1

1

If I understand your example, you should be able to do it like this:

foreach (var assembly in assemblies) {
    foreach (var attributeClass in assembly.ExportedTypes) {
          if (attributeClass.CustomAttributes.Any(s => s.AttributeType.Name.Contains("RegisterScope"))) {
              builder.RegisterType(attributeClass).AsSelf();
          }
     }
}

Autofac will do the instantiating for you, you might want to add ".SingleInstance()" to make sure only one instance is provided.

Another solution, from my point of view this is better, would be to use the assembly scanning of Autofac itself:

foreach (var assembly in assemblies) {
    builder
        .RegisterAssemblyTypes(assembly)
        .Where(t => t.CustomAttributes.Any(s => s.AttributeType.Name.Contains("RegisterScope")))
        .AsSelf();
}

Read more here: http://autofaccn.readthedocs.io/en/latest/register/scanning.html

Some hints:

Hope this helps.

Robin Krom
  • 180
  • 8
  • I actually work on a library, based on Autofac, which I wrote for Greenshot, to simplify the usage of addons. https://github.com/dapplo/Dapplo.Addons Still needs a lot of work on the documentation... – Robin Krom Jun 25 '18 at 07:16
  • many thanks I accepted your answer and I gave you poin. Thanks. – Rafał Developer Jun 25 '18 at 16:45