Load multiple versions of the same dll without putting it in the GAC - assemblies

I would like to load two different versions of the same dll within the same process. At the same time I would like to avoid placing any of them in the GAC.
Any ideas?
Thanks,
Krikor

Yes, it seems like i have to manually load the assembly, one way or another.
One solution that i found was to subscribe to the AssemblyResolve event of the appDomain. This event is raised when an assembly is not found and allows you to manually provide it.
Reregister an event handler like this
AppDomain.CurrentDomain.AssemblyResolve += MyResolveEventHandler;
static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
return Assembly.LoadFrom(#"OldAsm\Asm.dll");
}
Once the code that uses the specific code is reached the .NET Framework will try to load the assembly, it will crash and will call your handler (MyResolveEventHandler).
I would keep looking for a way to resolve the right reference without having to write any code and without having to put anything in the GAC. If anyone finds a way, please post it.
Thanks

Activator.CreateInstance. Check msdn for examples.

Related

Ninject failing to load assembly

I have a system which was using Ninject and loading assemblies using the file pattern kernel load method. Things were working fine with this setup.
A new requirement for the application was to bundle everything into a single exe. We used the technique described here for that. Thus to register everything with Ninject we needed to load the assemblies and call the kernel load for each assembly. However, this would not work. Ninject would always fail even though the binding was registered. I saw it in the debugger as being registered and it worked in the immediate window, but not in the code.
The only solution we found was to manually register each NinjectModule.
Is it possible to use Ninject when the assembly is bundled inside of another one?
The only solution was to manually pass in references to the NinjectModule.

Is there a way to point an ASP.NET app to references instead of copying them to the Bin folder?

We have a bunch of sample ASP.NET applications. I'd rather not copy the DLLs to the Bin folder in every sample because then all the files have to be updated on a change.
Is there a way to point the ASP.NET app at the references like can be done with a Forms or command line app?
Update: To answer the questions below let me explain a bit better what the situation is here. We have a commercial product that is a set of DLLs. We provide a number of sample applications using it, including several that are ASP.NET apps. All of this, our product DLLs and our sample source, is installed on a user's computer.
When they go to compile one of the samples we want that sample to use the version of the DLLs installed with it. The install process has place in GAC as the default option, but the user can uncheck that if they do not want the DLLs in the GAC and in that case we have to access the DLLs where they were installed, or copy them to each Bin directory.
To add reference right click on bin folder in visual studio and you will find add reference option there.
The question is clear but the background is not.
It makes no sense to me to have a couple of applications which all use the same application dll. Is it just a library used by all applications?
There are some options depending on what you have and what you need:
1. add reference directly
If you really just want to add a reference, right-click on "references" in your VS project and select "add reference". Choose the reference an click ok. After that, right-click the added reference and select "properties" and set "local copy" to false, so it's not copied to the bin folder.
Maybe the option names are a bit different, but I don't have an english VS right now. Should be nearly what you have to do.
EDIT
In this window set "local copy" to "false" (here shown as "Lokale Kopie", sorry, it's german).
2. put dlls in GAC
If you have a shared code library for a couple of applications on the same server you could think about putting that library into the GAC.
3. problems with source control
As mentioned from IrishChieftain you maybe use source control and don't want to update the dlls in the bin folder every time. The solution for that would be just ignoring the bin folder in your source control.
You could add any references you'd like using the context menu on the References node of your project:
In the 'Add Reference' dialog click on the Browse tab and you can browse to and add any outside references you need. For common assemblies we usually put them in a common location on the file system and then reference them from that location whenever we need to.
There are occasions where you will not want to reference certain assemblies at design-time. There is an avenue for you to load them, based on logic, at run-time with the AppDomain.AssemblyResolve event handler. If you have assemblies that you can reference through a level of abstraction and that you do not want to reference directly you can use the following pattern to omit them and execute some algorithm at run-time to find and then add the assembly to the AppDomain.
This is a snippet that I put in the global.asax, Application_Start handler:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// use this space to add logic to find your assemblies
return null; // will throw a Dependency-related exception
}
Let me know if there are any questions or if I am missing the point of your question.
-G

Is there a way to run code when an assembly loads?

I'm building an application that will load untrusted assemblies for inspection (i.e. retrieval of the assembly full name). For security reasons, I'm trying to think of a way that these assemblies could be written that would allow them to execute code when loaded. I haven't code up with a method yet, but wanted to throw it out here to see if anyone could.
I'm aware that I could load these assemblies into an untrusted app domain, effectively stopping them from doing almost anything, but I wanted to avoid the complexity if it's un-needed.
Specifically, I will be calling Assembly.Load and <LoadedAssebmly>.FullName. Maybe there's a better way to load the assembly name without using the Assembly class?
Thanks,
Matt
First of all, there's the AssemblyName class. It allows you to find the assembly's name without loading it. Second, you can load assemblies using Assembly.ReflectionOnlyLoad, which uses the reflection-only context -- no code can be executed from such an assembly.
Yes, it is possible: .Net: Running code when assembly is loaded
I suggest, you use a method to inspect the assembly, that doesn't load it, i.e. Mono.Cecil

Assembly unavailable after Web.config change

I'm using a custom framework that uses reflection to do a GetTypeByName(string fullName) on the fully-qualified type name that it gets from the database, to create an instance of said type and add it to the page, resulting in a standard modular kind of thing.
GetTypeByName is a utility function of mine that simply iterates through Thread.GetDomain().GetAssemblies(), then performs an assembly.GetType(fullName) to find the relevant type. Obviously this result gets cached for future reference and speed.
However, I'm experiencing some issues whereby if the web.config gets updated (and, in some scarier instances if the application pool gets recycled) then it will lose all knowledge of certain assemblies, resulting in the inability to render an instance of the module type. Debugging shows that the missing assembly literally does not exist in the current thread assemblies list.
To get around this I added a second check which is a bit dirty but recurses through the /bin/ directory's DLLs and checks that each one exists in the assemblies list. If it doesn't, it loads it using Assembly.Load and fixing the context issue thanks to 'Solving the Assembly Load Context Problem'.
This would work, only it seems that (and I'm aware this shouldn't be possible) some projects still have access to the missing assembly, for example my actual web project rather than the framework itself - and it then complains that duplicate references have been added!
Has anyone ever heard of anything like this, or have any ideas why an assembly would simply drop out of existence on a config change? Short of a solution, what is the most elegant workaround to get all the assemblies in the bin to reload? It needs to be all in one "hit" so that the site visitors don't see any difference other than a small delay, so an app_offline.htm file is out of the question. Programatically renaming a DLL in the bin and then naming it back does work, but requires "modify" permissions for the IIS user account, which is insane.
Thanks for any pointers the community can gather!
Generally, you should avoid relying on what assemblies are currently loaded in an appdomain, as that happens dynamically. Instead, simply call System.Web.Compilation.BuildManager.GetType() instead of Type.GetType() or Assembly.GetType(). This should just do the right thing for you, and not be affected by appdomain cycles.
As you obviously know, there are many situations where the current appdomain is unloaded and reloaded. After each reload, all assemblies are unloaded and the whole application starts running "from scratch".
Assemblies are by default loaded on demand. Usually that is the case when the JIT stumbles across some reference. In consequence, a appdomain reload will clear out the assemblies in the appdomain and they will only appear again later on when the JIT loads them.
As solution I'd rever to using the static Type.GetType() method and supply an assembly qualified name (e.g. a type name with the assembly name included). That's the same thing the framework uses when loading types specified in the config file, and it will make sure that the required assembly is searched and loaded on demand without using any tricks. See the remarks section of the method above (the method name above name is a link).
This will require updates to your database to hold assembly qualified names instead of "only" fully qualified type names. However, it also makes sure that you don't run into name collisions when two assemblies provide different type with the same name, so this is a good idea anyways I think.
I've never heard of this problem before.
I'm not sure if this will work, as I only recently read about it while researching workarounds to ODAC dependencies, but specifying the probing path for assemblies may fix your issue.
see: http://msdn.microsoft.com/en-us/library/823z9h8w(VS.80).aspx
sample:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>
I have a similar problem, when I update 2-5 files, ether web.config, ether other files, and asp.net needs to recreate the running files, then some times did not find some classes/function that exist on dll files, and my system is not working - throw errors like yours.
My solution to that is that I place the app_offline.htm on the root, make my updates, then rename/remove the app_offline.htm and my system works fine.
I am sure that have something to do with the cached compiled files, but I did not have deaply search whats exactly cause that.
[what is the most elegant workaround to get all the assemblies in the bin to reload]
Now what is the most elegant workaround on this is to call the HttpRuntime.UnloadAppDomain and actually make your application to stop and starts again.
http://msdn.microsoft.com/en-us/library/system.web.httpruntime.unloadappdomain(VS.80).aspx
I do not know if this solve your issue, you need to make tests.
probably on Global.asax make something like that
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError().GetBaseException();
...if ex is your error, and you get more than 2 ...
{
HttpRuntime.UnloadAppDomain();
}
}
I would try to create some basic class from which assembly, which is interesting for you without reflection on Application Start to make sure it is loaded.
E.g.
var temp = new BaseModuleBuilder();
This do not look smart, but it is very straitforward and asp.net should do everything for you. In case when your list is too dynamic, it could be something like
var temp = Activator.CreateInstance(Type.GetType("BaseModuleBuilder, Modules.dll"));
Make sure to always specify DLL when working with dynacmically loaded classes.

ASP.Net MissingMethodException - "ctor" method not found

We are getting intermittent problems on a production server that we cannot recreate.
There are two very strange things about the issue. Firstly it's a method not found error on the constructor (ctor) for an exception handling helper class and secondly we have custom errors switched on for remote users and this property is being ignored.
The detail of the error is:
Server Error in '/MyWebsite' Application.
Method not found: 'Void MyExceptionHelperClass..ctor (System.Exception)'.
...
Exception Details: System.MissingMethodException: Method not found: 'Void MyExceptionHelperClass..ctor (System.Exception)'.
...
The stack trace is pretty unhelpful.
My thoughts are that there may be an out-of-memory error or something like that that is killing the page. When the exception handling code kicks in it tries to create an exception object which fails for the same reason giving this error.
However this is wild speculation. We are waiting for the event logs to see whether anything is amiss with the server but in the meantime does anyone have any thoughts or suggestions?
UPDATE:
It has proven difficult to get information out of the team responsible for the production servers but I have managed to find out that as far as load balancing is concerned, this site is currently only running on one server (this can be made to switch over onto another if necessary). Given that this is an intermittent problem and there is only one server involved, then I find it difficult to believe that this could be an assembly issue. Surely if it was then the problem would occur every time?
If you see this error happening on a site that has custom errors turned on, then the error is happening in the custom error handling routine itself.
From the look of the .NET error message it appears that your routine is expecting a constructor that accepts an exception by reference - your comment above shows a constructor that accepts by value.
Check carefully that there isn't a stale version of an assembly in your system somewhere. These can lurk in the Temporary ASP.NET Files folder; you'll need to do an "iisreset /stop" before you can clear them out.
In that regard it's always a good idea to make sure that AssemblyInfo.cs is set up to automatically stamp version numbers in some way. We have our version numbers tied to our source code repository system and CI build box so we can tell exactly what was in what assembly really easily.
I would use elmah: http://code.google.com/p/elmah/ to hopefully give you a bit more insight into the issue. It is free and can be used on an existing site without any recompilation. Try it - and post back if the issue is still happening.
As others have also mentioned, I would suspect that your site is somehow using an out of date version of an assembly. Something you could try doing is a full Precompile of your site before deploying to your production server. This ensures that ASP .Net doesn't dynamically compile the site on the fly, and therefore should mean that it's using completely up to date code throughout.
Do you have a no parameter public constructor defined for MyExceptionHelperClass in your code? Or is the class meant to only have static methods, in which case it should be a static class.
public class MyExceptionHelperClass()
{
public MyExceptionHelperClass() { }
}
Unfortunately, this may be one of those cases where the error message is of little to no value. In my experience, this general class of exception may be the result of either a configuration issue or bad logic aroung threading/app domains. For example, I have seen similar issues upon attempting to load the same assembly into an app domain more than once.
You mention that this is difficult to reproduce. If it's only happening on one server in the production farm it's more likely to be a config issue (with that machine). If it's happening on more than one server than it could be either config or threading.
It might be worth spending some time looking at the larger code base around the areas mentioned above. The root cause may not be in this class. Good luck!
I think it's a Framework issue with keeping compiled versions consistency. It's common to see same sort of errors while updating site sources repeatedly. Just try something like
net stop iisadmin /y && del /q /f /s "%systemroot%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\*.*" && iisreset
I encountered this exception today on a webforms page. I found a solution, but I'm not sure why it worked.
Nest the code behind in a 'Namespace [YourNamespace]' tag.
Add the namespace to the html Page tag's Inherits property in the aspx page 'Inherits="PathStart.YourNameSpace.ClassName"'.
Rebuild
Navigate to the page again and you should not encounter the exception.
After following the steps above I reverted the changes and did not re-encounter the exception.

Resources