DI with using base class (C#) - c#

I have base Attachment controller
Here is code of it
public class ApiAttachmentControllerBase<T> : PM101MobileApiController where T : Entity<int>
{
private readonly IObjectStorageManager _storageManager;
private readonly IRepository<T> _repository;
public ApiAttachmentControllerBase(IObjectStorageManager storageManager, IRepository<T> repository)
{
_storageManager = storageManager;
_repository = repository;
}
private void CheckFileSize(IFormFile file)
{
if (file.Length > PM101Consts.MaxAttachmentSize)
{
throw new UserFriendlyException(L("Attachment_Warn_SizeLimit", PM101Consts.MaxAttachmentSizeMb.ToString()));
}
}
private void CheckFileType(IFormFile file, params string[] supportedTypes)
{
if (supportedTypes.Any())
{
var extention = Path.GetExtension(file.FileName);
if (!supportedTypes.ToList().Contains(extention))
{
throw new UserFriendlyException(L("Attachment_Warn_Type", extention));
}
}
}
}
}
I inherited it in another controller like this
public class InspectionsController : ApiAttachmentControllerBase<Inspection>
{
private readonly IRepository<Inspection> _inspectionRepository;
public InspectionsController(IObjectStorageManager storageManager, IRepository<Inspection> repository,
IRepository<Inspection> inspectionRepository) : base(storageManager, repository)
{
_inspectionRepository = inspectionRepository;
}
/// <summary>
/// Method for posting pre-inspection
/// </summary>
/// <remarks>When you start pre inspection you send just jobId, tenantId, and status
/// When you finishing inspection you send full DTO with all fields</remarks>
/// <response code="200">Returns if pre inspection created
/// </response>
[HttpPost]
public async Task<IActionResult> AddPreInspection(CreatePreInspectionDto input)
{
var preInspection = new Inspection();
ObjectMapper.Map(input, preInspection);
await _inspectionRepository.InsertAsync(preInspection);
return Ok();
}
In AddPreInspection I tried to use repository like repository.InsertAsync
But it not works, so I make DI for repository like private read-only IRepository<Inspection> _inspectionRepository;
Is this a good practice or I can use the repository from the base class?
If yes, how I can do it?

If you make the base ApiAttachmentControllerBase have a protected, rather than private, repository then the InspectionsController will be able to access it.
The protected access modifier allows the member to be accessed by the current class, or a derived class.
public class ApiAttachmentControllerBase<T> : PM101MobileApiController where T : Entity<int>
{
private readonly IObjectStorageManager _storageManager;
protected readonly IRepository<T> Repository;
public ApiAttachmentControllerBase(IObjectStorageManager storageManager, IRepository<T> repository)
{
_storageManager = storageManager;
Repository = repository;
}
....

Related

Unable to cast object of type AsyncStateMachineBox System.Threading.Tasks.VoidTaskResult to type System.Threading.Tasks.Task

I'm very new to ASP.NET Web API and I'm trying to use Entity Framework Core's Dependency Injection to POST data to the API Controller using MediatR pattern. But every time I run my code and it opens Swagger UI, I get an error 500 response saying
Unable to cast object of type 'AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,S3E1.Repository.CartItemRepository+<Createitem>d__5]' to type 'System.Threading.Tasks.Task1[S3E1.Entities.CartItemEntity]'.
First, I added Dependency Injections to Program.cs
//Dependency Injection
builder.Services.AddDbContext<AppDataContext>(contextOptions => contextOptions.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
));
//Connection
builder.Services.AddSingleton<DataConnectionContext>();
These are the classes.
AppDataContext.cs
public class AppDataContext : DbContext
{
public AppDataContext(DbContextOptions<AppDataContext> contextOptions) : base(contextOptions) { }
public DbSet<CartItemEntity> CartItems { get; set; }
public DbSet<OrderEntity> Orders { get; set; }
public DbSet<UserEntity> Users{ get; set; }
}
DataConnectionContext.cs
public class DataConnectionContext
{
private readonly IConfiguration _configuration;
private readonly string _connectionString;
public DataConnectionContext(IConfiguration configuration)
{
_configuration = configuration;
_connectionString = _configuration.GetConnectionString("DefaultConnection");
}
public IDbConnection CreateConnection() => new SqlConnection(_connectionString);
}
Next is making a repository which holds the interface that has the create method.
public interface ICartItemRepository
{
//public Task<IEnumerable<CartItemEntity>> GetCartItems();
//public Task<CartItemEntity> GetCartItemEntity(Guid id);
public Task Createitem(CartItemEntity itemEntity);
}
Then a class that inherits the interface and calls the dependency constructors
public class CartItemRepository : ICartItemRepository
{
private readonly DataConnectionContext _connectionContext;
private readonly AppDataContext _appDataContext;
public CartItemRepository(DataConnectionContext connectionContext, AppDataContext appDataContext)
{
_connectionContext = connectionContext;
_appDataContext = appDataContext;
}
public async Task Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
await _appDataContext.CartItems.ToListAsync();
}
}
Next is a command for POST request MediatR pattern
public record AddCartItemCommand(CartItemEntity cartItem) : IRequest<CartItemEntity>;
and a Handler which manages and returns the method createitem
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
private readonly ICartItemRepository _cartItemRepository;
public AddItemsHandler(ICartItemRepository cartItemRepository) => _cartItemRepository = cartItemRepository;
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await (Task<CartItemEntity>) _cartItemRepository.Createitem(request.cartItem);
}
}
and lastly, in the controller
[Route("api/cart-items")]
[ApiController]
public class CartItemsController : ControllerBase
{
private ISender _sender;
public CartItemsController(ISender sender) => _sender = sender;
[HttpPost]
public async Task<CartItemEntity> Post(CartItemEntity cartItemEntity)
{
return await _sender.Send(new AddCartItemCommand(cartItemEntity));
}
}
I tried modifying the return object in the handler but every time I change anything it always get the error squiggly line, so I just casted the (Task) after the await. Is this where I went wrong? Thank you for any answers.
The exception is clear. You can't cast a VoidTaskResult to Task<CartItemEntity>.
To solve the problem:
In ICartItemRepository, modify the return type for Createitem as Task<CartItemEntity>.
In CartItemRepository, implement Createitem method from the ICartItemRepository interface. Return the inserted itemEntity in the method.
Since you have implemented Task<CartItemEntity> Createitem(CartItemEntity itemEntity) in the ICartItemRepository interface, the casting to (Task<CartItemEntity>) is no longer needed, and suggested to be removed.
public interface ICartItemRepository
{
...
public Task<CartItemEntity> Createitem(CartItemEntity itemEntity);
}
public class CartItemRepository : ICartItemRepository
{
...
public async Task<CartItemEntity> Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
return itemEntity;
}
}
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
...
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await _cartItemRepository.Createitem(request.cartItem);
}
}

Implementing "Repository Rotator" factory

I have .Net Core Web API application. There is some Get method in controller and injected IRepositoryProviderFactory. Nothing special.
[ApiController]
public class DataController : ControllerBase
{
private readonly ILogger<DataController> _logger;
private readonly IRepositoryProviderFactory _repositoryProviderFactory;
#region ctor
/// <summary>
/// ctor
/// </summary>
public DataController(ILogger<DataController> logger, IRepositoryProviderFactory repositoryProviderFactory)
{
_logger = logger;
_repositoryProviderFactory = repositoryProviderFactory;
}
[HttpPost]
public async Task<IActionResult> GetData([FromBody] SearchModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
var data = await _repositoryProviderFactory.GetDataAsync(model);
return Ok(data);
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
}
}
There are repositories based on the same Interface to get data from different data sources.
public Repository1: IDataRepository {}
public Repository2: IDataRepository {}
public Repository3: IDataRepository {}
I'm using DI so all parts are registered in services as Scoped or Transients. Some repositories are using EntityFramework.
services.AddScoped<IDataRepository, Repository1>();
services.AddScoped<IDataRepository, Repository2>();
services.AddScoped<IDataRepository, Repository3>();
Ok, now I need to implement RepositoryProviderFactory to return repository. But there is one required functionality: it must return for every call different repository.
I have injected IEnumerable and I need to return Repository1, Repository2, Repository3 and again Repository1, … etc. So all repositores are used the same time.
/// <summary>
/// ctor
/// </summary>
public RepositoryProviderFactory(
ILogger<RepositoryProviderFactory> logger,
IEnumerable<IDataRepository> dataRepositories)
{
_logger = logger;
_dataRepositories = dataRepositories;
}
public IDataRepository GetRepository()
{
// TODO: Logic to cycle repositories
var instance = dataRepositories.Where();
return instance;
}
How to do this?
Factory can't be registered as Singleton, because repositories have another dependencies that have Scoped Lifetime (DbContext etc.)
How can I create some thread safe singleton object to be able persists last used repository and serve another one, for another call?
Well, I did it this way.
I made class GlobalAppData and registered is as Singleton.
services.AddSingleton<GlobalAppData>();
Then I made simple implementation (not finished yet).
public class GlobalAppData
{
private IDataRepository[] _availableRepositories;
private IDataRepository_lastUsedRepository;
/// <summary>
/// ctor
/// </summary>
public GlobalAppData()
{
_availableRepositories = new IDataRepository[0];
}
public void TryRegisterRepositories(IEnumerable<IDataRepository> repositories)
{
if (_availableRepositories.Length > 0)
{
return;
}
_availableRepositories = repositories.ToArray();
_lastUsedRepository = null;
}
public IDataRepository GetNextRepository()
{
if (_lastUsedRepository == null)
{
_lastUsedRepository = _availableRepositories[0];
return _lastUsedRepository;
}
var lastUsedIndex = _availableRepositories.IndexOf(_lastUsedRepository);
if (lastUsedIndex < _availableRepositories.Length - 1)
{
lastUsedIndex++;
}
else
{
lastUsedIndex = 0;
}
_lastUsedRepository = _availableRepositories[lastUsedIndex];
return _lastUsedRepository;
}
}
Then because of DI there will be stored original instances, not injected ones, I made just simple compare in factory.
var instanceData = _globalAppData.GetNextRepository();
var instance = _repositories.SingleOrDefault(r => r.GetType() == instanceData.GetType());
Not perfect, but it works as a start.

How to dynamically change change DI using autofac?

We are developing windows service, and i want to change dbcontext class dynamically in repositories.
bellow is the scenario.
I have three db context classes
public abstract class Context : DbContext, IUnitOfWork
{
protected Context(string connectionString) : base(connectionString)
{
}
}
public class PlatformContext : Context
{
private readonly string _connectionString;
public PlatformContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
public class PlatformReplicaContext : Context
{
private readonly string _connectionString;
public PlatformReplicaContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
public class TempContext : Context
{
private readonly string _connectionString;
public TempContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
and i have repository
public interface ICategoryRepository : IRepository<Category>
{
}
public class CategoryRepository :Repository<Category>, ICategoryRepository
{
public CategoryRepository(Context context) : base(context)
{
}
}
hence im using CQRS i have another three classes
public class CategoryBasicQuery:IRequest<BaseQueryResponse>
{
public int CategoryId { get; set; }
}
public class CategoryBasicQueryHandler : IRequestHandler<CategoryBasicQuery, BaseQueryResponse>
{
private readonly ICategoryRepository _categoryRepository;
private readonly IMapper _mapper;
public CategoryBasicQueryHandler(ICategoryRepository categoryRepository, IMapper mapper)
{
_categoryRepository = categoryRepository;
_mapper = mapper;
}
public async Task<BaseQueryResponse> Handle(CategoryBasicQuery request, CancellationToken cancellationToken)
{
var entry = await _categoryRepository.FindAsync(request.CategoryId);
if (entry == null)
{
return new NotFoundResponse();
}
var response = _mapper.Map<CategoryBasicResponse>(entry);
return response;
}
}
Now here is the issue
Here category repository should be able to execute queries in all 3 types of contexts.
but how should i register classes in using autofac?
then i came up with a solution generating repositories in run time as below
public class RepositoryFactory
{
public static TRepository GetRepositoryInstance<T, TRepository>(
params object[] args)
where TRepository : IRepository<T>
{
return (TRepository)Activator.CreateInstance(typeof(TRepository), args);
}
}
im calling this method inside CategoryBasicQueryHandler class like this
var categoryRepo = RepositoryFactory.GetRepositoryInstance<Category, CategoryRepository>(new PlatformReplicaContext("connectionString"));
but when calling from CQRS
var categoty = new Category();
var command = new CategoryBasicQuery {CategoryId = categoryId};
var result = _mediator.Send(command);
VS give me following error
and my autofac registration as follows
builder.RegisterType<CategoryService>().AsSelf();
builder.RegisterType<ActionRepository>().As<IActionRepository>();
builder.RegisterType<CategoryRepository>().As<ICategoryRepository>();
builder.RegisterType<Mapper>().As<IMapper>();
can anyone help me resolve this or suggest good method to handle this situation.
thanks.
This may give you a good starting point for a possible solution: http://autofaccn.readthedocs.io/en/latest/resolve/relationships.html#keyed-service-lookup-iindex-x-b
builder.RegisterType<PlatformContext>().Keyed<Context>("platform");
builder.RegisterType<PlatformReplicaContext>().Keyed<Context>("replica");
builder.RegisterType<TempContext>().Keyed<Context>("temp");
You mentioned in a comment that there is a variable named action somewhere that will indicate which implementation to use:
public class Class1
{
private readonly IIndex<string, Context> contexts;
public Class1(IIndex<string, Context> contexts)
{
this.contexts = contexts;
}
public void Whatever()
{
string action = ...; // platform, replica or temp
Context context = this.contexts[action];
...
}
}
Of course this needs to be adapted so that it will fit in the rest of your application design. A possible example could be:
Context context = this.contexts[action];
using(ILifetimeScope scope = container.BeginLifetimeScope(builder =>
{
builder.RegisterInstance(context).As<Context>();
}))
{
// Because we are resolving IMediator from the scope, the selected Context will be used in all dependencies
var mediator = scope.Resolve<IMediator>();
mediator.Send(...);
}

Microsoft Unity Dependency Injection with WebAPI

I have the following architecture:
Data
Database Layer
WebAPI
Presentation Layer
Resolver
IoC Register Layer
Services
Business Layer
In WebApiConfig.cs(App_Start) i register the unity container the following way:
// Unity Container Resolver
var container = new UnityContainer();
//Registers the repository interface in Resolver(IoC Register Layer)
var UResolver = new UnityRegisterContainer();
UResolver.RegisterContainer(ref container);
//Configures WebAPI DependecyResolver to use UnityResolver
config.DependencyResolver = new UnityResolver(container);
My Resolver(IoC Register Layer):
public class UnityRegisterContainer
{
public void RegisterContainer(ref UnityContainer container)
{
container.RegisterType<IUnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<IService>(new HierarchicalLifetimeManager());
}
}
Controller:
public static KeyService KeyLibrary{ get; set; }
// GET api/values
[Route("Keys")]
public IEnumerable<KeyDTO> Get()
{
var Keys = KeyLibrary.GetAllKeys();
return Keys;
}
KeyService:
public class KeyService: IService
{
IUnitOfWork UOW { get; set; }
/// <summary>
/// Get all Keys
/// </summary>
/// <returns></returns>
public IEnumerable<KeyDTO> GetAllKeys()
{
return Mapper.Map<IEnumerable<Key>, IEnumerable<KeyDTO>>(UOW.Keys.GetAllKeys());
}
}
IService
public interface IService
{
}
IUnitOfWork
public interface IUnitOfWork : IDisposable
{
IKeyRepository Keys { get; }
int Complete();
}
How can i inject the class libraries and repositories with unity?
You can use constructor injection and let the DependencyResolver do it job and pass the necessary dependencies to the classes.
public class KeyController : ApiController {
IKeyService keyService;
public KeyController(IKeyService keyService) {
this.keyService = keyService
}
// GET api/values
[Route("Keys")]
public IEnumerable<KeyDTO> Get() {
var Keys = keyService.GetAllKeys();
return Keys;
}
}
public interface IKeyService : IService {
IEnumerable<KeyDTO> GetAllKeys();
}
public class KeyService: IKeyService {
IUnitOfWork UOW;
public KeyService(IUnitOfWork uow) {
this.UOW = uow
}
/// <summary>
/// Get all Keys
/// </summary>
/// <returns></returns>
public IEnumerable<KeyDTO> GetAllKeys() {
return Mapper.Map<IEnumerable<Key>, IEnumerable<KeyDTO>>(UOW.Keys.GetAllKeys());
}
}
public class UnitOfWork: IUnitOfWork {
public UnitOfWork(IKeyRepository repository) {
Keys = repository;
}
IKeyRepository Keys { get;private set }
public int Complete(){...}
}
Though constructor injection is preferred (and property injection is sometimes not recommended), you can also use the [Dependency] attribute in implementation classes that have dependencies, like this:
public class KeyService: IService
{
// Public setter, private getter, so you can mock and manually assing in Unit Tests
[Dependency]
public IUnitOfWork UOW { private get; set; }
public IEnumerable<KeyDTO> GetAllKeys()
{
return Mapper.Map<IEnumerable<Key>, IEnumerable<KeyDTO>>(UOW.Keys.GetAllKeys());
}
}
See Annotating Objects for Property Injection

Generic Repository and Transaction

I have implemented my first Generic repository in MVC app. Works fine but how to put repositories in Transaction scope?
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query { get; }
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _db;
public Repository(DataContext db)
{
_db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return _db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
_db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
_db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
_db.SubmitChanges();
}
#endregion
}
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
var connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
kernel.Bind(typeof(DataContext)).ToMethod(context => new DataContext(connectionString));
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
public class AdminController : Controller
{
private readonly IRepository<User> _userRepository;
private readonly IRepository<Order> _orderRepository;
public AdminController(IRepository<User> userRepository, IRepository<Order> orderRepository)
{
_userRepository = userRepository;
_orderRepository = orderRepository;
}
public ActionResult InsertUser(UserViewModel model)
{
//Skip Code
//Do not commit data to database if _orderRepository is failed to save data
_userRepository.Add(user);
_userRepository.Save();
//Skip Code
_orderRepository.Add(order);
_orderRepository.Save();
}
}
What would be best method to wrap repository code with Transaction scope in InsertUser action?
You are missing an abstraction here. You should place all your business logic inside command handlers and create a command handler decorator that implements transaction behavior. This article describes how to do this, but in short:
Define an ICommandHandler<TCommand> interface:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
Create commands that define the contract of a business operation. Commands are simply DTOs (with only data and no behavior). For instance:
public class ShipOrderCommand
{
public int OrderId { get; set; }
public ShippingInfo Info { get; set; }
}
Implement command handlers that will contain the business logic / behavior for those commands:
public class ShipOrderCommandHandler
: ICommandHandler<ShipOrderCommand>
{
private readonly IRepository<Order> repository;
public ShipOrderCommandHandler(
IRepository<Order> repository)
{
this.repository = repository;
}
public void Handle(ShipOrderCommand command)
{
// do some useful stuf with the command and repository.
}
}
Let your MVC Controllers depend on the ICommandHandler<T> abstraction:
public ShipOrderController : Controller
{
private readonly ICommandHandler<ShipOrderCommand> handler;
public ShipOrderController(
ICommandHandler<ShipOrderCommand> handler)
{
this.handler = handler;
}
public void Ship(int orderId, ShippingInfo info)
{
this.handler.Handle(new ShipOrderCommand
{
OrderId = orderId,
Info = info
});
}
}
Define a generic decorator that implements transaction logic:
public TransactionalCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratedHandler;
public TransactionalCommandHandlerDecorator(
ICommandHandler<TCommand> decoratedHandler)
{
this.decoratedHandler = decoratedHandler;
}
public void Handle(TCommand command)
{
using (var scope = new TransactionScope())
{
this.decoratedHandler.Handle(command);
scope.Complete();
}
}
}
Ensure that each ShipOrderCommandHandler is decorated with a TransactionalCommandHandlerDecorator and injected into ShipOrderController. You can do this with your favorite DI container, or by hand:
protected override IController GetControllerInstance(
RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(ShipOrderController))
{
return new ShipOrderController(
new TransactionalCommandHandlerDecorator<ShipOrderCommand>(
new ShipOrderCommandHandler(
new OrderRepository())));
}
return base.GetControllerInstance(requestContext, controllerType);
}
With this in place you can run all your business logic inside a transaction, without the need for the business logic to be aware of that.
There's a pattern called Unit of work. Here's an explanation.

Categories