I'd like to share an issue which I stumbled upon while migrating to the new version of FluentMigrator on .NET Core. I have a setup in which I store all embedded scripts in a different project, namely Foo.Data and it was working flawlessly till the new version.
It seems even though we configure the runner with .WithMigrationsIn method, it doesn't search those assemblies for the embedded resources, instead, it only searches the assembly which creates the IServiceScope:
using (IServiceScope serviceScope = app.ApplicationServices.CreateScope())
{
IServiceProvider serviceProvider = serviceScope.ServiceProvider;
IMigrationRunner migrationRunner = serviceProvider.GetRequiredService<IMigrationRunner>();
migrationRunner.MigrateUp();
}
To overcome this issue, I had to create an IEmbeddedResourceProvider in my Foo.Data project, which only does the following.
namespace Foo.Data
{
public class EmbeddedResourceProvider : IEmbeddedResourceProvider
{
public IEnumerable<(string name, Assembly assembly)> GetEmbeddedResources()
{
Assembly assembly = this.GetType().Assembly;
foreach (var resourceName in assembly.GetManifestResourceNames())
{
yield return (resourceName, assembly);
}
}
}
}
And also I had to replace IEmbeddedResourceProvider definition in service registration:
public static IServiceCollection AddDatabaseMigration(this IServiceCollection services, string connectionString)
{
return services
.AddFluentMigratorCore()
.AddSingleton<IEmbeddedResourceProvider, EmbeddedResourceProvider>()
.ConfigureRunner(runner =>
runner
.AddSqlServer()
.WithGlobalCommandTimeout(TimeSpan.FromMinutes(5))
.WithGlobalConnectionString(connectionString)
.WithMigrationsIn(typeof(DataMigrations).Assembly)
.WithVersionTable(new VersionTableMetaData())
);
}
Is there any better solution to this? Wouldn't it be better if it could search the assemblies which are defined in the runner configuration?
There is indeed a difference between IMigrationSource (and IMigrationSourceItem) and IAssemblySource (and IAssemblySourceItem). The former and the latter are for migrations/profiles/stages (everything derived from IMigration) and the latter is also for version table metadata, embedded, resources, etc....
Maybe I should change the WithMigrationsIn to add an IAssemblySourceItem too.
The solution for you would be to remove the WithMigrationsIn call and your custom IEmbeddedResourceProvider and replace them with:
services
.AddSingleton<IAssemblySourceItem>(() => new AssemblySourceItem(typeof(DataMigrations).Assembly));
Most helpful comment
There is indeed a difference between
IMigrationSource(andIMigrationSourceItem) andIAssemblySource(andIAssemblySourceItem). The former and the latter are for migrations/profiles/stages (everything derived fromIMigration) and the latter is also for version table metadata, embedded, resources, etc....Maybe I should change the
WithMigrationsInto add anIAssemblySourceItemtoo.The solution for you would be to remove the
WithMigrationsIncall and your customIEmbeddedResourceProviderand replace them with: