1

I have the structure like so:

  • MyWork.BLL
  • MyWork.DAL
  • MyWork.Interfaces
  • MyWork.Models
  • MyWork.Web

I have unity by convention setup in MyWork.Web project. It works fine when I leave Service.cs and IService.cs under MyWork.BLL. I'm trying to move IService.cs to MyWork.Interfaces for organization and decoupling. This way when working on the web project, all I have to worry about is coding against interface and add the using statment for MyWork.Interfaces. However, if I attempt to move IService.cs to the interface project, Unity by convention no longer works. Anyone know if this is possible? Do I have to always keep the interface and its implementation under the same project in order for Unity by convention to work properly? Here is my code for Unity by convention:

public static void RegisterTypes(IUnityContainer container)
    {
            container.RegisterTypes(
            AllClasses.FromLoadedAssemblies(),
            WithMappings.FromMatchingInterface,
            WithName.Default);
    }

Here is the error:

The current type, MyWork.Interfaces.IService, is an interface and cannot be constructed. Are you missing a type mapping?

Update:

UnityConfig.cs under App_Start of MyWork.Web

namespace MyWork.Web.App_Start
{
public class UnityConfig
{
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }

    public static void RegisterTypes(IUnityContainer container)
    {
        container.RegisterType<ICalculatorService, Interfaces.ICalculatorService>(); // added this per suggested answer

        container.RegisterTypes(
            AllClasses.FromLoadedAssemblies(),
            WithMappings.FromMatchingInterface,
            WithName.Default);
    }
}

}

NKD
  • 1,039
  • 1
  • 13
  • 24

1 Answers1

1

I bet the MyWork.Interfaces assembly hasn't been loaded yet. Unity's FromLoadedAssemblies call simply calls AppDomain.CurrentDomain.GetAssemblies() which by definition only returns assemblies that are loaded (not all referenced assemblies!).

There are two options here:

  1. Reference a type in the MyWork.Interfaces assembly explicitly inside your RegisterTypes methods. This ensures the assembly gets loaded.
  2. Call System.Web.Compilation.BuildManager.GetReferencedAssemblies() before calling container.RegisterTypes. The GetReferencedAssemblies() call will load all assemblies that are located in the web applications /bin folder. This will ensure that not only your Interfaces project, but all projects are loaded.
Steven
  • 166,672
  • 24
  • 332
  • 435
  • thank you for your help. Option 1 works perfectly for me. However, option 2 returns an error message "This method cannot be called during the application's pre-start initialization phase." I tried this above the register type and as well as placing it in the global.aspx file. – NKD Jun 16 '16 at 16:59
  • My thought on option 1 - I'm currently taking advantage of unity register by convention feature and if I have to explicitly specify it inside the RegisterTypes method... it somewhat defeats the purpose of "register by convention". This is why I mention in the comment above Option 1 works for me but I still want to explore Option 2. I'm hoping you can help. Thanks in advance. – NKD Jun 16 '16 at 17:05
  • 1
    Move the registration of Unity to a later point in the application startup phase. For instance to Application_Start. – Steven Jun 16 '16 at 17:12
  • My UnityConfig class is indeed under the App_Start folder of the Web project. (Just updated my question with the code for App_Start) – NKD Jun 16 '16 at 17:39
  • That's not what I meant. You should configure Unity from within the `Application_Start` method in the global asax (or at least.during that time frame). – Steven Jun 16 '16 at 17:52
  • I'm using Unity bootstrapper for ASP.NET MVC. The files are in App_Start. https://msdn.microsoft.com/en-us/library/dn507440(v=pandp.30).aspx – NKD Jun 16 '16 at 18:05
  • You can move that logic. – Steven Jun 16 '16 at 18:57
  • 1
    I apologize. This should have worked 2 hrs ago when I tried to place it in the global.aspx. I must have fat finger earlier. Anyway, I started clean again it works like a charm. Thank you for your help and your patience. Up voted your key comment :) – NKD Jun 16 '16 at 19:28
  • Splitting the registration into a PreApplicationStartMethod in order to load plugin assemblies and a second initialization phase during application start with `BuildManager.GetReferencedAssemblies` made some disturbing problems go away. Thanks. – grek40 Nov 12 '18 at 09:04