I'm using StructureMap, v. 2.5.3 and am having trouble with chaining together implementations on an interface to implement the Decorator pattern.
I'm used to Windsor, where it is possible to name variations on interface implementations and send the named impl. into another (default) impl.
This is the default, non decorated version, which works fine:
ObjectFactory.Initialize(registry =>
{
registry.ForRequestedType<ICommentService()
.TheDefault.Is.OfConcreteType<CommentService>();
... }
This is the ctor on the decorator, that I want to call:
public CommentAuditService( ICommentService commentService,
IAuditService auditService )
This works, but does not give me access to the decorated object:
registry.ForRequestedType<ICommentService>()
.TheDefault.Is.OfConcreteType<CommentService>()
.EnrichWith(x => new CommentAuditService());
This takes me int an inf. loop:
registry.ForRequestedType<ICommentService>()
.TheDefault.Is.OfConcreteType<CommentService>()
.EnrichWith(x => new CommentAuditService( new CommentService(),
new AuditService()));
So far this is what seems to me should work:
registry.ForRequestedType<ICommentService.()
.TheDefault.Is.OfConcreteType<CommentAuditService>()
.WithCtorArg("commentService")
.EqualTo(new CommentService());
However it send it into an endless loop of creating new instances of CommentAuditService
Does anyone have an quick answer? (other than switching to Castle.Windsor, which I'm very close to at the moment)
You were very close. Try:
registry.ForRequestedType<ICommentService>()
.TheDefaultIsConcreteType<CommentService>()
.EnrichWith(original => new CommentAuditService(original,
new AuditService()));
If AuditService might itself have dependencies, you would do:
registry.ForRequestedType<ICommentService>()
.TheDefaultIsConcreteType<CommentService>()
.EnrichWith((ioc, original) => new CommentAuditService(original,
ioc.GetInstance<AuditService>()));
Or, if you change the last part to:
ioc.GetInstance<IAuditService>()
you can register the concrete type of your audit service separately.
Related
I'm trying to avoid referencing the concrete type library in my main project, but I'm getting this error:
No default instance or named instance 'Default' for requested plugin type StackExchangeChatInterfaces.IClient
1.) Container.GetInstance(StackExchangeChatInterfaces.IClient ,{username=; password=; defaultRoomUrl=; System.Action`2[System.Object,System.Object]=System.Action`2[System.Object,System.Object]})
I've setup my container to scan for assemblies, like so:
var container = new Container(x =>
{
x.Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.ExcludeNamespace("StructureMap");
scan.WithDefaultConventions();
scan.AddAllTypesOf<IMessageHandlers>();
});
//x.For<IClient>().Use<Client>(); //GetInstance will work if this line is not commented out.
});
When I try to get an instance, I get the error, my code for getting an instance is here:
chatInterface = container
.With("username").EqualTo(username)
.With("password").EqualTo(password)
.With("defaultRoomUrl").EqualTo(roomUrl)
.With<Action<object, object>>(delegate(object sender, object messageWrapper)
{
string message = ((dynamic)messageWrapper).Message;
Console.WriteLine("");
Console.WriteLine(message);
foreach (var item in messageHandlers)
{
item.MessageHandler.Invoke(message, chatInterface);
}
}).GetInstance<IClient>();
If I explicitly map the concrete class to the interface, everything works hunky dory, but that means I need to reference the project that Client is in, which I don't want to do.
This is really interesting. Looks like default conventions are not able to register types with such constructor (tried on both versions 2.6.3 and 3+). I was only registered when only parameterless constructor was specified. Looking at sources of both versions it is really suspicious as it should be registered. Deeper dive into the code would be needed...
Anyway try using custom registration convention:
public class ClientConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (type.IsClass && !type.IsAbstract && !type.IsGenericType &&
type.GetInterfaces().Contains(typeof(IClient)))
{
registry.For(typeof(IClient)).Use(type);
}
}
}
Configure it like this:
var container = new Container(
c => c.Scan(
s =>
{
s.ExcludeNamespace("StructureMap");
s.WithDefaultConventions();
s.Convention<ClientConvention>();
s.AddAllTypesOf<IMessageHandlers>();
}));
and this should work just fine.
The default type scanning will not pick up concrete types whose constructor functions contain primitive arguments like strings, numbers, or dates. The thinking is that you'd effectively have to explicitly configure those inline dependencies anyway.
"but that means I need to reference the project that Client is in, which I don't want to do."
Does that actually matter? I think you're making things harder than they have to be by trying to eliminate the assembly reference.
I'm attempting to implement Dependency Injection into my architecture (MVC, DDD - Domain Model, Repository). And my architecture includes ASP.NET Identity 2.0.
At this stage, I don't want DI controlling any of the Identity 2.0 objects (UserAdminController, RolesAdminController...). I'd prefer the security objects outside of DI. At this stage, integrating the Identity objects in DI looks very difficult. I had a good look to see if someone has already done this, so I could read and learn how to do this. I couldn't find anything. (Found one post which came close, but no resolution).
Anyway, I've followed the Simple Injector MVC implementation (see standard code below), and trying many things, I believe the problem lies in me calling RegisterMvcControllers.
Correct me if I'm wrong, but this statement will pickup all controllers with their name post-fixed with "controller".
Question: How can I select which controllers get registered with Simple Injector? (Is this called manually registering?)
Any help would be greatly appreciated, as I've spent most of today trying to get my head around all this, and proceed to the next step, i.e. have DI implemented, and instantiating my objects.
...
...
... called from Application_Start()
// Create a Simple Injector container
var container = new Container();
// Configure the container
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
// Verify the container's configuration
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
private static void InitializeContainer(Container container)
{
container.Register<MyService1>();
container.Register<IMyRepositoryA, MyRepositoryA>();
// Trying to include Identity into Simple Injector - please ignore
container.Register<IUserStore<ApplicationUser>>(() => new UserStore<ApplicationUser>(new ApplicationDbContext()));
}
The RegisterMvcControllers has the following constraints on the types it registers:
The type must be public
The type must implement System.Web.Mvc.IController
The type must not be abstract
The type must not be a generic type definition
Its name must end with "Controller"
You can see what happens here in the source code.
The RegisterMvcControllers extension method calls into the SimpleInjectorMvcExtensions.GetControllerTypesToRegister method to get the list of controllers to register. You can call that method yourself to see what is registered as follows:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly())
So instead of calling RegisterMvcControllers you can register the controllers yourself by calling the GetControllerTypesToRegister method:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly());
foreach (var controllerType in registeredControllerTypes)
{
container.Register(controllerType, controllerType, Lifestyle.Transient);
}
This way you can filter out any controller you want to register manually:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly())
.Where(type => type.Name != "UserStore`1");
foreach (var controllerType in registeredControllerTypes)
{
container.Register(controllerType, controllerType, Lifestyle.Transient);
}
Another option is to override the registration:
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Options.AllowOverridingRegistrations = true;
container.Register<IUserStore<ApplicationUser>>(
() => new UserStore<ApplicationUser>(new ApplicationDbContext()))
// Always set the option back to false ASAP to prevent configuration errors.
container.Options.AllowOverridingRegistrations = false;
One can use a value, type or factory for registering an object. I have tried to find simple examples how and when to use each of a registering types, but not succeed.
It would be wonderful, if someone could give brief examples and explain the typical use cases.
Here are some links about the subject:
https://stackoverflow.com/a/21245335/2777805
http://victorsavkin.com/post/72452331552/angulardart-for-angularjs-developers-introduction-to
type
// old syntax
type(SomeType); // or
type(SomeInterface, implementedBy: SomType)
// new syntax
bind(SomeType); // or
bind(SomeInterface, toImplementation: SomType)
default, DI creates an instance and all constructor parameters (if any are resolved by DI and provided)
value
// created inline or e.g. passed in from somewhere as a parameter
// old syntax
value(new SomeType('xxx', 123));
// new syntax
bind(SomeType, toValue: new SomeType('xxx', 123));
if you want to to pass a previously instantiated instance.
I usually use this for configuration settings.
factory
// old syntax
factory(NgRoutingUsePushState,
(_) => new NgRoutingUsePushState.value(false));
// or
factory(UsersRepository, (Injector inj) => new UsersRepository(inj.get(Http)));
// new syntax
bind(NgRoutingUsePushState,toFactory:
(_) => new NgRoutingUsePushState.value(false));
bind(UsersRepository, toFactory: (Injector inj) => new UsersRepository(inj.get(Http)));
(from http://victorsavkin.com/post/72452331552/angulardart-for-angularjs-developers-introduction-to)
when you want DI to delegate the instantiation to a factory function
When I try to register my class with autofac I get the following error: "The instance registration 'GetAllDivisionsCommand' can support SingleInstance() sharing only".
I don't understand why I'm getting this error, but assume it's something to do with the class having static member variables used for caching as that's the only thing that's different about this class. I haven't had any trouble registering any other classes as either SingleInstance or InstancePerDependency.
Essentially, the class is used to retrieve a rarely changing list of divisions from the database, and caches the result. Each time the command is run, it first checks for changes on the database and then re-runs the query if changes are detected; if not, it returns the cached list.
So I am trying to register GetAllDivisionsCommand with Autofac as an IGetAllDivisionsCommand. IGetAllDivisionsCommand itself implements IInjectableCommand, which is just a marker interface, and ICachedListCommand. The concrete command class inherits from the abstract base class CachedListCommand which is where the static member variables live.
Does anyone know what would cause this error message? SingleInstance won't work for me as I can't keep reusing the same session.
Code:
Type commandType = typeof(IInjectedCommand);
Type aCommandType = typeof(GetAllDivisions);
var commands =
from t in aCommandType.Assembly.GetExportedTypes()
where t.Namespace == aCommandType.Namespace
&& t.IsClass
&& !t.IsAbstract
&& (commandType.IsAssignableFrom(t))
let iface = t.GetInterfaces().FirstOrDefault(x => "I" + t.Name == x.Name)
select new { Command = t, Interface = iface };
foreach (var cmd in commands)
{
builder.RegisterInstance(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
RegisterInstace as the name implies is for registering instances not types.
What you need is RegisterType:
foreach (var cmd in commands)
{
builder.RegisterType(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
And by the way with the Autofac scanning feature your registration code is roughly equivalent:
builder
.RegisterAssemblyTypes(aCommandType.Assembly)
.AssignableTo<IInjectedCommand>()
.InNamespace(aCommandType.Namespace)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
In my case, I did want RegisterInstance because I actually have an instance in hand that I wanted to register.
I had
builder.RegisterInstance(myInstance).InstancePerDependency();
The documentation for InstancePerDependency reads:
Configure the component so that every dependent component or call to
Resolve() gets a new, unique instance (default.)
On closer inspection, it makes sense that registering an instance with "instance per dependency" is not possible, since it is not possible for Autofac to give back a new instance each time Resolve is called if there is in fact 1 instance registered.
So, in my case, the solution was this.
builder.RegisterInstance(myInstance).SingleInstance();
The Autofac exception could possibly have been worded more clearly to explain this problem.
I'm new to MSpec and would like to know if the way I wrote my test for ASP.NET MVC is correct. The test passes but I don't really like the way it's written and it seems awkward. I'm certainly missing something.
public class AccountControllerTests3
{
protected static AccountController controller;
static IFormsAuthenticationService formsService;
static IMembershipService membershipService;
protected static ActionResult result;
protected static LogOnModel model;
Establish context = () =>
{
var controllerBuilder = new TestControllerBuilder();
formsService = MockRepository.GenerateStub<IFormsAuthenticationService>();
membershipService = MockRepository.GenerateStub<IMembershipService>();
model = MockRepository.GenerateStub<LogOnModel>();
controller =
controllerBuilder.CreateController<AccountController>(new object[]
{
formsService,
membershipService
});
};
Because user_logs = () =>
{
bool rememberMe = false;
membershipService.Stub(
x => x.ValidateUser("bdd", "mspec")).Return(true);
formsService.Stub(x => x.SignIn("bdd", rememberMe));
controller.ModelState.IsValid.ShouldBeTrue();
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_good_login_and_password : AccountControllerTests3
{
private It user_should_be_redirected_to_the_home_page = () =>
{
model.UserName = "bdd";
model.Password = "mspec";
result = controller.LogOn(model, string.Empty);
result.AssertActionRedirect().ToAction<HomeController>(
x => x.Index());
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_bad_login_and_password : AccountControllerTests3
{
It The_error_message_should_be_shown = () =>
{
model.UserName = "BAD";
model.Password = "BAD";
result = controller.LogOn(model, string.Empty);
controller.ModelState[""].Errors[0].ErrorMessage.ShouldEqual(
"The user name or password provided is incorrect.");
};
}
Thanks in advance,
Thomas
One of my goals when I write tests with MSpec is to get the "Assert" or the "It" down to one line. MSpec is not like NUnit in that it only executes the Context (made up of the Establish clauses from the current class and all base classes and the Because clause) once followed by all of the Specifications (It clauses).
This is designed explicitly to force you to not perform any behavior in the It clauses, but rather observe it.
What you're actually doing here is using MSpec like NUnit. Try and rewrite the tests in a single class (using no inheritance). Work backwards... in the It, place a single line that asserts what you want to assert. Perhaps the AssertRedirect. In the Because, try and put a single line that causes the observations to be observable. This would probably be your call to the controller's logon method. Finally, in the "Establish context" you'd want to put everything else.
After a while, you may want to pull some of the things in the Establish context only into a base class, but in doing so, be sure that your entire subclass stands alone in terms of understanding. A reader shouldn't need to read the base class in order to understand what the actual spec is doing. It's ok to hide ceremonial implementation details, but be sure to hide them behind descriptive method names.
There's another line I'm not sure about:
controller.ModelState.IsValid.ShouldBeTrue();
If this is a test, it should probably be in its own It clause. Though really, do you want to test this? What are you testing here? Shouldn't your controller take an action based on whether or not the model is valid? Shouldn't the result of that action be observable (validation error instead of login error). I just wonder if you really need to test this.
A few other things to check out, first for styling with R#, it seems your tests are falling victim to R#'s defaults. I posted about how to fight this here:
http://codebetter.com/blogs/aaron.jensen/archive/2008/10/19/getting-resharper-and-vs-to-play-nice-with-mspec.aspx
Also, James Broome has some nice MVC MSpec extensions that are worth checking out:
http://jamesbroo.me/introducing-machinespecificationsmvc/
Good luck and Enjoy! Feel free to ping me on twitter if you have any other unrelated questions.
Here's a remark: instead of using CreateController method use InitializeController, because it is compile-time safer and refactor friendlier.
Instead of:
controller = controllerBuilder.CreateController<AccountController>(
new object[] { formsService, membershipService });
Do:
controller = new AccountController(formsService, membershipService);
controllerBuilder.InitializeController(controller);
The first will still compile if you change the controller constructor arguments and it will blow at runtime, while the second will generate a compile-time error.