Good Evening Jeremy,
This answer would be the continuation of the post above but also the problem investigated by me in this post:
https://forums.autodesk.com/t5/revit-api-forum/problem-with-modeless-form-window-which-implements-iw...
The clue of both problems seems to be the same.
So, following the discussion above, loading the "Logic Assembly" into Byte Array worked really well.
However, there is one issue I am struggling with - but first implementation:
//implementation of 'Reader' class
public class ExternalAssemblyByteArrayReader
{
//ctor
public ExternalAssemblyByteArrayReader(string assemblyFilename)
{
byte[] assemblyBytes = File.ReadAllBytes(assemblyFilename);
//static property assigned to External Application (IExternalApplication)
Application.Assembly = Assembly.Load(assemblyBytes);
}
public void Launch(Assembly assembly, object data, string commandName, string methodName)
{
Type typ = assembly.GetType(commandName);
object cmd = assembly.CreateInstance(typ.FullName);
object[] args = new object[0];
if (data is ExternalCommandData)
{
string message = null;
Autodesk.Revit.DB.ElementSet elements = null;
args = new object[] { data as ExternalCommandData, message, elements };
}
else if(data is UIControlledApplication)
{
args = new object[] { data as UIControlledApplication};
}
BindingFlags flags = (BindingFlags) ((int)BindingFlags.Default | (int)BindingFlags.InvokeMethod);
typ.InvokeMember(methodName, flags, null, cmd, args);
}
}
//"Reader" class implemented into Revit interfaces
//External Application
public class Application : IExternalApplication
{
public static Assembly Assembly { get; set; }
public static ExternalAssemblyByteArrayReader Reader{ get { return _reader; } }
private static ExternalAssemblyByteArrayReader _reader;
public Result OnStartup(UIControlledApplication uiControlledApp)
{
ExternalAssemblyByteArrayReader reader = new ExternalAssemblyByteArrayReader(assemblyPath);
_reader = reader;
reader.Launch(Application.Assembly, uiControlledApp, "LinkedDLL.MainApplication", "OnStartup");
return Result.Succeeded;
}
}
//External Command
public class SampleCommand : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
Application.Reader.Launch(Application.Assembly, commandData, "LinkedDLL.MainWindowCommand", "Execute");
return Result.Succeeded;
}
}
Solution works, however there is important thing to be considered:
Loaded Assembly would have to be defined(loaded) OnStartup in order to preserve values of static properties, which are declared in External Application. Otherwise, with every external command fired, new instance of updated Assembly is loaded and all declared static properties are reset to null. As a consequence of this limitation, every change in code (including changes to IExternalCommands) will have to be predecessed with Revit restart.... 😕
Therefore I would like to suggest a new direction of my interrogation:
Is there a way to load/update an Assembly only partially, in a way that Loaded Assembly 'OnStartup' remains untouched (keeping the values of all members assigned during ExternalApplication Runtime), apart form a specific class?
For example:
only Type of Name == "UpdatedCommand" and which implements IExternalCommand interface will be updated
As usual I would be extremally grateful for any suggestion/hints,
Have a nice evening,
Lukasz