This is the second part of Building ASP.Net Web API RESTful Service Series. The topics we’ll cover are:
- Building the Database Model using Entity Framework Code First – Part 1.
- Applying the Repository Pattern for the Data Access Layer – Part 2 (This Post).
- Getting started with ASP.Net Web API – Part 3.
- Implement Model Factory, Dependency Injection and Configuring Formatters – Part 4.
- Implement HTTP actions POST, PUT, and DELETE In Web API – Part 5.
- Implement Resources Association – Part 6.
- Implement Resources Pagination – Part 7.
- Securing Web API – Part 8.
- Preparing Web API for Versioning – Part 9.
- Different techniques to Implement Versioning – Part 10.
- Caching resources using CacheCow and ETag – Part 11.
Update (2014-March-5) Two new posts which cover ASP.Net Web API 2 new features:
Applying the Repository Pattern for the Data Access Layer
Applying Repository Pattern is useful to isolate domain objects from the details of database access layer. It will act as an abstraction layer over the mapping layer where query constructions and database objects manipulation take place. As well the Repository will act like in-memory domain object collection where objects can be added or removed from the Repository as they are removed from a simple collection of objects, moreover the Repository will be responsible to execute the appropriate operations behind the scenes.
Before we dig into the Repository implementation let’s list the use cases needed to be implemented in our Web API, this for sure will help us in building the right Repository methods and operations:
- Listing all available subjects, and listing single subject by querying ID.
- Listing all available courses including the sub-models (Subject, and Tutor).
- Getting single course by querying ID including the sub-models(Subject, Tutor, and Enrolled Students)
- Listing all available students including all sub-models (Enrolled in Courses, Course Subject, and Tutor)
- Get summary of all available students.
- List all enrolled students in specific course by querying course ID.
- List all classes for a certain student by querying Username.
- Get certain student by querying Username.
- Authenticate students by validating Username and Password.
- Enroll an authenticated student in a course.
- CRUD operations for Students.
- CRUD operations for Courses.
Building the Repository Pattern
We need to add new Interface named “ILearningRepository” to implement all the use cases listed above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public interface ILearningRepository { IQueryable<Subject> GetAllSubjects(); Subject GetSubject(int subjectId); IQueryable<Course> GetCoursesBySubject(int subjectId); IQueryable<Course> GetAllCourses(); 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 originalStudent, Student updatedStudent); bool DeleteStudent(int id); int EnrollStudentInCourse(int studentId, int courseId, Enrollment enrollment); bool Insert(Course course); bool Update(Course originalCourse, Course updatedCourse); bool DeleteCourse(int id); bool SaveAll(); } |
The methods in the interface above covers all the operations needed in our Web API, note how we are returning IQueryable<T> for any method returns a collection of objects, this will facilitate the pagination, sorting, and results ordering in our Web API because IQueryable will give us deferred execution and fully support for LINQ-to-SQL. In other words IQueryable result will save us from returning too many unwanted rows from the database.
Now we need to add new class called “LearningRepository” which will implement the interface “ILearningRepository”. I’ll list partial implementation of the class here. We’ll be able to see the full implementation by browsing the code on GitHub or by downloading the source.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class LearningRepository : ILearningRepository { private LearningContext _ctx; public LearningRepository(LearningContext ctx) { _ctx = ctx; } public IQueryable<Subject> GetAllSubjects() { return _ctx.Subjects.AsQueryable(); } /*Rest of methods implementation goes here....*/ } |
You can notice that the constructor of the class “LearningRepository” accepts the database context object “LearningContext” and there is a private member “_ctx” which is used to interact with all DbSet objects without instantiating it. That design pattern is called Dependency Injection, in simple words it means that objects do not create other objects on which they rely to do their work. Instead, they get the objects that they need from an outside source.
So in our situation the class “LearningRepository” depends on class “LearningContext”, but it won’t create an instance from it to complete its work, instead we will inject this object to it using an external DI framework called Ninject. We’ll cover this deeply in the coming parts. If you are new to Dependency Injection design pattern, I recommend you to read my previous blog post about it.
Until this point our data access layer is complete and ready to be used with our Web API, so lets jump to the next post where we’ll start working on Web API.
Thanks for the great post. How can I use this if my database already exists?!
Hello F Abtin,
Can you elaborate more? Didn’t get your question.
I need to build a resful api for an already existing crm, where every object is a new table in the database and there is no fix schema for the database(tables are being created and removed if not required anymore by the user). The crm is being used via a wcf api using session and server cache. I am facing few problems: No fix design for the database. user Session being used which is not restful and its very hard to ignore the layer as it is highly connected with server cache and my datalayer. Thanks for being helpful
I believe the LearningRepository should implement IDisposable and dispose of the LearningContext. Any controllers that use the repository would have to dispose of it as well. This would prevent database connections from waiting to be garbage collected and disconnected.
Hello Franklin,
You are right if I’m not using Ninject, you can’t dispose DBContext manually because it is injected using Ninject, I’m keeping the DBContext alive for each request scope, you can read more about Ninject Object scopes here.
Hi
This is great and it works all on my project. I have a question, though.
I’d try to delete the tables and run again the project. I’m expecting that it will recreate the tables and insert again the data procided by the seed(). However, it shows an error that the tables aren’t existing.
After that I deleted the whole DB, run the project and expect the whole thing again. This time it works.
As far as I know we map only the entities and its properties which is equivalent to the tables and its properties as well.
But why it doesn’t fixed on its own and the DB which I don’t know where it has been configured are recreated?
Thanks.
Sorry I know this was supposed to be in Part 1 🙂
Hello Shaina,
I believe that the initialization strategy I’m using will not create tables if they are deleted manually, try to use “DropCreateDatabaseifModelChanges” strategy. Usually when I use CF I do not delete tables manually from database, I delete certain columns and then they get recreated correctly. Never tried to delete the entire table before.
Hi Taiseer
Your tutorial has been seriously helpful in explaining some of these patterns. Now that I’m beginning to implement the concepts in my own work I’m encountering a few issues.
My implementation of the repository pattern involves developing separate interfaces for each of my domain model entities. Using a single large interface class (such as the ILearningRepository in your example) is going to result in an unmanageably large class. Unfortunately, using a large number of smaller interface classes results in something of a breakdown when I come to the subsequent stages in your tutorial, such as the Parse methods in the ModelFactory. It looks like I’m going to have to write separate overloaded constructors for the ModelFactory to meet the criteria for each of the separate Parse methods:
//As written in your GitHub example:
private ILearningRepository _repo;
public ModelFactory(HttpRequestMessage request, ILearningRepository repo) {}
//end GitHub example
//As required by my implementation:
private IAlphaRepository _alphaRepo;
private IBetaRepository _betaRepo;
private ICharlieRepository _charlieRepo;
private IDeltaRepository _deltaRepo;
public ModelFactory(HttpRequestMessage request, IAlphaRepository repo) {}
public ModelFactory(HttpRequestMessage request, IBravoRepository repo) {}
public ModelFactory(HttpRequestMessage request, ICharlieRepository repo) {}
public ModelFactory(HttpRequestMessage request, IDeltaRepository repo) {}
//end my implementation
I feel like I’m missing something fundamental here. Is it possible to use many smaller interfaces with the factory pattern as you’ve described it in your article?
Many thanks
Dale
Hi Dale,
Sorry for the late reply, well if I were you I will consider three options, first one is what you suggested, overloading the ModelFactory Class, second one is creating dedicated ModelFactory class for each Repo, i.e ModelFactoryForAlpha, and the third one you can consider using AutoMapper if you do not want to manipulate your data before presenting them to API consumers. I prefer the second option and maintain smaller ModelFactory classes.
Hope this help and if you find better solution let me know please 🙂
Thank you for the very good tutorial! I have a question!
Is it right to use the ModelFactory inside of Repository? Because in Repository i need to parse PocoModel classes to POCO
Hello Manos, glad you liked the article.
From design pattern perspective it is not recommended to use Model Factory pattern in the Repository Class, you should always try to have single class responsibility. But if your case is complicated then you can do this.
Hope this answers your question.
Taiseer thank you for your answer.
If i understand correctly the use of Repository Class is to communicate with entity model (query, insert ,save).May i include some business rule in Repository Class
In my case before save to database i need to call some web services, get the results in List (T custom POCOModel) and then call save (here is the need of Model Factory to parser POCOModel to POCO).
Thank you again!! Ι appreciate your help
And please another question.
Why do not declate a private variable for LearningContext in Controller(eg Course) and use it in functions(GET, POST….) against of use the Ninject library?
Thank you!
Hello Manos
If you declared private variable for LearningContext inside each controller then for every request we’ll instantiate this object and read connection string from configuration file which is expensive operation.
If you opened file NinjectWebCommon.cs and looked at method RegisterServices() you will notice that I’m using Ninject to create a single instance of LearningContext for each request handled by the API, this will boost be more efficient that creating private variable, you can read more about Ninject object scopes here: https://github.com/ninject/ninject/wiki/Object-Scopes
Hope this answers your question.
Hello Manos,
I recommend to have separate class/layer to do your business validations before calling the repository class, it always better to keep the repository calls clean and do single responsibility which is talking to your database.
Taiseer thank you for you answer. Ι appreciate a lot your help!
I cant understand about the private variable in LearningContext!
You said that ” for every request we’ll instantiate this object and read connection string from configuration file which is expensive operation”
But the Ninject for every request create LearningContext and pass it to repository!!! Where is the difference?
Thank you!
Thanks a lot for your incredible tutorials but I have a small comment, I see no use of using the AsQueryable() method on a DbSet collection that already implements the IQueryable interface since the compiler decides whether to generate code for a delegate or an expression tree from a lambda expression based on the type of the collection and if it is implicitly convertible to the IQueryable interface the compiler will generate an expression tree, so I hope you’d explain that bit, thanks.
hi Taiseer
thx for youer great post
but why you implement Service in Repository???