Ninject Circular Dependencies - dependency-injection

there are 2 classes in wpf app
First class
public class Context1 : BaseContext
{
private readonly Page1 _page1;
public Context1(Page1 page1)
{
_page1 = page1;
}
}
Second class
public class Context2 : BaseContext
{
private readonly Page2 _page2;
public Context2(Page2 page2)
{
_page2 = page2;
}
}
Configuration
container = new StandardKernel();
container.Bind<Page1>().ToMethod(context => new Page1() { DataContext = container.Get<Context1>() });
container.Bind<Page2>().ToMethod(context => new Page2() { DataContext = container.Get<Context2>() });
on start stackoverflow exception appears, how to resolve?

The Context requires a Page and the Page requires a Context, so it is a circular dependency. I would recommend refactoring some of the behaviors of each into standalone services so that at least one of them can get its dependencies from the services and break the circular reference.

Related

SaveChanges() and adding to DB not working

I am working on adding Entity Framework to our web app, asp.net MVC 5, but I am having a hardtime saving changes and adding to the database. I set up UnitOfWork with a generic BaseRepository, and I have tried a few things attempting to get this to work. first, I thought I could inject, with AutoFac, my repo in UnitOfWork like so
public UnitOfWork(IServiceItem serviceItem
, ITechServiceItem techServiceItem
, ITechnicianTime technicianTime
, ISproc sproc
, IRepairOrder repairOrder
, ICustomer customer
, IRepairOrderStatus repairOrderStatus
, IRepairOrderUnit repairOrderUnit
, IFiles files
, IPartInventory partInventory
, IRepairOrderItems repairOrderItems
)
{
RepairOrderItems = repairOrderItems;
PartInventory = partInventory;
Files = files;
RepairOrderUnit = repairOrderUnit;
RepairOrderStatus = repairOrderStatus;
RepairOrder = repairOrder;
Customer = customer;
Sproc = sproc;
ServiceItem = serviceItem;
TechServiceItem = techServiceItem;
TechnicianTime = technicianTime;
}
and my BaseRepo is like
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected DataDbContext _db;
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected DataDbContext _db;
internal void GetData()
{
if (_db == null)
{
string accountNumber = HttpContext.Current.User.Identity.GetCompanyAccountNumber();
var connectionToken = ConfigurationManager.AppSettings["LoginSplitToken"];
_db = new DataDbContext(ConfigurationManager.ConnectionStrings["NameOfConnString"].ConnectionString.Replace(connectionToken, accountNumber));
}
}
public TEntity Get(int id)
{
return _db.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return _db.Set<TEntity>().ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _db.Set<TEntity>().Where(predicate);
}
public void Add(TEntity entity)
{
_db.Set<TEntity>().Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
_db.Set<TEntity>().AddRange(entities);
}
public void Remove(TEntity entity)
{
_db.Set<TEntity>().Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
_db.Set<TEntity>().RemoveRange(entities);
}
public int CompleteData()
{
return _db.SaveChanges();
}
public TEntity Get(int id)
{
return _db.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return _db.Set<TEntity>().ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _db.Set<TEntity>().Where(predicate);
}
public void Add(TEntity entity)
{
_db.Set<TEntity>().Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
_db.Set<TEntity>().AddRange(entities);
}
public void Remove(TEntity entity)
{
_db.Set<TEntity>().Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
_db.Set<TEntity>().RemoveRange(entities);
}
public int CompleteData()
{
return _db.SaveChanges();
}
}
and my StartUp.Configuration
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
HttpConfiguration config = GlobalConfiguration.Configuration;
// REGISTER DEPENDENCIES
builder.RegisterType<EverLogicDbContext>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerRequest();
builder.Register(c => HttpContext.Current.User).InstancePerRequest();
builder.Register(c => app.GetDataProtectionProvider()).InstancePerRequest();
builder.RegisterType<ApplicationUserStore>().As<IUserStore<EverLogicMamber, int>>()
.WithParameter(new TypedParameter(typeof(ISecurityOfWork), new SecurityOfWork(new SecurityDbContext())))
.InstancePerRequest();
//Database
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
builder.RegisterType<SecurityOfWork>().As<ISecurityOfWork>().InstancePerRequest();
//Service
builder.RegisterType<TechnicianTimeService>().As<ITechnicianTimeService>().InstancePerRequest();
builder.RegisterType<PartService>().As<IPartService>().InstancePerRequest();
builder.RegisterType<TechServiceItemService>().As<ITechServiceItemService>().InstancePerRequest();
//Repo
builder.RegisterType<Company>().As<ICompany>().InstancePerRequest();
builder.RegisterType<Views>().As<IViews>().InstancePerRequest();
builder.RegisterType<RepairOrderItems>().As<IRepairOrderItems>().InstancePerRequest();
builder.RegisterType<PartInventory>().As<IPartInventory>().InstancePerRequest();
builder.RegisterType<Files>().As<IFiles>().InstancePerRequest();
builder.RegisterType<TechDashboardService>().As<ITechDashboardService>().InstancePerRequest();
builder.RegisterType<RepairOrderUnit>().As<IRepairOrderUnit>().InstancePerRequest();
builder.RegisterType<RepairOrderStatus>().As<IRepairOrderStatus>().InstancePerRequest();
builder.RegisterType<Customer>().As<ICustomer>().InstancePerRequest();
builder.RegisterType<ServiceItem>().As<IServiceItem>().InstancePerRequest();
builder.RegisterType<RepairOrder>().As<IRepairOrder>().InstancePerRequest();
builder.RegisterType<Sproc>().As<ISproc>().InstancePerRequest();
builder.RegisterType<TechServiceItem>().As<ITechServiceItem>().InstancePerRequest();
builder.RegisterType<TechnicianTime>().As<ITechnicianTime>().InstancePerRequest();
// REGISTER CONTROLLERS SO DEPENDENCIES ARE CONSTRUCTOR INJECTED
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
builder.RegisterWebApiModelBinderProvider();
var container = builder.Build();
// REPLACE THE MVC DEPENDENCY RESOLVER WITH AUTOFAC
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
ConfigureAuth(app);
}
But with this set up, the database does not update or add new entitys.
Then i tryed removing Dependcy injection from UnitOfWork and set UnitOfWork up like
protected DataDbContext _db;
public UnitOfWork(DataDbContext context)
{
GetData();
RepairOrderItems = new RepairOrderItems(_db);
PartInventory = new PartInventory(_db);
Files = new Files(_db);
RepairOrderUnit = new RepairOrderUnit(_db);
RepairOrderStatus = new RepairOrderStatus(_db);
RepairOrder = new RepairOrder(_db);
Customer = new Customer(_db);
Sproc = new Sproc(_db);
ServiceItem = new ServiceItem(_db);
TechServiceItem = new TechServiceItem(_db);
TechnicianTime = new TechnicianTime(_db);
}
internal void GetData()
{
if (_db == null)
{
string accountNumber = HttpContext.Current.User.Identity.GetCompanyAccountNumber();
var connectionToken = ConfigurationManager.AppSettings["LoginSplitToken"];
_db = new DataDbContext(ConfigurationManager.ConnectionStrings["NameOfConnString"].ConnectionString.Replace(connectionToken, accountNumber));
}
}
and moving SaveChanges from the BaseRepo to UnitOfWork, but still nothing is saving or adding to the database.
What am i missing????
TL;DR the problem is that all your repositories are using separate, independent DbContexts, so the DbContext injected into your UnitOfWork has no pending changes when you call SaveChanges on it, so that's why you aren't seeing any change to the database.
In order for the Unit of Work to function correctly, your UnitOfWork class, and all the repository classes which your code needs to perform data persistence, must all share the same DbContext instance. In your code, it's clear that each repository has a factory method to create it's own, independent DbContext instance.
Remove the GetData() factory method from your BaseRepository class, and instead, require an instance of your EverLogicDbContext instance to injected to the constructor of BaseRepository by AutoFac. This will require that all your Repository subclasses also need to have a constructor accepting this same EverLogicDbContext.
As per your last edit, the UnitOfWork class must accept the same, shared EverLogicDbContext that the repositories use. Since you've tagged with asp.net-mvc then RequestPerInstance lifetime scope is correct for your scenario.
Your UnitOfWork class needs to control the SaveChanges(Async) method, so remove the CompleteData method from the BaseRepository class.
As you already seem to have done, the DbContext needs to be registered InstancePerRequest:
builder.RegisterType<EverLogicDbContext>().AsSelf().InstancePerRequest();
If all this is tied together correctly:
AutoFac will create an instance of your concrete DbContext the first time it is needed during processing of each Request.
All Repositories will then share the same DbContext instance for the lifetime of the Request, and the DbContext will track interim changes made by your services.
The UnitOfWork injected into your main "business logic" (e.g. Controller, or Orchestrator / Handler) will then be able to Commit the actions taken by simply calling SaveChangesAsync on the shared DbContext. This will all happen under a single database connection, so will be a lightweight transaction.
As per other comments above, IMO Entity Framework is a already high level framework with transactional support built-in, so there's little point in over-engineering a "UnitOfWork" pattern if all the ACID activity will be conducted against the same Database (and can be wrapped into the same DbContext).

Dependency injection in Xunit project

I am working on an ASP.Net Core MVC Web application.
My Solution contains 2 projects:
One for the application and
A second project, dedicated to unit tests (XUnit).
I have added a reference to the application project in the Tests project.
What I want to do now is to write a class in the XUnit Tests project which will communicate with the database through entity framework.
What I was doing in my application project was to access to my DbContext class through constructor dependency injection.
But I cannot do this in my tests project, because I have no Startup.cs file. In this file I can declare which services will be available.
So what can I do to get a reference to an instance of my DbContext in the test class?
You can implement your own service provider to resolve DbContext.
public class DbFixture
{
public DbFixture()
{
var serviceCollection = new ServiceCollection();
serviceCollection
.AddDbContext<SomeContext>(options => options.UseSqlServer("connection string"),
ServiceLifetime.Transient);
ServiceProvider = serviceCollection.BuildServiceProvider();
}
public ServiceProvider ServiceProvider { get; private set; }
}
public class UnitTest1 : IClassFixture<DbFixture>
{
private ServiceProvider _serviceProvider;
public UnitTest1(DbFixture fixture)
{
_serviceProvider = fixture.ServiceProvider;
}
[Fact]
public void Test1()
{
using (var context = _serviceProvider.GetService<SomeContext>())
{
}
}
}
But bear in your mind using EF inside a unit test is not a good idea and it's better to mock DbContext.
The Anatomy of Good Unit Testing
You can use Xunit.DependencyInjection
For unit tests you need to mock your context.
There is a great nuget package for mocking that is called Moq.
Some help to get you started:
public ClassName : IDisposable
{
private SomeClassRepository _repository;
private Mock<DbSet<SomeClass>> _mockSomeClass;
public ClassName()
{
_mockSomeClass = new Mock<DbSet<SomeClass>>();
var mockContext = new Mock<IApplicationDbContext>();
mockContext.SetupGet(c => c.SomeClass).Returns(_mockSomeClass.Object);
_repository = new SomeClassRepository(mockContext.Object);
}
public void Dispose()
{
// Anything you need to dispose
}
[Fact]
public void SomeClassTest()
{
var someClass = new SomeClass() { // Initilize object };
_mockSomeClass.SetSource(new[] { someClass });
var result = _repository.GetSomethingFromRepo( ... );
// Assert the result
}
}
For integration tests you do the same thing but the setup is:
_context = new ApplicationDbContext();
Make sure that your TestClass inherits from IDisposable (TestClass : IDisposable) so that you can dispose the context after each test.
https://xunit.github.io/docs/shared-context
You can to use package Microsoft.EntityFrameworkCore.InMemory
var _dbContextOptions = new DbContextOptionsBuilder<DbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
And then
var context = new DbContext(_dbContextOptions);

Unable to inject Automapper and other layers using structuremap

I am implementing AutoMapper and structureMap in my WebAPI solution. I am unable to inject automapper using structuremap .I also want to inject my DAL,BAL and API layers. How do I do that with structure Map. I googled and thought I found a solution but that seems incompatible with the latest version of structure map. DefaultRegistry class doesnt compile. It doesnt find keywords MapperConfiguration, IMapperConfiguration, IMapper Please see my code below
AutoMapper
public class DomainToDtoMapping : Profile
{
public DomainToDtoMapping()
{
CreateMap<BaseEntity, BaseDto>().ReverseMap();
CreateMap<Movie, MoviesDto>().ReverseMap();
}
}
DefaultRegistry class in Webapi project
public class DefaultRegistry : Registry {
#region Constructors and Destructors
public DefaultRegistry() {
var profiles = from t in typeof(DefaultRegistry).Assembly.GetTypes()
where typeof(Profiles).IsAssignableFrom(t)
select (Profiles) Activator.CreateInstance(t);
//For each Profile, include that profile in the MapperConfiguration
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
//Create a mapper that will be used by the DI container
var mapper = config.CreateMapper();
//Register the DI interfaces with their implementation
For<IMapperConfiguration>().Use(config);
For<IMapper>().Use(mapper);
//Register the UserRepository and pass instance of Mapper to its constructor
For<IMovieBusiness>().Use<MovieBusiness>()
.Ctor<IMapper>().Is(mapper);
For<IConnectionFactory>().Use<ConnectionFactory>();
For<IMovieRepository>().Use<MovieRepository>();
For<IUnitOfWork>().Use<UnitOfWork>();
For<IMovieService>().Use<MovieService>();
For<IMovieBusiness>().Use<MovieBusiness>();
}
DataAccess Layer
public class MovieRepository : GenericRepository<Movie>, IMovieRepository
{
IConnectionFactory _connectionFactory;
public MovieRepository(IConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
}
public class MovieService : IMovieService
{
IUnitOfWork _unitOfWork;
public MovieService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
}
Business Access Layer
public class MovieBusiness: IMovieBusiness
{
IMovieService _movieService;
public MovieBusiness(IMovieService movieService)
{
_movieService = movieService;
}
}
WebAPI
public class MoviesController : ApiController
{
IMovieBusiness _movieBusiness;
public MoviesController(IMovieBusiness movieBusiness)
{
_movieBusiness = movieBusiness;
}
}

How to new up an object independent of the container? [duplicate]

I'm trying to implement IoC in my windows form application. My choice fell on Simple Injector, because it's fast and lightweight. I also implement unit of work and repository pattern in my apps. Here is the structure:
DbContext:
public class MemberContext : DbContext
{
public MemberContext()
: base("Name=MemberContext")
{ }
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();\
}
}
Model:
public class Member
{
public int MemberID { get; set; }
public string Name { get; set; }
}
GenericRepository:
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
internal DbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
}
MemberRepository:
public class MemberRepository : GenericRepository<Member>, IMemberRepository
{
public MemberRepository(DbContext context)
: base(context)
{ }
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
public DbContext context;
public UnitOfWork(DbContext context)
{
this.context = context;
}
public void SaveChanges()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
MemberService:
public class MemberService : IMemberService
{
private readonly IUnitOfWork unitOfWork;
private readonly IMemberRepository memberRepository;
public MemberService(IUnitOfWork unitOfWork, IMemberRepository memberRepository)
{
this.unitOfWork = unitOfWork;
this.memberRepository = memberRepository;
}
public void Save(Member member)
{
Save(new List<Member> { member });
}
public void Save(List<Member> members)
{
members.ForEach(m =>
{
if (m.MemberID == default(int))
{
memberRepository.Insert(m);
}
});
unitOfWork.SaveChanges();
}
}
In Member Form I only add a textbox to input member name and a button to save to database. This is the code in member form:
frmMember:
public partial class frmMember : Form
{
private readonly IMemberService memberService;
public frmMember(IMemberService memberService)
{
InitializeComponent();
this.memberService = memberService;
}
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
memberService.Save(member);
}
}
I implement the SimpleInjector (refer to http://simpleinjector.readthedocs.org/en/latest/windowsformsintegration.html) in Program.cs as seen in the code below:
static class Program
{
private static Container container;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(new frmMember((MemberService)container.GetInstance(typeof(IMemberService))));
}
private static void Bootstrap()
{
container = new Container();
container.RegisterSingle<IMemberRepository, MemberRepository>();
container.Register<IMemberService, MemberService>();
container.Register<DbContext, MemberContext>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Verify();
}
}
When I run the program and add a member, it doesn't save to database. If I changed container.Register to container.RegisterSingle, it will save to database. From the documentation, RegisterSingle will make my class to be a Singleton. I can't using RegisterLifeTimeScope because it will generate an error
"The registered delegate for type IMemberService threw an exception. The IUnitOfWork is registered as 'Lifetime Scope' lifestyle, but the instance is requested outside the context of a Lifetime Scope"
1) How to use SimpleInjector in Windows Form with UnitOfWork & Repository pattern?
2) Do I implement the patterns correctly?
The problem you have is the difference in lifestyles between your service, repository, unitofwork and dbcontext.
Because the MemberRepository has a Singleton lifestyle, Simple Injector will create one instance which will be reused for the duration of the application, which could be days, even weeks or months with a WinForms application. The direct consequence from registering the MemberRepository as Singleton is that all dependencies of this class will become Singletons as well, no matter what lifestyle is used in the registration. This is a common problem called Captive Dependency.
As a side note: The diagnostic services of Simple Injector are able to spot this configuration mistake and will show/throw a Potential Lifestyle Mismatch warning.
So the MemberRepository is Singleton and has one and the same DbContext throughout the application lifetime. But the UnitOfWork, which has a dependency also on DbContext will receive a different instance of the DbContext, because the registration for DbContext is Transient. This context will, in your example, never save the newly created Member because this DbContext does not have any newly created Member, the member is created in a different DbContext.
When you change the registration of DbContext to RegisterSingleton it will start working, because now every service, class or whatever depending on DbContext will get the same instance.
But this is certainly not the solution because having one DbContext for the lifetime of the application will get you into trouble, as you probably already know. This is explained in great detail in this post.
The solution you need is using a Scoped instance of the DbContext, which you already tried. You are missing some information on how to use the lifetime scope feature of Simple Injector (and most of the other containers out there). When using a Scoped lifestyle there must be an active scope as the exception message clearly states. Starting a lifetime scope is pretty simple:
using (ThreadScopedLifestyle.BeginScope(container))
{
// all instances resolved within this scope
// with a ThreadScopedLifestyleLifestyle
// will be the same instance
}
You can read in detail here.
Changing the registrations to:
var container = new Container();
container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
container.Register<IMemberRepository, MemberRepository>(Lifestyle.Scoped);
container.Register<IMemberService, MemberService>(Lifestyle.Scoped);
container.Register<DbContext, MemberContext>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
and changing the code from btnSaveClick() to:
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
using (ThreadScopedLifestyle.BeginScope(container))
{
var memberService = container.GetInstance<IMemberService>();
memberService.Save(member);
}
}
is basically what you need.
But we have now introduced a new problem. We are now using the Service Locator anti pattern to get a Scoped instance of the IMemberService implementation. Therefore we need some infrastructural object which will handle this for us as a Cross-Cutting Concern in the application. A Decorator is a perfect way to implement this. See also here. This will look like:
public class ThreadScopedMemberServiceDecorator : IMemberService
{
private readonly Func<IMemberService> decorateeFactory;
private readonly Container container;
public ThreadScopedMemberServiceDecorator(Func<IMemberService> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Save(List<Member> members)
{
using (ThreadScopedLifestyle.BeginScope(container))
{
IMemberService service = this.decorateeFactory.Invoke();
service.Save(members);
}
}
}
You now register this as a (Singleton) Decorator in the Simple Injector Container like this:
container.RegisterDecorator(
typeof(IMemberService),
typeof(ThreadScopedMemberServiceDecorator),
Lifestyle.Singleton);
The container will provide a class which depends on IMemberService with this ThreadScopedMemberServiceDecorator. In this the container will inject a Func<IMemberService> which, when invoked, will return an instance from the container using the configured lifestyle.
Adding this Decorator (and its registration) and changing the lifestyles will fix the issue from your example.
I expect however that your application will in the end have an IMemberService, IUserService, ICustomerService, etc... So you need a decorator for each and every IXXXService, not very DRY if you ask me. If all services will implement Save(List<T> items) you could consider creating an open generic interface:
public interface IService<T>
{
void Save(List<T> items);
}
public class MemberService : IService<Member>
{
// same code as before
}
You register all implementations in one line using Batch-Registration:
container.Register(typeof(IService<>),
new[] { Assembly.GetExecutingAssembly() },
Lifestyle.Scoped);
And you can wrap all these instances into a single open generic implementation of the above mentioned ThreadScopedServiceDecorator.
It would IMO even be better to use the command / handler pattern (you should really read the link!) for this type of work. In very short: In this pattern every use case is translated to a message object (a command) which is handled by a single command handler, which can be decorated by e.g. a SaveChangesCommandHandlerDecorator and a ThreadScopedCommandHandlerDecorator and LoggingDecorator and so on.
Your example would then look like:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
public class CreateMemberCommand
{
public string MemberName { get; set; }
}
With the following handlers:
public class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>
{
//notice that the need for MemberRepository is zero IMO
private readonly IGenericRepository<Member> memberRepository;
public CreateMemberCommandHandler(IGenericRepository<Member> memberRepository)
{
this.memberRepository = memberRepository;
}
public void Handle(CreateMemberCommand command)
{
var member = new Member { Name = command.MemberName };
this.memberRepository.Insert(member);
}
}
public class SaveChangesCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratee;
private DbContext db;
public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}
public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}
And the form can now depend on ICommandHandler<T>:
public partial class frmMember : Form
{
private readonly ICommandHandler<CreateMemberCommand> commandHandler;
public frmMember(ICommandHandler<CreateMemberCommand> commandHandler)
{
InitializeComponent();
this.commandHandler = commandHandler;
}
private void btnSave_Click(object sender, EventArgs e)
{
this.commandHandler.Handle(
new CreateMemberCommand { MemberName = txtName.Text });
}
}
This can all be registered as follows:
container.Register(typeof(IGenericRepository<>),
typeof(GenericRepository<>));
container.Register(typeof(ICommandHandler<>),
new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(ThreadScopedCommandHandlerDecorator<>),
Lifestyle.Singleton);
This design will remove the need for UnitOfWork and a (specific) service completely.

How can I use Ninject in my ASP MVC MSpec tests?

I'm trying to write an MSpec test that instantiates one of my controllers with all the correct Ninject bindings. How do I go about doing that? This is what I have so far:
[Subject(Concern.Initialization)]
public class when_permanent_employee_page_is_loaded_for_first_time
{
private static PermanentEmployeeController controller;
Establish context = () =>
{
NinjectControllerFactory controllerFactory = new NinjectControllerFactory();
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
controller = (PermanentEmployeeController)controllerFactory.CreateController(new RequestContext(), "PermanentEmployee");
};
private Because of = () => controller.Index();
private It should_load_all_available_jobs = () =>
{
var blah = controller;
var blah3 = 3;
};
It should_load_all_available_locations;
It should_load_all_available_departments;
}
In the above code I'm simply trying to see if I can instantiate my controller with all the Ninject bindings in tact. The NinjectControllerFactory class looks like this:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new DefaultModule());
public IKernel Kernel
{
get
{
return kernel;
}
set
{
this.kernel = value;
}
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
return (IController)kernel.Get(controllerType);
}
}
And the DefaultModule class like this:
public class DefaultModule : NinjectModule
{
/// <summary>
/// Performs the binding of interfaces to their respective implementations. 'Tis very cool.
/// </summary>
public override void Load()
{
// Data service bindings
Bind<IJobService>().To<JobServiceImpl>().InTransientScope();
Bind<IJobWsWrapper>().To<JobWsWrapperImpl>().InTransientScope();
// View model factory bindings
Bind<IPermanentEmployeeViewModelFactory>().To<PermanentEmployeeViewModelFactoryImpl>().InTransientScope();
}
}
So my question is: is there a way to specify the bindings of my Ninject module in my MSpec test and then have my instantiated controller use those bindings? I want to avoid instantiating my Controller like this: var controller = new Controller() since that doesn't allow me to test the Ninject bindings. I've also looked into the TestControllerBuilder class from the MvcContrib library but I haven't figured out how to instantiate controllers with Ninject bindings with it. Thanks for the help!
Ok I figured out how to initialize my controller along with the Ninject Bindings in my MSpec tests! Well I didn't figure it out. A coworker did but that's irrelevant now. Here is how it's done:
public class when_permanent_employee_page_is_loaded_for_first_time
{
private static Mock<IJobService> jobServiceMock;
private static Mock<IUtilsService> utilsServiceMock;
private static PermanentEmployeeController controller;
private static ContextMocks mocks;
private static IList<Job> jobs = new List<Job>();
private static IList<string> departments = new List<string>();
private static IList<string> locations = new List<string>();
private static PermanentEmployeeJobsViewModel viewModel;
Establish context = () =>
{
jobServiceMock = new Mock<IJobService>();
jobServiceMock.Setup(x => x.GetJobs(1)).Returns(jobs);
jobServiceMock.Setup(x => x.GetDepartmentsFromJobs(jobs)).Returns(departments);
jobServiceMock.Setup(x => x.GetLocationsFromJobs(jobs)).Returns(locations);
utilsServiceMock = new Mock<IUtilsService>();
var kernel = new StandardKernel(new DefaultModule());
kernel.Rebind<IJobService>().ToConstant(jobServiceMock.Object);
kernel.Rebind<IUtilsService>().ToConstant(utilsServiceMock.Object);
controller = kernel.Get<PermanentEmployeeController>();
mocks = new ContextMocks(controller);
};
Because of = () =>
{
PartialViewResult view = (PartialViewResult)controller.Index();
viewModel = (PermanentEmployeeJobsViewModel)view.ViewData.Model;
};
It should_load_all_available_jobs = () =>
{
jobServiceMock.Verify(x => x.GetJobs(1));
jobServiceMock.Verify(x => x.GetDepartmentsFromJobs(jobs));
jobServiceMock.Verify(x => x.GetLocationsFromJobs(jobs));
viewModel.Departments.ShouldEqual(departments);
};
It should_load_all_available_locations;
It should_load_all_available_departments;
}
Ok that's it :). Hopefully someone else can benefit from this answer. Special thanks to my coworker for figuring this out. You know who you are :D

Resources