My problems is that I want to register two types for one interface:
I've checked this articles:
https://groups.google.com/forum/#!msg/structuremap-users/2T_WTAjRVJ8/HKsELqJEOi4J
https://groups.google.com/forum/#!topic/structuremap-users/75-1AV1boMw
For<IPageManager>().Singleton().Use<PageManager>().Named("pageManager");
For<IPageManager>().Singleton().Use<EnhancedPageManager>().Named("enhancedPageManager");
And in my controllers:
public class ValuesController
{
public ValuesController(IPageManager pageManger)
{
// Here I want to be instance of page Manager
}
}
public class PagesController
{
public PagesController(IPageManager enhancedPageManger)
{
// Here I want to be instance of enhancedPageManger
}
}
But the problems is that I always receive instance of enhancedPageManger.
How to fix that ?
In the documentation there are example of configuration, but not the usage: http://structuremap.github.io/glossary/#sec3
var container = new Container(c =>
{
c.For<IFoo>().Use<Foo>();
c.For<IFoo>().Add<SomeOtherFoo>();
});
Related
Until recently I used AutoFac which had the method AsImplementedInterfaces()
which does
Register the type as providing all of its public interfaces as services (excluding IDisposable).
that means (for example a service) I have some base interface and an interface for every concerte service-class
See the simple code below:
public interface IService {}
public interface IMyService: IService
{
string Hello();
}
public class MyService: IMyService
{
public string Hello()
{
return "Hallo";
}
}
// just a dummy class to which IMyService should be injected
// (at least that's how I'd do it with AutoFac.
public class MyClass
{
public MyClass(IMyService myService) { }
}
Basically I want to inject my service's interface (so to speak) and not the concrete service.
Now I have to use StructureMap but I struggle to find what I need.
There is AddAllTypesOf<T> but this would register the concrete type.
is this even possible with StructureMap and if so how?
so, I found the answer(s)
1.
first you could use
public class TestRegistry : Registry
{
public TestRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.RegisterConcreteTypesAgainstTheFirstInterface();
});
}
}
this will register every concrete class against the first interface which might be too broad.
2.
if so you can use the following code I adapted from http://structuremap.github.io/registration/auto-registration-and-conventions/.
I had to change Each() to foreach because of compilation errors and made the whole class generic.
public class AllInterfacesConvention<T> : IRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
// Only work on concrete types
foreach (var type in types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed).Where(x => typeof(T).IsAssignableFrom(x)))
{
if(type == typeof(NotInheritedClass))
{
continue;
}
// Register against all the interfaces implemented
// by this concrete class
foreach (var #interface in type.GetInterfaces())
{
registry.For(#interface).Use(type);
}
}
}
}
if you take the code sample from the link every concrete type would be included. With my changes only concerte classes which inherit from T will be included.
in your registry you would use it like that
public class TestRegistry : Registry
{
public TestRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.Convention<AllInterfacesConvention<YOUR_BASE_INTERFACE>>();
});
}
}
Be aware the structuremap's GetInstance will always resolve concrete classes no matter if you previously registered them.
See here https://stackoverflow.com/a/4807950/885338
I've been playing around with SimpleInjector and I'm trying to register properly all command handlers.
Here is my code:
CQRS.cs
public interface ICommand {}
public interface ICommandDispatcher
{
void Execute(ICommand command);
}
public class CommandDispatcher : ICommandDispatcher
{
private readonly Container container;
public CommandDispatcher(Container container)
{
this.container = container;
}
public void Execute(ICommand command)
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
dynamic handler = container.GetInstance(handlerType);
handler.Handle((dynamic)command);
}
}
public interface ICommandHandler<in TParameter> where TParameter : ICommand
{
void Handle(TParameter command);
}
Handler.cs
public class UserCommandsHandler : ICommandHandler<CreateUser>
{
public void Handle(CreateUser message)
{
var user = new User(message.Email);
/* logic here */
}
}
Command.cs
public class CreateUser : ICommand
{
public readonly string Email;
public CreateUser(string email)
{
Email = email;
}
}
Global.asax.cs
var assemblies = new[] { typeof(ICommandHandler<>).Assembly };
var container = new SimpleInjector.Container();
container.RegisterCollection(typeof(ICommandHandler<>), assemblies);
container.RegisterSingleton<ICommandDispatcher>(new CommandDispatcher(container));
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
HomeController.cs
public class HomeController : Controller
{
private readonly ICommandDispatcher _commandDispatcher;
public HomeController(ICommandDispatcher commandDispatcher)
{
_commandDispatcher = commandDispatcher;
}
public ActionResult Index()
{
var command = new CreateUser("email#example.com");
_commandDispatcher.Execute(command);
return Content("It works");
}
}
at CQRS.cs
dynamic handler = container.GetInstance(handlerType);
I get:
No registration for type ICommandHandler<CreateUser> could be found.
There is, however, a registration for IEnumerable<ICommandHandler<CreateUser>>;
Did you mean to call GetAllInstances<ICommandHandler<CreateUser>>() or depend on IEnumerable<ICommandHandler<CreateUser>>?
The Simple Injector API clearly separates between registrations for collections and one-to-one mappings. In your composition root, you are making the following registration:
container.RegisterCollection(typeof(ICommandHandler<>),
new[] { typeof(ICommandHandler<>).Assembly });
The API Documentation for RegisterCollection states:
Registers a collection of serviceTypes, whose instances will be resolved lazily each time the resolved collection of serviceType is enumerated. The underlying collection is a stream that will return individual instances based on their specific registered lifestyle, for each call to IEnumerator<T>.Current. The order in which the types appear in the collection is the exact same order that the items were registered, i.e the resolved collection is deterministic.
In other words, you are allowing command handlers to be resolved as collections, by requesting IEnumerable<ICommandHandler<T>>.
In your CommandDispatcher however, you request a single ICommandHandler<T> by calling container.GetInstance(handlerType). Since there is no one-to-one mapping for an ICommandHandler<T>, Simple Injector informs you about this by throwing:
No registration for type ICommandHandler<CreateUser> could be found.
There is, however, a registration for IEnumerable<ICommandHandler<CreateUser>>;
Did you mean to call GetAllInstances<ICommandHandler<CreateUser>>() or depend on IEnumerable<ICommandHandler<CreateUser>>?
To fix this, there are two options:
Either you register your handlers using the one-to-one mapping, or
You resolve a collection of handlers within your CommandDispatcher by calling GetAllInstances(Type).
Since there will always be a one-to-one mapping between a command and its handler (meaning: there will be exactly one handler per command), option 1 is the most obvious solution. So change your registration to the following:
// Use 'Register' instead of 'RegisterCollection'.
container.Register(typeof(ICommandHandler<>),
new[] { typeof(ICommandHandler<>).Assembly });
Hello Experts I have class in folowing structure
public class Apple:IApple
{
public IBall _ball{get;private set}
public Apple()
{
_ball=new Ball();
}
}
Public class Cat:ICat
{
private readonly IBall _ball;
Public Cat(IBall ball)
{
this._ball=ball
}
}
I am configuring my structure map as below (Not displayed standard registry and controller registry with controller conventions)
ObjectFactory.Container.Configure(cfg =>
{
cfg.For<IApple>().Use<Apple>();
cfg.For<ICat>.Use<Cat>();
});
When I reference ICat in Controller as below
private readonly ICat _cat;
public HomeController(ICat cat)
{
this._cat = cat;
}
I am receiving error "No default Instance is registered and cannot be automatically determined for type IBall".
Experts, please provide some suggestions.
You should register IBall like this:
cfg.For<IBall>().Use(c => ((Apple)c.GetInstance<IApple>())._ball);
I have this interface:
public interface IUserProfileService
{
// stuff
}
Implemented by:
public class UserProfileService : IUserProfileService
{
private readonly string m_userName;
public UserProfileService(string userName)
{
m_userName = userName;
}
}
I need this injected into a controller like this:
public class ProfilesController : BaseController
{
private readonly IUserProfileService m_profileService;
public ProfilesController(IUserProfileService profileService)
{
m_profileService = profileService;
}
}
I don't know how I can register this interface and its implementation into Ninject container so that userName param is passed in when the Ninject inits an instance of this service.
Any ideas how I can achieve this?
The technical ninject answer is to use constructor arguments like so:
Bind<IUserProfileService>().To<UserProfileService>().WithConstructorArgument("userName", "karl");
Of course you need to figure out where "karl" comes from. It really depends on your app. Maybe its a web app and it's on the HttpContex? I don't know. If it gets rather complicated then you might want to write a IProvider rather than doing a regular binding.
One alternative is to inject a factory and create your dependency using Create(string userName).
public class UserProfileServiceFactory
{
public IUserProfileService Create(string userName)
{
return new UserProfileService(userName);
}
}
It might seem off to have to create another class but the benefits mostly comes when UserProfileService takes in additional dependencies.
The trick is to not inject the username in that class. You call this class a service so it would probably work transparantly with multiple users. I see two solutions:
Inject an abstraction into the service that represents the current user:
public class UserProfileService : IUserProfileService
{
private readonly IPrincipal currentUser;
public UserProfileService(IPrincipal currentUser)
{
this.currentUser = currentUser;
}
void IUserProfileService.SomeOperation()
{
var user = this.currentUser;
// Do some nice stuff with user
}
}
Create an implementation that is specific to the technology you are working with, for instance:
public class AspNetUserProfileService : IUserProfileService
{
public AspNetUserProfileService()
{
}
void IUserProfileService.SomeOperation()
{
var user = this.CurrentUser;
// Do some nice stuff with user
}
private IPrincipal CurrentUser
{
get { return HttpContext.Current.User; }
}
}
If you can, go with option one.
How can I mock a DataServiceQuery for unit testing purpose?
Long Details follow:
Imagine an ASP.NET MVC application, where the controller talks to an ADO.NET DataService that encapsulates the storage of our models (for example sake we'll be reading a list of Customers). With a reference to the service, we get a generated class inheriting from DataServiceContext:
namespace Sample.Services
{
public partial class MyDataContext : global::System.Data.Services.Client.DataServiceContext
{
public MyDataContext(global::System.Uri serviceRoot) : base(serviceRoot) { /* ... */ }
public global::System.Data.Services.Client.DataServiceQuery<Customer> Customers
{
get
{
if((this._Customers==null))
{
this._Customers = base.CreateQuery<Customer>("Customers");
}
return this._Customers;
}
}
/* and many more members */
}
}
The Controller could be:
namespace Sample.Controllers
{
public class CustomerController : Controller
{
private IMyDataContext context;
public CustomerController(IMyDataContext context)
{
this.context=context;
}
public ActionResult Index() { return View(context.Customers); }
}
}
As you can see, I used a constructor that accepts an IMyDataContext instance so that we can use a mock in our unit test:
[TestFixture]
public class TestCustomerController
{
[Test]
public void Test_Index()
{
MockContext mockContext = new MockContext();
CustomerController controller = new CustomerController(mockContext);
var customersToReturn = new List<Customer>
{
new Customer{ Id=1, Name="Fred" },
new Customer{ Id=2, Name="Wilma" }
};
mockContext.CustomersToReturn = customersToReturn;
var result = controller.Index() as ViewResult;
var models = result.ViewData.Model;
//Now we have to compare the Customers in models with those in customersToReturn,
//Maybe by loopping over them?
foreach(Customer c in models) //*** LINE A ***
{
//TODO: compare with the Customer in the same position from customersToreturn
}
}
}
MockContext and MyDataContext need to implement the same interface IMyDataContext:
namespace Sample.Services
{
public interface IMyDataContext
{
DataServiceQuery<Customer> Customers { get; }
/* and more */
}
}
However, when we try and implement the MockContext class, we run into problems due to the nature of DataServiceQuery (which, to be clear, we're using in the IMyDataContext interface simply because that's the data type we found in the auto-generated MyDataContext class that we started with). If we try to write:
public class MockContext : IMyDataContext
{
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers { get { /* ??? */ } }
}
In the Customers getter we'd like to instantiate a DataServiceQuery instance, populate it with the Customers in CustomersToReturn, and return it. The problems I run into:
1~ DataServiceQuery has no public constructor; to instantiate one you should call CreateQuery on a DataServiceContext; see MSDN
2~ If I make the MockContext inherit from DataServiceContext as well, and call CreateQuery to get a DataServiceQuery to use, the service and query have to be tied to a valid URI and, when I try to iterate or access the objects in the query, it will try and execute against that URI. In other words, if I change the MockContext as such:
namespace Sample.Tests.Controllers.Mocks
{
public class MockContext : DataServiceContext, IMyDataContext
{
public MockContext() :base(new Uri("http://www.contoso.com")) { }
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers
{
get
{
var query = CreateQuery<Customer>("Customers");
query.Concat(CustomersToReturn.AsEnumerable<Customer>());
return query;
}
}
}
}
Then, in the unit test, we get an error on the line marked as LINE A, because http://www.contoso.com doesn't host our service. The same error is triggered even if LINE A tries to get the number of elements in models.
Thanks in advance.
I solved this by creating an interface IDataServiceQuery with two implementations:
DataServiceQueryWrapper
MockDataServiceQuery
I then use IDataServiceQuery wherever I would have previously used a DataServiceQuery.
public interface IDataServiceQuery<TElement> : IQueryable<TElement>, IEnumerable<TElement>, IQueryable, IEnumerable
{
IDataServiceQuery<TElement> Expand(string path);
IDataServiceQuery<TElement> IncludeTotalCount();
IDataServiceQuery<TElement> AddQueryOption(string name, object value);
}
The DataServiceQueryWrapper takes a DataServiceQuery in it's constructor and then delegates all functionality to the query passed in. Similarly, the MockDataServiceQuery takes an IQueryable and delegates everything it can to the query.
For the mock IDataServiceQuery methods, I currently just return this, though you could do something to mock the functionality if you want to.
For example:
// (in DataServiceQueryWrapper.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return new DataServiceQueryWrapper<TElement>(_query.Expand(path));
}
// (in MockDataServiceQuery.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return this;
}
[Disclaimer - I work at Typemock]
Have you considered using a mocking framework?
You can use Typemock Isolator to create a fake instance of DataServiceQuery:
var fake = Isolate.Fake.Instance<DataServiceQuery>();
And you can create a similar fake DataServiceContext and set it's behavior instead of trying to inherit it.