I am trying to implement dependency injection using entity framework but it is giving an exception of "An unhandled exception of type 'System.StackOverflowException' occurred in Unity.Container.dll" and application is gone on break mode
public class CategoryRepository : ICategoryRepository
{
private LaundryManagementSystemEntities context;
private ICategoryRepository _iCategory;
//public CategoryRepository(LaundryManagementSystemEntities db) //For repositoty Patterns or Unit of work
//{
// this.context = db;
//}
//For dependency Injection
public CategoryRepository(ICategoryRepository iCategory,LaundryManagementSystemEntities _context)
{
this._iCategory = iCategory;
this.context = _context;
}
public void CreateCategory(CategoryViewModel categoryViewModel)
{
var category = new Category();
category.CategoryName = categoryViewModel.CategoryName;
category.IsActive = categoryViewModel.IsActive;
context.Categories.Add(category);
context.SaveChanges();
}
Here is making Repository class of category
public interface ICategoryRepository:IDisposable
{
List<Category> GetCategories();
Category GetCategoryById(int? categoryId);
void CreateCategory(CategoryViewModel category);
void DeleteProductOfCategory(int productId);
void DeleteCategory(int categoryId);
void PostEditCategory(CategoryViewModel category);
CategoryViewModel GetEditCategory(int? categoryId);
}
This is an interface
public class CategoryController : AdminBaseController
{
LaundryManagementSystemEntities db = new LaundryManagementSystemEntities();
private ICategoryRepository interfaceobj;
//private UnitOfWork unitOfWork;
public CategoryController(ICategoryRepository iCategory)
{
this.interfaceobj = iCategory;
//For Repositorypatterns
//this.interfaceobj = new CategoryRepository(new LaundryManagementSystemEntities());
//For Unit Of Work
// this.unitOfWork = new UnitOfWork(new LaundryManagementSystemEntities());
}
// GET: Category
public ActionResult Index()
{
return View();
}
public ActionResult Create()
{
CategoryViewModel categoryViewModel = new CategoryViewModel();
return PartialView("Create",categoryViewModel);
}
[HttpPost]
public ActionResult Create(CategoryViewModel category)
{
if (ModelState.IsValid)
{
interfaceobj.CreateCategory(category);
// unitOfWork.CategoryRepository.CreateCategory(catogery);
// interfaceobj.CreateCategory(catogery);
}
return PartialView("Create",category);
}
This is the controller
I am not getting the exception
I want to know about it properly and how it would run
The injection of ICategoryRepository into CategoryRepository which is derived from the same interface is creating a cyclic/circular dependency which is causing the stack to overflow.
Remove that dependency. The code originally shown does not appear to use nor need that dependency.
public class CategoryRepository : ICategoryRepository {
private readonly LaundryManagementSystemEntities context;
public CategoryRepository(LaundryManagementSystemEntities context) {
this.context = context;
}
//...
Related
I use UnitOfWork with repository in an ASP.NET Core 6 Web API and want to use XUnit for testing. I use the code shown below, and it works.
I have two questions:
I use accept-language in the methods to know what is the language for returning correct error messages. How can I add accept-language for test?
How should I use token that I get with Authenticate method?
UnitOfWork
public interface IUnitOfWork : IDisposable
{
IUserRepository UserRepository { get; }
}
public class UnitOfWork : IUnitOfWork
{
protected readonly DatabaseContext db;
private IUserRepository userRepository;
public IUserRepository UserRepository
{
get
{
if (userRepository == null)
{
userRepository = new UserRepository(db);
}
return userRepository;
}
}
//...
}
UserRepository
public interface IUserRepository : IGenericRepository<UserRole>
{
Task<User> GetUserWithRolesAsync(string username);
}
public class UserRepository : GenericRepository<User>, IUserRepository
{
public async Task<User> GetUserWithRolesAsync(string username)
{
//...
}
}
AuthController
private readonly IUnitOfWork _uow;
public AuthController(IUnitOfWork uow) : base(uow)
{
_uow = uow;
}
[HttpPost("authenticate")]
public async Task<IActionResult> Authenticate([FromBody] UserLoginViewModel Request)
{
User user = await _uow.UserRepository.GetUserWithRolesAsync(Request.Username);
//....
}
Test method:
[Fact]
public async Task Authenticate_WithInvalidUsernamePassword_ReturnsNotFound()
{
// Arrange
var dbOption = new DbContextOptionsBuilder<DatabaseContext>().UseSqlServer("connection string").Options;
DatabaseContext databaseContext = new DatabaseContext(dbOption);
databaseContext.Database.EnsureCreated();
var jwtAuthenticatorManager = new JwtAuthenticatorManager("key");
var unitOfWorkStub = new Mock<IUnitOfWork>();
UserRepository userRep = new UserRepository(databaseContext);
unitOfWorkStub.SetupGet(uow => uow.UserRepository).Returns(userRep);
var options = Options.Create(new LocalizationOptions { ResourcesPath = "Resources" });
var factory = new ResourceManagerStringLocalizerFactory(options, NullLoggerFactory.Instance);
var localizer = new StringLocalizer<SharedTranslate>(factory);
var controller = new AuthController(unitOfWorkStub.Object, localizer, jwtAuthenticatorManager);
UserLoginViewModel userLoginViewModel = new UserLoginViewModel
{
Username = "admin",
Password = "admin#123"
};
// Act
var result = await controller.Authenticate(userLoginViewModel);
// Assert
result.Should().BeOfType<NotFoundResult>();
}
I'm trying to test my project. I have never used tests before and I am starting to learn I would like a help, in the simplest case I want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Controller:
Controller:
public class WorkPlacesController : Controller
{
private readonly IWorkPlaceService workPlaceService;
public WorkPlacesController(IWorkPlaceService workPlaceService)
{
this.workPlaceService = workPlaceService;
}
// GET: WorkPlaces
public ActionResult Index()
{
var workPlaces = workPlaceService.GetWorkPlaces(includedRelated:
true);
return View(workPlaces);
}
}
Here is my Service
Service
public class WorkPlaceService : IWorkPlaceService
{
private readonly IWorkPlaceRepository workPlacesRepository;
private readonly IUnitOfWork unitOfWork;
public WorkPlaceService(IWorkPlaceRepository workPlacesRepository, IUnitOfWork unitOfWork)
{
this.workPlacesRepository = workPlacesRepository;
this.unitOfWork = unitOfWork;
}
}
public interface IWorkPlaceService
{
IEnumerable<WorkPlace> GetWorkPlaces(string workPlaceDescription = null, bool includedRelated = true);
}
And my Repository
Repository
public class WorkPlaceRepository : RepositoryBase<WorkPlace>, IWorkPlaceRepository
{
public WorkPlaceRepository(IDbFactory dbFactory)
: base(dbFactory) { }
public WorkPlace GetWorkPlaceByDescription(string workPlaceDescription)
{
var workPlace = this.DbContext.WorkPlaces.Where(c => c.Description == workPlaceDescription).FirstOrDefault();
return workPlace;
}
}
public interface IWorkPlaceRepository : IRepository<WorkPlace>
{
WorkPlace GetWorkPlaceByDescription(string workPlaceDescription);
}
Factory
public class DbFactory : Disposable, IDbFactory
{
AgendaEntities dbContext;
public AgendaEntities Init()
{
return dbContext ?? (dbContext = new AgendaEntities());
}
protected override void DisposeCore()
{
if (dbContext != null)
dbContext.Dispose();
}
}
I tried to do something like this:
public void BasicIndexTest()
{
// Arrange
var mockRepository = new Mock<IWorkPlaceService>();
var controller = new WorkPlacesController(mockRepository.Object);
// Act
ActionResult actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsInstanceOfType(actionResult, typeof(List<WorkPlace>));
}
How do I inject in this controller the data needed to go in the database and bring the results?
I Want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Mock the behavior of required dependencies of the controller for the test and assert the desired behavior when the test is exercised.
For example, based on what you have done so far
public void BasicIndexTest() {
// Arrange
var mockService = new Mock<IWorkPlaceService>();
var workPlaces = new List<WorkPlace>() {
new WorkPlace()
};
mockService
.Setup(_ => _.GetWorkPlaces(It.IsAny<string>(), It.IsAny<bool>()))
.Returns(workPlaces);
var controller = new WorkPlacesController(mockService.Object);
// Act
var actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(actionResult);
var model = actionResult.Model;
Assert.IsNotNull(model)
Assert.IsInstanceOfType(model, typeof(List<WorkPlace>));
Assert.AreEqual(workPlaces, model);
}
Only the IWorkPlaceService was needed for the testing of Index action, but fake data was needed for the invocation of the GetWorkPlaces method. So the mock was configured to return a list of objects when called and pass it to the view result.
Below is a controller with a Post Method. How do i write a unit-test against the CREATE method without saving the changes to the database?
I am trying to write test against my controllers so that when other developers change the code it will not break my functionality ( i have a little bit of functionality on the Create method to keep it simple for now).
public class AdministratorController : Controller
{
private IUnitOfWork _uow;
[HttpPost]
public ActionResult Create(MyModel model)
{
ViewBag.id = model.Id;
if (model.FirstName == model.LastName)
{
ModelState.AddModelError("", "Cannot have same first name and last name.");
}
if (ModelState.IsValid)
{
MyClass record = new MyClass();
record.SAFirstName = model.FirstName;
record.SALastName = model.LastName;
record.SATitle = model.Title;
record.SAEmail = model.EmailAddress;
record.Since = DateTime.Now;
_uow.AdministratorRepository.AddRecord(record);
_uow.SaveChanges();
return RedirectToAction("Index", "Administrator");
}
return View(model);
}
}
2.) my UOW looks something like this:
public class UnitOfWork : IUnitOfWork
{
private readonly MasterContext _context;
public UnitOfWork(MasterContext context)
{
_context = context;
}
public UnitOfWork()
{
_context = new MasterContext();
}
public void SaveChanges()
{
_context.SaveChanges();
}
private IAdministratorRepository _Repo;
public IAdministratorRepository AdministratorRepository
{
get
{
if (this._Repo == null)
{
this._Repo = new IAdministratorRepository(_context);
}
return _Repo;
}
}
3) And my AdministratorRepository constructor looks like:
private readonly MasterContext _context;
public AdministratorRepository(MasterContext context)
{
_context = context;
}
You need to be able to inject a fake/mock IUnitOfWork into your controller. The simplest way to do that is to create an internal constructor on the controller that takes the fake object and create a property that either creates a new instance or returns the existing one.
private IUnitOfWork _uow;
private IUnitOfWork UnitOfWork
{
get
{
_uow = _uow ?? new UnitOfWork();
return _uow;
}
}
public AdministratorController() {}
internal AdministratorController( IUnitOfWork uow )
{
_uow = uow;
}
You'll also need to modify the AssemblyInfo file for the MVC project to make the internal constructor visible to the unit test project. Look up the InternalsVisibleToAttribute for that.
Now in the unit test you can create your fake/mock object and inject it. You don't indicate what mocking framework you're using. We use FakeItEasy, so it would be something like:
var uow = A.Fake<IUnitOfWork>();
var controller = new AdministratorController( uow );
A.CallTo( () => uow.SaveChanges() ).MustHaveHappened();
You should mock your dependencies.In your example AddRecord() of your repository.And after that you should test the returning model fields with your expected model(that you have to set in your unit testing method).
How can I test ClassifyComment() method from my service. I have that test code:
[TestClass]
public class SpamServiceTest
{
[TestMethod]
public void ClassifyCommentTest()
{
var spamComments = Builder<Comments>.CreateListOfSize(10).All().With(x => x.Content = "spam spam spam")
.Build().AsQueryable();
var mocker = new AutoMoqer();
mocker.GetMock<IUnitOfWork>()
.Setup(x => x.CommentsRepository.GetComments(It.Is<bool>(y => y == true)))
.Returns(spamComments);
//.......
}
}
But it gives me error: Can not instantiate proxy of class: CommentsRepository. Could not find a parameterless constructor.
Below is my code which I want test:
public class SpamService : ISpamService
{
private readonly IUnitOfWork _unitOfWork;
public SpamService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public bool ClassifyComment(Comments comment)
{
var spam = _unitOfWork.CommentsRepository.GetComments(true).ToList();
//.............
}
}
public class UnitOfWork : IUnitOfWork
{
private DatabaseContext context = new DatabaseContext();
private CommentsRepository commentsRepository;
public CommentsRepository CommentsRepository
{
get
{
if (this.commentsRepository == null)
{
this.commentsRepository = new CommentsRepository(context);
}
return commentsRepository;
}
}
}
public class CommentsRepository : ICommentsRepository
{
private DatabaseContext context;
public CommentsRepository(DatabaseContext context)
{
this.context = context;
}
public virtual IQueryable<Comments> GetComments(bool isSpam)
{
//.......
}
}
IUnityOfWork should return a ICommentsRepository, i.e. an interface, not an implementation. The mock of IUnityOfWork should return a mock of ICommentsRepository.
Let the abstraction work with other abstractions, not with implementations.
I have a controller action that gets invoked directly, but throws this error:
The operation cannot be completed because the DbContext has been disposed.
I have only found solutions online regarding deferred excecution, but I don't think that applies here, because everywhere I use the context (in this instance) I call either .ToList() or .FirstOrDefault(). Here is my code:
CONTROLLER CONTENT
private IUnitOfWork UnitOfWork;
public MyFavouritesController(
IAccountServices accountServices,
IUnitOfWork unitOfWork
)
{
AccountServices = accountServices;
UnitOfWork = unitOfWork;
}
public ActionResult Index()
{
int? id = AccountServices.GetCurrentUserId();
if (!id.HasValue)
{
return RedirectToAction("Login", "Account", new { ReturnUrl = this.HttpContext.Request.Url.AbsolutePath });
}
var user = UnitOfWork.UserRepo.Get(id.Value, "Favourites", "Favourites.County", "Favourites.Country");
//THE ABOVE CALL GETS THE ERROR
//.....
return View();
}
REPOSITORY BASE CLASS
public class RepositoryBase<C, T> : IDisposable
where C:DbContext, new()
where T : ModelBase
{
private DbContext _context;
public DbContext Context
{
get
{
if (_context == null)
{
_context = new C();
this.AllowSerialization = true;
}
return _context;
}
set
{
_context = value;
}
}
public virtual T Get(int Id, params string[] includes)
{
if (Id > 0)
{
var result = Context.Set<T>().Where(t => t.Id == Id);
foreach (string includePath in includes)
{
result = result.Include(includePath);
}
return result.FirstOrDefault(); //This is where the error occurs.
}
else
{
throw new ApplicationException("Id is zero (0).");
}
}
//... (More CRUD methods)
public void Dispose()
{
if (Context != null)
{
Context.Dispose(); //Debugger never hits this before the error
}
}
}
UNIT OF WORK CLASS
public class UnitOfWork:IUnitOfWork
{
public UnitOfWork(
//... DI of all repos
IUserRepository userRepo
)
{
//... save repos to an local property
UserRepo = userRepo;
//create a new instance of the context so that all the repo's have access to the same DbContext
Context = new Context();
//assign the new context to all the repo's
//...
UserRepo.Context = Context;
}
public Context Context { get; set; }
public IUserRepository UserRepo { get; set; }
//... (some more repositories)
public void Dispose()
{
Context.Dispose(); //THIS IS NOT HIT AT ALL
}
}
LASTLY, THE MODEL CONTAINER HAS THIS LINE
_Instance.RegisterType<IUnitOfWork, UnitOfWork>(new PerThreadLifetimeManager());
As you can see, the index action will recieve a new instance of UnitOfWork which contains a new DbContext object. But at the first call to this context, it throws the above error. This pattern works everywhere else in my code.
Thanks
UPDATE
The answer below was to use a perRequestLifetimeManager. Here is the implimentation of one in unity:
public class HttpRequestLifetimeManager : LifetimeManager
{
private string _key = Guid.NewGuid().ToString();
public override object GetValue()
{
if (HttpContext.Current != null && HttpContext.Current.Items.Contains(_key))
return HttpContext.Current.Items[_key];
else
return null;
}
public override void RemoveValue()
{
if (HttpContext.Current != null)
HttpContext.Current.Items.Remove(_key);
}
public override void SetValue(object newValue)
{
if (HttpContext.Current != null)
HttpContext.Current.Items[_key] = newValue;
}
}
I noticed you're using a PerThreadLifetimeManager to control the creation and disposal of your unit of work class. You should probably change it to something like PerRequestLifetimeManager if your IoC container supports that.
Its because your are disposing the Unit Of Work, after wich you are requesting your data, store your data in a Variable after the query then you can release the Unit Of Work instance as well.