0

I am trying to load external Assembly to list out all Types, Methods and Properties during run time, just like Object Browser in Visual Studio. My requirement is, I want to Load external Assembly list out its Members in a treeview and Unload the Assembly or AppDomain after the use. Later in the same project I am using the same assembly to modify and add some more code to it. Since I have already opened the assembly, CompileAssemblyFromFile is not allowing me to Compile and produce the output. How can I deal with this situation? How is Object Browser works in Visual Studio without creating the instance of Assembly or if at all it is created, how to unload it after usage?

P.S.

I have already tried to use another AppDomain to load the assembly but did not success. As the treeview is created in main appdomain, I cannot access this in custom appdomain to add nodes.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
coding_cs
  • 77
  • 9
  • Which .NET version are you targeting? .NET Framework or .NET (Core)? There are fundamental differences how to achieve what you want depending on .NET version. – Ondrej Tucny Jan 31 '22 at 15:34
  • I tried .Net Core also, but it has its own limitations for my project. Now I am trying in .Net Framework. – coding_cs Jan 31 '22 at 15:50
  • Sounds like you might need a view model to decouple what you're displaying from what's loaded? You'd only need to have the assembly loaded while you're harvesting its contents, no? – Mathieu Guindon Jan 31 '22 at 15:53
  • I have an Assembly, I want load and show its contents to the user. Later I need to use the same Assembly as 'Output' from CompileAssemblyFromFile. Now second part is not working because I am not able to compile as already an instance is under use. – coding_cs Jan 31 '22 at 15:57
  • Sounds like you want to break you project in multiple processes that are easy to start and stop. So create a host process that loads the assembly communicates its findings in the assembly to your main process and exits after that. Presumably you want to do the same for the compiling step. That gives you the chance to do as much examine, compile, examine roundtrips as you want. The solution should also work framework version independent. – Ralf Jan 31 '22 at 16:08
  • @Ralf: Breaking in to multiple processes? How to load Assembly from another process? Also I guess what you mean here by process is different project? If I load assembly from another project wont it load into same appdomain in which host project is running? – coding_cs Jan 31 '22 at 16:18
  • Possibly, duplicate: https://stackoverflow.com/questions/225330/how-to-load-a-net-assembly-for-reflection-operations-and-subsequently-unload-it – Yevhen Cherkes Jan 31 '22 at 17:14
  • No i meant different process. Idea was that you load the assembly in another process read everything you need to know in that process and then hand that data over to a different process (via a ipc mechanism) and exit the process that has loaded the assembly initially. – Ralf Jan 31 '22 at 17:26
  • @YevhenCherkes: No I cannot use the solution. Because in the solution they are just talking about loading types using ReflectionOnly Mode. The reflection-only context is no different from other contexts. Assemblies that are loaded into the context can be unloaded only by unloading the application domain as mentioned in msdn document. (https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.reflectiononlyload?redirectedfrom=MSDN&view=net-6.0#System_Reflection_Assembly_ReflectionOnlyLoad_System_String_) – coding_cs Jan 31 '22 at 17:36
  • @coding_cs The solutions proposed by Yevhen Cherkes as a duplicate shows how to create a temporary app domain, and reflection-only load the assembly into it. The temporary app domain can then be unloaded. That should satisfy your need, shouldn't it? – Ondrej Tucny Jan 31 '22 at 17:43
  • @OndrejTucny: Sorry I tried it already. I created AppDomain but can't I load Members of Assembly in to Winforms `Treeview`? Because TreeView is in default appdomain. I can get types, methods in Temporary appdomain, but I can't load it into TreeView. TreeView is blank even after I try `treeview.nodes.add()`. which is my ultimate requirement as explained in the question. – coding_cs Jan 31 '22 at 18:05
  • 3
    Don't load the assembly itself into the UI, load a view model instead. You load the assembly, traverse its types and members, and for each type and member you create an instance of a type that you own, that belongs to your presentation layer. This really doesn't feel any different than loading a view model into a UI rather than displaying entity types straight off a database and leaking IQueryable into your UI. Treat the loaded assembly as a data source: pull the data, close the data source, present the data. – Mathieu Guindon Jan 31 '22 at 18:24
  • @MathieuGuindon: Thanks for the suggestion, any example source for "Treat the loaded assembly as a data source: pull the data, close the data source, present the data." would be much helpful. – coding_cs Feb 01 '22 at 14:20
  • Oh that's a solved problem, you're looking for a design pattern here: if it's a web app, look into Model-View-Controller (MVC) architecture; if it's WinForms, Model-View-Presenter (MVP) works nicely; if it's WPF, you'll want to look into Model-View-ViewModel (MVVM). In every case, the code that's responsible for pulling the data is separate from the code that displays the data. Cheers! – Mathieu Guindon Feb 01 '22 at 14:38
  • 1
    @MathieuGuindon: Your comment helped me to achieve what was intended. Thanks for your help! – coding_cs Feb 08 '22 at 07:17

1 Answers1

1

Based on Mathieu Guindon's Comment. I am loading assembly in my ASP.Net Web API and Serializing the assembly content to JSON Array. Later in my client application I am Deserializing the response with the help HttpClient and populating the WinForms TreeView.

Here's how I did. Sample code.

//Action Model
public class ActionModel
{
   public string ActionName {get;set;}
   public IList<MethodInformation> ActionMethods {get;set;}
}

public class MethodInformation
{
   public string MethodName {get;set;}
   public IList<ParameterInformation> GetParameters {get;set;}
}

//API
public Object Get(string id)
{
    switch(id)
    {
        case "Assembly1":
           Type[] typesInAssembly = Assembly.LoadFrom(pathToAssembly).GetTypes();
           
           List<ActionModel> actionModel = new List<ActionModel>();
           
           for(var t in typesInAssembly)
           {
               /* add the items to the List actionModel */
           }
           return actionModel;
     }
}

On the client side I am having one more Class which consumes this API and parses the content by Deserializing the JSON Content and display it in treeview.

Now the requirement is met. I can use the same copy of Assembly to show and build which was main requirement. Hope I am doing this correctly.

coding_cs
  • 77
  • 9