Dependency Injection

Dependency Injection and Repository Pattern

  1. Dependency Injection, we have a great article here
    and also we have a framework with the name Ninject which is used to help us to build our design.

Let's make things simple. Generally to say, we abstract the methods with Interface, Then we use Instanced class to implement the interface, we can keep more than one versions, e.g. one for
released product, one for Testing, to decouple our class.
Then, if we need these methods, we can include a property with the type Interface, then we initialize this from the constructor. This is so-called Dependency Injection.
for the instance of the class, the framework can shift the efforts.
Ok, Let's take an example.

Code Sample:

Interface code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models;
using DataAccess;

namespace BusinessLayer
{
    public interface IDataAccessRepository
    {
        IQueryable<Subject> GetAllSubjects();
        Subject GetSubject(int subjectId);
        IQueryable<Course> GetAllCourses();
        IQueryable<Course> GetCoursesBySubject(int subjectId);
        Course GetCourse(int courseId, bool includeEnrollments = true);
        bool CourseExists(int courseId);
        IQueryable<Student> GetAllStudentsWithEnrollments();
        IQueryable<Student> GetAllStudentsSummary();
        IQueryable<Student> GetEnrolledStudentsInCourse(int CourseId);
        Student GetStudentEnrollments(string userName);
        Student GetStudent(string userName);
        Tutor GetTutor(int tutorId);
        bool LoginStudent(string userName, string password);
        bool Insert(Student student);
        bool Update(Student orignalStudent, Student updatedStudent);
        bool DeleteStudent(int studentId);
        int EnrollStudentInCourse(int studentId, int courseId, Enrollment enrollment);
        bool Insert(Course course);
        bool Update(Course orignalCourse, Course updatedCourse);
        bool DeleteCourse(int courseId);
        bool saveAll();
    }
}

The implementaion class code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models;
using DataAccess;

namespace BusinessLayer
{
    public class DataAccessRepositoy:IDataAccessRepository
    {
        private readonly DataContext _dc;
        public DataAccessRepositoy(DataContext dc)
        {
            _dc = dc;
        }
        public IQueryable<Subject> GetAllSubjects()
        {
            return _dc.Subjects.AsQueryable();
        }
        public Subject GetSubject(int subjectId)
        {
            return _dc.Subjects.Find(subjectId);
        }
        public IQueryable<Course> GetCoursesBySubject(int subjectId)
        {
            return _dc.Courses.Include("Subject").Include("Tutor").Where(e => e.Subject.SubjectId == subjectId).AsQueryable();
        }
        public IQueryable<Course> GetAllCourses()
        {
            return _dc.Courses.Include("Subject").Include("Tutor").AsQueryable();
        }
        public Course GetCourse(int courseId,bool includeEnrollments=true)
        {
            if(includeEnrollments)
            {
                return _dc.Courses
                    .Include("Enrollments")
                    .Include("Subject")
                    .Include("Tutor")
                    .Where(e => e.CourseId == courseId)
                    .SingleOrDefault();
            }
            else
            {
                return _dc.Courses
                    .Include("Subject")
                    .Include("Tutor")
                    .Where(e => e.CourseId == courseId)
                    .SingleOrDefault();
            }
        }
        public bool CourseExists(int courseId)
        {
            return _dc.Courses.Any(e => e.CourseId == courseId);
        }
        public IQueryable<Student> GetAllStudentsWithEnrollments()
        {
            return _dc.Students
                .Include("Enrollments")
                .Include("Enrollments.Course")
                .Include("Enrollments.Course.Subject")
                .Include("Enrollments.Course.Tutor")
                .AsQueryable();
        }
        public IQueryable<Student> GetAllStudentsSummary()
        {
            return _dc.Students.AsQueryable();
        }
        public Student GetStudentEnrollments(string userName)
        {
            return _dc.Students
                .Include("Enrollments")
                .Include("Enrollments.Course")
                .Include("Enrollments.Course.Subject")
                .Include("Enrollments.Course.Tutor")
                .Where(e => e.UserName == userName)
                .SingleOrDefault();
        }
        public Student GetStudent(string userName)
        {
            return _dc.Students
                .Include("Enrollments")
                .Where(e => e.UserName == userName)
                .SingleOrDefault();
        }
        public IQueryable<Student> GetEnrolledStudentsInCourse(int courseId)
        {
            return _dc.Students
                .Include("Enrollments")
                .Where(e => e.Enrollments.Any(t => t.Course.CourseId == courseId))
                .AsQueryable();
        }
        public Tutor GetTutor(int tutorId)
        {
            return _dc.Tutors.Find(tutorId);
        }
        public int EnrollStudentInCourse(int studentId,int courseId,Enrollment enrollment)
        {
            try
            {
                if(_dc.Enrollments.Any(e=>e.Course.CourseId==courseId&&e.Student.StudentId==studentId))
                {
                    return 2;
                }
                _dc.Database.ExecuteSqlCommand("INSERT INTO Enrollments VALUES (@p0,@p1,@p2)", enrollment.EnrollmentDate, courseId.ToString(), studentId.ToString());
                return 1;
            }//we need to log the ouput to log file.
            catch(System.Data.Entity.Validation.DbEntityValidationException dbex)
            {
                foreach(var eve in dbex.EntityValidationErrors)
                {
                    string line = string.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                        eve.Entry.Entity.GetType().Name, eve.Entry.State);
                    foreach(var ve in eve.ValidationErrors)
                    {
                        line += string.Format("- Property: \"{0}\", Error: \"{1}\"",
                            ve.PropertyName, ve.ErrorMessage);
                    }
                }
                return 0;
            }
            catch(Exception ex)
            {
                return 0;
            }
        }
        public bool LoginStudent(string userName,string password)
        {
            return _dc.Students.Any(e => e.UserName == userName && e.Password == password);
        }
        public bool Insert(Student student)
        {
            try
            {
                _dc.Students.Add(student);
                return true;
            }
            catch
            {
                return false;
            }
        }
        public bool Update(Student originalStudent, Student updatedStudent)
        {
            _dc.Entry(originalStudent).CurrentValues.SetValues(updatedStudent);
            return true;
        }
        public bool DeleteStudent(int id)
        {
            try
            {
                var entity = _dc.Students.Find(id);
                if(entity!=null)
                {
                    _dc.Students.Remove(entity);
                    return true;
                }
            }
            catch
            {

            }
            return false;
        }
        public bool Insert(Course course)
        {
            try
            {
                _dc.Courses.Add(course);
                return true;
            }
            catch
            {
                return false;
            }
        }
        public bool Update(Course originalCourse, Course updatedCourse)
        {
            _dc.Entry(originalCourse).CurrentValues.SetValues(updatedCourse);
            //have question here for the following actions
            //originalCourse.Subject = updatedCourse.Subject;
            //originalCourse.Tutor = updatedCourse.Tutor;
            return true;
        }
        public bool DeleteCourse(int id)
        {
            try
            {
                var Course = _dc.Courses.Find(id);
                if(Course!=null)
                {
                    _dc.Courses.Remove(Course);
                }
                return true;
            }
            catch
            {

            }
            return false;
        }
        public bool saveAll()
        {
            return _dc.SaveChanges() > 0;
        }
    }
}

we can see the key Point of Dependency Injection , The DataContex depends on the caller of DataAccessRepositoy, Let's see the code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using BusinessLayer;
using Models;
using ViewModels;
using DataAccess;

namespace WebAPIRest.Controllers
{
    public class CoursesController : BaseApiController
    {
        public CoursesController(IDataAccessRepository repo):base(repo)
        { }
    }
}

we can pass different implementation of IDataAccessRepository to fetch different target.
So, we can pass the instance of IDataAccessRepository manually like create in our code, or just using the config with the help of framework like Ninjext.


How to use Ninject Document

OK, we have a brief sample here using Constructor Inection, (Generally, we have constructor injection, property inection, Method injection, ambient context).
we can log these usage in the coming future. Here, we just start up.

as it is stragiforward, we need some where to configure which implementation to use, Then, use it.

Module

they are components to register types, that is to say, we config the relationship between interface and implementation class.
we need to define a class inheriting the NinjectModule. Sample code Here

public class RegisterModule : NinjectModule
{
    public override void Load()
    {
        Bind<IDataAccessRepository>().to<DataAccessRepository>();
    }
}

StandardKernel

It is everything to controller injection. we can user it to load the configuration we make from pre step and get the implementtation class.
code sample:

StandardKernel _Kernal = new StandardKernel();
_Kernal.Load(Assembly.GetExecutingAssembly());
IDataAccessRepository DataAccessRep = _Kernal.Get<IDataAccessRepository>();
posted @ 2016-09-01 17:47  kongshu  阅读(194)  评论(0编辑  收藏  举报