What's the difference between these two Struct

2019-07-10 00:05发布

问题:

We're struggling with understanding the difference between these two ways to configure StructureMap. Our understanding is that they should be identical but we get different results between these two lines inside of Initialize:

ObjectFactory.Initialize(x =>
{
    x.For<IBusinessRelationsContext>().Use<BusinessRelationsContext>().Ctor<string>().Is(ConfigurationManager.ConnectionStrings["BusinessRelationsContext"].ConnectionString);
    x.For<IBusinessRelationsContext>().Use(_ => new BusinessRelationsContext(ConfigurationManager.ConnectionStrings["BusinessRelationsContext"].ConnectionString));
});

(we only use 1 of the two at a time - not both, obviously)

Our various constructor signatures on this object (it's EF4 stuff if you care):

public BusinessRelationsContext();
public BusinessRelationsContext(string connectionString);
public BusinessRelationsContext(EntityConnection connection);

The code we use to invoke this is:

ObjectFactory.TryGetInstance<IBusinessRelationsContext>();

The difference in behavior that we see is that the line that includes Ctor<string> fails because StructureMap fails with a 202 "No Default Instance defined for PluginFamily System.Data.Common.DbConnection" (we have no idea why it thinks it needs this). However, if I comment that line out and use the other one, it works perfectly as we would expect. Given that the other one works, I suspect that my understanding that it shouldn't need config for DbConnection is correct.

So rather than tracking down WHY it needs the DbConnection I would rather track down the answer to my question: What's the difference between these two?

回答1:

I think StructureMap is selecting the most complex constructor to try to create your datacontext. What you have defined up there with the Ctor call is a definition on how to define that class using a less complex constructor.

So your definition isn't incorrect, it's just that StructureMap isn't calling the constructor you think it's supposed to be calling.

Note: I usually use your second call, since I know what constructor will be called, even if you have to add new ones for testing or other purposes.

x.For<IBusinessRelationsContext>().Use(_ => new BusinessRelationsContext(ConfigurationManager.ConnectionStrings["BusinessRelationsContext"].ConnectionString));


回答2:

So I had somebody offline help me with this (didn't think I'd have any offline resources on this!) and the problem is as Khalid Abuhakmeh explained - it's picking the most complex one (the "greediest" - read more here).

Now that we know the problem, we can look for the solution. In my case (and the case of those commenting here), the solution is to add a line like so:

x.SelectConstructor<IBusinessRelationsContext>(() => new BusinessRelationsContext(""));