Export to GitHub

mybatisnet - issue #20

Assembly.Load(): Fails / Unable To Load Resource Via T4 Template


Posted on Dec 13, 2010 by Helpful Horse

Using SVN version of Subversion. Custom repository library embeds the SqlMap.config file into the assembly as a resource. The following is the initialization code that is used to setup the various custom repositories (shared base class):

protected static void Initialize()
{
  ConfigurationSetting configurationSetting = new ConfigurationSetting();
  configurationSetting.Properties.Add("nullableInt", "int?");

  string resource = String.Format("assembly://{0}/Configuration/SqlMap.config", Assembly.GetAssembly(typeof(BaseRepository)).GetName().Name);
  try {
    IConfigurationEngine engine = new DefaultConfigurationEngine(configurationSetting);
    engine.RegisterInterpreter(new XmlConfigurationInterpreter(resource));

    IMapperFactory mapperFactory = engine.BuildMapperFactory();
    _sessionFactory = engine.ModelStore.SessionFactory;
    _dataMapper = ((IDataMapperAccessor) mapperFactory).DataMapper;
  }
  catch (Exception ex) {
    Exception e = ex;
    while (e != null) {
      Console.WriteLine(e.Message);
      Console.WriteLine(e.StackTrace);
      e = e.InnerException;
    }
    throw;
  }

However, when attempting to use the specified custom data repository in a T4 template, a System.IO.FileNotFoundException is generated with the name of the assembly containing the repository.

When tracing the problem, I discovered that if I pass in the fully qualified assembly name (Name=mydata,Version=1.0,etc) to the Assembly.Load function, it would work. My first thought was to just update the assembly:// reference with the full assembly name, however the new Uri() fails validation when creating the Uri. Instead, I updated the AssemblyResource() constructor to do a try catch, first attempting to load the resource as before and then to walk the loaded assembly references looking for a name match.

        assembly = Assembly.Load(resourceAssemblyName);

change to

        try {
          assembly = Assembly.Load(resourceAssemblyName);
        }
        catch (FileNotFoundException) {
          // Attempt to find assembly in loaded assembly list
          int index = 0;
          Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
          while ((assembly == null) && (index < assemblies.Length)) {
            if (String.Compare(assemblies[index].GetName().Name, resourceAssemblyName) == 0) {
              assembly = assemblies[index];
            }
            index++;
          }
        }

Similar changes were made to TypeResolver.cs and DbProvider.cs. There should probably be a LoadAssembly() function created in a common module shared by all projects.

When not running in the T4 context, the exception is not thrown, so I'm assuming this is a dynamic compiler issue. The additional check to find the referenced assembly for the user shouldn't adversely affect performance.

Status: New

Labels:
Type-Defect Priority-Low