Can NInject load modules/assemblies on demand? - assemblies

Are there facilities in NInject that will allow me to load services from other modules (assemblies) on demand like it's done in Unity?

I'm pretty sure this is what you're looking for:
var kernel = new StandardKernel();
kernel.Load( Assembly.Load("yourpath_to_assembly.dll");
If you look at KernelBase with reflector in Ninject.dll you will see that this call will recursively load all modules in the loaded assemblies (Load method takes an IEnumerable)
public void Load(IEnumerable<Assembly> assemblies)
{
foreach (Assembly assembly in assemblies)
{
this.Load(assembly.GetNinjectModules());
}
}

I don't quite understand what you mean by "Like Unity" but you can do a few different things for loading assemblies. Ninject itself will load local assemblies for extensions/plugins by default. Ninject can also load NinjectModule classes from assemblies. If you want to do something more complex, you can use the Ninject.Extensions.Conventions project to do a lot of different scanning and type binding.

If you're referring to loading Assemblies non-statically out of the box, no it doesnt.
There are many other questions on this, e.g., Using Ninject in a plugin like architecture

Related

Loading all referenced assemblies .NET even if not used explicitly in code

We have a windows service which is using Autofac, when we try to load the referenced assemblies not all are listed as some contain objects we aren't using anywhere in the application but interface implementations are in there we need to be included. The following method loads the assemblies:
private IEnumerable<Assembly> GetReferencedAssemblies(Assembly assembly)
{
var assemblyNames = assembly.GetReferencedAssemblies();
List<Assembly> assemblies = new List<Assembly>();
assemblies.Add(assembly);
foreach (var item in assemblyNames)
{
var loadedAssembly = System.Reflection.Assembly.Load(item.FullName);
assemblies.Add(loadedAssembly);
}
return assemblies;
}
If we make a dummy reference to an object contained in the assembly then it loads the assembly and the types are built by autofac, if we remove the dummy object the assembly is no longer included.
Is there any way to include all referenced assemblies regardless of whether you are directly using an object in there (bearing in mind we still need it as the interface implementations are in there).
This works fine on ASP.NET as it just loads all DLLs in the bin.
If you do not actually reference a type in the assembly the compiler will remove the reference as it is assumed to be redundant. You need to manually load the required assemblies into the AppDomain using Assembly.Load(). How you determine the assemblies to load is up to you. You might choose to look through the files in a particular folder or you perhaps use a configuration file that contains the assemblies names.

Unable to load assembly in new appDomain

I have an mvc3 application.
I have a subfolder in my application project called "Plugins"
All of the dll's stored in that folder should be updateable during runtime, so then we an put down the appdomain and reload the new version of the dlls, so I am attemping to load all the plugin dll's in a different appDomain and set it's shadowCopy properties.
Looking through SO, msdn and some blogs, I got to this "solution". (this is called during my Application_Start)
static AppDomain pluginDomain;
static PluginHolder()
{
AppDomainSetup domainSetup = AppDomain.CurrentDomain.SetupInformation;
domainSetup.ApplicationName = "Plugins";
domainSetup.PrivateBinPathProbe = domainSetup.PrivateBinPath;
domainSetup.PrivateBinPath = GetPluginsDirectory();
domainSetup.ShadowCopyFiles = "true";
domainSetup.ShadowCopyDirectories = domainSetup.PrivateBinPath;
pluginDomain= AppDomain.CreateDomain("Plugins", null, domainSetup);
var item = pluginDomain.Load(File.ReadAllBytes(GetPluginsDirectory() + "Item.dll"));
}
"Item.dll" is the dll i am attemping to load. The last line throws a "Could not load file or assembly Item or one of its dependencies".
This seems to be the way other people have succeded with, but it just wont work for me.
I have no previous experience with AppDomains, so I am not sure on how to approach this problem, or if I am tackling it correctly.
Is my Assembly loading via the new AppDomain an ok approach?
To decypher these kind of error messages, you should use the Assembly Binding Log Viewer.
Also pay attention on the remarks section on the documentation page of AppDomain.Load(byte[]). If you want to load the assembly on the new AppDomain, then you should use CreateInstanceAndUnwrap instead.
If you want to implement a plugin engine in .NET, then you will need to understand AppDomains, assembly resolving and loading and a then choose on a mechanism for the communication between objects from different AppDomains. Most good books on .NET and CLR include a chapter or two on AppDomains and they will get you up to speed. Now as far as the cross-AppDomain communication is concerned, you could use WCF or .NET Remoting (MarshalByRefObject).
Good luck.

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.

Can I combine local resources in satellite assemblies?

I have a lot of local resourse files
/Controls/App_LocalResources/SomeControl.ascx.resx,
/Pages/App_LocalResources/SomePage.aspx.resx, etc.
I want to add another language and I do not want to go through all folders and add SomeControl.ascx.de.resx files for example and then have to recompile the whole think.
I would like to use satellite assemblies and embed all the files into something like MyWebPage.de.dll
This was possible in VS2003 version for global resources, but I'm not sure can I do it in VS2008 version for local resources?
I am accessing the resource with the syntax:
<asp:label id="lblSomething" runat="server" meta:resourcekey="labelFirstName"/>
Your question isn't really too clear on whether you are looking for a feature of VS2008 or a feature of the ASP.NET framework. So I'll go with the code solution.
The implicit binding syntax you're using uses ASP.NET's default LocalResourceProvider which takes in the path of page under which the resources live to work out which resources to load. If your resources are stored elsewhere and you still want to use the implicit binding systax in your code in front you'll need to use your own Provider. Sounds complicated but it's fairly straightforward.
To do this you'll need to first subclass ResourceProviderFactory
and override both
IResourceProvider CreateGlobalResourceProvider(string classKey)
IResourceProvider CreateLocalResourceProvider(string virtualPath)
...then implement your own IResourceProvider that gets your resources from your satellite assemblies using a ResourceManager
public interface IResourceProvider
{
object GetObject(string resourceKey, CultureInfo culture);
IResourceReader ResourceReader { get; }
}
You then need to add configuration to your web.config file to let ASP.NET know to use your SatelliteResourceProviderFactory and move your resources in to your external assemby, but that should be you good to go.
Plenty of documentation can be found here...under the "Building a Database Resource Provider" section...
http://msdn.microsoft.com/en-us/library/aa905797.aspx#exaspnet20rpm_topic4

Problem reflecting in ASP.net context

I have a ASP.net application that is referencing a external assembly that I need to dynamically load and discover any types implementing a known interface. The problem I am having is that the type I reflect does not match the same interface that is running and so I cannot cast it.
Example:
This code is run in ASP.net app.
var assembly = Assembly.LoadFile(Path.Combine(HttpRuntime.BinDirectory, "ExternalAssembly.dll"));
var type = assembly.GetExportedTypes().First<Type>(x => x.Name == "AClass"); // AClass implements IAInterface
var reflectedInterface = type.GetInterface(typeof(IAmAInterface).ToString());
if (reflectedInterface != typeof(IAmAInterface))
throw new Exception("This makes me sad"); // This code gets run
The only difference I can see between the reflected interface I loaded from the bin and the interface returned from typeof is that the typeof assembly has a location in the temp ASP.net path (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\08c43c8b\3adac8cf\assembly\dl3\eb7a4127\0235ea60_a3c8c901\ReflectionTest.DLL)
Thanks Paul Alexander I have changed the code to use the Assembly.Load method not Assembly.LoadFile which solves the problem.
wwilden: I also tried extracting the interface into it's own assembly and this does also solve the problem.
When you use LoadFile the assembly is not loaded into the same context as your other assemblies at runtime so to the CLR interface runtime types are different. You can read more in Suzanne Cook's Debugging Assembly Load Failures.
If the assembly that you're loading is already in the Bin directory - you can load it by name. You don't need to know the exact path as the Bin folder is already in the assembly probing path.
Where is your interface type defined? Does it exist both in the reflected assembly as well as in the application itself? Then you actually have two different interfaces, even though they have the same namespace and name.
What you need to do is extract the interface from the reflected assembly and put it into another assembly that you refer to both from the reflected assembly as well as your application. Then it should work.
Apart from your problem, if you have a lot of assemblies to dynamically load, remember that they will remain in memory until the ASP.NET worker process reloads. This could influence your server's performance.
You could load the assemblies in a separate AppDomain (the smallest unit that is possible to unload), load a proxy class in that AppDomain which you reference with .NET remoting. Once finished, you unload the AppDomain.
There is an interesting article over at CodeProject about a situation like this. Where you have a class that has a structure that is identical with an interface without implementing the interface itself. The article outlines a method of dynamically creating wrapper classes that implement the needed interface. It could be helpful in your situation.

Resources