2

I have an asp.net core 3.1 web application

I have an Interface which is implemented by 3 classes to configure database mapping. I want to call the method automatically during application configuration setup.

Following is my interface and their implementation.

public interface IMongoMapper
    {
        void Configure();
    }
 class TenantMap : IMongoMapper
{
    public void Configure()
    {
        BsonClassMap.RegisterClassMap<Entities.Tenant>(cm =>
        {
            cm.AutoMap();
        });
    }
}
class CourseMap : IMongoMapper
    {
        public void Configure()
        {
            BsonClassMap.RegisterClassMap<Course>(cm =>
            {
                cm.AutoMap();
            });
        }
    }

How to get all the classes that implement interface and call Configure method appropriately?

10
  • Show how you are getting instances of these classes in your application startup Commented Apr 1, 2020 at 15:08
  • I don't know the way except DI. Is it possible to call method via DI? Commented Apr 1, 2020 at 15:09
  • 1
    You can use Reflection to get all types implementing that interface, then use Activator.CreateInstance() and execute Configure method on created instances Commented Apr 1, 2020 at 15:13
  • 1
    These classes seem to contain (simple) configuration. Why do you need to register and resolve them through your DI container? I would expect those classes to be created and consumed at startup, at which point you typically don't have (nor need) a container). Commented Apr 1, 2020 at 15:13
  • 1
    Can you elaborate why you need to use reflection at all at this point? Why can't you instantiate a list of IMongoMapper instances, loop over them, and call their Configure method? Commented Apr 1, 2020 at 15:15

4 Answers 4

2

You can use scope.ServiceProvider.GetServices<IMongoMapper>(); to get all classes that implement IMongoMapper interface.

You can use an extension method and call it in Configure method in startup class.

public static void IntializeMapping(this IApplicationBuilder app)
{
    using (var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        var mappers = scope.ServiceProvider.GetServices<IMongoMapper>();
        foreach (var map in mappers)
        {
             map.Configure();
        }
    }
}

and use it in startup class

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.IntializeMapping();
}

Update

According to Microsoft documentation better way is use this

public static async Task Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();
    using (var scope = host.Services.CreateScope())
    {
        try
        {
            var mappers = scope.ServiceProvider.GetServices<IMongoMapper>();
            foreach (var map in mappers)
            {
                 map.Configure();
            }
        }
        catch (Exception ex)
        {
             var logger = service.GetService<ILogger<Program>>();
             logger.LogError(ex, "An error occurred mapping");
        }
    }
    await host.RunAsync();
}           
 public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                }); 

Microsoft Documentation In older tutorials, you may see similar code in the Configure method in Startup.cs. We recommend that you use the Configure method only to set up the request pipeline. Application startup code belongs in the Main method.

Now the first time you run the application, the database will be created and seeded with test data. Whenever you change your data model, you can delete the database, update your seed method, and start afresh with a new database the same way. In later tutorials, you'll see how to modify the database when the data model changes, without deleting and re-creating it.

Sign up to request clarification or add additional context in comments.

7 Comments

WHat if I make the extension via IServiceCollection and use in Configure Service method. What difference does it make to use in Configure method vs ConfigurationService method
aspcore configure vs configure service
@HaseebKhan i updated my answer and hope to help you :)
@HaseebKhan Good luck ;)
@FarhadZamani .. this needs them to be registered in the configureservice correct ?
|
0

Assuming that you have empty constructor for the derived classes as mentioned in your example,you can do the below code you can get the interface by reflection and check which type can be assignable and !c.IsInterface so as it doesn't return the interface itself:

  var result = typeof("Any Class").Assembly.GetTypes().Where(c => typeof(IMongoMapper).IsAssignableFrom(c) && !c.IsInterface);
  foreach (var i in result)
  {
    ((IMongoMapper)Activator.CreateInstance(i)).Configure();
  }

4 Comments

The first code sample answers the question. It discovers the types that implement the interface and calls the Configure method on each one. But it's unclear why it takes an IServiceCollection as a parameter and returns it. The method has nothing to do with IServiceCollection. It doesn't use the argument. You could just remove that.
I was adding extra code if you want to use it in the configure service to add it as extension method and it returns it if you wanna continue chaining..
If it's an extension that does something with the services that would make more sense. But it's not clear why it would be an extension used with services if it doesn't do anything with them. An extension is just shorthand for calling a method and passing a parameter. There's no reason to pass a parameter to a method that isn't used.
if it helped, kindly don't forget to mark it as a valid ans ;)
0

In Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IPersonals, Personals>();
    }

Comments

-1

You can do it via Reflection.

I just tried the code below and it works in dotnet core 3.1. It works with the interface and the implementation class:

  • in the same assembly
  • in separate assemblies
var asm = Assembly.GetAssembly(typeof(YourClass));
var mapperTypes = asm.GetTypes().Where(x => x.GetInterface(nameof(IMongoMapper)) != null);
foreach(var mapperType in mapperTypes)
{
    var mapper = (IMongoMapper)Activator.CreateInstance(mapperType);
    mapper.Configure();
}

You can also plug any parameters you need to create an instance of your objects:

IConfiguration _configuration;
public Startup(IConfiguration configuration)
{
    _configuration = configuration;
}

//other code

foreach(var mapperType in mapperTypes)
{
    var mapper = (IMongoMapper)Activator.CreateInstance(mapperType, _configuration);
    mapper.Configure();
}

There is also this question that has lots of examples (some do not work in dotnet core anymore): Getting all types that implement an interface

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.