I have a SysMsgManager class defined in CoreService project as following:
public class SysMsgManager
{
private ISysMsgRepository _SysMsgRepository;
public SysMsgManager()
{
_SysMsgRepository = ObjectFactory.GetInstance<ISysMsgRepository>();
}
....
}
In my DataAccess project I have 'ISysMsgRepository' interface and two concrete implementations defined as following:
namespace DataAccess.Repository
{
[Pluggable("Default")]
public class SysMsgRepository : ISysMsgRepository
{
...
}
}
namespace DataAccess.Repository
{
[Pluggable("Stub")]
public class SysMsgRepository_Test : ISysMsgRepository
{
...
}
}
and this is what I have in my StructureMap.config file
<StructureMap>
<Assembly Name="CoreService" />
<Assembly Name="DataAccess" />
<PluginFamily
Assembly="DataAccess"
Type="DataAccess.Repository.ISysMsgRepository"
DefaultKey="Default" />
</StructureMap>
When I try to run my app, I got the following error:
StructureMap Exception Code: 202\nNo Default Instance defined for PluginFamily DataAccess.Repository.ISysMsgRepository, DataAccess, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Can anyone help me to solve this problem? Thanks!
Unfortunately I have little familiarity with configuring StructureMap via Xml. Let me show you how it is done using C#.
var container = new Container(config=>
{
config.For<ISysMsgRepository>().Use<SysMsgRepository>();
});
It seems you are using the standard naming convention for your interfaces and classes (just tacking an I onto the front of the class name). If you do that for all your types you can just configure your container like this:
var container = new Container(config=>
{
config.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
});
I hope this helps. It is much easier to configure your container using code rather than Xml. Give it a try. You'll be a convert.
Related
I'm currently working through this code snippet from a design patterns book:
public static class DomainEvents
{
public static IDomainEventHandlerFactory DomainEventHandlerFactory { get; set; }
public static void Raise<T>(T domainEvent) where T : IDomainEvent
{
DomainEventHandlerFactory.GetDomainEventHandlersFor(domainEvent).ForEach(h => h.Handle(domainEvent));
}
}
This deals with wiring up DomainEvents, and this particular code snippet is responsible allowing me to raise an event via the Raise method on DomainEvents.
Here is the code in my Bootstrapper file:
public class ControllerRegistry : Registry
{
public ControllerRegistry()
{
ForRequestedType<IDomainEventHandlerFactory>().TheDefault.Is.OfConcreteType<StructureMapDomainEventHandlerFactory>();
ForRequestedType<IDomainEventHandler<OrderSubmittedEvent>>().AddConcreteType<OrderSubmittedHandler>();
}
}
When I go to access DomainEvents.Raise from my Service layer (in this example, I'm raising the OrderSumittedEvent), DomainEvents is null (when it should be set via StructureMap):
public class OrderService
{
public void Create(Order order)
{
DomainEvents.Raise(new OrderSubmittedEvent() { Order = order });
}
}
Unless I explicitly set the DomainEvents.DomainEventHandlerFactory by hand to StructureMapDomainEventHandlerFactory like this:
public class OrderService
{
public void Create(Order order)
{
// this is the manual assignment I have to make into the DomainEventHandlerFactory of
// the static DomainEvents class. Basically, this is what StructureMap should take care
// of for me, but is not.
DomainEvents.DomainEventHandlerFactory = new StructureMapDomainEventHandlerFactory();
DomainEvents.Raise(new OrderSubmittedEvent() { Order = order });
}
}
Below is the output of StrucutureMap using .WhatDoIHave(), and it appears that StructureMap does have a configured instance of StructureMapDomainEventHandlerFactory for type IDomainEventHandlerFactory. Here is the dump:
================================================================================================================================================================================================================================================================================================================================================================================================
PluginType Name Description
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Func`1<TResult> (Func`1<TResult>)
Scoped as: Transient
311731d7-60c7-46de-9ef4-24608f21df04
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IDomainEventHandlerFactory (DE.Infrastructure.Domain.Events.IDomainEventHandlerFactory) dbcb010c-fa92-4137-85b8-161ab17c2c98 Configured Instance of DE.Infrastructure.Domain.Events.StructureMapDomainEventHandlerFactory, DE.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Scoped as: Transient
dbcb010c-fa92-4137-85b8-161ab17c2c98 Configured Instance of DE.Infrastructure.Domain.Events.StructureMapDomainEventHandlerFactory, DE.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IDomainEventHandler`1<OrderSubmittedEvent> (IDomainEventHandler`1<OrderSubmittedEvent>) DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Configured Instance of DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Scoped as: Transient
DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Configured Instance of DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IContainer (StructureMap.IContainer) e24f9e45-caaf-48b6-89f7-d8125310102a Object: StructureMap.Container
Scoped as: Transient
e24f9e45-caaf-48b6-89f7-d8125310102a Object: StructureMap.Container
================================================================================================================================================================================================================================================================================================================================================================================================
I've used StructureMap, but I haven't used Setter Injection, nor have I had to deal with using StructureMap with static classes (if that even makes sense), so I'm a little lost as to why this code won't work.
Is it possible to use Setter Injection with a static implementation of a class like this?
Am I not using StructureMap properly?
Should StructureMap be responsible for creating the DomainEvents class as a Singleton, and I can get rid of the static implementation?
Thanks,
Mike
Is it possible to use Setter Injection with a static implementation of a class like this?
No. It is only possible with createable classes.
Am I not using StructureMap properly?
You are not. Dependency injection deals with creating and providing instances. By definition static classes are non-createable in code and therefore, non-injectable.
Should StructureMap be responsible for creating the DomainEvents class as a Singleton, and I can get rid of the static implementation?
It looks like a core feature of this design is to use a single instance so the event is only fired once. I am not sure what design pattern you are going for, but in many cases you can substitute Action<T> or Func<T> for events, and if you use the singleton lifestyle properly you can probably register a single instance that can be shared between all of your classes rather than resorting to a static class.
If the static event is absolutely required, you can inject an instance of IDomainEventHandlerFactory in your application startup code by resolving the instance and setting it manually after you have completed your registration code (in your composition root).
// Provide the DI container with configuration
var container = DIConfig();
// Set the static event
DomainEvents.DomainEventHandlerFactory = container.Resolve<IDomainEventHandlerFactory>();
To ensure your application doesn't abuse the setter by calling it more than once or using it before it is set, you can put some guard clauses in your static class.
public static class DomainEvents
{
private static IDomainEventHandlerFactory domainEventHandlerFactory;
public static IDomainEventHandlerFactory DomainEventHandlerFactory
{
get
{
return domainEventHandlerFactory;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
if (domainEventHandlerFactory != null)
throw new ArgumentException("DomainEventHandlerFactory is already set and cannot be set again.");
domainEventHandlerFactory = value;
}
}
public static void Raise<T>(T domainEvent) where T : IDomainEvent
{
ThrowIfNotInitialized()
DomainEventHandlerFactory.GetDomainEventHandlersFor(domainEvent).ForEach(h => h.Handle(domainEvent));
}
private static void ThrowIfNotInitialized()
{
if (domainEventHandlerFactory == null)
{
throw new MvcSiteMapException("Not initialized. You must set DomainEventHandlerFactory at application start.");
}
}
}
First off, here's the code:
Binding in the NinjectControllerFactory
class MrBigglesworthServices : NinjectModule
{
public override void Load()
{
Bind<IAuthenticationRepository>()
.To<AuthenticationRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["VoiceDB"].ConnectionString
);
Bind<IAppRepository>()
.To<AppRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["SessionStore"].ConnectionString
);
}
}
Constructor for the Search Controller:
private IAppRepository appRepository;
public SearchController(IAppRepository appRepository)
{
this.appRepository = appRepository;
}
Based on what I've seen with online examples, this should be enough, but for some reason, it's bringing up the error mentioned above. Any suggestions? Please and thank you.
Because you mention using a NinjectControllerFactory I think you are using an incorrect implementation. Consider to switch to https://github.com/ninject/ninject.web.mvc/wiki/MVC3 instead. This is a widely used integration of Ninject and MVC3.
I am Using Entity Framework 4.0 calling the below mentioned code from asp.net. I have a address table in which I need to insert some data. my code is :
IRepository<Address> addressRepository;
int addressHOCODE = 0;
try
{
**addressRepository = ObjectFactory.GetInstance<IRepository<Address>>();**
addressRepository.Add(address);
addressRepository.SaveChanges();
addressHOCODE = address.HOCODE;
}
catch ...
At the addressRepository = ObjectFactory.GetInstance<IRepository<Address>>(); line, we're getting the following error.
StructureMap Exception Code: 202 No
Default Instance defined for
PluginFamily
Domain.IRepository`1[[Data.Address,
DataAccessLayerNew, Version=1.0.0.0,
Culture=neutral,
PublicKeyToken=null]],
DataAccessLayerNew, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null
Looks like you worked this out for yourself, but to help others who might come across this page, I'd expect to see something like this in the Global.asax.cs file:
using System;
namespace Host
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start (object sender, EventArgs e) {
ObjectFactory.Configure(config =>
{
config.For<IRepository>().Use<ConcreteRepository>();
});
}
}
}
This is what the current code looks like:
public static class WidgetFactory
{
public static AbstractWidget CreateWidget(WidgetSpec spec)
{
if (spec.ModelNo == "FOO")
return new FooWidget(spec);
if (spec.ModelNo == "BAR")
return new BarWidget(spec);
if (spec.ModelNo == "BOO")
return new BooWidget(spec);
}
}
This is my implementation that uses DI:
app.config
<components>
<component id="FOO"
service="MyCo.App.AbstractWidget"
type="MyCo.App.FooWidget, MyApp"
lifestyle="transient" />
<component id="BAR"
service="MyCo.App.AbstractWidget"
type="MyCo.App.BarWidget, MyApp"
lifestyle="transient" />
....
</components>
Code
static class WidgetFactory
{
static IWindsorContainer _container =
new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
public static AbstractWidget CreateWidget(WidgetSpec spec)
{
return _container.Resolve<AbstractWidget>(spec.ModelNo, new { widgetSpec = spec });
}
}
Is this the correct approach? What am I overlooking/doing wrong/misunderstanding? Should I create interfaces for the abstract classes and return them from the factory instead?
(I would prefer to stick to XML configuration for this particular application)
Edit:
Suggestion by Krzysztof Koźmic:
public interface IFactory
{
AbstractFactory CreateWidget(WidgetSpec widgetSpec);
void ReleaseWidget(AbstractFactory widget);
}
public class CustomTypedFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
WidgetSpec widgetSpec = arguments[0] as WidgetSpec;
if (method.Name == "CreateWidget" && arguments.Length == 1 && widgetSpec != null)
{
// The component mappings are stored as config settings
// for the sake of example
var componentName = Properties
.Settings
.Default
.Properties[widgetSpec.ModelNo]
.DefaultValue.ToString();
return componentName;
}
return base.GetComponentName(method, arguments);
}
}
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IFactory>().AsFactory(c => c.SelectedWith(new CustomTypedFactoryComponentSelector())));
//...
var factory = container.Resolve<IFactory>();
var widgetFactory = factory.CreateWidget(widgetSpec);
You could use Typed Factory with custom selector (see this post for an example and the documentation).
When answering questions about dependency injection here on SO, I almost always say: "use a factory". I think your solution looks pretty good ;-)
Perhaps there still is some room for improvement, though.
Because the factory is a static type, you have no choice than calling that directly from code. This makes it hard to test that code (if testability is a concern of course). What you might try is to inject the factory as a dependency in the types you are using. So instead of having a hard dependency on a static type, create a dependency on an interface. This could look like this:
public interface IWidgetFactory
{
AbstractWidget CreateWidget(WidgetSpec spec);
}
internal class WidgetFactory : IWidgetFactory
{
// code
}
Now you can easily register this type by its interface:
<component
service="MyCo.App.IWidgetFactory, MyApp"
type="MyCo.App.WidgetFactory, MyApp"
lifestyle="singleton" />
Now you can request an IWidgetFactory from the container, or even better, inject the IWidgetFactory as constructor argument on the types that need to use it:
public class TypeUsingWidgets
{
private IWidgetFactory widgetFactory;
public TypeUsingWidgets(IWidgetFactory widgetFactory)
{
this.widgetFactory = widgetFactory;
}
public void MethodUsingWidgets()
{
var widget = this.factory.CreateWidget("Foo");
}
}
Perhaps this is beneficial for your application.
I am trying to configure the NCommon NHRepository in my project with Structure Map. How do I stop it from choosing the greediest constructor?
public class NHRepository<TEntity> : RepositoryBase<TEntity>
{
public NHRepository () {}
public NHRepository(ISession session)
{
_privateSession = session;
}
...
}
My structure map configuration
ForRequestedType(typeof (IRepository<>))
.TheDefaultIsConcreteType(typeof(NHRepository<>))
Cheers
Jake
You can set the [DefaultConstructor] Attribute for the constructor you wish as a default. In your case, setting it on the NHRepository() constructor would make it the default constuctor for StructureMap to initialize.
Update: well, in the latest version of StructureMap, using .NET 3.5 you can also specify it using the SelectConstructor method:
var container = new Container(x =>
{
x.SelectConstructor<NHRepository>(()=>new NHRepository());
});
Finally, I'm sure you would be able to define it in the XML configuration of StructureMap, but I haven't used that. You could do a little search on it. For more information on the above method, see: http://structuremap.sourceforge.net/ConstructorAndSetterInjection.htm#section3
So +1 for Razzie because this would work if the NHRepository was in my own assembly, instead I choose to wrap the NHRepository with my own Repository like below..
public class Repository<T> : NHRepository<T>
{
[DefaultConstructor]
public Repository()
{
}
public Repository(ISession session)
{
}
}
ForRequestedType(typeof (IRepository<>))
.TheDefaultIsConcreteType(typeof (Repository<>));