I develop a system with plugins, which loads assemblies at runtime. I have a common interface library, which i share between server and its plugins. But, when i perform LoadFrom for plugin folder and try to find all types, which implement common interface IServerModule i get runtime exception:
The type 'ServerCore.IServerModule' exists in both 'ServerCore.dll'
and 'ServerCore.dll'
I load plugins like this:
foreach (var dll in dlls)
{
var assembly = Assembly.LoadFrom(dll);
var modules = assembly.GetExportedTypes().Where(
type => (typeof (IServerModule)).IsAssignableFrom(type)
&& !type.IsAbstract &&
!type.IsGenericTypeDefinition)
.Select(type => (IServerModule)Activator.CreateInstance(type));
result.AddRange(modules);
}
How can i deal with this trouble?
I'll be gratefull for any help
Inspect the problem DLL and its dependencies. Chances are good that it is pulling in ServerCore.dll from a different version of .NET than your main application.
I recommend you use MEF if you want to do plugins.
Well, my solution is ugly, but works and i'll go forward for MEF in future (maybe). For now, i added such thing:
if(Path.GetFileNameWithoutExtension(dll)==Assembly.GetCallingAssembly().GetName().Name)
continue;
Thanks everybody for awesome replies
EDIT: I came up to more elegant solution, here it is:
var frameworkAssemblies =
from file in new DirectoryInfo(frameworkDirectory).GetFiles()
where (file.Extension.ToLower() == ".dll" || file.Extension.ToLower() == ".exe")
&& !AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).Contains(file.GetFileNameWithoutExtension())
select Assembly.LoadFrom(file.FullName);
Related
I am using autofac in my solution to resolve library dependencies across the different projects. The idea is to make hotplug libraries in the sense that, there are only a few core libraries that the application is dependent on, they are prefixed "vmecore.*.dll". Which must be registered with autofac before any other libraries.
Any other library that is prefixed with "vme.*.dll is are loaded, I then look for the first type that implements "IVmeExtension" - which defines an Initiate() method -, i register it, activate it and finally initialize it.
The code that does the registering of core libraries:
Directory.GetFiles(path, "vmecore.*.dll")
.Select(Assembly.LoadFile)
.ToList()
.ForEach(ass =>
{
//var validAss = Assembly.Load(ass.FullName);
builder.RegisterAssemblyTypes(ass)
.Where(t => t.IsAssignableTo<IVmeExtension>())
.SingleInstance();
//return;
// Iterate through all the types in the assembly
foreach (var type in ass.GetExportedTypes()
.Where(a => a.IsClass &&
!a.IsAbstract &&
a.Namespace != null &&
a.Namespace.Contains(#"VME")))
{
// Get the first type of IVmeExtension
if (!typeof(IVmeExtension).IsAssignableFrom(type)) continue;
//builder.RegisterType(type).SingleInstance();
coreExtension.Add(type);
break;
}
});
The snippet below is the callback delegate invoked when the container is built. Core libraries need to be resolved and initialized before hotplugged extensions since most extensions depend on them.
//Register a call back when container is built so we can resolve core extensions first
builder.RegisterBuildCallback(container =>
{
coreExtension.ForEach(ext =>
{
try
{
var inst = (IVmeExtension)container.Resolve(ext);
inst.Initiate();
Interface.LogInfo($"VME: Core extension '{inst.Name}'");
}
catch (Exception e)
{
// we log the error here.
throw;
}
});
});
The second extension that's resolved needs the former to be inject on the constructor -for this experiment i manually resolved it in the constructor to see the registered services- . The problem occurs here; I get the exception "The requested service '..' has not been registered" yet looking at the registration the type is literary there.
Screenshot
I have tried the solution suggest on this post https://github.com/autofac/Autofac/issues/593 but when i do that, I get a system pointer exception, and its very clear since when step into the activation of the instance (var inst = (IVmeExtension)container.Resolve(ext)) the IDE is actually taking me to the constructor of a completely different class - the different class is in the executing assembly -
After some time really digging, I simplified the loading of files into this:
var path = "C:\\rust server\\RustDedicated_Data\\Managed";
var coreFiles = Directory.GetFiles(path, "vmecore.*.dll");
var coreExtension = new List<Type>();
// Load each assembly into domain
foreach (var file in coreFiles)
{
var lAssembly = Assembly.LoadFile(file);
var assembly = Assembly.Load(lAssembly.FullName);
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.IsAssignableTo<IVmeExtension>())
.SingleInstance();
// Add all IVmeExtension types
coreExtension.AddRange(assembly.GetExportedTypes()
.Where(a => a.IsClass &&
!a.IsAbstract &&
a.Namespace != null &&
a.Namespace.Contains(#"VME") &&
typeof(IVmeExtension).IsAssignableFrom(a)));
}
The reason my original version was not working was because, even though the file assembly was loaded, it was not loaded into the application domain, so when I registered a type it would get a hash code -which autofac uses-. When the app was trying to resolve the type it would at this point load the assembly into the app domain. At this point all the newly loaded types have different hash codes - I assume this is what was happening-, resulting in the error I described.
Oddly enough the invalid pointer exception i mention was actually resulting when the second extension was activated and resolved its dependencies - in the right way-, one of which opened a tcp socket which had a wrongly typed ip address ( uurghh co-workers ehh )
Sometimes, simpler code is better code :)
On "normal" .NET assemblies targeting .NET Framework 4, I can use AppDomain.CurrentDomain.GetAssemblies() to get a list of all loaded assemblies.
How to do this on a Windows Universal App or on a CoreCLR application?
One way to kinda do what you want is to get the DLLs/assemblies which is located in the folder in which your app is installed (which one can assume in some cases is being used/loaded in your app).
public static async Task<List<Assembly>> GetAssemblyList()
{
List<Assembly> assemblies = new List<Assembly>();
var files = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFilesAsync();
if (files == null)
return assemblies;
foreach (var file in files.Where(file => file.FileType == ".dll" || file.FileType == ".exe"))
{
try
{
assemblies.Add(Assembly.Load(new AssemblyName(file.DisplayName)));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
return assemblies;
}
Then to loop through them you could do:
foreach (var assembly in GetAssemblyList().Result)
{
//Do something with it
}
Credits to this reddit thread/user.
How to do this on a Windows Universal App or on a CoreCLR application?
No, you can’t. Comparing with the Full.NET, the .NET for UWP only provides limited-level reflection functions.
In .NET for UWP, you can only get the assembly information by using the code below.
var assembly = this.GetType().GetTypeInfo().Assembly;
In our case, we can use AppDomain.CurrentDomain.GetAssemblies() which is in .NET Standard.
The only problem with this is that it won't find the assembly if the there are no direct code references to the project, even though there is a project reference. This was the case for us, as we use MEF to do things. To work around this, we just set up a dummy code reference.
I love "smart" compilers :)
I want to load several assemblies at runtime from my plugin directory. The core app does not have references to the assemblies beforehand, the assemblies implement an interface given by the core app, thus have a reference to it. I found and article from 2005 explaining exactly what I need to do to make this work.
Currently I have this code, which is basically a LINQ'd version of what you find in the article above:
foreach (
IModule module in
Directory.EnumerateDirectories(string.Format(#"{0}/{1}", Application.StartupPath, ModulePath))
.Select(dir => Directory.GetFiles(dir, "*.dll"))
.SelectMany(files => files.Select(Assembly.LoadFrom)
.SelectMany(assembly => (from type in assembly.GetTypes()
where type.IsClass && !type.IsNotPublic
let interfaces = type.GetInterfaces()
where
((IList) interfaces).Contains(
typeof (IModule))
select
(IModule) Activator.CreateInstance(type))))
)
{
module.Core = this;
module.Initialize();
AddModule(module);
}
So what is the current way to dynamically load plugins/modules/assemblies at runtime?
You might want to look at Microsoft Managed Extensibility Framework also this Tutorial its kinda nice intro.
I'd suggest Managed Extensibility Framework
Alternatively, if you need to load "plugins" with no need to keep a reference, there is also PRISM
Doesn't the roslyn project provide with some helpful things?
http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx
http://www.developerfusion.com/article/143896/understanding-the-basics-of-roslyn/
var scriptEngine = new ScriptEngine();
var session = Session.Create();
scriptEngine.Execute("foo.dll", session);
Aloha
Given a plug-in architecture (C# / .NET 3.5) with the plug-ins stored in the GAC, how can I list/load all dll's that contain types that implement my specific interface? In other words, I'd like to investigate which plug-ins for my application are installed on a machine, by looking in the GAC.
-Edoode
To add to BFree's answer, I suggest that you could load the assemblies for reflection only. This gives you enhanced security (the assemblies aren't able to execute at all) without appdomains, and flexibility (you can load assemblies that are for a different architecture).
First a little clarification: a DLL cannot implement an interface. The DLL contains types that could implement a specific interface. Here's a .NET wrapper around fusion.dll that allows you to enumerate all the assemblies in the GAC. Once you have loaded the assembly with Assembly.Load you can try to find all the types that implement the specific interface:
foreach (var type in assembly.GetTypes())
{
var myInterfaceType = typeof(IMyInterface);
if (type != myInterfaceType && myInterfaceType.IsAssignableFrom(type))
{
Console.WriteLine("{0} implements IMyInterface", type);
}
}
The Gac is really just a directory on your machine like any other. Here's the typical breakdown:
c:\windows\assembly\GAC
\GAC_32
\GAC_MSIL
And maybe some others..
Within each of those folders, you'll find subfolders where the actual dll's are stored. You'll first need to write a recursive method to get you all the dll's found under \assembly\, (you can find these online easily if you're not comfortable doing it yourself). Once you have that list of dll's you can proceed to use Assembly.LoadFile to load up the assembly and check all the types to see if they implement a given interface.
My only suggestion would be to load up these dll's in a seperate appdomain so that you're not allowing any potential harmful dll's to get loaded into your app.
Some links:
Searching Directories.
Loading Assemblies and checking for a given interface.
Creating new AppDomain.
You should look at the Type Selector Tool in Enterprise Library. It's probably not what you want directly, but it does what you are describing and you might be able to borrow some implementation from it.
First off, I'd recommend not doing this. To do this, you have to load all the assemblies from the GAC. I'd recommend you have your user (or an admin, or whatever) tell you what assemblies to try to load from (though for that, you might want a list of all the options, which might be why you're asking this...)
That said, this might work, but it's throwing errors for several assemblies it should work for, and I'm not sure why.... Also, I'm not sure how to detect where the GAC is -- c:\windows\assembly is the default, but I don't know where the real value is stored (registry?)
var targetType = typeof(IComparable);
var errors = new List<Exception>();
var c = Directory.GetFiles(#"c:\windows\assembly", "*.dll", SearchOption.AllDirectories).ToList()
.ConvertAll(f => Path.GetFileNameWithoutExtension(f))
.Where(f => !f.EndsWith(".ni"))
.Distinct().ToList()
.ConvertAll(f => { try { return Assembly.ReflectionOnlyLoad(f); } catch (Exception ex) { errors.Add(ex); return null; } })
.Where(a => a != null)
.SelectMany(a => { try { return a.GetTypes(); } catch (Exception ex) { errors.Add(ex); return new Type[] { }; } })
.Where(t => targetType.IsAssignableFrom(t));
Good luck with that.
How do I obtain the version number of the calling web application in a referenced assembly?
I've tried using System.Reflection.Assembly.GetCallingAssembly().GetName() but it just gives me the dynamically compiled assembly (returning a version number of 0.0.0.0).
UPDATE: In my case I needed a solution that did not require a reference back to a class within the web application assembly. Jason's answer below (marked as accepted) fulfils this requirement - a lot of others submitted here don't.
Here is some code I use that supports getting the application's "main" assembly from either Web or non-web apps, you can then use GetName().Version to get the version.
It first tries GetEntryAssembly() for non-web apps. This returns null under ASP.NET.
It then looks at HttpContext.Current to determine if this is a web application. It then uses the Type of the current HttpHandler - but this type's assembly might be a generated ASP.NET assembly if the call is made from with an ASPX page, so it traverses the HttpHandler's BaseType chain until it finds a type that isn't in the namespace that ASP.NET uses for its generated types ("ASP").
This will usually be a type in your main assembly (eg. The Page in your code-behind file). We can then use the Assembly of that Type.
If all else fails then fall back to GetExecutingAssembly().
There are still potential problems with this approach but it works in our applications.
private const string AspNetNamespace = "ASP";
private static Assembly getApplicationAssembly()
{
// Try the EntryAssembly, this doesn't work for ASP.NET classic pipeline (untested on integrated)
Assembly ass = Assembly.GetEntryAssembly();
// Look for web application assembly
HttpContext ctx = HttpContext.Current;
if (ctx != null)
ass = getWebApplicationAssembly(ctx);
// Fallback to executing assembly
return ass ?? (Assembly.GetExecutingAssembly());
}
private static Assembly getWebApplicationAssembly(HttpContext context)
{
Guard.AgainstNullArgument(context);
object app = context.ApplicationInstance;
if (app == null) return null;
Type type = app.GetType();
while (type != null && type != typeof(object) && type.Namespace == AspNetNamespace)
type = type.BaseType;
return type.Assembly;
}
UPDATE:
I've rolled this code up into a small project on GitHub and NuGet.
I find that the simplest one-liner way to get the version of your "main" assembly (instead of the dynamic one) is:
typeof(MyMainClass).Assembly.GetName().Version
Use your top-level class, which isn't likely to ever "change its meaning" or to be replaced as part of a refactoring effort, as MyMainClass. You know in which assembly this very class is defined and there can no longer be confusion as to where the version number comes from.
I prefer the Web.Config to store the current version of the site.
You can also try create an AssemblyInfo.cs file in the web application root that has the following:
using System.Reflection;
using System.Runtime.CompilerServices;
...
[assembly: AssemblyVersion("1.0.*")]
...
then access the value via the code like this:
System.Reflection.Assembly.GetExecutingAssembly()
Here is more informaiton on the AssemblyInfo class.
To add to the responders that have already posted. In order to get the assembly version in an ASP.Net web application you need to place a method in the code behind file similar to:
protected string GetApplicationVersion() {
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
In the ASPX page you want to display the version number simply place:
<%= GetApplicationVersion() %>
Just in case anyone is still interested; this should do the trick and should be a tad safer than just taking the BaseType of ApplicationInstance to get your hands on the Global.asax implementation.
Global.asax is always compiled into the same assembly as the assembly attributes from AssemblyInfo.cs, so this should work for all web applications that define a Global.asax.
For those that don't define their own Global.asax, it will fall back to the version of the generated global_asax type, which is always 0.0.0.0, and for applications that aren't web applications, it will just return no version at all.
Bonus; using the BuildManager class does not require an active HttpContext instance, which means you should be able to use this from application startup code as well.
public static Version GetHttpApplicationVersion() {
Type lBase = typeof(HttpApplication);
Type lType = BuildManager.GetGlobalAsaxType();
if (lBase.IsAssignableFrom(lType))
{
while (lType.BaseType != lBase) { lType = lType.BaseType; }
return lType.Assembly.GetName().Version;
}
else
{
return null;
}
}
HttpContext.Current.ApplicationInstance is derived from the class in the global.asax.cs. You can do the following
var instance = HttpContext.Current.ApplicationInstance;
Assembly asm = instance.GetType().BaseType.Assembly;
System.Version asmVersion = asm.GetName().Version;
It works both in ASP.NET (ASPX) and ASP.NET MVC
I encountered a similar problem, and thought you might find the solution useful.
I needed to report the current application version (of a web application project) from a custom server control, where the server control was contained in a different library. The problem was that the "easiest" assembly getters did not provide the right assembly.
Assembly.GetExecutingAssembly() returned the assembly containing the control; not the application assembly.
Assembly.GetCallingAssembly() returned different assemblies depending on where I was at in the call tree; usually System.Web, and sometimes the assembly containing the control.
Assembly.GetEntryAssembly() returned null.
new StackTrace().GetFrames()[idx].GetMethod().DeclaringType.Assembly retrieves the assembly of a frame in the stack trace at index idx; however, besides being inelegant, expensive, and prone to miscalculation on the frame index, it is possible for the stack trace to not contain any calls to the application assembly.
Assembly.GetAssembly(Page.GetType()) scored me the App_Web_##$##$%# assembly containing the dynamically generated page. Of course, the dynamic page inherits a class from my application assembly, so that led to the final solution:
Assembly.GetAssembly(Page.GetType().BaseType)
With the assembly reference in hand, you can drill to the version through its name:
var version = Assembly.GetAssembly(Page.GetType().BaseType)
.GetName()
.Version;
Now, this solution works because I had a reference to a type from the application assembly. We don't use any pages that do not inherit from a code behind, so it happens to be effective for us, but your mileage may vary if your organization's coding practices are different.
Happy coding!
Version version = new Version(Application.ProductVersion);
string message = version.ToString();
Some info here: http://www.velocityreviews.com/forums/showpost.php?p=487050&postcount=8
in asp.net 2.0 each page is built into it own assembly, so only the dll
the AssemblyInfo.cs is built into will
return the correct answer. just add a
static method to AssemblyInfo.cs that
returns the version info, and call
this method from your other pages.
-- bruce (sqlwork.com)
But I wrote a simple method to do that:
public static string GetSystemVersion(HttpServerUtility server)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(server.MapPath("~/web.config"));
System.Xml.XmlNamespaceManager ns = new System.Xml.XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("bla", "http://schemas.microsoft.com/.NetConfiguration/v2.0");
System.Xml.XmlNode node = doc.SelectSingleNode("/bla:configuration/bla:system.web/bla:authentication/bla:forms[#name]", ns);
string projectName = "";
if (node != null && node.Attributes != null && node.Attributes.GetNamedItem("name") != null)
projectName = node.Attributes.GetNamedItem("name").Value; //in my case, that value is identical to the project name (projetname.dll)
else
return "";
Assembly assembly = Assembly.Load(projectName);
return assembly.GetName().Version.ToString();
}
If you are looking for this from a web control, one hack is to find the type of the code-behind Page (ie. the class that inherits from System.Web.UI.Page). This is normally in the consumer's web assembly.
Type current, last;
current = Page.GetType();
do
{
last = current;
current = current.BaseType;
} while (current != null && current != typeof(System.Web.UI.Page));
return last;
I hope there is a better way.
The question states with no reference (instances) it did not (originally) say with no knowledge of web application types.
EDIT the OP clarified to state that yes they do really require no knowledge of types within the calling web assembly, so the answer is appropriate. However I would seriously consider refactoring such a solution such that the version is passed into the other assembly.
For most people in this scenario if you know the custom HttpApplication type:
typeof(MyHttpApplication).Assembly.GetName().Version
and if you only have a dynamic generated type:
typeof(DynamiclyGeneratedTypeFromWebApp).BaseType.Assembly.GetName().Version
Stop voting me down for this answer :)
So, I had to get the Assembly from a referenced dll.
In the asp.NET MVC/WebAPI world, there is always going to be at least one class which inherits from System.Web.HttpWebApplication. The implementation below searches for that class.
using System;
using System.Linq;
static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
The above uses System.Linq in order to find that relationship, but this can also be implemented without.
First, we get all loaded assemblies
AppDomain.CurrentDomain.GetAssemblies()
Then, enumerate through the IEnumerable<Assembly>, and get all of the types directly located in the assembly.
a.GetExportedTypes()
Then, see if any of the types inherit from System.Web.HttpWebApplication
t.BaseType?.FullName == "System.Web.HttpApplication"
In my implementation, I ensured this code would only be called once, but if that is not guaranteed, I'd highly wrapping this in a Lazy<T> or other cached lazy load implementation as it is rather expensive to keep performing the blind search.
using System;
using System.Linq;
// original method
private static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
// lazy load implementation
private static Lazy<Assembly> _webAssembly = new Lazy<Assembly>(GetWebAssembly);
public static Assembly WebAssembly { get => _webAssembly.Value; }