EF .Net Core reach class from Controller - c#

I have .net core project and wanted to connect db with ef. Below code is my db context.
public class YTContext:DbContext
{
public YTContext(DbContextOptions<YTContext> options) : base(options) { }
//protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
//{
// optionsBuilder.UseMySql(#"Server=localhost;Database=kariyer_portal;Uid=root;Pwd=1234;");
//}
public DbSet<Student> Students { get; set; }
public DbSet<University> Universities { get; set; }
public DbSet<Bolum> Bolums { get; set; }
public DbSet<Admin> Admins { get; set; }
public DbSet<Announcement> Announcements { get; set; }
}
In Startup.class I wrote conntection.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITest, MyConfig>();
services.AddMvc();
services.AddMvc().AddJsonOptions( options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore );
services.AddDbContext<YTContext>(options => options.UseMySql(Configuration.GetConnectionString("MySqlCon")));
}
In my repository class I wrote below .
public class StudentRepository
{
private readonly YTContext _db;
public StudentRepository(YTContext context)
{
_db = context;
}
public List<Student> GetStudents(int page, int limit = 8, string query = null)
{
try
{
var skip = (page - 1) * limit;
var students = _db.Students.Where(x => query == null || x.Name.Contains(query) || x.Surname.Contains(query) || x.University.Name.Contains(query) || x.Bolum.Name.Contains(query))
.Include(x=>x.Bolum).Include(x=>x.University)
.Skip(skip).Take(limit).ToList();
return students;
}
catch (Exception ex)
{
return null;
}
}
}
My problem is that I cant reach this class from controller below code.
public class StudentController : Controller
{
public StudentRepository repo;
[HttpGet]
public IActionResult List()
{
var students = repo.GetStudents(1, 6,null);
return View(students);
}
[HttpPost]
public IActionResult Paginate(Paginate paginate)
{
var students = repo.GetStudents(paginate.page, paginate.limit,paginate.query);
return Json(new {status = 200, student = students});
}
}
public StudentRepository repo;
The code above return null in controller. How can I reach this class from controller?

You need to register it in the DI-Container in Startup:
services.AddScoped<StudentRepository, StudentRepository>();
And then inject it to your controller's constructor:
public StudentController(StudentRepository studentRepo) {
repo = studentRepo;
}

Related

EF Core: Implement a single endpoint for all Subtypes

I'm having an issue where I try to make one endpoint for all classes that derive the same class.
One of my Core Entities is called Cell and has many deriving types such as ImageCell, VideoCell and so on.
The project is implemented using Ardalis.Specification and Ardalis.Specification.EntityFrameworkCore.
For reference here is the base class Cell and two deriving classes.
public abstract class Cell : IAggregateRoot
namespace Core.Entities.Aggregates
{
public abstract class Cell : IAggregateRoot
{
public int CellId { get; set; }
public string CellType { get; set; }
public int RowIndex { get; set; }
public int ColIndex { get; set; }
public int RowSpan { get; set; }
public int ColSpan { get; set; }
public int PageId { get; set; }
public Page Page { get; set; }
}
}
namespace Core.Entities.Cells
{
public class ImageCell : Cell
{
public string Url { get; set; }
}
}
namespace Core.Entities.Cells
{
public class TextCell : Cell
{
public string Text { get; set; }
}
}
All classes have a corresponding DTO.
namespace API.DTOs
{
public class CellDTO : DTO
{
public int CellId { get; set; }
public string CellType { get; set; }
public int RowIndex { get; set; }
public int ColIndex { get; set; }
public int RowSpan { get; set; }
public int ColSpan { get; set; }
public int PageId { get; set; }
}
}
namespace API.DTOs.Cells
{
public class ImageCellDTO : CellDTO
{
public string ImageUrl { get; set; }
}
}
namespace API.DTOs.Cells
{
public class TextCellDTO : CellDTO
{
public string Text { get; set; }
}
}
The MappingProfile is set up according to the documentation:
namespace API
{
public class MappingProfile : Profile
{
public MappingProfile()
{
// Entity -> DTO
...
// Cells
// https://docs.automapper.org/en/stable/Mapping-inheritance.html
CreateMap<Cell, CellDTO>()
.IncludeAllDerived();
CreateMap<ImageCell, ImageCellDTO>();
CreateMap<AudioTextCell, AudioTextCellDTO>();
CreateMap<AudioCell, AudioCellDTO>();
CreateMap<GameCell, GameCellDTO>();
CreateMap<TextCell, TextCellDTO>();
CreateMap<VideoCell, VideoCellDTO>();
...
// DTO -> Enitity
...
// Cells
CreateMap<CellDTO, Cell>()
.IncludeAllDerived();
CreateMap<AudioTextCellDTO, AudioTextCell>();
CreateMap<AudioCellDTO, AudioCell>();
CreateMap<GameCellDTO, GameCell>();
CreateMap<TextCellDTO, TextCell>();
CreateMap<VideoCellDTO, VideoCell>();
CreateMap<ImageCellDTO, ImageCell>();
...
}
}
}
The Repository is set up like this:
using Ardalis.Specification;
namespace Core.Interfaces
{
public interface IRepository<T> : IRepositoryBase<T> where T : class, IAggregateRoot
{
}
}
using Ardalis.Specification;
namespace Core.Interfaces
{
public interface IReadRepository<T> : IReadRepositoryBase<T> where T : class, IAggregateRoot
{
}
}
namespace Infrastructure.Data
{
public class EfRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
public EfRepository(BookDesinerContext dbContext) : base(dbContext)
{
}
}
}
Service like this:
namespace Core.Interfaces
{
public interface IService<T> where T : class, IAggregateRoot
{
Task<bool> ExistsByIdAsync(int id);
Task<T> GetByIdAsync(int id);
Task<T> GetByIdAsyncWithSpec(Specification<T> spec);
Task<IEnumerable<T>> ListAsync();
Task<IEnumerable<T>> ListAsyncWithSpec(Specification<T> spec);
Task DeleteByIdAsync(int id);
Task DeleteRangeAsync(IEnumerable<T> range);
Task<T> AddAsync(T t);
Task UpdateAsyc(T t);
}
}
Now I created a default implementation:
using Ardalis.Specification;
using Core.Interfaces;
namespace Core.Services
{
public class GenericService<T> : IService<T> where T : class, IAggregateRoot
{
private readonly IRepository<T> _repository;
private readonly IAppLogger<GenericService<T>> _logger;
public GenericService(IRepository<T> repository, IAppLogger<GenericService<T>> logger)
{
_repository = repository;
_logger = logger;
}
public async Task<bool> ExistsByIdAsync(int id)
{
return await _repository.GetByIdAsync(id) != null;
}
public async Task<T> GetByIdAsync(int id)
{
var t = await _repository.GetByIdAsync(id);
if (t == null)
{
_logger.Error($"Element with id: {id} can not be found!");
throw new ArgumentException($"Element with id: {id} can not be found!");
}
return t;
}
public async Task<T> GetByIdAsyncWithSpec(Specification<T> spec)
{
if (!(spec is ISingleResultSpecification))
{
throw new ArgumentException("Specification does not implement marker interface.");
}
ISingleResultSpecification<T> specification = (ISingleResultSpecification<T>)spec;
var t = await _repository.GetBySpecAsync(specification);
if (t == null)
{
_logger.Error($"Element can not be found!");
throw new ArgumentException($"Element can not be found!");
}
return t;
}
public async Task<IEnumerable<T>> ListAsync()
{
return await _repository.ListAsync();
}
public async Task<IEnumerable<T>> ListAsyncWithSpec(Specification<T> spec)
{
return await _repository.ListAsync(spec);
}
public async Task DeleteByIdAsync(int id)
{
var t = await _repository.GetByIdAsync(id);
if (t == null)
{
_logger.Error($"Element with id: {id} can not be found!");
throw new ArgumentException($"Element with id: {id} can not be found!");
}
await _repository.DeleteAsync(t);
}
public async Task DeleteRangeAsync(IEnumerable<T> range)
{
await _repository.DeleteRangeAsync(range);
}
public async Task<T> AddAsync(T t)
{
return await _repository.AddAsync(t);
}
public async Task UpdateAsyc(T t)
{
await _repository.UpdateAsync(t);
}
}
}
I registered a Service for every single Subtype:
builder.Services.AddScoped<IService<Cell>, GenericService<Cell>>();
builder.Services.AddScoped<IService<ImageCell>, GenericService<ImageCell>>();
builder.Services.AddScoped<IService<TextCell>, GenericService<TextCell>>();
builder.Services.AddScoped<IService<AudioCell>, GenericService<AudioCell>>();
builder.Services.AddScoped<IService<AudioTextCell>, GenericService<AudioTextCell>>();
builder.Services.AddScoped<IService<VideoCell>, GenericService<VideoCell>>();
builder.Services.AddScoped<IService<GameCell>, GenericService<GameCell>>();
And for the final part the controller:
namespace API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CellsController : BaseController<Cell, CellDTO>
{
private readonly IService<ImageCell> _imageCellService;
private readonly IService<TextCell> _textCellService;
private readonly IService<AudioCell> _audioCellService;
private readonly IService<AudioTextCell> _audioTextCellService;
private readonly IService<VideoCell> _videoCellService;
private readonly IService<GameCell> _gameCellService;
public CellsController(
IService<Cell> service,
IService<ImageCell> imageCellService,
IService<TextCell> textCellService,
IService<AudioCell> audioCellService,
IService<AudioTextCell> audioTextCellService,
IService<VideoCell> videoCellService,
IService<GameCell> gameCellService,
IMapper mapper) : base(service, mapper)
{
_imageCellService = imageCellService;
_textCellService = textCellService;
_audioCellService = audioCellService;
_audioTextCellService = audioTextCellService;
_videoCellService = videoCellService;
_gameCellService = gameCellService;
}
[HttpGet]
public override async Task<IActionResult> Get()
{
var result = new List<Object>();
// Add ImageCells
ICollection<ImageCell> imageCells = (ICollection<ImageCell>)await _imageCellService.ListAsync();
result.AddRange(_mapper.Map<ICollection<ImageCell>, ICollection<CellDTO>>(imageCells));
// Add TextCells
ICollection<TextCell> textCells = (ICollection<TextCell>)await _textCellService.ListAsync();
result.AddRange(_mapper.Map<ICollection<TextCell>, ICollection<CellDTO>>(textCells));
...
return Ok(result);
}
[HttpGet("Page/{pageId}")]
public async Task<IActionResult> GetByPageId(int pageId)
{
var result = new List<Object>();
// Add ImageCells
ICollection<ImageCell> imageCells = (ICollection<ImageCell>)await _imageCellService.ListAsync();
result.AddRange(_mapper.Map<ICollection<ImageCell>, ICollection<ImageCellDTO>>(imageCells.Where(c => c.PageId == pageId).ToList()));
// Add TextCells
ICollection<TextCell> textCells = (ICollection<TextCell>)await _textCellService.ListAsync();
result.AddRange(_mapper.Map<ICollection<TextCell>, ICollection<TextCellDTO>>(textCells.Where(c => c.PageId == pageId).ToList()));
...
return Ok(result);
}
[HttpGet("{id}")]
public override async Task<IActionResult> Get(int id)
{
if (await _imageCellService.ExistsByIdAsync(id))
{
var result = await _imageCellService.GetByIdAsync(id);
return Ok(_mapper.Map<ImageCell, ImageCellDTO>(result));
}
if (await _textCellService.ExistsByIdAsync(id))
{
var result = await _textCellService.GetByIdAsync(id);
return Ok(_mapper.Map<TextCell, TextCellDTO>(result));
}
...
return NotFound();
}
...
}
}
This is a highly inefficient implementation to my understanding.
Problems:
I can call /Cells to get all Cells the way it was intended with the List<Object>. List<CellDTO> always led to a downcast, which was unintended.
The same problem occures in a DTO that is not shown, that has a List<CellDTO> as a property. But I would need the concrete subtypes in this list.
My goals:
Remove redundant code in the controller
Only register one CellSerivce
Correct mapping Entity <=> DTO
Things I have considered, but I could not find information to back my thesis:
Writing a CellSpecification that includes all subtypes
Creating a DTO that covers all fields from the subtypes
Try the following:
var cells = (ICollection<Cell>)await _cellService.ListAsync();
result.AddRange(_mapper.Map<ICollection<Cell>, ICollection<CellDTO>>(cells));
Where _cellService is IService<Cell>

InvalidOperationException: Unable to resolve service for type 'DataAccessContext' while attempting to activate 'UnitOfWork'

I am getting the below error. I am using .Net Core web API.
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'CustomerManager.Db.DataAccessContext' while attempting to activate 'CustomerManager.Repository.UnitOfWork'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)
Api Controller
[Route("api/[controller]")]
[ApiController]
public class CustomerController : ControllerBase
{
private ICustomersManager _customersManager = null;
public CustomerController(ICustomersManager customersManager)
{
_customersManager = customersManager;
}
[HttpGet]
public async Task<IActionResult> Get()
{
var customers = await _customersManager.GetAll();
return Ok(customers);
}
}
Customer Model
public class Customers
{
public Customers()
{
Customers customer = this;
customer.CustomerBankDetails = new List<CustomerBankDetail>();
customer.CustomerContactDetails = new List<CustomerContactDetail>();
customer.CustomerFamilyDetails = new List<CustomerFamilyDetail>();
customer.CustomerPhotos = new List<CustomerPhoto>();
}
public int Id { get; set; }
public string CustomerNo { get; set; }
public string CustomerName { get; set; }
public string Gender { get; set; }
public DateTime? CustomerEntryDate { get; set; }
public DateTime? DateOfBirth { get; set; }
public string Nationality { get; set; }
public bool? IsApproved { get; set; }
public bool IsActive { get; set; }
public bool? IsDeleted { get; set; }
public byte? SortedBy { get; set; }
public string Remarks { get; set; }
public virtual IEnumerable<CustomerBankDetail> CustomerBankDetails { get; set; }
public virtual IEnumerable<CustomerContactDetail> CustomerContactDetails { get; set; }
public virtual IEnumerable<CustomerFamilyDetail> CustomerFamilyDetails { get; set; }
public virtual IEnumerable<CustomerPhoto> CustomerPhotos { get; set; }
}
Customer Business Layer Code
public interface ICustomersManager
{
Task<List<Customers>> GetAll();
}
BLL Implementation
public class CustomersManager : ICustomersManager
{
private IUnitOfWork _unitOfWork = null;
public CustomersManager(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task<List<Customers>> GetAll()
{
return await _unitOfWork.CustomerRepository.GetAllAsync();
}
}
Unit Of Work Interface
public interface IUnitOfWork : IDisposable
{
ICustomerRepository CustomerRepository { get; }
}
Unit of work implementation
public class UnitOfWork : IUnitOfWork
{
#region properties
private readonly DataAccessContext _context;
private ICustomerRepository _customerRepository;
public UnitOfWork(DataAccessContext context)
{
_context = context;
}
#endregion
public ICustomerRepository CustomerRepository =>
_customerRepository ?? (_customerRepository = new CustomerRepository(_context));
public void Dispose()
{
_customerRepository = null;
}
}
Customer Repository Interface
public interface ICustomerRepository : IRepository<Customers>
{
}
Customer Repository Implementation
public class CustomerRepository : BaseRepository, ICustomerRepository
{
public CustomerRepository(DataAccessContext objDataAccessContext) : base(objDataAccessContext)
{
}
public Task<List<Customers>> GetAllAsync()
{
return Task.Run(() =>
{
var objCustomerList = new List<Customers>();
ObjDbCommand.Parameters.Clear();
ObjDbCommand.AddInParameter("#Id", null);
try
{
ObjDbDataReader = ObjDataAccessContext.ExecuteReader(ObjDbCommand, "dbo.prGetAllCustomers", CommandType.StoredProcedure);
if (ObjDbDataReader.HasRows)
while (ObjDbDataReader.Read())
{
var objCustomer = new Customers();
BuildModel(ObjDbDataReader, objCustomer);
objCustomerList.Add(objCustomer);
}
}
catch (Exception ex)
{
throw new Exception("Error : " + ex.Message);
}
finally
{
if (ObjDbDataReader != null) ObjDbDataReader.Close();
ObjDataAccessContext.Dispose(ObjDbCommand);
}
return objCustomerList;
});
}
}
Generic Repository Interface
public interface IRepository<TEntity> where TEntity : class
{
Task<List<TEntity>> GetAllAsync();
}
Generic Repository Implementation
public class BaseRepository
{
protected readonly DataAccessContext ObjDataAccessContext;
protected readonly DbCommand ObjDbCommand;
protected DbDataReader ObjDbDataReader;
protected BaseRepository(DataAccessContext objDataAccessContext)
{
ObjDataAccessContext = objDataAccessContext;
ObjDbCommand = ObjDataAccessContext.GetCommand(true, IsolationLevel.ReadCommitted);
}
protected void BuildModel<T>(DbDataReader objDataReader, T item) where T : class
{
for (var inc = 0; inc < objDataReader.FieldCount; inc++)
{
var type = item.GetType();
var prop = type.GetProperty(objDataReader.GetName(inc));
var val = objDataReader.GetValue(inc) is DBNull || objDataReader.GetValue(inc).Equals(null) ||
string.IsNullOrEmpty(Convert.ToString(objDataReader.GetValue(inc)))
? null
: objDataReader.GetValue(inc);
prop?.SetValue(item, val, null);
}
}
}
Database Access Context using ADO.NET
public abstract class DataAccessContext
{
public DbCommand GetCommand(bool isTransaction, IsolationLevel isolationLevel)
{
var connectionString = DbConfiguration.ConnectionString;
return GetDbCommand(isTransaction, isolationLevel, connectionString);
}
public int ExecuteNonQuery(DbCommand objDbCommand, string textOrSpName, CommandType commandType)
{
try
{
objDbCommand.CommandType = commandType;
objDbCommand.CommandText = textOrSpName;
return objDbCommand.ExecuteNonQuery();
}
catch (DbException sqlEx)
{
throw new Exception("ExecuteNonQuery " + textOrSpName, sqlEx);
}
}
public int ExecuteNonQuery(DbCommand objDbCommand)
{
try
{
return objDbCommand.ExecuteNonQuery();
}
catch (DbException sqlEx)
{
throw new Exception("ExecuteNonQuery " + objDbCommand.CommandText, sqlEx);
}
}
public DbDataReader ExecuteReader(DbCommand objDbCommand, string textOrSpName, CommandType commandType)
{
try
{
objDbCommand.CommandType = commandType;
objDbCommand.CommandText = textOrSpName;
return objDbCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (DbException sqlEx)
{
throw new Exception("ExecuteReader " + textOrSpName, sqlEx);
}
}
public DbDataReader ExecuteReader(DbCommand objDbCommand)
{
try
{
return objDbCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (DbException sqlEx)
{
throw new Exception("ExecuteReader " + objDbCommand.CommandText, sqlEx);
}
}
public void Dispose(DbCommand objDbCommand)
{
if (objDbCommand.Connection != null)
{
objDbCommand.Connection.Dispose();
objDbCommand.Connection = null;
}
if (objDbCommand.Transaction != null)
{
objDbCommand.Transaction.Dispose();
objDbCommand.Transaction = null;
}
objDbCommand.Dispose();
objDbCommand = null;
}
private DbCommand GetDbCommand(bool bIsTransaction, IsolationLevel isolationLevel, string connectionString)
{
// retrieve provider invariant name from web.config
var providerInvariantName = string.Empty;
if (string.IsNullOrEmpty(providerInvariantName))
providerInvariantName = "System.Data.SqlClient";
// create the specific invariant provider
//DbProviderFactories.RegisterFactory("System.Data.SqlClient", SqlClientFactory.Instance);
var objDbProviderFactory = DbProviderFactories.GetFactory(providerInvariantName);
var objDbConnection = objDbProviderFactory.CreateConnection();
if (objDbConnection == null) return null;
objDbConnection.ConnectionString = connectionString;
var objDbCommand = objDbProviderFactory.CreateCommand();
if (objDbCommand == null) return null;
objDbCommand.Connection = objDbConnection;
objDbConnection.Open();
if (bIsTransaction)
{
var objDbTransaction = objDbConnection.BeginTransaction(isolationLevel);
objDbCommand.Transaction = objDbTransaction;
return objDbCommand;
}
return objDbCommand;
}
}
Here is the Startup.cs file
public void ConfigureServices(IServiceCollection services)
{
DbConfiguration.ServerName = Configuration["DbConnection:ServerName"];
DbConfiguration.DatabaseName = Configuration["DbConnection:DatabaseName"];
DbConfiguration.UserId = Configuration["DbConnection:UserId"];
DbConfiguration.Password = Configuration["DbConnection:Password"];
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//services.AddSingleton(typeof(DataAccessContext));
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
//Dependency Injection
//services.AddScoped(sp => sp.GetService(typeof(DataAccessContext)));
services.AddScoped<ICustomerRepository, CustomerRepository>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddScoped<ICustomersManager, CustomersManager>();
}
How to solve this issue?
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type
'CustomerManager.Db.DataAccessContext' while attempting to activate
'CustomerManager.Repository.UnitOfWork'.
That is because you do not register DataAccessContext in Startup.cs.
For your DataAccessContext is abstract,note that you generally cannot register abstract classes because they cannot be instantiated.
Change like below:
public class DataAccessContext {}
Register like below:
services.AddScoped(typeof(DataAccessContext));
Nothing in the shown code snippets demonstrates why DataAccessContext should be an abstract class.
Make it a concrete class
public class DataAccessContext {
//...code omitted for brevity
}
Second, classes should depend on abstractions of services and not concretions. DataAccessContext should have a backing abstraction.
public interface IDataAccessContext {
DbCommand GetCommand(bool isTransaction, IsolationLevel isolationLevel);
int ExecuteNonQuery(DbCommand objDbCommand, string textOrSpName, CommandType commandType);
int ExecuteNonQuery(DbCommand objDbCommand);
DbDataReader ExecuteReader(DbCommand objDbCommand, string textOrSpName, CommandType commandType);
DbDataReader ExecuteReader(DbCommand objDbCommand);
Dispose(DbCommand objDbCommand);
//...
}
and
public class DataAccessContext: IDataAccessContext {
//...code omitted for brevity
}
Dependent classes should then explicitly depend on that abstraction
For example
public class UnitOfWork : IUnitOfWork {
private readonly IDataAccessContext _context;
private ICustomerRepository _customerRepository;
public UnitOfWork(IDataAccessContext context) {
_context = context;
}
//...omitted for brevity
And the abstraction and implementation registered with the DI container
services.AddSingleton<IDataAccessContext, DataAccessContext>();
so that it is aware of how to resolve the service while activating its dependents
services.AddScoped is bether than AddSingleton for this solve

Cannot Implicilty Convert Type - Autofac C# & ASP.NET MVC

I have a fairly simple ASP.NET MVC app that I am trying to resolve some dependencies in my controller. I have casting problems with List and I am not sure what to do at this moment. I have read about the Resolve() method with Autofac, but again I am not sure if this will resolve my particular issue.
Here is my controller code:
public class NumbersController : Controller
{
private INumbersModel _model;
private INumbersBusinessLayer _numbersBusinessLayer;
private IEnumerable<INumbersModel> _modelList;
public NumbersController(INumbersModel model, IEnumerable<INumbersModel> modelList, INumbersBusinessLayer numbersBusinessLayer)
{
_model = model;
_numbersBusinessLayer = numbersBusinessLayer;
_modelList = new List<INumbersModel>(modelList);
}
public ActionResult Index()
{
_modelList = _numbersBusinessLayer.AllNumbers.ToList();
return View(_modelList);
}
[HttpGet]
public ActionResult Edit(int id)
{
_model = _numbersBusinessLayer.AllNumbers.Single(n => n.ID == id);
return View(_model);
}
}
Here are my two interfaces:
public interface INumbersBusinessLayer
{
IEnumerable<NumbersModel> AllNumbers { get; }
void AddNumbers(NumbersModel model);
void DeleteNumbers(int id);
void UpdateNumbers(NumbersModel model);
}
public interface INumbersModel
{
int ID { get; set; }
bool IsValid { get; set; }
string Numbers { get; set; }
string Order { get; set; }
string Time { get; set; }
}
Here is my container config:
public static void ConfigureDependencyInjection()
{
var builder = new ContainerBuilder();
// ...or you can register individual controlllers manually.
builder.RegisterType<NumbersController>().InstancePerRequest();
// register models
builder.RegisterType<NumbersModel>().As<INumbersModel>();
builder.RegisterType<List<NumbersModel>>().As<List<INumbersModel>>();
builder.RegisterType<NumbersBusinessLayer>().As<INumbersBusinessLayer>();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
In the browser I get this error:
The type 'System.Collections.Generic.List1[BusinessLayer.NumbersModel]' is not assignable to service 'System.Collections.Generic.List1[[BusinessLayer.INumbersModel, BusinessLayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
You should only need to register your INumbersBusinessLayer, since that is the only thing you actually need to inject into your controller.
Furthermore, change INumbersModel to a class, so you can use it.
So your controller then looks like this:
public class NumbersController : Controller
{
private INumbersBusinessLayer _numbersBusinessLayer;
public NumbersController(INumbersBusinessLayer numbersBusinessLayer)
{
_numbersBusinessLayer = numbersBusinessLayer;
}
public ActionResult Index()
{
var modelList = _numbersBusinessLayer.AllNumbers.ToList();
return View(modelList);
}
[HttpGet]
public ActionResult Edit(int id)
{
var model = _numbersBusinessLayer.AllNumbers.Single(n => n.ID == id);
return View(model);
}
}
Then you can simplify your AutoFac config:
public static void ConfigureDependencyInjection()
{
var builder = new ContainerBuilder();
// ...or you can register individual controlllers manually.
builder.RegisterType<NumbersController>().InstancePerRequest();
builder.RegisterType<NumbersBusinessLayer>().As<INumbersBusinessLayer>();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
and change your interface to a class:
public class NumbersModel
{
int ID { get; set; }
bool IsValid { get; set; }
string Numbers { get; set; }
string Order { get; set; }
string Time { get; set; }
}
Since your businesslayer interface already expects Numbersmodel, but not INumbersmodel, no changes are needed there.
Only two parameters require to be injected
private INumbersModel _model;
private INumbersBusinessLayer _numbersBusinessLayer;
public NumbersController(INumbersModel model,INumbersBusinessLayer numbersBusinessLayer)
{
_model = model;
_numbersBusinessLayer = numbersBusinessLayer
}
and no need to register a list of NumbersModel, comment this line and try again
builder.RegisterType<List<NumbersModel>>().As<List<INumbersModel>>();

Object Reference Not Set to an Instance of an Object at Repository Layer

I am receiving null exception error on my framework. I have tried to apply Repository and Unit of Work design patterns in my application. What I am trying to do is simply retreiving user titles from my data base with GetAll() method.
Here is my repository class:
public class Repository<T> : IRepository<T> where T : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
this.Context = context;
}
public T Get(int id)
{
return Context.Set<T>().Find(id);
}
public IEnumerable<T> GetAll()
{
return Context.Set<T>().ToList();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Where(predicate);
}
public void Add(T entity)
{
Context.Set<T>().Add(entity);
}
public void AddRange(IEnumerable<T> entityList)
{
Context.Set<T>().AddRange(entityList);
}
public void Remove(T entity)
{
Context.Set<T>().Remove(entity);
}
public void RemoveRange(IEnumerable<T> entityList)
{
Context.Set<T>().RemoveRange(entityList);
}
}
This is IUserTitlesRepository:
public interface IUserTitlesRepository : IRepository<UserTitles>
{
}
And, the class where above interface implemented:
public UserTitlesRepository(XaPaDataContext context) : base(context)
{
}
public XaPaDataContext XaPaDataContext
{
get { return Context as XaPaDataContext; }
}
Before coming to Controller layer, I have two more layers, which are Operation and Manager layers. And, I think I have messed up on that part (on Base Manager class as shown below).
This is operation layer:
public class UserTitlesOperations
{
private readonly IUnitOfWork _uow;
public UserTitlesOperations(IUnitOfWork uow)
{
_uow = uow;
}
public List<UserTitles> GetAllUserTitles()
{
try
{
List<UserTitles> userTitleList = _uow.UserTitles.GetAll().ToList();
_uow.Complete();
return userTitleList;
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
}
Below is the BaseManager class which gives inheritance to all manager classes.
public abstract class BaseManager
{
private IUnitOfWork _iUow;
private readonly XaPaDataContext _context;
public IUnitOfWork IUOW
{
get
{
if (_iUow == null)
{
_iUow = new XaPaUnitOfWork(_context);
}
return _iUow;
}
}
}
This is the manager class:
public class UserTitlesManager : BaseManager
{
private readonly UserTitlesOperations _userTitlesOperations;
public UserTitlesManager()
{
_userTitlesOperations = new UserTitlesOperations(base.IUOW);
}
public List<UserTitlesWM> GetAllUserTitles()
{
try
{
return UserTitlesMapping.MaptoWM(_userTitlesOperations.GetAllUserTitles());
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
}
Finally, this is my API Controller:
[Route("api/LoginRequest")]
public class TitlesController : BaseController
{
UserTitlesManager _userTitlesManager;
public LoginController()
{
_userTitlesManager = new UserTitlesManager();
}
[Route("RetreiveTitles")]
public HttpResponseMessage GetTitles()
{
try
{
return Request.CreateResponse(HttpStatusCode.OK, _userTitlesManager.GetAllUserTitles());
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex.ToString());
}
}
}
By the way BaseController is just another API controller which gives inheritance to all other API controllers, and houses a method which is used by all the other controllers.
So, I'm still trying to sharpen my self on this design patterns and would be glad if anyone could show my mistake on BaseManager class. As I said, I suppose the problem is caused by that private readonly XaPaDataContext _context; line. On the other hand,I can't figure out how to corrrect it as my operation classes' constructors are asking for IUnitOfWork.
Thank you in advance!
EDIT:
Just realized that I forgot to share my Unit of Work class:
public class XaPaUnitOfWork : IUnitOfWork
{
private readonly XaPaDataContext _context;
public XaPaUnitOfWork(XaPaDataContext context)
{
_context = context;
Categories = new CategoriesRepository(_context);
OrderDetails = new OrderDetailsRepository(_context);
Orders = new OrdersRepository(_context);
ProductImages = new ProductImagesRepository(_context);
Products = new ProductsRepository(_context);
Users = new UsersRepository(_context);
UserTitles = new UserTitlesRepository(_context);
UserTokens = new UserTokensRepository(_context);
}
public ICategoriesRepository Categories { get; private set; }
public IOrderDetailsRepository OrderDetails { get; private set; }
public IOrdersRepository Orders { get; private set; }
public IProductImagesRepository ProductImages { get; private set; }
public IProductsRepository Products { get; private set; }
public IUsersRepository Users { get; private set; }
public IUserTitlesRepository UserTitles { get; private set; }
public IUserTokensRepository UserTokens { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
After I have changed my BaseManager class as below:
public abstract class BaseManager
{
private IUnitOfWork _iUow;
public IUnitOfWork IUOW
{
get
{
if (_iUow == null)
{
_iUow = new XaPaUnitOfWork(new XaPaDataContext());
}
return _iUow;
}
}
}
I have achived to receive HttpStatusCode.OK
But, honestly, I'm still unsure about the real reason. I make this correction mostly by heart.

ConcurrencyExeption on ASP.NET MVC Application

Introduction to the Problem
First of all I tried everything to figure out this problem by no result. I am currently trying to design a repository pattern on my own for the first time.
My application is just a Blog Website and it has some components. I will directly point to the problem for you.
Problem
When I want to update a post through repository system throws an exception (Concurrency Exception) but I am sure that this type of exception occurs when you define a "[TimeStamp]" column type in Post Table. I know how to handle this exception exactly and I am sure nobody is updating the post which I am updating currently because it works on local system. I think no reason to occur this exception except a reason which I don't know and maybe you can help me at this point.
I defined the problem explicitly for you then let's go code blocks;
Components
I have this AdminController
public class AdminController : Controller
{
private IDbFactory _dbFactory;
private IUnitOfWork _unitOfWork;
private ICategoryRepository _categoryRepository;
private IPostRepository _postRepository;
private ITagRepository _tagRepository;
public ICategoryRepository categoryRepository
{
get
{
return _categoryRepository ?? (_categoryRepository = new CategoryRepository(HttpContext.GetOwinContext().Get<DbFactory>()));
}
set
{
_categoryRepository = value;
}
}
public IPostRepository postRepository
{
get
{
return _postRepository ?? (_postRepository = new PostRepository(HttpContext.GetOwinContext().Get<DbFactory>()));
}
set
{
_postRepository = value;
}
}
public ITagRepository tagRepository
{
get
{
return _tagRepository ?? (_tagRepository = new TagRepository(HttpContext.GetOwinContext().Get<DbFactory>()));
}
set
{
_tagRepository = value;
}
}
public IDbFactory dbFactory
{
get
{
return _dbFactory ?? (_dbFactory =
HttpContext.GetOwinContext().Get<DbFactory>());
}
}
public IUnitOfWork unitOfWork
{
get
{
return _unitOfWork ?? (_unitOfWork =
HttpContext.GetOwinContext().Get<UnitOfWork>());
}
}
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult UpdatePost([Bind(Include = "IntroText, PostText, CodeText, Header, Author, ImagePath, CategoryID")] ViewPostModel model)
{
if (ModelState.IsValid)
{
Post post = new Post();
post = Mapper.Map<ViewPostModel, Post>(model);
if (model.CodeText != null)
post.PostText = GetCodedPostText(model.PostText, model.CodeText);
post.CreatedDate = DateTime.Now.ToShortDateString();
post.CategoryID = model.CategoryID;
postRepository.Update(post);
unitOfWork.SaveChanges(); // Throws and exception (Concurrency Exception)
}
ViewBag.Categories = FillCategoriesForDropdownList();
return RedirectToAction("DetailPost");
}
}
I have this RepositoryBase generic class;
private IDbFactory dbFactory;
private AppDbContext context;
private ICategoryRepository _categoryRepository;
private IPostRepository _postRepository;
private ITagRepository _tagRepository;
//public ICategoryRepository categoryRepository
//{
// get
// {
// return _categoryRepository ?? (_categoryRepository = new CategoryRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>()));
// }
// set
// {
// _categoryRepository = value;
// }
//}
//public IPostRepository postRepository
//{
// get
// {
// return _postRepository ?? (_postRepository = new PostRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>()));
// }
// set
// {
// _postRepository = value;
// }
//}
//public ITagRepository tagRepository
//{
// get
// {
// return _tagRepository ?? (_tagRepository = new TagRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>()));
// }
// set
// {
// _tagRepository = value;
// }
//}
AppDbContext db
{
get
{
return context ?? (context = dbFactory.Init());
}
}
public ICategoryRepository categoryRepository
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public IPostRepository postRepository
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public ITagRepository tagRepository
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public static UnitOfWork Create()
{
return new UnitOfWork(HttpContext.Current.GetOwinContext().Get<DbFactory>());
}
public UnitOfWork(IDbFactory _dbFactory)
{
dbFactory = _dbFactory;
}
public void SaveChanges()
{
db.SaveChanges();
}
public void Dispose()
{
}
}
I have this Post Repository;
public class PostRepository : RepositoryBase<Post>, IPostRepository, IDisposable
{
public PostRepository(IDbFactory dbFactory) : base(dbFactory) { }
public static PostRepository Create()
{
return new PostRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>());
}
public void Dispose()
{
}
}
I have this Database Initializer;
public class AppDbInitializer : DropCreateDatabaseAlways<AppDbContext>
{
protected override void Seed(AppDbContext context)
{
SeedIdentity(context);
SeedTables(context);
base.Seed(context);
}
private void SeedIdentity(AppDbContext context)
{
//var userManager = HttpContext.Current.GetOwinContext().GetUserManager<AppUserManager>();
//var roleManager = HttpContext.Current.GetOwinContext().Get<AppRoleManager>();
const string name = "admin#example.com";
const string password = "SelcuK99.";
const string roleName = "Admin";
#region Old
//var role = roleManager.FindByName(roleName);
//AppRole role = null;
//if (role == null)
//{
// role = new AppRole(roleName);
// var roleresult = roleManager.Create(role);
//}
//AppUser user = null;
////var user = userManager.FindByName(name);
//if (user == null)
//{
// user = new AppUser { UserName = name, Email = name };
// var result = userManager.Create(user, password);
// result = userManager.SetLockoutEnabled(user.Id, false);
//}
//var rolesForUser = userManager.GetRoles(user.Id);
//if (!rolesForUser.Contains(role.Name))
//{
// var result = userManager.AddToRole(user.Id, role.Name);
//}
#endregion
RoleStore<AppRole> roleStore = new RoleStore<AppRole>(context);
RoleManager<AppRole> roleManager = new RoleManager<AppRole>(roleStore);
AppRole role = new AppRole
{
Name = roleName
};
roleManager.Create(role);
UserStore<AppUser> userStore = new UserStore<AppUser>(context);
AppUserManager userManager = new AppUserManager(userStore);
AppUser user = new AppUser { Email = name, UserName = name};
userManager.Create(user, password);
userManager.AddToRole(user.Id, roleName);
}
}
I have this OwinContext startup class;
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext(AppDbContext.Create);
app.CreatePerOwinContext(DbFactory.Create);
app.CreatePerOwinContext(TagRepository.Create);
app.CreatePerOwinContext(CategoryRepository.Create);
app.CreatePerOwinContext(PostRepository.Create);
app.CreatePerOwinContext(UnitOfWork.Create);
app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create);
app.CreatePerOwinContext<AppSignInManager>(AppSignInManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType =
DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity =
SecurityStampValidator.OnValidateIdentity<AppUserManager, AppUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) =>
user.GenerateUserIdentityAsync(manager))
}
});
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
}
Here is AppDbContext
public class AppDbContext : IdentityDbContext<AppUser>
{
public AppDbContext() : base("AppDbContext", throwIfV1Schema: false) { }
public static AppDbContext Create()
{
return new AppDbContext();
}
public DbSet<Category> Categories { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
static AppDbContext()
{
Database.SetInitializer(new AppDbInitializer());
}
//protected override void OnModelCreating(DbModelBuilder modelBuilder)
//{
// modelBuilder.Configurations.Add(new CategoryConfiguration());
// modelBuilder.Configurations.Add(new PostConfiguration());
//}
}
I have this Post class
public class Post : BaseEntity, IAudit
{
public int CategoryID { get; set; }
public string IntroText { get; set; }
public string PostText { get; set; }
public string CodeText { get; set; }
public string Header { get; set; }
public string Author { get; set; }
public string ImagePath { get; set; }
public string CreatedDate { get; set; }
public string UpdatedDate { get; set; }
public virtual ICollection<PostTagMapping> PostTags { get; set; }
public Category Category { get; set; }
}
and finaly I have this ViewPostModel;
public class ViewPostModel : BaseEntity
{
public string PostText { get; set; }
public string IntroText { get; set; }
public string CodeText { get; set; }
public string Author { get; set; }
public string Header { get; set; }
public string ImagePath { get; set; }
public DateTime? CreatedDate { get; set; }
public DateTime? UpdatedDate { get; set; }
public int CategoryID { get; set; }
}
I forget to give you the DbFactory;
public class DbFactory : Disposable, IDbFactory
{
private AppDbContext context;
public static DbFactory Create()
{
return new DbFactory();
}
public AppDbContext Init()
{
int a;
if (context == null)
a = 5;
return (HttpContext.Current.GetOwinContext().Get<AppDbContext>());
}
protected override void DisposeCore()
{
if (context != null)
context.Dispose();
}
}
I give you everything to solve this issue.
Here is my assumptions and questions ##
Maybe somewhere there could be a race condition but how is that possible I am using static DbContext ?
Maybe there are two running DbContext instances but how is that possible again I am using static DbContext ?
Here is the details of the Exception
InnerException Message:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
StackTrace:
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at HybridBlog.Model.RepositoryBase`1.Update(TEntity entity) in D:\MVC_Projects\TrialProjects\HybridBlog\HybridBlog.Model\RepositoryBase.cs:line 71
at HybridBlog.Web.Controllers.AdminController.UpdatePost(ViewPostModel model) in D:\MVC_Projects\TrialProjects\HybridBlog\HybridBlog.Web\Controllers\AdminController.cs:line 153
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
BaseEntity.cs
public class BaseEntity
{
public int ID { get; set; }
}
I strongly suspect you aren't setting post.ID in your update method. You can verify this by checking the value of post.ID prior to the postRepository.Update(post); call.
I suspect you need to change:
public ActionResult UpdatePost([Bind(Include = "IntroText, PostText, CodeText, Header, Author, ImagePath, CategoryID")] ViewPostModel model)
{
to:
public ActionResult UpdatePost([Bind(Include = "ID, IntroText, PostText, CodeText, Header, Author, ImagePath, CategoryID")] ViewPostModel model)
{

Categories