Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I configure StructureMap to use a generic repository?

I have an interface IGenericRepository<TEntity> where TEntity : IEntity and an implementation GenericRepository<TEntity> where TEntity : Entity.

I'm trying to inject a specific IGenericRepository<Section> into a class using StructureMap:

    ObjectFactory.Initialize(x =>
        {
            x.For(typeof(IGenericRepository<>)).Use(typeof(GenericRepository<>));
        });

But when I try to use ObjectFactory.GetInstance<IGenericRepository<Section>>(); I get:

StructureMap Exception Code: 202 No Default Instance defined for PluginFamily System.Data.Common.DbConnection

Any ideas why this is or what I'm doing wrong?

Thanks in advance,

Simon

like image 320
simonjreid Avatar asked May 14 '10 15:05

simonjreid


3 Answers

You are receiving in your GenericRepository's constructor a DbConnection, which is an abstract class, and are not configuring SM to know which specific class should use for it.

i.e.:

 ObjectFactory.Initialize(x =>
        {
            x.For(typeof(DbConnection)).Use(typeof(SqlConnection));
            x.For(typeof(IGenericRepository<>)).Use(typeof(GenericRepository<>));
        });
like image 195
eglasius Avatar answered Nov 17 '22 09:11

eglasius


I had this exact same problem:

Have a Generic Repository:

public interface IRepository<TEntity> : IDisposable where TEntity : class
    { }

and a Concrete Implementation:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    { }

which i wanted injected into the constructor of the Controllers at runtime where the TEntity would be the Model relevant to that Controller:

public FooBarController(IRepository<FOO_BAR_TYPE> repository)
        {
            _repo = repository;
        }

the Controller would then use Repository "_repo" to update the Model:

//
// POST: /EmergencyServiceType/Create
[HttpPost]
public ActionResult Create(FOO_BAR_TYPE foobar)
{
    if (ModelState.IsValid)
    {            
        // GetNextSequenceValue() deals with Oracle+EF issue with auto-increment IDs
        foobar.FOO_BAR_ID = _repo.GetNextSequenceValue(); 
        _repo.Add(foobar);
        _repo.SaveChanges();
        return RedirectToAction("Index");  
    }

    return View(foobar); // display the updated Model
}

simonjreid elluded to the answer for me: had to add the ObjectContext to the StructureMap configuration (the Repository's purpose was to wrap up the Context generated by EntityFramework, which i called MyContextWrapper. Therefore because the Repository depended on MyContextWrapper, which in turn depends on ObjectContext):

// This avoids 'No Default Instance for ...DbConnection' exception
x.For<System.Data.Objects.ObjectContext>().Use<MyContextWrapper>();
x.For<System.Web.Mvc.IController>().Use<Controllers.FooBarController>().Named("foobarcontroller"); // note that Named is required and is Case Sensitive

However, now i get the StructureMap runtime Exception:

StructureMap Exception Code: 205 Missing requested Instance property "connectionString"

After reading a post by Jeremy Miller A Gentle Quickstart (right at the bottom) i found that you can define what arguments to pass into the constructor of your registered types ie i needed to pass in the Connection String to the Constructor of the MyCustomContext class (here is the full listing of how i am initializing the ObjectFactory:

string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["MyContextWrapper"].ConnectionString;
ObjectFactory.Initialize(x =>
            {
                x.Scan(scan =>
                        {
                            // Make sure BUSINESS_DOMAIN assembly is scanned
                            scan.AssemblyContainingType<BUSINESS_DOMAIN.MyContextWrapper>(); 
                            scan.TheCallingAssembly();
                            scan.WithDefaultConventions();
                        });
                // 'connStr' below is a local variable defined above
                x.For<System.Data.Objects.ObjectContext>()
                    .Use<MyContextWrapper>()
                    .Ctor<string>().Is(connStr);
                x.For<System.Web.Mvc.IController>().Use<Controllers.FooBarController>().Named("foobarcontroller"); 
            });

And BOOM! Can now have my Controller instaniated at runtime by StructureMap and get it to inject an instance of IRepository...happy days.

like image 4
HellspawnDeveloper Avatar answered Nov 17 '22 09:11

HellspawnDeveloper


What is your constructor like for GenericRepository<>?

It or one of its dependencies is expecting a DbConnection that SM can't create.

like image 3
Andrew Bullock Avatar answered Nov 17 '22 09:11

Andrew Bullock