I'm currently learning interfaces and repository pattern and have difficulties with it. I have domain class "VehicleMake"
public class VehicleMake
{
public VehicleMake()
{
}
[Key]
[Column(Order = 1)]
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public virtual ICollection<VehicleModel> VehicleModels { get; set; }
}
I also have an Interface "IVehicleRepository"
public interface IVehicleRepository
{
IEnumerable<VehicleMake> All { get; }
}
and a class "VehicleRepository" which implements that interface
public class VehicleRepository : IVehicleRepository
{
private readonly VehicleDbContext _context;
public VehicleRepository(VehicleDbContext context)
{
_context = context;
}
public IEnumerable<VehicleMake> All => _context.VehicleMakes;
}
My DbContext class is following
public class VehicleDbContext : DbContext
{
public VehicleDbContext() : base("VehicleDbContext")
{
}
public DbSet<VehicleMake> VehicleMakes { get; set; }
public DbSet<VehicleModel> VehicleModels { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
And my "VehicleController" is following
public class VehicleController : Controller
{
private readonly IVehicleRepository _vehicleRepository;
public VehicleController()
{
}
public VehicleController(IVehicleRepository vehicleRepository)
{
_vehicleRepository = vehicleRepository;
}
// GET: VehicleMakes
public ActionResult Index()
{
return View(_vehicleRepository.All);
}
}
So the problem is that when I try in my controller to retrieve "Vehicle Makes", I get null reference exception and I don't why. Did I implemented this properly? If not, what is the proper way to do this?
You are getting NullReferenceException because it's calling your parameterless constructor where you don't have initialization of _vehicleRepository field. Your initialization is in constructor where you are passing IVehicleRepository object.
I believe, you don't have dependedency injection framework registered for correctly getting instance. So, you can simply initialize _vehicleRepository in default constructor :
public class VehicleController : Controller
{
private readonly IVehicleRepository _vehicleRepository;
public VehicleController()
{
_vehicleRepository = new VehicleRepository();
}
// GET: VehicleMakes
public ActionResult Index()
{
return View(_vehicleRepository.All);
}
}
Change your VehicleRepository to support default constructor in following way :
public class VehicleRepository : IVehicleRepository
{
private readonly VehicleDbContext _context;
public VehicleRepository() : this(new VehicleDbContext())
{
}
public VehicleRepository(VehicleDbContext context)
{
_context = context;
}
public IEnumerable<VehicleMake> All => _context.VehicleMakes;
}
Related
am a beginner in ASP.NET Core. I am creating a Web API service. While I am fetching the data from the database, I had a problem. What is the error I got? I have successfully done the database migration part and created the database successfully.
StudentDbContext is null
StudentController
namespace webb.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class StudentController : ControllerBase
{
private StudentDbContext studentDbContext;
public StudentController(StudentDbContext studentDbContext)
{
studentDbContext = studentDbContext;
}
// GET: api/<EmployeeController>
[HttpGet]
public IEnumerable<Student> Get()
{
// var studens = studentDbContext.Student;
return studentDbContext.Student;
}
}
}
Model
public class Student
{
public int id { get; set; }
public string stname { get; set; }
public string course { get; set; }
}
}
StudentDbContext
public class StudentDbContext : DbContext
{
public StudentDbContext(DbContextOptions<StudentDbContext> options) : base(options)
{
}
public DbSet<Student> Student { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=ams;Integrated Security=True; TrustServerCertificate = True");
}
}
IDataService
public interface IDataService<T>
{
Task<IEnumerable<T>> GetAll();
Task<T> Get(int id);
Task<T> Create(T entity);
Task<bool> Delete(T entity);
Task<T> Update(T entity);
}
}
I have successfully done the database migration part and created the
database successfully. StudentDbContext is null
Well, two mistake has been done. Your model has no primary key. So you will always get null data when there is no primary key set to your table column.
Therefore, your model should be as following:
Model:
public class Student
{
[Key]
public int id { get; set; }
public string stname { get; set; }
public string course { get; set; }
}
Controller:
Another misake is here studentDbContext.Student; this will not bring anything. You would be liking to fetch student list instead. So you should write studentDbContext.Student.ToList();. As following"
[HttpGet]
public IEnumerable<Student> Get()
{
// var studens = studentDbContext.Student;
return studentDbContext.Student.ToList();
}
Note: In addition, your constructor convension is not correct, it can be written as following:
[Route("api/[controller]")]
[ApiController]
public class StudentController : ControllerBase
{
private readonly StudentDbContext _studentDbContext;
public StudentController(ApplicationDbContext studentDbContext)
{
_studentDbContext = studentDbContext;
}
// GET: api/<EmployeeController>
[HttpGet]
public IEnumerable<Student> Get()
{
// var studens = studentDbContext.Student;
return _studentDbContext.Student.ToList();
}
}
Note: You can check more details on asp.net core web api official document here
Output:
For further details you can have a look on official document here.
I have extended the IdentityUserRole which is as follow
public class ApplicationUserRoles : IdentityUserRole<string>
{
[Key]
public string ApplicationId { get; set; }
public virtual AspNetApplications AspNetApplications { get; set; }
}
and my AspNetApplications Class is as follow
public class AspNetApplications
{
[Key]
public string ApplicationId { get; set; }
public string ApplicationName { get; set; }
}
Migration has created the AspNetApplications and ApplicationUserRoles tables in DB. A screen shot is as follow.
Following is my Identity Model
public class ApplicationUser : IdentityUser
{
public virtual AspNetApplications AspNetApplication { get; set; }
public virtual ApplicationUserRoles AspNetUserRoles { get; set; }
//public virtual ICollection<AspNetApplicationUsers> AspNetApplicationUsers { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public DbSet<AspNetApplications> AspNetApplications { get; set; }
public DbSet<ApplicationUserRoles> AspNetUserRoles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUserRoles>().HasKey(m => new { m.ApplicationId, m.UserId, m.RoleId });
}
}
everything is good so far but now when I inspect the User in my Account Controller, it is still bringing Role based information from AspNetUserRoles. Could please anyone tell me how I can make use of my custom ApplicationUserRoles instead of IdentityUserRole.
If you look at the signature of IdentityUser (your ApplicationUser inherits from it)
public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
where TLogin : Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin<TKey>
where TRole : Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole<TKey>
where TClaim : Microsoft.AspNet.Identity.EntityFramework.IdentityUserClaim<TKey>
{
}
you can see that it accepts your custom definition of IdentityUserRole.
Your class MyApplicationUser you have to implement must implement the right type:
public class MyApplicationUser : IdentityUser<string, MyUserLogin, ApplicationUserRoles, MyUserClaim>
{
}
and your role:
public class MyRole : IdentityRole<string, ApplicationUserRoles>
{
}
and your ApplicationDbContext:
public class MyContext : IdentityDbContext<MyUser, MyRole, string, MyUserLogin, ApplicationUserRoles, MyUserClaim>
{
}
and your UserStore:
public class MyUserStore: UserStore<MyUser, MyRole, string, MyUserLogin, ApplicationUserRoles, MyUserClaim>
{
public MyUserStore(MyContext context)
: base(context)
{
}
}
That should be it, I guess. There's a github repo where I've played a bit with custom class and custom tables names.
I Have a PhoneBook Project in MVC and use IUnitOfWork .
but I dont Know that How do this project.
the link of the project :
http://www.mediafire.com/download/jy0b5ins5eisy5t/MvcAppPhoneBook.rar
please complate thie project for me
i'm doing CRUD in this project.
I've used generic repo and UoW in my projects as below. You can take reference of this to complete your project. I usually have 4 layer solution architecture:
Core
Model classes
Data
Generic Repo and UoW
DbContext
Code first migrations
Web
applications solution with dependency injection implementation (e.g.Ninject)
Test
Model classes
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
}
MyDbContext.cs:
public class MyDbContext : DbContext
{
public MyDbContext() : base("name=DefaultConnection”)
{
}
public System.Data.Entity.DbSet<User> Users { get; set; }
public System.Data.Entity.DbSet<Course> Courses { get; set; }
}
Unit of Work:
public class UnitOfWork : IUnitOfWork
{
//private variable for db context
private MyDbContext _context;
//initial db context variable when Unit of Work is constructed
public UnitOfWork()
{
_context = new MyDbContext();
}
//property to get db context
public MyDbContext Context
{
//if not null return current instance of db context else return new
get { return _context ?? (_context = new MyDbContext()); }
}
//save function to save changes using UnitOfWork
public void Save()
{
_context.SaveChanges();
}
}
Generic Repository:
public class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
protected readonly IUnitOfWork _unitOfWork;
private readonly IDbSet<T> _dbSet;
public RepositoryBase(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_dbSet = _unitOfWork.Context.Set<T>();
}
public virtual void Save()
{
_unitOfWork.Save();
}
public virtual void Add(T entity)
{
_dbSet.Add(entity);
_unitOfWork.Save();
}
//Similarly you can have Update(), Delete(), GetAll() implementation here
}
Entity Repository inheriting from generic repo:
public class UserRepository:RepositoryBase<User>,IUserRepository
{
public UserRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
//Here you can also define functions specific to User
}
controller.cs
public class UserController : Controller
{
private readonly IUserRepository _dbUserRepository;
public UserController(IUserRepository dbUserRepository)
{
_dbUserRepository = dbUserRepository;
}
// GET: /User/
public ActionResult Index()
{
var users = _dbUserRepository.GetAll();
return View(users.ToList());
}
//Other CRUD operations
}
I have a Model :
public class Post:
{
public string Description { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public Guid UniqId { get; set; }
public DateTime CreatedDate { get; set; }
public byte[] RowVersion { get; set; }
}
and i have a DataLayer that has EfContext and Iunitofwok pattern
using System.Data.Entity;
namespace Data
{
public interface IUnitOfWork
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
}
using System.Data.Entity;
using DomainModel;
namespace Data
{
public class EfContext : DbContext, IUnitOfWork
{
public DbSet<Post> Post { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Category> Categories { get; set; }
public EfContext()
: base("TavanGruop")
{
}
#region IUnitOfWork Members
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
#endregion
}
}
in another project i have repository
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using Data;
namespace ServiceLayer.ServiceDbSet
{
public class ServiceContext<T> : IServiceDbSet<T> where T : class
{
private readonly IDbSet<T> _dbSet;
public ServiceContext(IUnitOfWork iUnitOfWork)
{
_dbSet = iUnitOfWork.Set<T>();
}
#region IContext<T> Members
public bool TryGet(Func<T, bool> predicate, out T entity)
{
entity = List(predicate).SingleOrDefault();
return entity != null;
}
public T Get(Func<T, bool> predicate)
{
return List(predicate).Single();
}
public virtual List<T> List(Func<T, bool> predicate = null)
{
IEnumerable<T> result = _dbSet.AsEnumerable();
if (predicate != null)
result = result.Where(predicate);
return result.ToList();
}
public T Add(T t)
{
_dbSet.Add(t);
return t;
}
public void Delete(Func<T, bool> predicate)
{
List(predicate).ToList().ForEach(p => _dbSet.Remove(p));
}
public void Delete(T t)
{
_dbSet.Remove(t);
}
#endregion
}
}
and service
using Data;
using DomainModel;
using ServiceLayer.ServiceDbSet;
namespace ServiceLayer.EfServices
{
public class EfPostService : ServiceContext<Post>
{
public EfPostService(IUnitOfWork uow)
: base(uow)
{
}
}
}
and this my services
using Data;
using ServiceLayer.EfServices;
namespace ServiceLayer
{
public class Services
{
private readonly IUnitOfWork _unitOfWork;
private EfPostService _post;
private EfCommentService _comment;
public Services(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public EfPostService Post
{
get { return _post ?? new EfPostService(_unitOfWork); }
set { _post = value; }
}
public EfCommentService Comment
{
get { return _comment ?? new EfCommentService(_unitOfWork); }
set { _comment = value; }
}
}
}
I use tructuremap for dependency injection
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Data;
using StructureMap;
namespace MVCTemplateProject
{
public static class StructuremapMvc
{
public static void InitStructureMap()
{
ObjectFactory.Initialize(x => x.For<IUnitOfWork>().HttpContextScoped().Use(() => new EfContext()));
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
}
}
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return ObjectFactory.GetInstance(controllerType) as Controller;
}
}
}
in base controller i get Iunitofwork
using System.Web.Mvc;
using Data;
using ServiceLayer;
namespace MVCTemplateProject.Controllers
{
public class BaseController : Controller
{
public readonly IUnitOfWork Context;
public readonly Services DataContext;
public BaseController(Data.IUnitOfWork context)
{
Context = context;
DataContext = new Services(context);
}
}
}
and this my home controller
using System.Web.Mvc;
using Data;
using DomainModel;
namespace MVCTemplateProject.Controllers
{
public class HomeController : BaseController
{
public HomeController(IUnitOfWork context)
: base(context)
{
}
public ActionResult Index()
{
return View(DataContext.Post.List());
}
}
}
how can i test index action with moq
i write this test but i get error
public void IndxShouldReturnListOfPage()
{
var posts = new List<Post>
{
new Post {Name = "Test"},
new Post {Name = "Test"},
new Post {Name = "Test"},
new Post {Name = "Test"}
};
var efContext = new Mock<EfContext>();
var mockRepository = new Mock<ServiceLayer.Services>(efContext);
mockRepository.Setup(x => x.Post.List(It.IsAny<Func<Post, bool>>())).Returns(posts);
var controller = new HomeController(efContext.Object);
List<Post> model = controller.DataContext.Post.List();
var result = controller.Index() as ViewResult;
Assert.AreEqual(model.Count, 4);
Assert.AreEqual(string.Empty, result.ViewName);
}
i get it and i test the project
[TestFixture]
public class PostControllerTest
{
#region Setup/Teardown
[SetUp]
public void Setup()
{
UnitOfWork = TestHelper.TestHelper.GetMockUnitOfWork();
PostDbSet = TestHelper.TestHelper.GetMockPostDbSet();
Posts = TestHelper.TestHelper.GetFakePosts();
TagDbSet = TestHelper.TestHelper.GetMockTagDbSet();
CategoryDbSet = TestHelper.TestHelper.GetMockCategoryDbSet();
PostController = new PostController(UnitOfWork.Object, PostDbSet.Object, CategoryDbSet.Object, TagDbSet.Object);
}
#endregion
private Mock<IServiceDbSet<Post>> PostDbSet { get; set; }
private Mock<IServiceDbSet<Tag>> TagDbSet { get; set; }
private Mock<IServiceDbSet<Category>> CategoryDbSet { get; set; }
private PostController PostController { get; set; }
private List<Post> Posts { get; set; }
private Mock<IUnitOfWork> UnitOfWork { get; set; }
[Test]
public void DetailShouldRedirectToHomePageWhenNotFoundPostOrPostIdIs0()
{
PostDbSet.Setup(x => x.Get(It.IsAny<Func<Post, bool>>())).Returns(Posts.Find(post => post.Id == 100));
var redirectToRoutResult =
(RedirectToRouteResult) PostController.Details(100);
Assert.AreEqual("Index", redirectToRoutResult.RouteValues["action"]);
Assert.AreEqual("Home", redirectToRoutResult.RouteValues["Controller"]);
}
[Test]
public void DetailShouldShowPostById()
{
PostDbSet.Setup(x => x.Get(It.IsAny<Func<Post, bool>>())).Returns(Posts.First());
var result = PostController.Details(1) as ViewResult;
var model = result.Model as PostViewModel;
Assert.AreNotEqual(null, model);
Assert.AreEqual("I Can", model.Title);
Assert.AreEqual(string.Empty, result.ViewName);
}
[Test]
public void ListOfStringTagMustConvertToListOfTagCollection()
{
PostViewModel postViewModel = TestHelper.TestHelper.GetFakePostViewModel();
PostController.Create(postViewModel);
//Assert.AreEqual(postViewModel.RawTags[0], postViewModel.RawTags.First().Name);
}
I have an entity named Tour which can have many Agents. I am able to add agents, but I cannot remove them.
// _repo is injected....
var tour = _repo.GetById(tourId);
tour.AddAgent(new Agent(tour.TourId));
When I attempt to call the Tour.RemoveAgent() method nothing is actually removed. I set a breakpoint inside the Tour.RemoveAgent() method I see that the _agents property has a count of 0.
tour.RemoveAgent(agentId); // This doesn't work because _agents is empty
Do I have to do something special for EF to populate the _agents property when I retrieve the Tour from my repository?
UPDATE: PROBLEM SOLVED (thanks to Paul's answer)
I decided to just create a Repository unique to each aggregate, that way it is easy to define exactly what needs to be included using the Include() function. This is an example where I inherit from the GenericRepository<T> class (which is also included at the bottom of this question).
public class TourRepository : GenericRepository<Tour>
{
public TourRepository(IDatabaseFactory databaseFactory) : base (databaseFactory)
{
}
public override Tour GetById(Guid id)
{
return dataContext.Tours
.Include(x => x.Agents)
.Single(x => x.TourId == id);
}
}
Tour Class
public partial class Tour
{
public Guid TourId { get; private set; }
protected virtual List<Agent> _agents { get; set; }
public Tour()
{
TourId = Guid.NewGuid();
_agents = new List<Agent>();
}
public void AddAgent(Agent agent)
{
_agents.Add(agent);
}
public void RemoveAgent(Guid agentId)
{
_agents.RemoveAll(a => a.AgentId == agentId);
}
}
Agent Class
public partial class Agent
{
public Guid AgentId { get; private set; }
public Guid TourId { get; private set; }
public Tour Tour { get; private set; }
public Agent(Guid tourId)
{
TourId = tourId;
AgentId = Guid.NewGuid();
}
}
OnModelCreating
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// AGENTS ============================
modelBuilder.Entity<Agent>()
.HasKey(x => x.AgentId)
.Property(p => p.AgentId);
modelBuilder.Entity<Agent>()
.HasRequired(p => p.Tour)
.WithMany(t => t.Agents);
// TOURS =============================
modelBuilder.Entity<Tour>()
.HasKey(x => x.TourId)
.Property(x => x.TourId);
}
Repository Class
public class GenericRepository<T> : IRepository<T> where T : class {
private MyContext dataContext;
private readonly IDbSet<T> dbset;
public GenericRepository(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
dbset = DataContext.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get;
private set;
}
protected MyContext DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
// ... stuff removed for brevity ...
public T GetById(Guid id)
{
return dbset.Find(id);
}
}
Try making protected virtual List _agents { get; set; } public
public virtual List<Agent> _agents { get; set; }
You can also eager load by doing something like this:
_databaseContext.Tours.Include(x => x.Agents).Single(x => x.TourId == tourId)
you can read more here: http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx