0

I'm trying to create a console application for generating a SQL Migration script for automation purposes - the same script generated by:

Update-Database -Script

From Package Manager Console.

In the console app I've created I can generate the script if I reference the DLL directly that has my DBMigrationsConfiguration in it.

For example this works:

using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.IO;
using TAPS.Infrastructure.Migrations;

namespace msg
{
    class Program
    {
        static void Main(string[] args)
        {

            var migrator = new DbMigrator(new Configuration());
            var scriptor = new MigratorScriptingDecorator(migrator);
            var sql = scriptor.ScriptUpdate(null, null);            
            File.WriteAllText(@"c:\script.sql", sql);
        }
    }
}

Note that I have a direct reference to the DLL, a using statement and I use a new statement to instantiate the Config object.

Now if I try to do it via reflection I get back null from the line:

DbMigrationsConfiguration configuration = (DbMigrationsConfiguration)assembly.CreateInstance("TAPS.Infrastructure.Migrations, Configuration");            

The full code sample follows that I'm trying to get working via reflection:

using System;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.IO;
using System.Reflection;

namespace msg
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assembly = AppDomain.CurrentDomain.Load(File.ReadAllBytes(@"C:\DLLPath\TAPS.Infrastructure.dll"));
            DbMigrationsConfiguration configuration = (DbMigrationsConfiguration)assembly.CreateInstance("TAPS.Infrastructure.Migrations, Configuration");            
            var migrator = new DbMigrator(configuration);
            var scriptor = new MigratorScriptingDecorator(migrator);
            var sql = scriptor.ScriptUpdate(null, null);            
            File.WriteAllText(@"c:\script.sql", sql);
        }
    }
}

The configuration variable comes back as null.

Stephen Huff
  • 154
  • 2
  • 9

2 Answers2

1

If the Configuration type is in the TAPS.Infrastructure.Migrations namespace you need to get it like this with reflection, the syntax you are using is wrong.

var foo = assembly.CreateInstance("TAPS.Infrastructure.Migrations.Configuration");   

Try this to loop through all the types in your loaded assembly, the name must match.

foreach (var type in assembly.GetTypes())
{
    Console.WriteLine(type);
}
Janne Matikainen
  • 5,061
  • 15
  • 21
  • If I try this the GetTypes() gives me an error of: {"Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."} In the LoaderExceptions it refers to another DLL that I've tried loading in addition with AppDomain.CurrentDomain.Load but that doesn't fix the problem. Odd that if I just add a reference I only need the one DLL. Suggestions? – Stephen Huff Nov 17 '15 at 13:38
  • The reference for the TAPS.Infrastructure.Migrations is most likely Copy to Local = true, thus all the required dlls are copied along, are there some types that are used in the configuration? Are both applications using same version of entity framework and target framework? – Janne Matikainen Nov 17 '15 at 13:48
  • I see what you are saying now - when I add the single reference to my console app it's also copying additional DLLs to my BIN directory behind the scenes. I guess my question is now - how do I automatically load those also? If I just addin an additional AppDomain Load such as: AppDomain.CurrentDomain.Load(File.ReadAllBytes(@"C:\Development\eTaps\Dev\Source\TAPS.Web\bin\TAPS.Core.dll")); It still says that Taps.Core.Dll is not loaded when I try to CreateInstance. – Stephen Huff Nov 17 '15 at 14:14
  • I got it to work! You defiantly pushed me in the right direction. Thanks. – Stephen Huff Nov 17 '15 at 14:34
0

This code fixed it:

class ProxyDomain : MarshalByRefObject
{
    public Assembly GetAssembly(string assemblyPath)
    {
        try
        {
            return Assembly.LoadFrom(assemblyPath);
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException(ex.Message);
        }
    }
}

From @shytikov answers at:

How to Load an Assembly to AppDomain with all references recursively?

Community
  • 1
  • 1
Stephen Huff
  • 154
  • 2
  • 9