How to use Ninject Conventions extension without referencing Assembly (or Types within it)

1,313 views
Skip to first unread message

qstarin

unread,
Oct 26, 2010, 10:45:25 AM10/26/10
to ninject
Please allow me to cross-post my stackoverflow question (http://
stackoverflow.com/questions/4019585/how-to-use-ninject-conventions-
extension-without-referencing-assembly-or-types-w) here. I've been
trying to figure out a particular usage of
Ninject.Extensions.Conventions, but having some trouble. Any help
will be greatly appreciated!

Sorry in advance for the long question, it's long because I've been
digging at this all day.
The general problem:


<h2>The general problem:</h2>

I have an ASP.Net MVC2 application with the following projects:
MyApp.Web, MyApp.Services, MyApp.Data.

We code to interfaces and utilize Ninject 2 for DI/IoC.

However, I'm getting awfully tired of typing (and forgetting to type):

Bind<ISomeService>.To<SomeService>;

So, knowing about Ninject.Extensions.Convensions, I have attempted to
use it to automatically scan and register modules and simply
dependencies of the type IXxxx => Xxxx.


<h2>What I tried that works (but isn't quite enough):</h2>

I can use the following code to setup Ninject, and everything seems to
get wired up as expected.

public static IKernel Initialize()
{
var kernel = new StandardKernel();

kernel.Scan(a => {

a.FromAssemblyContaining<MyApp.Data.SomeDataClass>();

a.FromAssemblyContaining<MyApp.Services.SomeServiceClass>();
a.AutoLoadModules();
a.BindWithDefaultConventions();
a.InTransientScope();
});

return kernel;
}


<h2>What I want to accomplish instead:</h2>

However ... I'd like to take this a bit further in a way I think is
supported, but I cannot seem to get it working.

Since our MyApp.Web project uses nothing at all (directly) from
MyApp.Data, I am trying to avoid a reference to MyApp.Data. With the
above code, I must reference MyApp.Data from MyApp.Web because of the
compile time reference to SomeDataClass.

I would prefer to specify the name of an assembly for Ninject to scan
and register. It seems the Conventions extension supports this through
the From overloads that take a string (or enumerable of strings).


<h2>What I tried and how it breaks:</h2>

So, I've tried several variations on the From overloads:

public static IKernel Initialize()
{
var kernel = new StandardKernel();

kernel.Scan(a => {
a.From("MyApp.Data");
a.From("MyApp.Services.dll");
a.From("AnotherDependency, Version=1.0.0.0,
PublicKeyToken=null"); //etc., etc. with the From(...)'s
a.AutoLoadModules();
a.BindWithDefaultConventions();
a.InTransientScope();
});

return kernel;
}

But I receive FileNotFoundExceptions with a message like:

Could not load file or assembly 'file:///C:\Program Files
(x86)\Common Files\Microsoft Shared\DevServer\10.0\MyApp.Data' or one
of its dependencies. The system cannot find the file
specified.":"file:///C:\Program Files (x86)\Common Files\Microsoft
Shared\DevServer\10.0\


<h2>What I've found trying to solve this myself:</h2>

I've checked out the source for Ninject.Extensions.Conventions, and
I'll admit I get totally lost as to how this is supposed to work, but
I can see what it is doing.

The assembly scanner builds up a list of assemblies to scan as we call
various FromXXX methods.

When I call the From("assemblyName") method, it first checks if the
list already contains any assemblies where the
assembly.AssemblyName.Name equals the name I passed in (and
AssemblyName.Name is the simple name, i.e. MyApp.Data, according to
MSDN).

Flow passes through a couple unimportant methods, landing in the
FindAssemblies method. This method takes the name I passed in (which
we already saw is supposed to be a simple assembly name). It then
creates a new AssemblyName, with our passed in name used as the
AssemblyName.CodeBase.

Then, it attempts to Load the assembly into a temporary AppDomain.
This is the step that fails with the above exception.

Obviously, the path it's searching is wrong, but I cannot supply a
path through the From() method. That doesn't work either.

I've tried some of the other FromXXX methods, but I've gotten nowhere
and spent too much time on this already. The FromAssembliesInPath and
FromAssembliesMatching also do not work because, again, it is
searching in the completely wrong directory.


<h2>Uh .. what was the question again:</h2>

Can anyone explain how to get Ninject Conventions to load assemblies
by name, without creating a reference to the assembly and loading it
by specifying a contained type? Please.

I've already searched through pages and pages of the Ninject google
group, and I've read it's only (so it seems) relevant documentation
and haven't been able to solve this .. yet.

Remo Gloor

unread,
Oct 26, 2010, 1:04:15 PM10/26/10
to ninject
Hi

The assemblies must reside in a probing path of the application.
Otherwise you would have a different set of problems such as switching
the loading context from loadfrom to load.
See: http://msdn.microsoft.com/en-us/library/823z9h8w%28VS.80%29.aspx
about how to define a probing path.

Secondly, From(x) takes the path of an assembly. I consider changing
this in a comming version to accept full qualified names as well.

Remo

qstarin

unread,
Oct 26, 2010, 1:13:37 PM10/26/10
to ninject
I'm not seeing how the probing paths would be related to this.

From the exception details, it seems the only location checked for the
assemblies is C:\Program Files(x86)\Common Files\Microsoft Shared
\DevServer\10.0\ (when running under Visual Studio in debug mode),
and there are *none* of my project files there. Furthermore, the
assemblies should be right beside the assembly in which Ninject is
setup (and therefore in the probing path already), as they are
currently referenced and CopyLocal is set to true. It seems that
instead of the base directory being at all related to my web
application, it is instead related to the host application.

And then, if From(x) takes a *path*, I cannot see how the method would
work since, as I found in the source, it checks that parameter
directly against the list of AssemblyName.Name's it already has. If I
pass in a path, that would never match. Unless I missed something in
there.

Remo Gloor

unread,
Oct 28, 2010, 4:42:44 AM10/28/10
to ninject
Did you try or do you just assume?

It searches C:\Program Files(x86)\Common Files\Microsoft Shared
\DevServer\10.0\ as this it the working directory when running web
apps in the debugger. As I said the string is a path. Either specify a
full path or a relative path from the working dir and make sure the
assembly is located in a probing path (There are already some by
default). I know It is a bit complicated at the moment and not really
implemented with web apps in mind. But I added to the tasklist that it
should support full qualified names to make it a bit easier.

-Remo

Remo Gloor

unread,
Nov 3, 2010, 1:51:32 PM11/3/10
to ninject
Support for full qualified file names has been added.
Reply all
Reply to author
Forward
0 new messages