views:

879

answers:

3

Hi there,

I am trying to use unity to automatically inject a datacontext on my repository using a new instance each time.., my idea is the ensure that each time a new datacontext is injected

Currently its failing on creating the repository, i think it can't resolve MyDataContext

Before creating a constructor on "the repository" (see below) to take in the DataContext on my repository everything worked but now its failing..

I currently have this setup in my unity container which i create in global.asax, i have also registered the type MyDataContext which is standard DataContext

        container = new UnityContainer();

        Container.RegisterType<MyDataContext, MyDataContext>()
            .RegisterType<IOfficeRepository, OfficeRepository>()
            .RegisterType<IOfficeService, OfficeService>();

basically i have a service that calls the repository like so

public class OfficeService : IOfficeService
{

    IOfficeRepository repository = null;

    public OfficeService(IOfficeRepository repository)
    {
        this.repository = repository;

        if (this.repository == null)
            throw new InvalidOperationException("Repository cannot be null");
    }

here is my repository

public class OfficeRepository : IOfficeRepository
{
    private MyDataContext db;

    public OfficeRepository (MyDataContext dataContext)
    {
        this.db = dataContext;
    }

EDIT

I almost forgot i am doing this to create the service

officeService = Bootstrapper.Container.Resolve<IOfficeService>();

EDIT - THE ERROR BEING GENERATED

 Resolution of the dependency failed, type = "MarkSmith.IOfficeService", name = "".
 Exception message is: The current build operation (build key Build 
 Key[MarkSmith.OfficeService, null]) failed: The parameter repository could not be 
 resolved when attempting to call constructor 
 MarkSmith.OfficeService(MarkSmith.IOfficeRepository repository). (Strategy type BuildPlanStrategy, index 3)

EDIT - REMOVING Constructor on repository works

It is something to do with the datacontext because if i remove the constrcutor on the repository that takes a DataContext then all works, but of course i need it to accept a DataContext to be able to inject a "NEW" datacontext each time

public class OfficeRepository : IOfficeRepository
{
    private MyDataContext db new MyDataContext(); // CHANGE

    //public OfficeRepository (MyDataContext dataContext)
    //{
        //this.db = dataContext;
    //}

EDIT - ACTUAL ERROR

After digging deeper i have found this error ....

The type MyDataContext has multiple constructors of length 2. 
Unable to disambiguate. (Strategy type DynamicMethodConstructorStrategy, index 0)
(Strategy type BuildPlanStrategy, index 3)

EDIT - TEST TO RESOLVE THE DATACONTEXT with 1 line of code

This also fails with the same error as above - multiple constructors

  MyDataContext test = Bootstrapper.Container.Resolve<MyDataContext >();

EDIT - ALL CONSTRUCTORS ON MY DATACONTEXT

These were created by an exernal util but all should be well..

    [System.Diagnostics.DebuggerNonUserCode]
    public MyDataContext()
        : base(ConnectionString, mappingCache)
    {
        OnCreated();
    }

    [System.Diagnostics.DebuggerNonUserCode]
    public MyDataContext(string connection)
        : base(connection, mappingCache)
    {
        OnCreated();
    }

    [System.Diagnostics.DebuggerNonUserCode]
    public MyDataContext(System.Data.IDbConnection connection)
        : base(connection, mappingCache)
    {
        OnCreated();
    }

    [System.Diagnostics.DebuggerNonUserCode]
    public MyDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource)
        : base(connection, mappingSource)
    {
        OnCreated();
    }

    [System.Diagnostics.DebuggerNonUserCode]
    public MyDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource)
        : base(connection, mappingSource)
    {
        OnCreated();
    }

EDIT - To demonstrate creating the DataContext in code without Unity works 100% without issue

   MyDataContext tes2t = new MyDataContext ();
+2  A: 

I'm not sure this works, but have you tried to register MyDataContext as a component rather than a type mapping?

container.RegisterType<MyDataContext>();

instead of

container.RegisterType<MyDataContext, MyDataContext>();


EDIT based on new information

The culprit seems to be that MyDataContext has more than one constructor. This is a common issue with most DI Containers, because they need to pick and use only one. If you can remove the ambiguity by constraining MyDataContext to have only one constructor, that will probably be the simplest solution.

Otherwise, you should be able to use an InjectionConstructor instance to identify the constructor when you register the repository. Let's assume you want to use a constructor that takes a connection string as an argument:

string connectionString =
    ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
var injectedConnectionString = new InjectionConstructor(connectionString);
container.RegisterType<MyDataContext>(injectedConnectionString);
Mark Seemann
Thanks Mark, i did try that and its the same. I have updated my question with the specific error..
mark smith
Updated question also to show removing constructor works but of course i need the constructor to accept a DataContext - any ideas?
mark smith
See my updated answer.
Mark Seemann
Thanks mark! excellent thank you.. going to give it a try now.. 1 sec ! thanks
mark smith
Excellent! You sorted it it!! I learn something new everyday! I took the shortcut way as i am interested in 0 params so i did this... and it seems to work RegisterType<MyataContext>(new InjectionConstructor());
mark smith
With regards to removing the constructors, this isn't really an option due to the fact its created by an external tool and who knows one day i may need them .. :-) ... but passing in the InjectionConstructor works great
mark smith
Excellent! Thanks for the update :)
Mark Seemann
+1  A: 

I don't see your MyDataContext constructors; but try to add the [InjectionConstructor] attribute to the one you want to use.

Scott
That should work, but will tightly couple MyDataContext to Unity.
Mark Seemann
This infact does work!!! But as pointed out by Mark its tightly coupled and also my datacontext is created by an external util so the attribute would be overwritten... I really don't fully understand why unity is having an issue, i am not interested in any constructor (i.e. constructors with 2 aprams) i am only interested in the zero param constructor and of course there is only 1... Is there an alternative ???
mark smith
+2  A: 

With multiple constructors to choose from, Unity doesn't know which one to use. It will choose the one with the most arguments that can all be satisfied, but in this case there are two constructors each with two resolvable arguments.

If you don't want to couple your MyDataContext class to Unity and use the InjectionConstructor attribute as suggested by Scott (upvoted :)), you can specify the constructor that should be used at the time of registration using the fluent interface. See Configuring Constructor, Property, and Method Injection for details.

GraemeF
Thanks GraemeF, this is some great info.. Thanks for all your help..
mark smith