Generic DI from interface not resolving in Startup - c#

I have created a generic interface
public interface ISqlTradeDataRetriever<T> where T : class
{
Task<T> GetSingleDayForSymbolAsync(string symbol, string date);
Task<ICollection<T>> GetAllAsync(string symbol);
}
and an implementation of such
public class SqlCommodityDataRetriever: ISqlTradeDataRetriever<Commodity>
{
private readonly BatlGroupWebContext _context;
public SqlCommodityDataRetriever(BatlGroupWebContext context)
{
_context = context;
}
public Task<Commodity> GetSingleDayForSymbolAsync(string symbol, string date)
{
var data = _context.Commodities.FirstOrDefaultAsync(m => m.Symbol == symbol
&& m.TradeDate == Convert.ToDateTime(date));
return data;
}
public Task<ICollection<Commodity>> GetAllAsync(string symbol)
{
throw new NotImplementedException();
}
}
and in startup.cs of the web application
services.AddScoped<ISqlTradeDataRetriever<Commodity>, SqlCommodityDataRetriever>();
but when I try to access the page where I am using this implementation I get an unresolved DI error
Unable to resolve service for type 'Infrastructure.DataRetrievers.SqlCommodityDataRetriever' while attempting to activate 'BATLGroupApp.Pages.Commodity.TradeData.EditModel'.
The edit model is as follows
public class EditModel : PageModel
{
private readonly SqlCommodityDataRetriever _retriever;
public EditModel(SqlCommodityDataRetriever retriever)
{
_retriever = retriever;
}
[BindProperty]
public DomainClasses.Classes.Commodity Commodity { get; set; }
public string CommoditySymbol { get; set; }
public async Task<IActionResult> OnGetAsync([FromQuery]string symbol, [FromQuery]string date)
{
if (string.IsNullOrEmpty(symbol) || string.IsNullOrEmpty(date))
{
return NotFound();
}
Commodity = await _retriever.GetSingleDayForSymbolAsync(symbol, date);
if (Commodity == null)
{
return NotFound();
}
CommoditySymbol = Commodity.CommoditySymbol.Symbol;
return Page();
}
}
What am I doing wrong in terms of registering the DI for this OR is my implementation wrong?

The registration is fine in its current form.
services.AddScoped<ISqlTradeDataRetriever<Commodity>, SqlCommodityDataRetriever>();
The page model however expects the concrete SqlCommodityDataRetriever implementation while the container is only aware of its ISqlTradeDataRetriever<Commodity> abstraction.
Refactor the page model to match the registration
public class EditModel : PageModel {
private readonly ISqlTradeDataRetriever<Commodity> _retriever;
public EditModel(ISqlTradeDataRetriever<Commodity> retriever) {
_retriever = retriever;
}
//... omitted for brevity since nothing else needs to change
as the class should ideally be dependent on abstractions instead of concretions for a more SOLID design.

Related

generic methods for API controller

I'm writing an API for my game and I'm starting to realize that the amount of GET, POST, and PUT API methods can really add up.
So right now, I'm trying to make it more generic so that I don't have to write a separate method like GetMonsterList, GetTreasureList, GetPlayerInfo, etc.
But I'm not quite sure how to go about doing that.
Here is a non-generic PUT method that I currently have.
// PUT: api/MonsterLists/5
[HttpPut("{id}")]
public async Task<IActionResult> PutMonsterList(string id, MonsterList monsterList)
{
if (id != monsterList.MonsterId)
{
return BadRequest();
}
_context.Entry(monsterList).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MonsterListExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
And here is my attempt at outlining a generic method:
// PUT: api/AnyLists/5
[HttpPut("{id}")]
public async Task<IActionResult> PutAnyList(string id, AnyList anyList)
{
if (id != anyList.AnyId)
{
return BadRequest();
}
_context.Entry(anyList).State = EntityState.Modified;
return NoContent();
}
My problem that I don't understand is, how do I pass in a model to a generic control like this? Like if I have a model for MonsterList, TreasureList, PlayerInfo, WeaponList, etc.
How could I use one generic method for all of them?
I did find one similiar question here, Generic Web Api controller to support any model , but the answer seemed to imply that this isn't a good idea.
Is that possible?
Thanks!
Before we create the generic controller, it is worth to mention that the structure model of your entities is so important to easily or hardly build the generic controller.
For example you could have some models with int id and others with string id, so we need to have a common base for both types.
Start by creating the common interface for Id property to handle int or string Ids in the generic interface:
public interface IHasId<TKey>
where TKey : IEquatable<TKey>
{
TKey Id { get; set; }
}
Another thing to consider is ordering the entities, when querying for a list of entities we need to sort them to get the right paged entities. So, we can create another interface to specify the sorting property e.g. Name.
public interface IOrdered
{
string Name { get; set; }
}
Our objects must implement the common interfaces like below:
public class Player : IHasId<string>, IOrdered
{
public string Id { get; set; }
public string Name { get; set; }
...
}
public class Treasure : IHasId<int>, IOrdered
{
public int Id { get; set; }
public string Name { get; set; }
...
}
Now create a generic base api controller, make sure to mark the methods as virtual so we can override them in the inherited api controllers if necessary.
[Route("api/[controller]")]
[ApiController]
public class GenericBaseController<T, TKey> : ControllerBase
where T : class, IHasId<TKey>, IOrdered
where TKey : IEquatable<TKey>
{
private readonly ApplicationDbContext _context;
public GenericBaseController(ApplicationDbContext context)
{
_context = context;
}
// make methods as virtual,
// so they can be overridden in inherited api controllers
[HttpGet("{id}")]
public virtual T Get(TKey id)
{
return _context.Set<T>().Find(id);
}
[HttpPost]
public virtual bool Post([FromBody] T value)
{
_context.Set<T>().Add(value);
return _context.SaveChanges() > 0;
}
[HttpPut("{id}")]
public virtual bool Put(TKey id)
{
var entity = _context.Set<T>().AsNoTracking().SingleOrDefault(x => x.Id.Equals(id));
if (entity != null)
{
_context.Entry<T>(value).State = EntityState.Modified;
return _context.SaveChanges() > 0;
}
return false;
}
[HttpDelete("{id}")]
public virtual bool Delete(TKey id)
{
var entity = _context.Set<T>().Find(id);
if (entity != null)
{
_context.Entry<T>(entity).State = EntityState.Deleted;
return _context.SaveChanges() > 0;
}
return false;
}
[HttpGet("list/{pageNo}-{pageSize}")]
public virtual (IEnumerable<T>, int) Get(int pageNo, int pageSize)
{
var query = _context.Set<T>();
var totalRecords = query.Count();
var items = query.OrderBy(x => x.Name)
.Skip((pageNo - 1) * pageSize)
.Take(pageSize)
.AsEnumerable();
return (items, totalRecords);
}
}
The rest is easy, just create api controllers that inherits from the base generic controller:
PlayersController :
[Route("api/[controller]")]
[ApiController]
public class PlayersController : GenericBaseController<Player, string>
{
public PlayersController(ApplicationDbContext context) : base(context)
{
}
}
TreasuresController :
[Route("api/[controller]")]
[ApiController]
public class TreasuresController : GenericBaseController<Treasure, int>
{
public TreasuresController(ApplicationDbContext context) : base(context)
{
}
}
you don't have to create any methods, but you are still able to override the base methods since we marked them as virtual e.g.:
[Route("api/[controller]")]
[ApiController]
public class TreasuresController : GenericBaseController<Treasure, int>
{
public TreasuresController(ApplicationDbContext context) : base(context)
{
public ovedrride Treasure Get(int id)
{
// custom logic ….
return base.Get(id);
}
}
}
You can download a sample project from GitHub: https://github.com/LazZiya/GenericApiSample
I guess you can pass over the name of the type of the parameter and do something like this (not tested):
// PUT: api/AnyLists/5
[HttpPut("{id}")]
public async Task<IActionResult> PutAnyList(string id, object anyList, string anyListType)
{
var anyListObject = Convert.ChangeType(anyList, Type.GetType(anyListType)));
if (id != anyListObject.AnyId)
{
return BadRequest();
}
_context.Entry(anyListObject).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
// Whatever error handling you need
}
return NoContent();
}
However, I wouldn't recommend to use this in production code. What will likely happen is that you will need to create quite a lot of exceptions for different types in the end - and you'll end up with the code that is much more convoluted and hard to support than if you just had separate methods per type.
Also, I'm not sure it will be easy to test this.

The current type is an interface and could not be constructed. Are you missing type mapping?

I am trying to start a new web project and I am new to asp.net mvc. Everytime I debug the following code, the error appears stating
the current type, BBNepal.Repository.Interface.IUnitOfWork, is an interface and cannot be constructed.
Are you missing a type mapping?'
Where did I go wrong?
This is my controller
public class RegisterController : Controller
{
private IRegisterService registerService;
public RegisterController(IRegisterService _registerService)
{
registerService = _registerService;
}
// GET: Register
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Create(RegisterDTO registerDTO)
{
try
{
bool isSaved;
if (registerDTO.Id == 0)
isSaved = registerService.Create(registerDTO);
else
return View();
}
This is my service layer
public interface IRegisterService
{
bool Create(RegisterDTO registerDTO);
}
#endregion
#region Implementation
public class RegisterService : IRegisterService
{
private IUnitOfWork unitOfWork;
public RegisterService(IUnitOfWork _unitOfWork)
{
unitOfWork = _unitOfWork ?? new UnitOfWork();
}
public bool Create(RegisterDTO registerDTO)
{
Register register = registerDTO.Convert();
unitOfWork.RegisterRepository.Insert(register);
unitOfWork.Save();
return true;
}
}
This is my interfaced repository
public interface IUnitOfWork
{
#region Core Method
int Save();
Task<int> SaveAsync();
#endregion
IRepository<Register> RegisterRepository { get; }
}
This is my repository
private IRepository<Register> _registerRepository;
public IRepository<Register> RegisterRepository
{
get
{
return _registerRepository ?? (_registerRepository = new RepositoryBase<Register>(_context));
}
}
My DI registrations are:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IRegisterService, RegisterService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
You need to update the registrations, and include one for IUnitOfWork as it is passed into the constructor of class RegisterService.
It should be something like:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IRegisterService, RegisterService>();
container.RegisterType<IUnitOfWork, UnitOfWork>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}

How to fix DbContext has been disposed for an async scenario?

We have upgraded our application from NserviceBus v5 to v6 and after that we run into major problem, most of the time receiving the following error.
The operation cannot be completed because the DbContext has been
disposed.
It was not obvious until we got load to our system.
We are running with eight concurrent threads and by that we receive the above error.
public class EndpointInitializer
{
public void Initialize(IKernel container)
{
var endpointConfiguration = new EndpointConfiguration("MyEndpoint");
endpointConfiguration.UseContainer<NinjectBuilder>(
customizations => { customizations.ExistingKernel(container); });
//More settings...
}
}
.
public class MyMessageHandler : IHandleMessages<MyCommand>
{
private readonly IPersonRepository _personRepository;
public MyMessageHandler(IPersonRepository personRepository)
{
_personRepository = personRepository;
}
public async Task Handle(MyCommand message, IMessageHandlerContext context)
{
var person = await _personRepository.GetByIdentifierAsync(message.Identifier).ConfigureAwait(false);
//More code...
await _personRepository.UpdateAsync(person);
}
}
.
[Serializable]
public class MyCommand
{
public string Identifier { get; set; }
}
.
public class DependencyRegistrar
{
public IKernel Container { get; set; }
public void Create()
{
Container = new StandardKernel();
RegisterTypes(Container);
}
public void RegisterTypes(IKernel kernel)
{
kernel.Bind<IPersonRepository>().To<PersonRepository>();
kernel.Bind<DbContext>().To<MyDbContext>().InThreadScope();
//More registrations...
}
}
.
public class MyDbContext : DbContext
{
public MyDbContext() : base("MyConn")
{
}
}
.
public interface IPersonRepository
{
Task<Person> GetByIdentifierAsync(string identifier);
Task UpdateAsync(Person entity);
//More methods...
}
.
public class PersonRepository : IPersonRepository
{
private readonly DbContext _dbContext;
public PersonRepository(DbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Person> GetByIdentifierAsync(string identifier)
{
var personList = await _dbContext.Set<Person>().Where(x => x.Identifier == identifier).ToListAsync().ConfigureAwait(false);
//More code...
return personList.SingleOrDefault();
}
public async Task UpdateAsync(Person entity)
{
//More code...
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
.
public class Person
{
public int Id { get; set; }
public string Identifier { get; set; }
//More properties...
}
One option that we noticed is working is to pick up DataContext using Particulars example to use UnitOfWorkSetupBehavior. But it does not fit that well in our scenario because we have a complicated setup with services and repositories injecting the DbContext in the constructor throughout our application.
Ie, the (partial) solution for now is to call the method on the repository like;
var person = await _personRepository.GetByIdentifierAsync(context.DataContext(), message.Identifier).ConfigureAwait(false);
But now, when we run inte more complicated scenarios this won¨t suffice.
So, what are we missing? What is really the issue here?
Ninject PerThreadScope uses System.Threading.Thread.CurrentThread. With async in place the thread can change potentially for every continuation (the code that follows an await statement). You can either use a custom named scope, an async local scope or use the InUnitOfWorkScope from NServiceBus.Ninject.

How to get controller's ModelState in service for validation

I am exactly at the situation where this person (Controller ModelState with ModelStateWrappper) is except that I am using Castle Windsor DI. I am trying to validate my model's business logic side in my service before I save the model pass it to the data store. if the validation fails I want to get the model state errors and display in my view.
(I am following this article as a guide to implement validation from service: http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs)
Below is my sample code,
//My controller code
public class TimeEntryController : TempoBaseController
{
public TimeEntryController(TimeService service, UserService userService)
{
_service = service;
_userService = userService;
}
[Authorize(Roles = "Worker")]
public ActionResult Index()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(EntryLogDto entry)
{
if(_service.AddEntryLog(entry))
{
return ViewSuccess();
}else
{
return ViewFailue();
}
}
}
//My Service class
public class TimeService : GenericService
{
public TimeService(IRepository repository, IValidationDictionary validationDictionary, UserManager<ApplicationUser> userManager)
: base(repository, validationDictionary, userManager)
{
}
public bool AddEntryLog(EntryLogDto log)
{
if (!ValidateEntryLog(log))
{
//return false;
}
else
{
//insert entry into database and return true
}
}
protected bool ValidateEntryLog(EntryLogDto log)
{
//Check if the entry overlaps with any other entries
bool res = _repository.Find<EntryLogDto>(//my linq logic);
if (res)
{
_validationDictionary.IsValid = true;
}else
{
_validatonDictionary.AddError("Entry", "Entry Overlaps.");
_validationDictionary.IsValid = false;
}
return _validationDictionary.IsValid;
}
}
//Validation class
public class TempoValidation : IValidationDictionary
{
private ModelStateDictionary _modelState;
public TempoValidation(ModelStateDictionary modelState) // Issue is how am I gona give it this as the ModelStateDictiona ry is controller specific
{
_modelState = modelState;
}
public void AddError(string key, string error)
{
_modelState.AddModelError(key, error);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
}
//Global.asax castle compnonent registration method
container
.Register(Component
.For<Tempo.Model.Configuration.TempoDbContext>()
.LifestylePerWebRequest()
.DependsOn(new { connectionString }))
.Register(Component
.For<DbRepositories.ITempoDataContextFactory>()
.AsFactory())
.Register(Component
.For<IRepository>()
.ImplementedBy<Tempo.Repositories.EntityFrameworkRepository.Repository>())
.Register(Component
.For<TimeService>().LifestyleTransient())
I am injecting IValidationDictionary in my service class where I set the model state depending on the validation result. Is there a way I can pass in the model state of the controller when I use it? I don't know how to approach this, I have many controllers and I don't know how I will/when will I pass the respective controller's model state (I would like to do that by DI if its possible )... I don't know if castle can create a separate instance of TempoValidation class for each controller??
I know that this is impossible to do this by default, but you can use Fluent Validation to achieve this.
Example:
ViewModel
[Validator(typeof(VmSysTestValidator))]
public class VmSysTestModel
{
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
Fluent validation implementation :
public class VmSysTestValidator : AbstractValidator<VmSysTestModel>
{
public VmSysTestValidator()
{
RuleFor(x => x.FirstName).NotNull().WithMessage("First name is required");
RuleFor(x => x.LastName).NotNull().WithMessage("Last Name is required");
}
}
Controller or business logic side :
[HttpPost]
public ActionResult TestPost(VmSysTestModel obj)
{
//Start Validation From start to end you can call this code everywhere you want , this will work like server side valdiatin
//Instead of ModelState.IsValid you will call your fluent validator
var testValidator = new VmSysTestValidator();
var validationResult = testValidator.Validate(obj);
if (validationResult.IsValid)
{
}
else
{
}
//End valdiation
}

Ninject not injecting and throwing null reference exceptions

I'm new to Ninject so I'm sure that it's something I'm doing wrong, I'm just not sure what. I'm using Ninject and Ninject.MVC3 in my MVC3 web application. Here's an example of what I'm trying to do.
I'm using the Repository pattern:
public interface IRepository<T>
{
T Get(object id);
IList<T> GetAll();
void Add(T value);
void Update(T value);
void Delete(T value);
}
For a concrete type:
public Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Customer()
{
}
}
Now I have 2 separate repositories, a cached version that needs injection to the database repository:
public CachedCustomerRepository : IRepository<Customer>
{
private IRepository<Customer> _repository;
public Customer Get(object id)
{
Customer cust = new Customer();
IList<Customer> custs = GetAll();
if (custs != null && custs.Count > 0)
cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString()));
return cust;
}
public IList<Customer> GetAll()
{
IList<Customer> custs = HttpRuntime.Cache["Customers"] as IList<Customer>;
if (custs == null)
{
custs = _repository.GetAll();
if (custs != null && custs.Count() > 0)
{
double timeout = 600000d;
HttpRuntime.Cache.Insert("Customers", custs, null, DateTime.UtcNow.AddMilliseconds(timeout), System.Web.Caching.Cache.NoSlidingExpiration);
}
else
{
throw new NullReferenceException();
}
}
return custs;
}
public void Add(Customer value)
{
throw new NotImplementedException();
}
public void Update(Customer value)
{
throw new NotImplementedException();
}
public void Delete(Customer value)
{
throw new NotImplementedException();
}
public CachedCustomerRepository()
{
}
[Inject]
public CachedCustomerRepository(IRepository<Customer> repository)
{
_repository = repository;
}
}
public class CustomerRepository : IRepository<Customer>
{
public Customer Get(object id)
{
Customer cust = new Customer();
IList<Customer> custs = GetAll();
if (custs != null && custs.Count > 0)
cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString()));
return cust;
}
public IList<Customer> GetAll()
{
//Customer retrieval code
}
public void Add(Customer value)
{
throw new NotImplementedException();
}
public void Update(Customer value)
{
throw new NotImplementedException();
}
public void Delete(Customer value)
{
throw new NotImplementedException();
}
public CachedCustomerRepository()
{
}
}
I set up a NinjectModule like this:
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IRepository<Customer>>().To<CustomerRepository>();
}
}
and I modified the NinjectMVC3.cs in the AppStart folder to get the module when creating the kernel:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel(new ServiceModule());
RegisterServices(kernel);
return kernel;
}
In my controller I am using this:
public ViewResult Index()
{
IRepository<Customer> custRepo = new CachedCustomerRepository();
return View(custRepo.GetAll());
}
It blows up on the line _repository.GetAll() in my CachedCustomerRepository.
I've set a breakpoint to make sure that the CreateKernel() is executing and getting the bindings, which it is. I'm just not sure why the injection isn't happening. One other side note, I don't know if it's important or not, the IRepository, the Repositories and the concrete type are in a separate class library and is referenced in the mvc3 web app. Both the web app and the class library have a reference to Ninject and the web app also has a reference to Ninject.MVC3. The binding and kernel creation is all taking place in the Web App.
First, you're calling the wrong constructor in your controller. This parameterless constructor doesn't call anything else and that's why you're getting the null exception. Second, you want to refactor your controller so that there are no direct dependencies.
You'd want to do something like the following:
public class SomeController
{
private readonly IRepository<Customer> repo;
public SomeController(IRepository<Customer> repo)
{
this.repo = repo;
}
public ViewResult Index()
{
return View(this.repo.GetAll());
}
}
This way, Ninject resolves the dependency for you! Ninject's kernel will be asked to create a controller with IRepository<Customer> by MVC. Since Ninject has this "binding", it'll try to instantiate the CustomerRepository for you.
Also, why are you creating a "CachedRepository"? I really, really think you're prematurely optimizing this. Honestly, you only need the one CustomerRepository and you'd wire that up within the Ninject module.
Have you made the class in Global.asax inherit NinjectHttpApplication?
Make sure you're calling DependencyResolver.SetResolver(CreateKernel()); in order to tell MVC which resolver you're going to use. You might be calling it but I didn't see it in your post - otherwise your code looks fine.
To get the full benefit of using an IOC you should refactor the CachedCustomerRepository dependency from you controller class. You will need to add a new binding to the your Ninject module. This binding will need to use the context to determine if it is binding the 'IRepository' to a CachedCustomerRepository instance or to the MVC Controller instance. Once you have that factored out, then Ninject will create and manage the lifetimes of both objects.
The problem is that when you create the CachedCustomerRepository in your action method, you're just instantiating it yourself and you're not getting Ninject to instantiate it for you and subsequently inject it's dependencies.
What you should do is use constructor injection for the controller.
E.g.
public class MyController : Controller
{
public IRepository<Customer> CustomerRepo { get; protected set; }
public MyController(IRepository<Customer> customerRepo)
{
CustomerRepo = customerRepo;
}
public ViewResult Index()
{
return View(CustomerRepo.GetAll());
}
}
Your scenario is slightly confusing though, because you are injecting a IRepository<Customer> into a IRepository<Customer> that needs to be injected into MyController.

Categories

Resources