NEW == GLUE
public class MyDependency : IMyDependency
{
private readonly ILogger<MyDependency> _logger;
public MyDependency(ILogger<MyDependency> logger)
{
_logger = logger;
}
public Task WriteMessage(string message)
{
_logger.LogInformation(
"MyDependency.WriteMessage called. Message: {MESSAGE}",
message);
return Task.FromResult(0);
}
}//startup.cs
public void ConfigureServices(IServiceCollection services)
{
//Demo (show with an example)
...
}public void ConfigureServices(IServiceCollection services)
{
services.Add(new ServiceDescriptor(typeof(IX), typeof(X), ServiceLifetime.Scoped));
services.AddScoped<IX, X>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
...
}//https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IAuthorRepository, AuthorRepository>();
services.AddScoped<IMessageRepository, MessageRepository>();
services.AddScoped<IBlackListRepository, BlackListRepository>();
services.AddTransient<IUnitOfWork, UnitOfWork>();
...
}
Object Marker
Repository behaves like a collection!
public interface IRepository<T> where T : class
{
T GetById(int id);
IEnumerable<T> Get();
IEnumerable<T> Get(Expression<Func<T, bool>> predicate);
void Insert(T entity);
void Delete(T entity);
void Update(T entity);
}public abstract class Repository<T> : IRepository<T> where T : class
{
protected readonly DbContext _dbContext;
//Normally Repository works only with UnitOfWork!
//this is only for demonstration purpose, such that this repository
//also works without a UnitOfWork.
public Repository(DbContext dbContext)
{
_dbContext = dbContext;
}
//exposes IQueryable interface to outside world (with a public access modifier)
//is not a good idea!
protected IQueryable<T> AsQueryable()
{
return _dbContext.Set<T>().AsNoTracking();
}
public virtual T GetById(int id)
{
return _dbContext.Set<T>().Find(id);
}
public virtual IEnumerable<T> Get()
{
return _dbContext.Set<T>().AsEnumerable();
}
public virtual IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
{
return _dbContext.Set<T>()
.Where(predicate)
.AsEnumerable();
}
public void Insert(T entity)
{
_dbContext.Set<T>().Add(entity);
}
public void Update(T entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
}
public void Delete(T entity)
{
_dbContext.Set<T>().Remove(entity);
}
} public interface IAuthorRepository : IRepository<Author>
{
Author GetByIdWithOwner(int id);
}
public class AuthorRepository : Repository<Author>, IAuthorRepository
{
public AuthorRepository(BlogContext dbContext) : base(dbContext)
{
}
public Author GetByIdWithOwner(int id)
{
return AsQueryable().Include(x => x.Owner)
.FirstOrDefault(x => x.Id == id);
}
}
[HttpGet(Name = nameof(GetAuthor))]
public ActionResult<IEnumerable<AuthorVM>> GetAuthor()
{
// var authorDtos = _db.Authors
// .Include(x => x.Owner)
// .Select(x => AuthorVM.From(x)).ToList();
var authors = _authorRepository.Get();
var authorDtos = _mapper.Map<IEnumerable<AuthorVM>>(authors);
// .Select(x => AuthorDto.From(x));
return Ok(authorDtos);
}
[HttpGet("{id}")]
public ActionResult<AuthorVM> GetAuthors(int id)
{
// var author = _db.Authors
// .Include(x => x.Owner)
// .SingleOrDefault(x => x.Id == id);
var author = _authorRepository.GetByIdWithOwner(id);
if (author == null)
{
return NotFound();
}
return Ok(AuthorVM.From(author));
}[Fact]
public void Get_ReturnsAuthorVm_VMModelHasCorrectAuthorValues()
{
// Arrange
var mockRepo = new Mock<IAuthorRepository>();
var author = new Author()
{
Id = 1,
BirthDate = new DateTime(2000, 1, 1),
Email = "test@test.com",
FirstName = "test1 firstname",
LastName = "test1 lastname",
Owner = new IdentityUser("AdminTest")
};
mockRepo.Setup(repo => repo.GetByIdWithOwner(1))
.Returns(author);
var controller = new SimpleControllerForTest(mockRepo.Object);
// Act
var result = controller.Get(1);
var okObjectResult = Assert.IsAssignableFrom<OkObjectResult>(result.Result);
var authorVm = Assert.IsAssignableFrom<AuthorVM>(okObjectResult.Value);
// Assert
Assert.Equal(author.Id, authorVm.Id);
Assert.Equal(author.FirstName + " " +author.LastName, authorVm.Name);
Assert.Equal(author.Owner.UserName, authorVm.OwnerName);
}
[HttpGet("{id}")]
public ActionResult<bool> BlackListAuthorWithoutUnitOfWork(int id)
{
var author = _authorRepository.GetById(id);
bool blackList = false;
foreach (var message in _messageRepository.GetMessageForAuthor(author))
{
if (message.Description.Contains("f**k"))
{
_messageRepository.Delete(message);
//suppose something goes wrong with deleting or program crashes (Exception)!
//some messages are delete and others not
blackList = true;
}
}
if (blackList)
{
_blackListRepository.AddAuthorToBlacklist(author);
}
return Ok(blackList);
}
[HttpGet("{id}")]
public ActionResult<bool> BlackListAuthorWithUnitOfWork(int id)
{
bool blackList = false;
var author = _authorRepository.GetById(id);
foreach (var message in _messageRepository.GetMessageForAuthor(author))
{
if (message.Description.Contains("f**k"))
{
_messageRepository.Delete(message);
//suppose something goes wrong with deleting or program crashes (Exception)!
//some message are delete and others not
blackList = true;
}
}
if (blackList)
{
_blackListRepository.AddAuthorToBlacklist(author);
_db.SaveChanges(); //Commit() the Unit Of Work
}
return Ok(blackList);
}public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BlogContext>(options =>
options.UseSqlite("Data Source=Blog.db"));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<BlogContext>();
services.AddScoped<IAuthorRepository, AuthorRepository>();
services.AddScoped<IMessageRepository, MessageRepository>();
services.AddTransient<IBlacklistService, BlacklistService>();