How to run managed code on different version assemby - c#

I'm working with one application that that has and C# API. This program has different versions of it. But the api stays the same through its versions.
So i have written a managed code to one of its versions, and now i want to run the same code at different version of the application at runtime where i exactly know witch version of the app is running.
Question is:
Is it possible to replace assembly version and dll location at run time without writing unmanaged code using reflections?

Yes, you can use Assembly.LoadFrom to load an assembly. You can then use reflection to go thru the types of said assembly and call methods.
To avoid needing to use reflection for everything there should be a shared interface-assembly that define your api. There should also be a single entry point to the API. So you can use reflection find the class that implements the entry-interface, create an instance of this class and cast it to the interface. That lets the rest of the code use actual types.
You still need to be careful however, if there is any miss match between the interface and the actual types, you will get an runtime exception. You will not get an exception when the interface method is called (as might be expected), but when the method that calls the interface method is called. This due to the jitter resolving types when a method is compiled, and this is done the first time it is called.

Related

Difference between GetEntryAssembly and GetExecutingAssembly

I've read docs for GetEntryAssembly and GetExecutingAssembly trying to make sense of the difference between them. I simply fail to understand how the definitions relate to each other. Altough I see two different formulations, I can't understand the distinction implied. In my head, it's a potayto-potahto situation, which is reinforced by the same contents on my screen when I try to display the values of each returned Assemby object.
Naturally, there must be some difference and it's simply my competence that prevents me from realizing what it is. So I've done some research, only discovering that most of the wisdom out there is about obtaining the path. The lonely resource that was explicitly targeting the comparison between them was here.
Can I ask for a specific example where those two methods return objects the contents of which differ? Preferably with a brief explanation of why.
Let's say you have a console project MyConsoleProject that references library project MyLibrary. Inside MyConsoleProject both Entry and Executing assemblies will be the same. But inside MyLibrary the ExecutingAssembly will refer to library project, not the console one.
GetExecutingAssembly:
Gets the assembly that contains the code that is currently executing.
GetEntryAssembly returns:
The assembly that is the process executable in the default application domain, or the first executable that was executed by ExecuteAssembly(String). Can return null when called from unmanaged code.
The GetEntryAssembly method can return null when a managed assembly has been loaded from an unmanaged application. For example, if an unmanaged application creates an instance of a COM component written in C#, a call to the GetEntryAssembly method from the C# component returns null, because the entry point for the process was unmanaged code rather than a managed assembly.
References:
Assembly.GetEntryAssembly Method - https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.getentryassembly
Assembly.GetExecutingAssembly Method - https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.getexecutingassembly

Is it possible to instantiate and call a method of the class my Analyzer is analyzing right now?

My analyzer will match methods with certain signatures. I would like from inside my analyzer to create an instance of the class I'm analyzing and call the method that caused the analyzer to kick in.
Assuming the source code is in a compilable state, is it possible?
Getting the class name and method name is pretty easy, but Type.GetType(...) will always return null.
The purpose of this is that I would like for my analyzer to kick in when I'm on a test method and run it, failing if the test fails.
If the code is not ready for compilation, it would be fine to just return.
It seems possible, but you'd need to check the efficiency of these solutions. Also, you can't guarantee that the code is compilable.
You can grab the Compilation object (from let's say context.SemanticModel.Compilation), call Emit on it, and write it to disc. Then use Assembly.Load to load it, and then it's simple reflection to instantiate the class, whose name you already know, and call the method on it with appropriate arguments.
Another approach would be to use the Compilation in a scripting session as a reference assembly, and use the Roslyn Scripting API to invoke the method. There is a ToMetadataReference method on the Compilation, so you could get a MetadataReference, which could be then passed to ScriptOptions.Default.AddReferences. And then you'd need to pass the resulting options instance to CSharpScript.EvaluateAsync().
There's another fundamental reason you can't run code from the user's compilation, even if it did actually compile -- it might be the wrong environment. Consider a scenario where you're targeting Windows Phone, or Xamarin Android/iOS, .NET Core on Linux, or whatever. In any of these cases the compiler has reference assemblies that you can compile against but obviously you can't actually run that code because it's targeting a different platform. People often ask why you can't convert an ITypeSymbol to a reflection System.Type and back, and this is one of the reasons why -- the compiler can compile code on platform A for platform B, when it can't actually run (or fully load) B's assemblies in the first place.

Can you use a class library if you don't reference all of it's dependencies?

Let me clarify:
I have built a class library to be used in several projects. As part of this DLL I want to add a few different custom providers for Owin Cookies by extending CookieAuthenticationProvider so I need to include a reference to Microsoft.Owin.Security.Cookies. This is safe because the newer projects that will use my library also use Microsoft.Owin.Security.Cookies.
However some of the projects are older and dont use Owin etc... Will they blow up if I include the library for other use? Or will they only blow up if I try to use the provider (which I wouldn't since they cant use it).
I want to put some commonly used things in my library without having to reference every one of it's dependent DLL's to every project that uses them. I'm pretty sure what I'm doing is ok but I was hoping somone could tell me before I waste many hours going forward with this. Also if there is a better way I'm all ears.
The rules:
All types which are visible to a given assembly must be declared in assemblies referenced by that assembly.As long as your class library does not actually expose in its public API the types found in the Microsoft.Owin.Security.Cookies assembly, then other assemblies can safely compile with your DLL without referencing that assembly.
A referenced assembly need not be present at runtime, except when code in that assembly is actually needed, i.e. some other code attempts to call that code.
In general, this means that as long as other assemblies which are referencing your assembly and which don't reference Microsoft.Owin.Security.Cookies also don't call any code in your assembly that would then in turn attempt to call code in Microsoft.Owin.Security.Cookies, that assembly need not be present at runtime.
The tricky part on that second point is that what constitutes "calling code in Microsoft.Owin.Security.Cookies" is not always clear. Typically, as long as you don't access the types in the assembly at all, .NET won't try to execute any code in that assembly. But it's not hard to accidently access the types even when they are not necessarily needed (e.g. in initializers, static or otherwise, code that checks for interface implementations, etc.).
If you really want your clients to be able to use your DLL, which references Microsoft.Owin.Security.Cookies, without necessarily needing that DLL to be present at runtime, you will need to be very careful to ensure you've fully supported that scenario. It is possible to do, but it's also not hard to make a mistake.
(I have to admit, I'm surprised that this useful question hasn't already been addressed on Stack Overflow. Seems like it would have come up before by now. But I was unable to find a duplicate, hence the answer above. If anyone is aware of a duplicate I've overlooked, I welcome any suitable notice of that.)

Can I run code prior to a CLR type being loaded?

I have a .NET dll wrapper around a mixed (Managed/Unmanaged) type. If some crucial dll's are missing from the hard drive or their location is not entered into the path, then the type will not load resulting in a TypeLoadException("Could not load file or assembly or one of its dependencies"). This hampers xcopy deployability of any utility that consumes this class library.
I would prefer to fix this problem without instructing all clients to change client code. I hope to achieve this by running code before the type is loaded by the CLR. I have included its dependencies in a zip file which is included with the distribution.
Clients call into a static factory method.
var MyMixedTypeInstance = MyMixedType.Create();
However, since the factory method signature return type is MyMixedType, then MyMixedType is attempted loaded before any code inside the create method is executed. I have considered make the return type an interface to avoid this. But if the interface at some deals with (eg returns) a concrete mixed type, then AFAICT I'm back to square one.
I attempted stuff like using a static constructor, but it seems (as maybe all of you others know) that types exposed by the public API are immediately loaded. However, I do not know much about how the loading of types unfold, so I may be missing something obvious. I know that you can help the CLR resolve assemblies, but I do not know if this relates to a type.
Naturally, it would be possible to create a complete separate "MakeSureNeededBinariesAreInPlaceAndInPath" kind of method and demand/force all clients to invoke it prior to calling the Create() method, but I would like to avoid it if I can.
Is there for instance any attribute I can decorate the type with to intercept the type loading of the class?

get information on an assembly

I want to get information on an Assembly in my C# application. I use the following:
Assembly.GetCallingAssembly();
This works perfectly returning information on the calling Assembly.
I want to share this functionality with other applications, so I include this in a class in my class library.
I reference this class library in multiple applications. When I make a call to this method from my applications, it returns information on the class library and not the application. Is there a way I can alter my above code to return information on the web applications assembly while still having the code included in the class library?
Instead of having the class library being intelligent why don't you have the caller pass an Assembly as argument to the method? So when you call the method from within some application you would pass Assembly.GetExecutingAssembly() and the method within the class library will now be able to fetch the assembly of the actual caller.
I'm not sure what you provide on top of reflections, but maybe you're abstracting a facility that doesn't need to be abstracted. Reflections already handles this, so why not let it do its job?
But if this API gives you back some useful information (such as plugging nicely into your database, etc), then maybe your approach makes some sense. But I still recommend that you refactor it:
Put this code in only one shared project/assembly, and just link that project/assembly when you need to call that functionality. Needing to duplicate code to get your job done is considered code smell.
Take an Assembly object as a parameter, rather than trying to determine the current assembly. This will allow more flexibility in case you come up with some code that wants to get data on a bunch of other assemblies, and will still allow you to pass the current assembly. (Note: Darin already made this point)

Categories

Resources