Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UNITY: passing in a new datacontext each time?

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 ();
like image 861
mark smith Avatar asked Nov 08 '09 12:11

mark smith


3 Answers

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);
like image 89
Mark Seemann Avatar answered Oct 20 '22 22:10

Mark Seemann


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.

like image 28
GraemeF Avatar answered Oct 20 '22 23:10

GraemeF


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

like image 1
Scott Avatar answered Oct 21 '22 00:10

Scott