TFS Integration Platform – Provider not found Error. Question & answer 6

Context

Blue Fireman in a Uniform, Fighting a Fire Clipart Illustration I have been battling with the following error and finally decided to delve into the debugger and isolate the gremlin. It just got worse, because when I finally found the method …LoadProvider(), which loads each Adapter DLL in the PlugIns directory and looks for the IProvider interface. The reflection code claimed that the IProvider interface was not a known type within any of the adapters and therefore returned an empty provider dictionary to the pipeline … which in turn threw its toys out of the cot.

clip_image002

This is the problematic logic … statement on line 29 claims that type == null. Looking at the assembly in Reflector claims otherwise … which is when I called my colleague Terry for help.

    1: /// <summary>
    2:         /// Discovers providers under the specified directories and loads them if used in MigrationSources 
    3:         /// defined in the configuration. It instantiates a unique provider instance for each MigrationSource.
    4:         /// </summary>
    5:         public Dictionary<Guid, ProviderHandler> LoadProvider(params DirectoryInfo[] probingDirectories)
    6:         {
    7:             // Initialize a list that will contain all plugin types discovered
    8:             Dictionary<Guid, ProviderHandler> providerHandlers = new Dictionary<Guid, ProviderHandler>();
    9:  
   10:             if (probingDirectories != null)
   11:             {
   12:                 // Iterate over the probing directories and look for plugins
   13:                 foreach (DirectoryInfo directory in probingDirectories)
   14:                 {
   15:                     if (directory.Exists)
   16:                     {
   17:                         // Try to load plugins from each dll
   18:                         foreach (FileInfo file in directory.GetFiles("*.dll"))
   19:                         {
   20:                             try
   21:                             {
   22:                                 // Load the dll into an assembly
   23:                                 Assembly assembly = Assembly.LoadFrom(file.FullName);
   24:  
   25:                                 // Iterate over all types contained in the assembly
   26:                                 foreach (Type type in assembly.GetTypes())
   27:                                 {
   28:                                     // Only consider public, concrete types that implement IProvider
   29:                                     if (type.IsPublic && !type.IsAbstract && (type.GetInterface(typeof(IProvider).Name) != null))
   30:                                     {
   31:                                         ProviderHandler handler = ProviderHandler.FromType(type);
   32:                                         if (null == handler
   33:                                             || handler.ProviderId == null
   34:                                             || handler.ProviderId == Guid.Empty)
   35:                                         {
   36:                                             continue;
   37:                                         }
   38:  
   39:                                         Guid[] sourceIds = GetMigrationSourceId(handler.ProviderId);
   40:                                         if (sourceIds == null || sourceIds.Length == 0)
   41:                                         {
   42:                                             TraceManager.TraceWarning(String.Format("Provider {0} is not used in any MigrationSource", handler.ProviderId.ToString()));
   43:                                             continue;
   44:                                         }
   45:  
   46:                                         // try persist provider information to db
   47:                                         handler.FindSaveProvider();
   48:  
   49:                                         // create a unique provider instance for each migration source
   50:                                         foreach (Guid migrationSource in sourceIds)
   51:                                         {
   52:                                             ProviderHandler providerHandler = new ProviderHandler(handler);
   53:                                             
   54:                                             if (!providerHandlers.ContainsKey(migrationSource))
   55:                                             {
   56:                                                 providerHandlers.Add(migrationSource, providerHandler);
   57:                                                 TraceManager.TraceInformation("provider {0} {1} is loaded", providerHandler.ProviderName, handler.ProviderId.ToString());
   58:                                             }
   59:                                         }
   60:                                     }
   61:                                 }
   62:                             }
   63:                             catch (Exception ex)
   64:                             {
   65:                                 TraceManager.TraceError("A failure occurred while trying to load the {0} Provider: {1}{2}", 
   66:                                     file.FullName, Environment.NewLine, ex.ToString());
   67:                             }
   68:                         }
   69:                     }
   70:                 }
   71:             }
   72:             return providerHandlers;
   73:         }

Rule 42 (the answer to IT) … when you are unable to resolve a problem within a reasonable period of time, call a colleague and discuss the problem on the whiteboard. I do not know why I always tell everyone to adhere to this rule, yet I constantly find myself breaking it and exploring black holes :(

Cause

If any of your TFS Integration Platform adapters have the copy to local property set to true as part of their project build properties, the EditorFoundation, EntityModel and Toolkit assemblies are copied to the PlugIns directory as well. Once these assemblies make themselves at home the the PlugIns directory, the reflection logic misbehaves and fails to locate the IProvider interface type.

Resolution

This is a known bug and is under investigation. In the interim, please ensure that only Assemblies with an IProvider interface are located within the PlugIns directory. Remove all other assemblies … or face the gremlins as above.

I will update this post as soon as we have a resolution for the bug.