For school we have to write our own WebApi using the .NET Entity Core Framework. I've written my api but when I tried to use it in swagger, it always returned a HTTP 500 error: internal server error. I downloaded Fiddler to start debugging and came across a circular dependency error in my repository but I can't figure out where this would take place.
The interface (for mock testing)
public interface IVisitorRepository
{
Visitor GetBy(string email);
void AddVisitor(Visitor visitor);
void SaveChanges();
}
The concrete class
public class VisitorRepository : IVisitorRepository
{
private readonly ApplicationDbContext _context;
private readonly DbSet<Visitor> _visitors;
public VisitorRepository(ApplicationDbContext context, IVisitorRepository visitorRepository)
{
_context = context;
_visitors = _context.Visitors;
}
public void AddVisitor(Visitor visitor)
{
_visitors.Add(visitor);
}
public Visitor GetBy(string email)
{
return _visitors.SingleOrDefault(v => v.Email == email);
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
I've scoped it in my pipeline.
It's a JWT token based login and register api (that's what we need to make) and here's my register method (the method I'm testing)
[AllowAnonymous]
[HttpPost("register")]
public async Task<ActionResult<String>> Register(RegisterDTO model)
{
IdentityUser user = new IdentityUser { UserName = model.Email, Email = model.Email };
Visitor visitor = new Visitor(model.FirstName + " " + model.LastName, model.Email, model.PhoneNumber, model.Country);
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_visitorRepository.AddVisitor(visitor);
_visitorRepository.SaveChanges();
string token = GetToken(user);
return Created("", token);
}
return BadRequest();
}
The exception:
InvalidOperationException: A circular dependency was detected for the service of type 'DigitizedApi.Models.Repositories.IVisitorRepository'. DigitizedApi.Models.Repositories.IVisitorRepository(DigitizedApi.Data.Repositories.VisitorRepository) -> DigitizedApi.Models.Repositories.IVisitorRepository
Problem is your VisitorRepository (which implements IVisitorRepository) has a dependency on IVisitorRepository itself.
Actually it should be as follows:
public class VisitorRepository : IVisitorRepository
{
private readonly ApplicationDbContext _context;
private readonly DbSet<Visitor> _visitors;
public VisitorRepository(ApplicationDbContext context)
{
_context = context;
_visitors = _context.Visitors;
}
.........
}
Related
I'm trying to mock using Moq, xUnit,.Net 6, Entity framework Core, I have this service:
public class CompanyService : ICompanyService
{
private readonly ICompanyRepository _repository;
public CompanyService(ICompanyRepository repository)
{
_repository = repository;
}
public async Task<Company> Create(Company Company) => await _repository.Create(Company);
}
this is the company service interface:
public interface ICompanyService
{
Task<Company> Create(Company Company);
}
this is my company repository class:
public class CompanyRepository : ICompanyRepository
{
private readonly ApplicationDbContext _context;
public CompanyRepository(ApplicationDbContext context)
{
_context = context;
}
public async Task<Company> Create(Company Company)
{
Company.Id = Guid.NewGuid();
await _context.Companies.AddAsync(Company);
await _context.SaveChangesAsync();
return Company;
}
}
and this is its interface:
public interface ICompanyRepository
{
Task<Company> Create(Company Company);
}
this is my DbContext:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options): base(options)
{}
public DbSet<Company> Companies { get; set; }
}
and finally this is my class for testing:
public class CompanyServiceTest
{
private readonly CompanyService _sut;
private readonly Mock<ICompanyRepository> _companyRepositoryMock = new Mock<ICompanyRepository>();
public CompanyServiceTest()
{
_sut = new CompanyService(_companyRepositoryMock.Object);
}
[Fact]
public async void CreateACompanyShouldWorks()
{
//Arrange
var CompanyEntity = new Company();
CompanyEntity.Name = "Test Company";
//Act
var companyCreated = await _sut.Create(CompanyEntity);
//Assert
Assert.NotNull(companyCreated);
_companyRepositoryMock.Verify(r => r.Create(CompanyEntity));
}
}
but when I run the test I get this message error:
"Assert.NotNull() Failure"
Stack Trace:
CompanyServiceTest.CreateACompanyShouldWorks() line 31
<>c.b__128_0(Object state)
I don't know if I have to mock the ApplicationDbContext, or if I have to mock anything else, I'm Using xUnit, .Net 6, Entity framework core, also I have downloaded the Moq package.
You just forgot to setup the mock inside the Arrange phase
_companyRepositoryMock
.Setup(r => r.Create(It.IsAny<CompanyEntity>()))
.ReturnsAsync(expectedCompany);
OR
_companyRepositoryMock
.Setup(r => r.Create(It.IsAny<CompanyEntity>()).Result)
.Returns(expectedCompany);
If you don't setup the mock then it will return the default value.
If you change the MockBehaviour to strict then it will throw exception.
UPDATE #1
in the case of the method GetAllCompanies I have to create a List<Company>() and then return them ? and in the method GetCompanyById I have to create an object of Company and returns it ? I mean xUnit does not go to the database using my repository?
The short answer is yes you have to mock all the methods that you want to use on your dependency. Since the CompanyService is relying correctly on abstraction (ICompanyRepository interface) rather than on the implementation (CompanyRepository class) that's why you are not depending on the Entity Framework directly.
If you want to test your repository tier/layer/module than you have to mock the DbContext to avoid database calls. There are tons of nuget packages which can be used to ease the mocking burden.
This is the solution:
//Arrange
var CompanyEntity = new Company();
CompanyEntity.Name = "Test Company";
CompanyEntity.Id = Guid.NewGuid();
CompanyEntity.Employees = new HashSet<Employee>();
//arrange
_companyRepositoryMock
.Setup(r => r.Create(It.IsAny<Company>()))
.ReturnsAsync(CompanyEntity);
//Act
var companyCreated = await _sut.Create(CompanyEntity);
//Assert
Assert.NotNull(companyCreated);
_companyRepositoryMock.Verify(r => r.Create(companyCreated));
I am new to Integration test, I have a controller which has IMediator and I am using Moq framework for the integration test.
The issue I am having is that I keep getting null in the response when trying to mock MediatR. Before trying to mock MediatR, I tried to mock a service (in this case IUserService) and it worked perfectly (the return type for the Delete controller and other methods was bool).
Since I am now using IMediator in the controller so trying to change the integration test to mock MediatR, I can do integration test for the handler which has IUserService but I am trying to test the whole pipeline. Below is what I have in terms of code starting from the controller to the integration test.
//Controller
private IMediator _mediator;
public UserController(IMediator mediator)
{
_mediator = mediator;
}
[HttpDelete("{id}")]
public async Task<ActionResult<Result<Unit>>> DeleteUser(int id)
{
return await _mediator.Send(new DeleteUserCommand { UserId = id });
}
public class DeleteUserCommand : IRequest<Result<Unit>> {public int UserId { get; set; }}
//Command handler
public class DeleteUserCommandHandler : IRequestHandler<DeleteUserCommand, Result<Unit>>
{
private readonly IUserService _userService;
public DeleteUserCommandHandler(IUserService userService)
{
_userService = userService;
}
public async Task<Result<Unit>> Handle(DeleteUserCommand request, CancellationToken cancellationToken)
{
return await _userService.DeleteUser(request.UserId);
}
}
//Service layer
public async Task<Result<Unit>> DeleteUser(int userId)
{
var userExist = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId);
if (userExist == null) return Result<Unit>.Failure("User Id doesn't exsist");
_context.Remove(userExist);
var result = await _context.SaveChangesAsync() > 0;
return Result<Unit>.Success(Unit.Value);
}
//Integration test
[TestFixture]
public class UserControllerTests
{
private readonly Mock<IMediator> _mockMediator;
private UserController _userController;
public UserControllerTests()
{
_mockMediator = new Mock<IMediator>();
}
[Test]
public async Task DeleteUser_NotSuccessful_NoIdDeleted()
{
Result<Unit> expected = new Result<Unit>();
_mockMediator.Setup(x => x.Send(It.IsAny<DeleteUserCommand>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(expected));
_userController = new UserController(_mockMediator.Object);
var result = await _userController.DeleteUser(6);
Assert.AreEqual("User Id doesn't exsist", result?.Value?.Error);
}
}
//Response in the integration test
I have two UserIds 6 and 7
UserId 6: doesn't exsist so I am expecting a message saying id doesn't exsist but the current response I am getting is null.
UserId 7: does exsist and expecting something like IsSuccess: true which is a custom code I added
Note: the attached code for the test is just for user Id 6.
You might notice in the code above starting from the controller, part of the return type is Result which is a custom class I added and below is the code.
public class Result<T>
{
public bool IsSuccess { get; set; }
public T Value { get; set; }
public string Error { get; set; }
public static Result<T> Success(T value) => new Result<T> { IsSuccess = true, Value = value };
public static Result<T> Failure(string error) => new Result<T> { IsSuccess = false, Error = error };
}
`
I am trying to find out what I have done wrong with mocking MediatR and why it keep returning null.
Thanks for the help in advance.
First thing I tried to do integration test mock the IUserService then switched to IMediator then started to get null in the response when doing integration test. I tried to google the issue but no luck.
I am getting a dependancy injection error when i try to access my controller. the error is 'unable to resolve service for IOrderPartRepository while attempting to activate. I followed examples from tutorials, but am still not sure why it won't resolve. I reviewed similar questions, but it looked like i had incorporated the fix from similar questions in my solution
Error:
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Route matched with {action = "GetOrderParts", controller = "OrderPart"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.IActionResult] GetOrderParts(DatingApp.API.Helpers.UserParams) on controller DatingApp.API.Controllers.UsersController (DatingApp.API).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action DatingApp.API.Controllers.UsersController.GetOrderParts (DatingApp.API) in 3.2277ms
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Unable to resolve service for type 'DatingApp.API.Data.IOrderPartRepository' while attempting to activate 'DatingApp.API.Controllers.OrderPartController'.
Here is the code
public interface IOrderPartRepository
{
void Add<T>(T entity) where T: class;
void Delete<T>(T entity) where T: class;
Task<bool> SaveAll();
Task<PagedList<OrderPart>> GetOrderParts(UserParams userParams);
Task<OrderPart> GetOrderPart(int id);
}
public class OrderPartRepository: IOrderPartRepository
{
private readonly DataContext _context;
public OrderPartRepository(DataContext context)
{
_context = context;
}
public void Add<T>(T entity) where T : class
{
_context.Add(entity);
}
public void Delete<T>(T entity) where T : class
{
_context.Remove(entity);
}
public async Task<OrderPart> GetOrderPart(int id)
{
var orderPart = await _context.OrderParts.Include(p => p.Photos).FirstOrDefaultAsync(u => u.Id == id);
return orderPart;
}
public async Task<PagedList<OrderPart>> GetOrderParts(UserParams userParams)
{
var orderparts = _context.OrderParts.Include(p => p.Photos)
.OrderByDescending(u => u.Added).AsQueryable();
if (!string.IsNullOrEmpty(userParams.OrderBy))
{
switch (userParams.OrderBy)
{
case "created":
orderparts = orderparts.OrderByDescending(u => u.Added);
break;
default:
orderparts = orderparts.OrderByDescending(u => u.Added);
break;
}
}
return await PagedList<OrderPart>.CreateAsync(orderparts, userParams.PageNumber, userParams.PageSize);
}
public async Task<bool> SaveAll()
{
return await _context.SaveChangesAsync() > 0;
}
}
}
controller
private readonly IOrderPartRepository _repo;
public OrderPartController(IOrderPartRepository repo)
{
this._repo = repo;
}
startup
services.AddScoped<IAuthRepository, AuthRepository>();
services.AddScoped<IDatingRepository, DatingRepository>();
services.AddScoped<IOrderPartRepository, OrderPartRepository>();
Did you register your DB context in the Startup class too? If not, that might be the reason of the problem, try something like:
services.AddDbContext<DataContext>(options => {
options.UseSqlServer("Connection string");
});
I have a simple web-app with angular on client-side and asp.net core web-api on server-side. I use InMemoryDatabase
services.AddDbContext<ItemsContext>(options => options.UseInMemoryDatabase("ItemsDB"));
to store data for the simplisity of the development. But I've encountered an issue with that. I have one controller on web-api to response for users' requests:
[Route("api/[controller]")]
public class ItemsController : Controller
{
private readonly IApiService apiService;
public ItemsController(IApiService apiService)//using DI from Startup.cs
{
this.apiService = apiService;
}
[HttpPost, Route("addItem")]
public async Task<Response> Add([FromBody]Item item)
{
return await apiService.Add(item);
}
[HttpDelete("{id}")]
public async Task<Response> Delete(int id)
{
return await apiService.Delete(id);
}
[HttpPut]
public async Task<Response> Put([FromBody]Item item)
{
return await apiService.Put(item);
}
}
and the following Startup.cs configurations:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<ItemsContext>(options => options.UseInMemoryDatabase("ItemsDB"));
services.AddSingleton<IUnitOfWork, UnitOfWork>(provider => {
var context = services.BuildServiceProvider().GetService<ItemsContext>();
return new UnitOfWork(context);
});
services.AddSingleton<IApiService, ApiService>(provider => {
return new ApiService(services);
});
}
The problem is, that when I add new item, everything goes just fine...but then I post another request to delete this item it may show there there is no such an item at all or sometimes it may delete it...so in other words, the database exists and then disappears and I'm not sure when. Here is some additional code refering to the above
public class ApiService: IApiService
{
private readonly IUnitOfWork database;
private readonly IServiceProvider provider;
public ApiService(IServiceCollection serviceCollection)
{
provider = serviceCollection.BuildServiceProvider();
}
public IUnitOfWork Database
{
get
{
return provider.GetService<IUnitOfWork>();
}
}
public async Task<Response> Add(Item item)
{
Database.Items.Add(item);
await Database.SaveAsync();
var id = Database.Items.LastItem().Id;
return new Response() { Result = true, ItemId = id };
}
public async Task<Response> Delete(int id)
{
var item = await db.Items.Find(id);
Database.Items.Remove(item);
await Database.SaveAsync();
return new Response() { Result = true };
}
public async Task<Response> Put(Item item)
{
Database.Items.Update(item);
await Database.SaveAsync();
return new Response() { Result = true };
}
}
Update:
UnitOfWork Implementation:
public class UnitOfWork: IUnitOfWork
{
private readonly DbContext context;
private IRepository<Item> itemsRepository;
public UnitOfWork(DbContext dbContext)
{
context = dbContext;
}
public IRepository<Item> Items
{
get
{
return itemsRepository ?? (itemsRepository = new Repository<Item>(context));
}
}
public void Dispose()
{
context.Dispose();
}
public void Save()
{
context.SaveChanges();
}
public async Task SaveAsync()
{
await context.SaveChangesAsync();
}
}
Your code has multiple serious problems, let's go through them.
services.AddDbContext adds a Scoped service, meaning that instances will be created and disposed on each request. services.AddSingleton adds a Singleton service, so only a single instance will ever be created. You cannot add a scoped service to a singleton one, because the reference the singleton service uses will be disposed and you will end up with a disposed context.
This code:
return provider.GetService<IUnitOfWork>();
represents the service locator anti-pattern. As you can guess, an anti-pattern is something you want to avoid. I also don't know why you would want a service to build the entire DI container nor why you would want a service to have the responsibility of getting the dependencies it needs itself.
This part here is where your question actually comes from:
Database.SaveAsync();
You are calling an asynchronous function and not awaiting for it to finish. The task may finish or not, it may throw an error or not, you will never know what happened.
The best thing is that all of these could be avoided if people stopped attempting to create a Unit of Work + Repository pattern over yet another Unit of Work and Repository. Entity Framework Core already implements these:
DbContext => Unit of Work
DbSet => Repository (generic)
Why do you want yet another abstraction? Will you really ever throw away EF Core from the project to justify the maintenance cost of your code?
The entire question code could have just been this:
[Route("api/[controller]")]
public class ItemsController : Controller
{
private readonly YourContext _context;
public ItemsController(YourContext context)
{
_context = context;
}
[HttpPost]
public async Task<IActionResult> Add([FromBody]Item item)
{
context.Items.Add(item);
await context.SaveChangesAsync();
return Ok(item.Id);
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
var item = await context.Items.FindAsync(id);
context.Items.Remove(item);
await context.SaveChangesAsync();
return Ok();
}
[HttpPut]
public async Task<IActionResult> Put([FromBody]Item item)
{
context.Items.Update(item);
await context.SaveChangesAsync();
return Ok();
}
}
I am trying to implement multi tenancy in my WebAPI project.
In my Startup.Auth.cs , i am adding selected Tenant object into IOwinContext.
app.Use(async (ctx, next) =>
{
Tenant tenant = GetTenantBasedUrl(ctx.Request.Uri.Host);
if (tenant == null)
{
throw new ApplicationException("tenant not found");
}
ctx.Environment.Add("MultiTenant", tenant);
await next();
}
Where GetTenantBaseUrl function is returnnig us the selected Tenant object.
I have made a class implementing ApiController which i would implement to every controller of mine in order to get the Tenant object.
public class MultiTenantWebApiController : ApiController
{
public Tenant Tenant
{
get
{
object multiTenant;
IDictionary<string, object> dic = HttpContext.Current.GetOwinContext().Environment;
if (!HttpContext.Current.GetOwinContext().Environment.TryGetValue("MultiTenant", out multiTenant))
{
throw new ApplicationException("Could Not Find Tenant");
}
return (Tenant)multiTenant;
}
}
}
In my controller i am getting "MultiTenant" key from OwinContext Environment but i try to fetch the same from ApplicationOAuthProvider class it doesn't show "MultiTenant" key in my OwinContext Environment ie : getEnvironment variable below:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
// some code here
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
try
{
**IDictionary getEnvironment = HttpContext.Current.GetOwinContext().Environment;**
// some code
Does anybody know why i am not getting the "MultiTenant" key in OwinContext.Environment of ApplicationOAuthProvider whereas i get it inside my controller ?
Thanks!
I would like to suggest that you can use the context injected to each of your api controllers so that the tenant and its context is visible across the layers. The context provider can be looking something like this
public class ClaimsContextDataProvider : IUserContextDataProvider
{
public Guid UserId
{
get
{
var userId = (Thread.CurrentPrincipal as ClaimsPrincipal)?.FindFirst(ClaimTypes.Sid)?.Value;
return TryGetGuidFromString(userId);
}
}
}
Then registering the context provider in the DI framework [example of using the Autofac is given below]
builder.RegisterType<ClaimsContextDataProvider>().As<IUserContextDataProvider>();
Then have a BaseApiController something like the below snippet
public Guid TenantId { get { return _userContext.TenantId; } }
public BaseApiController(IMapper mapper, IUserContextDataProvider userContext)
{
_mapper = mapper;
_userContext = userContext;
}
Accessing the TenantId property of the BaseApiController inside the derived controllers [CountriesController.cs]
// POST api/countries
public async Task<HttpResponseMessage> PostCountry(CountryRequestModel requestModel)
{
Country country = _mapper.Map<CountryRequestModel, Country>(requestModel);
country.CreatedOn = DateTimeOffset.Now;
country.TenantId = TenantId;
await _countryService.AddAsync(country);
CountryDto countryDto = _mapper.Map<Country, CountryDto>(country);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, countryDto);
response.Headers.Location = GetCountryLink(country.Id);
return response;
}
You can take a look at the sample app and the template given in the below link
Multi-Tenant dev template
Its a little bit deep to explain here, please feel free to read the docs here