·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【四】——实现模型工厂,依赖注入以及格式配置

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【四】——实现模型工厂,依赖注入以及格式配置

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

使用asp.net Web Api构建基于REST风格的服务实战系列教程【四】——实现模型工厂,依赖注入以及格式配置

系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html

前言

在上一篇中,我们已经初步开始使用Web Api了,但同时出现了一些很多不足之处,本章我们就着重来解决这些不足。

上篇导航:http://www.cnblogs.com/fzrain/p/3510035.html

配置JSON的格式

Web Api提供xml和JSON作为返回数据的格式,框架会自动把这些格式注入管线。客户端可以通过Http请求头部来声明需要的数据格式,我们可以通过在“WebApiConfig”这个类来配置JSON数据的格式:

public static class WebApiConfig   {        public static void Register(HttpConfiguration config)        {        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();   
     jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePRopertyNamesContractResolver();
   }    }

首先根据HttpConfiguration对象获得jsonFormatter对象,然后设置ContractResolver属性。那么以后当我们使用JSON数据格式的时候就是“Camel”风格的了。

用Ninject实现依赖注入

如果读者是第一次接触依赖注入这个概念的话,可以参考:http://www.cnblogs.com/xray2005/archive/2009/07/28/1532908.html

OK,接下来我们就来实现依赖注入,在Controller文件夹中创建一个类“BaseApiController”继承自“APIController”。由于我们打算使用构造函数注入模式,因此它的构造函数接受一个ILearning类型的变量,下面上代码:

public class BaseApiController : ApiController    {        private ILearningRepository _repo;         public BaseApiController(ILearningRepository repo)        {            _repo = repo;        }         protected ILearningRepository TheRepository        {            get            {                return _repo;            }        }    }

将我们的“CoursesController”继承自“BaseApiController”,接下来就是使用Ninject框架来建立2者之间的关联:

首先使用NuGet来添加3个程序集:

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

添加好上述引用后,在APP_Start文件夹下就会出现一个类“NinjectWebCommon”,这个类就是在我们项目中配置依赖关系的。在之前的系列中,我们创建了“LearningRepository”,在它的构造函数中需要接受一个LearningContext对象(前篇导航:http://www.cnblogs.com/fzrain/p/3503952.html),因此我们也将这个依赖关系配置进来:

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            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();        }    }

我们使用了Ninject配置了Learningcontext对象,使得在http请求范围共用一个context对象,这么做对于创建复杂对象是非常好的。关于Ninject对象范围,可以参考:http://music.573114.com/Blog/Html/EB43/815024.html

实现模型工厂模式

模型工厂帮助我们创建需要响应给客户端的模型,因此我们将创建一些区别于领域模型(domain model)的新模型,新模型将与领域模型映射。例如:“Course”将映射到”courseModel”,”Tutor”将映射到“TutorModel“。同时应当考虑对象间的依赖关系。

为了实现这个功能,我们在”Model”文件夹中创建这几个类”SubjectModel“,”TutorModel“,”CourseModel“,”EnrollmentModel“,这些类就是一些简单的”POCO”类,用来响应给客户端的,下面上代码:

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; }}

有了这些响应给客户端的类,我们还需要一个创建这些类对象的工厂——”ModelFactory“:

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)            };        }    }

我们做的很简单,重载了Create方法,传入领域模型即可创建我们响应给客户端的模型,在这里我们可以很轻易的控制对象间的依赖关系(CourseModel引用TutorModel,CourseModel引用SubjectModel)

到此为止我们已经解决了2个瑕疵:

(1)对象间的循环依赖

(2)控制了返回客户端的字段(PassWord不会响应给客户端了)

由于我们可能要在各个Controller中使用到ModelFactory对象,因此我们在BaseController中添加如下代码:

public class BaseApiController : ApiController    {         private ModelFactory _modelFactory;          protected ModelFactory TheModelFactory        {            get            {                if (_modelFactory == null)                {                    _modelFactory = new ModelFactory();                }                return _modelFactory;            }        }    }

在介绍”CoursesController”的变化之前,我们先解决一下之前提到的2个问题:

(1)对于每个资源返回一个URI

(2)对于单个资源返回一个Http响应码

为每个资源添加URI:

做法不复杂因为我们已经创建了模型工厂,举个简单的例子——如果我们要返回一个URI,要通过一下步骤:

1.给ModelFactory的构造函数传入一个”HttpRequestMessage“对象来创建”System.Web.Http.Routing.UrlHelper“对象,它会根据我们在WebApiConfig中配置的路由名字来构造URI

2.在”BaseApiController“中的”ModelFactory“构造函数中传入”System.Web.Http.Routing.UrlHelper“对象

3.在”CourseModel”中新增一个属性”URL“

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;            }        }    }
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*/            };        }

关于模型工厂的更多介绍,可以参考:http://pluralsight.com/training/courses/TableOfContents?courseName=implementing-restful-aspdotnet-web-api(英文的,而且收费,唉。。 亚历山大)

为单个资源返回Http状态码:

Web Api框架中有一个”HttpResponseMessage“类可以用来返回Http状态码。有的时候使用状态码代替model来响应给客户端会更好,下面的例子就是在“Courses‘中的Getcourse(int id)方法中响应一个状态码。下面是我们最终修改后的CoursesController的代码:

public class CoursesController : BaseApiController