Quantcast
Channel: ASP.Net Web API – Bit of Technology
Viewing all articles
Browse latest Browse all 37

Building ASP.Net Web API RESTful Service – Part 4

$
0
0

This is the fourth part of Building ASP.Net Web API RESTful Service Series. The topics we’ll cover are:

Implement Model Factory, Dependency Injection and Configuring Formatters

In the previous post we have highlighted the flaws in current implementation of Courses controller, in this post we’ll be fixing those flaws.

Configuring Formatters

Web API provides media-type formatters for both JSON and XML. The framework inserts these formatters into the pipeline by default. Clients can request either JSON or XML in the Accept header of the HTTP request. In order to configure the JSON formatter we need to implement the code below in class “WebApiConfig”:


public static class WebApiConfig
   {
        public static void Register(HttpConfiguration config)
        {

        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    	}
    }

What we did here that we looked at the built in formatters of type JSON, then we changed the contract resolver of the serialization settings to use Camel Case resolver. Now all JSON objects properties return in camel case.

Implement Dependency Injection using Ninject

If Dependency Injection concept is new to you, I recommend to read my previous post about it.

Now to prepare our code for dependency injection we need to add new Base API controller class named “BaseApiController” to folder “Controllers”. This class will derive from “APIController” class and its constructor accepts the Repository Interface “ILearningRepository” as parameter, we’re planing to implement DI Constructor Injection Pattern. The code will look as below:

public class BaseApiController : ApiController
    {
        private ILearningRepository _repo;

        public BaseApiController(ILearningRepository repo)
        {
            _repo = repo;
        }

        protected ILearningRepository TheRepository
        {
            get
            {
                return _repo;
            }
        }
    }

Now our “CoursesController” will derive from the “BaseApiController”, we need to use now Ninject as DI framework to do the heavy lifting for us and resolve the dependencies between our components, to install Ninject use NuGet package Manager and install the following packages:

  • Ninject
  • Ninject.Web.Common
  • WebApiContrib.IoC.Ninject

After we install those package successfully a new file named “NinjectWebCommon” is added to the App_Start folder, this file is responsible of the heavy lifting to configure the dependencies in our project, now we need to specify the dependencies between our components. As you remember in this post, when we created the “LearningRepository” its constructor accepts the database context object “LearningContext” so the “LearningRepository” class depends on the database context to work, we need register this in Ninject Kernel.

So to configure Web API to use DI we need to add the following code to the class “NinjectWebCommon”:

public static class NinjectWebCommon
    {
        private static IKernel CreateKernel()
        {
			var kernel = new StandardKernel();
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

			//Suport WebAPI Injection
            System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new WebApiContrib.IoC.Ninject.NinjectResolver(kernel);

			RegisterServices(kernel);
            return kernel;
		}

		private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<LearningContext>().To<LearningContext>().InRequestScope();
            kernel.Bind<ILearningRepository>().To<LearningRepository>().InRequestScope();
        }
    }

As you notice we are configuring Ninject to have a single instance of database context object shared by all objects created via the kernel for that HTTP request. This is good technique for sharing objects that are expensive to create. you can read more about Ninject Object Scopes here.

Implement the Model Factory Pattern

The Model Factory Pattern will help us in shaping and controlling the response returned to the client, so what we will do here is to create a simplified model for each domain object model (entity) we have in the database. i.e. “Course” entity will map to “CourseModel”, “Tutor” entity will map to “TutorModel” taking in consideration the relations between models (Each course is taught by a Tutor and related to a Subject) etc…

To implement this we need to add new folder named “Models” and add four classes named ”SubjectModel”, “TutorModel”, “CourseModel”, and “EnrollmentModel”. Those are only simple POCO classes which will be used to return the data to the client, the code for classes will be as below:


    public class SubjectModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

	public class TutorModel
    {
        public int Id { get; set; }
        public string Email { get; set; }
        public string UserName { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Data.Enums.Gender Gender { get; set; }

    }

	public class CourseModel
    {
        public int Id { get; set; }
        public string Url { get; set; }
        public string Name { get; set; }
        public double Duration { get; set; }
        public string Description { get; set; }
        public TutorModel Tutor { get; set; }
        public SubjectModel Subject { get; set; }

    }

	public class EnrollmentModel
    {
        public DateTime EnrollmentDate { get; set; }
        public CourseModel Course { get; set; }
    }

Now we need to use those classes to create the response for the client, we need a single class which is responsible for creating those models, so we’ll add a class named “ModelFactory” as the code below:


public class ModelFactory
    {
        public ModelFactory()
        {

        }

        public CourseModel Create(Course course)
        {
            return new CourseModel()
            {
                Id = course.Id,
                Name = course.Name,
                Duration = course.Duration,
                Description = course.Description,
                Tutor = Create(course.CourseTutor),
                Subject = Create(course.CourseSubject)
            };
        }

        public TutorModel Create(Tutor tutor)
        {
            return new TutorModel()
            {
                Id = tutor.Id,
                Email = tutor.Email,
                UserName = tutor.UserName,
                FirstName = tutor.FirstName,
                LastName = tutor.LastName,
                Gender = tutor.Gender
            };
        }

        public SubjectModel Create(Subject subject)
        {
            return new SubjectModel()
            {
                Id = subject.Id,
                Name = subject.Name
            };
        }

		public EnrollmentModel Create(Enrollment enrollment)
        {
            return new EnrollmentModel()
            {
                EnrollmentDate = enrollment.EnrollmentDate,
                Course =  Create(enrollment.Course)
            };
        }
    }

What we’ve done above is simple, we’ve overloaded the function named “Create”,  so it accepts domain object input i.e. “Course” and returns a new model of type “CourseModel”. Notice how we can control the object graph and the chaining of objects and sub-objects i.e (CourseModel -> TutorModel, and CourseModel -> SubjectModel).

By doing this we’ve fixed two important flaws we have identified in the previous post which they are:

  • Self referencing when returning chain ob objects.
  • Controlling the fields returned to the client. (i.e. “TutorModel” is not returning the “password” fields in the response).

Using the Model Factory in “CoursesController” and coming controllers we’ll talk about is fairly simple, thanks for the “BaseApiController” where all controllers will derive from it. Open “BaseApiController” and add the code below:


public class BaseApiController : ApiController
    {
		 private ModelFactory _modelFactory;

		 protected ModelFactory TheModelFactory
        {
            get
            {
                if (_modelFactory == null)
                {
                    _modelFactory = new ModelFactory();
                }
                return _modelFactory;
            }
        }
    }

What we done here is adding read only property which is responsible to create an instance of the model factory class.

Before introducing changes to the “CoursesController” we need to fix the last two flaws in the previous implementation which they are:

  • Link each resource returned to a URI.
  • Returning HTTP status codes when returning single resource.

Fix the flaw in Linking each resource returned to a URI:

Returning URI for each resource is simple, thanks to the Model Factory pattern we implemented, so for example if we want to add URI to identify Course resource we need to do the following:

  1. Pass an instance of “HttpRequestMessage” to the “ModelFactory” constructor in order to create object of type “System.Web.Http.Routing.UrlHelper” which is responsible to formulate the URI link for this resource based on the “Route Name” we configured in class “WebApiConfig”.
  2. Pass “Request” object of type “System.Net.Http.HttpRequestMessage” in class “BaseApiController” to “ModelFactory” constructor.
  3. Add new property named “URL” to the “CourseModel” which will contain the URI for this resource.

Code listing as the below respecting points sequence:


public class ModelFactory
    {
        private System.Web.Http.Routing.UrlHelper _UrlHelper;

        public ModelFactory(HttpRequestMessage request)
        {
            _UrlHelper = new System.Web.Http.Routing.UrlHelper(request);
        }
    }

 


public class BaseApiController : ApiController
    {
		 private ModelFactory _modelFactory;

		 protected ModelFactory TheModelFactory
        {
            get
            {
                if (_modelFactory == null)
                {
                    _modelFactory = new ModelFactory(Request);
                }
                return _modelFactory;
            }
        }
    }

 


public class ModelFactory
    {
		public CourseModel Create(Course course)
        {
            return new CourseModel()
            {
                Url = _UrlHelper.Link("Courses", new { id = course.Id }),
                Id = course.Id,
                /*Other CourseModel properties remain the same*/
            };
        }
    }

There is a nice plural sight learning course produced by Shawn Wildermuth which discuss deeply this Model Factory Pattern. I recommend watching this course.

Fix the flaw in returning HTTP status codes when returning single resource

Web API framework contains class named “HttpResponseMessage” which can be used to return HTTP status code and data if needed, it is a good practice to return “HttpResponseMessage” objects because it gives us the flexibility to set response code and actual content, you will notice in the code below that we’ll be returning object of type “HttpResponseMessage” for action GetCourse(int id) instead of returning the actual Course domain object.

In the code listing below we’ll implement all the fixes we’ve discussed:


public class CoursesController : BaseApiController
    {
		public CoursesController(ILearningRepository repo)
            : base(repo)
        {
        }

		public IEnumerable<CourseModel> Get()
        {
            IQueryable<Course> query;

            query = TheRepository.GetAllCourses();

            var results = query
                          .ToList()
                          .Select(s => TheModelFactory.Create(s));

            return results;
        }

        public HttpResponseMessage GetCourse(int id)
        {
            try
            {
                var course = TheRepository.GetCourse(id);
                if (course != null)
                {
                    return Request.CreateResponse(HttpStatusCode.OK, TheModelFactory.Create(course));
                }
                else
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }

            }
            catch (Exception ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
            }
        }
    }

  • We’ve introduced multiple changes to “CoursesController” which they are:
  • Injected the “ILearningRepository” inside “CoursesController” constructor.
  • Using the model factory to create “CourseModel” and sub models “TutorModel” and “SubjectModel”.
  • Returning HTTP status codes for action GetCourse(int id), so if the course was not found we’ll return 404, in case of an exception we’ll return 400 (Bad request) along with the exception message, and if the course is found we’ll return 200 (OK) along with a serialized representation of “CourseModel” object found.

To test the new changes let’s issue a GET request the URI http://localhost:{your_port}/api/courses, and notice how each resource returned has a URL property, as well we have shaped the response returned and controlled the object graph to overcome circular reference serialization issue.

[
    {
        "id": 1,
        "url": "http://localhost:8323/api/courses/1",
        "name": "History Teaching Methods 1",
        "duration": 5,
        "description": "The course will talk in depth about: History Teaching Methods 1",
        "tutor": {
            "id": 1,
            "email": "Ahmad.Joudeh@outlook.com",
            "userName": "AhmadJoudeh",
            "firstName": "Ahmad",
            "lastName": "Joudeh",
            "gender": 0
        },
        "subject": {
            "id": 1,
            "name": "History"
        }
    },
    {
        "id": 2,
        "url": "http://localhost:8323/api/courses/2",
        "name": "History Teaching Methods 2",
        "duration": 4,
        "description": "The course will talk in depth about: History Teaching Methods 2",
        "tutor": {
            "id": 1,
            "email": "Ahmad.Joudeh@outlook.com",
            "userName": "AhmadJoudeh",
            "firstName": "Ahmad",
            "lastName": "Joudeh",
            "gender": 0
        },
        "subject": {
            "id": 1,
            "name": "History"
        }
    }
]

So in the next post we’ll cover how to implement the HTTP verbs (POST,PUT, and DELETE).

Source code is available on GitHub.



Viewing all articles
Browse latest Browse all 37

Trending Articles