Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection inside Excel VSTO and Ninject.Extensions.Factory

I'm trying to configure DI for an Excel VSTO project.

The generated code-behind for a given worksheet offers me a event called Startup, which is reponsible to set event handlers for events like Startup, Change, BeforeDoubleClick and so on.

I think is generally a good practice do avoid code in code-behind files.
What I do is create external classes that are responsible to manipulate the worksheet and call external code like web services, databases and domain logic.

I can create successfully a Factory to be consumed by the codebehind file and instantiate the worksheet logic class.

For example:

//...inside Sheet1.cs

private IExpenseWorksheetFactory _factory;

void ExpensesBeforeRightClick(Excel.Range target, ref bool cancel)
{
    Application.EnableEvents = false;

    var popup = _factory.CreateContextMenu();
    popup.ShowContextMenu(target, ref cancel);

    Application.EnableEvents = true;
}
// ... rest of Sheet1.cs

The code above is inside the code-behind file Visual Studio generates and it's minimal. The responsibility to show the popup is delegated to a distinct object. The factory object is responsible to talk with Ninject and get the object for me. This proxy is generated automatically using Ninject.Extensions.Factory project as I pass an interface like this:

/// <summary>
/// Abstract Factory for creating Worksheet logic objects. Meant to be used with Ninject Factory extension.
/// </summary>
public interface IExpenseWorksheetFactory
{
    ExpenseWorksheet CreateWorksheet();
    ExpenseWorksheet.ContextMenus CreateContextMenu();
    ExpenseWorksheet.Events CreateEventHandlers();
}

In the application startup, I have defined the the bindings and the binding for the factory itself:

//instantiate the kernel in app's Composition Root
_kernel = new StandardKernel();

//worksheet related stuff - seems to be ok to be singleton
_kernel.Bind<ExpenseWorksheet>().ToSelf().InSingletonScope();
_kernel.Bind<ExpenseWorksheet.Events>().ToSelf().InSingletonScope();
_kernel.Bind<ExpenseWorksheet.ContextMenus>().ToSelf().InSingletonScope();

//"automagic" factories
_kernel.Bind<IExpenseWorksheetFactory>().ToFactory();

The problem is:

How can I inject this factory in the generated code of VSTO worksheet? I don't like the idea of calling _kernel.Get<IExpenseWorksheetFactory> inside the Startup method of the worksheet. Is it possible to look for all available instances of Sheet1 and force the injection of the factory?

like image 844
Mário Meyrelles Avatar asked Sep 07 '12 14:09

Mário Meyrelles


People also ask

What is ninject dependency injection?

Ninject is a lightweight dependency injection framework for . NET applications. It helps you split your application into a collection of loosely-coupled, highly-cohesive pieces, and then glue them back together in a flexible manner.

Can we use Dependency Injection in. net framework?

NET supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. Dependency injection in . NET is a built-in part of the framework, along with configuration, logging, and the options pattern.


1 Answers

Short answer: No.

You're looking for something like constructor injection, which reads admittedly more elegant. But as it is, this is not possible here because you don't have access to the c'tor in a VSTO addin.

But anyway, what's so bad in calling _kernel.Get<IExpenseWorksheetFactory>? After all, calling the DI container explicitly to resolve a dependency is one of its normal use cases, and the code-behind file is made for exactly that: Wiring things up.

You're right, that the code-behind should not contain any business logic, but on the other hand it definitely should contain all code that is required to wire things up. That's the primary reason why it exists. Or, in other words:

I think is generally a good practice do avoid code in code-behind files.

is not true in each and every case (but only for the vast majority of them) and you shouldn't overdo it here. If you do so, you'll find yourself fighting against the system - and remember, the system always wins ;-)...

like image 66
Thomas Weller Avatar answered Oct 03 '22 11:10

Thomas Weller