ASP. Net Ядро получает все классы, которые реализуют интерфейс, и вызывает их методы. - PullRequest
0 голосов
/ 01 апреля 2020

У меня есть asp. net ядро ​​3.1 веб-приложения

У меня есть Интерфейс , который реализуется 3 классами для настройки отображения базы данных. Я хочу вызвать метод автоматически во время настройки конфигурации приложения.

Ниже приведен мой интерфейс и их реализация.

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();
            });
        }
    }

Как получить все классы, реализующие интерфейс, и вызвать Configure метод соответственно?

Ответы [ 3 ]

1 голос
/ 01 апреля 2020

Вы можете использовать scope.ServiceProvider.GetServices<IMongoMapper>();, чтобы получить все классы, которые реализуют интерфейс IMongoMapper.

Вы можете использовать метод расширения и вызывать его в Configure методе в startup классе.

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();
        }
    }
}

и используйте его в startup классе

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

Обновление

Согласно документации Microsoft лучше использовать это

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 В более старых руководствах вы можете увидеть похожий код в методе Configure в Startup.cs. Мы рекомендуем использовать метод Configure только для настройки конвейера запросов. Код запуска приложения принадлежит методу Main.

Теперь при первом запуске приложения база данных будет создана и заполнена тестовыми данными. Всякий раз, когда вы изменяете свою модель данных, вы можете удалить базу данных, обновить свой начальный метод и начать заново sh с новой базой данных таким же образом. В следующих руководствах вы узнаете, как изменить базу данных при изменении модели данных, не удаляя и не создавая ее заново.

1 голос
/ 01 апреля 2020

Предполагая, что у вас есть пустой конструктор для производных классов, как упомянуто в вашем примере, вы можете сделать следующий код, вы можете получить интерфейс с помощью отражения и проверить, какой тип может быть назначен и !c.IsInterface, так как он не возвращает Сам интерфейс:

  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();
  }
0 голосов
/ 01 апреля 2020

Вы можете сделать это с помощью Reflection.

Я только что попробовал приведенный ниже код, и он работает в do tnet core 3.1. Он работает с интерфейсом и классом реализации:

  • в одной сборке
  • в отдельных сборках
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();
}

Вы также можете подключить любые параметры вам нужно создать экземпляр ваших объектов:

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

//other code

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

Есть также этот вопрос, который имеет множество примеров (некоторые больше не работают в do tnet core): Получение всех типов, которые реализовать интерфейс

...