《精通ASP.NET MVC5》第7章 SportStore:一个真正的应用程序(1)


7.1 开始 #

7.1.1 解决方案 #

我们首先要创建的是一个空的Visual Studio solution。在这个 solution 中,我们将创建3个工程。

1. 一个域模块工程。

2.一个MVC4应用。

3.一个单元测试工程。

       

现在我们就创建一个名为 SportsStore 的空 solution ,

工程名

VS工程模板

目的

SportsStore.Domain

Class Library

使用Entity Framework 创建一个repository,并将其设置为一个持久层。

SportsStore.WebUI

ASP.NET MVC Web Application

controllers and views

SportsStore.UnitTests

Unit Test Project

unit tests

       

       

       

7.1.2 安装工具包 #

Install-Package Ninject -version 3.0.1.10

Install-Package Ninject.Web.Common -version 3.0.0.7

Install-Package Ninject.MVC3 -Version 3.0.0.6

Install-Package Moq -version 4.1.1309.1617

Install-Package Microsoft.Aspnet.Mvc -version 5.0.0

       

       

7.1.3 项目之间的引用 #

到这一步我们的项目框架的雏形已经出来了,现在我们要为它添加引用。在solusion管理器中,一次右击

每个工程,选择Add Reference

       

工程名

工具依赖

工程依赖

微软引用

SportsStore.Domain

Entity Framework

None

System.Web.Mvc

System.ComponentModel.DataAnnotations

SportsStore.WebUI

Ninject

Moq

SportsStore.Domain

    

None

SportsStore.UnitTests

Ninject

Moq

SportsStore.Domain

SportsStore.WebUI

System.Web.Mvc

System.Web

Microsoft.CSharp

       

注意: System.Web.Mvc 的版本一定选择4.0.0

       

7.1.4 设置DI Container #

       

在我们这个应用中,对MVC框架做了很多扩展,这也是我们学习的重点内容,掌握了这些知识点,

我们再以后的开发项目中,就能得心应手,构建出稳定的,易于扩展和维护的企业应用架构。

右击 SportsStore.WebUI 工程的 Infrastructure 文件夹,选择添加类,类名为 NinjectControllerFactory

       

using System;  

using System.Collections.Generic;  

using System.Linq;  

using System.Web;  

using System.Web.Mvc;  

using System.Web.Routing;  

        

namespace SportStore.WebUI.Infrastructure  

{  

   /// <summary>  

    /// 工厂类  

   /// </summary>  

    public class NinjectControllerFactory : DefaultControllerFactory  

    {  

        private IKernel ninjectKernel;  

        

        public NinjectControllerFactory()  

        {  

            ninjectKernel = new StandardKernel();  

            AddBindings();  

        }  

        

        protected override IController GetControllerInstance(RequestContext  

            requestContext, Type controllerType)  

        {  

            return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);  

        }  

        

        private void AddBindings()  

        {  

            //put bindings here  

        }  

    }  

}  

我们现在还没有添加任何绑定,但是,当我们需要时,能使用 AddBindings 方法去添加. 现在,我们需要去

告诉 MVC 我们打算使用 NinjectController 类去创建Controller对象,要实现这一点,请打开SportsStore.WebUI工程的 Global.asax.cs 文件

       

public class Global : System.Web.HttpApplication  

{  

        

    protected void Application_Start(object sender, EventArgs e)  

    {  

        AreaRegistration.RegisterAllAreas();  

        RouteConfig.RegisterRoutes(RouteTable.Routes);  

        

        //我们需要告诉我们想要使用 Ninject Controller MVC  

        //类来创建控制器对象  

        ControllerBuilder.Current.SetControllerFactory(new  

                    NinjectControllerFactory());  

    }  

}  

       

7.2 启动域模块 #

现在我们将要启动域模块,在MVC应用中应用领域模型,能使每一件事情都变得完美,因此,域 也就必然 是启动应用的最完美的地方。因为我们要做的电子商务应用,所以,我们需要一个产品,这是在明显不过的事了。右击我们刚刚建立的 Entities 文件夹,然后新建一个C#类,命名为 Product 

namespace SportStore.Domain.Entities  

{  

    public class Product  

    {  

        public int ProductID { get; set; }  

        public string Name { get; set; }  

        public string Description { get; set; }  

        public decimal Price { get; set; }  

        public string Category { get; set; }  

    }  

}  

       

7.2.1 创建抽象存储库 #

       

我们知道,我们需要一些途径或方式,去数据库中取得Product entities。为了保持架构上的完美,我们要遵循持久逻辑与域模型实体分离的原则,要做到这一点,我们使用repository 设计模式. 我们不需要担心怎样去实现持久层,我们从定义一个接口开始,去启动它。

       

Abstract 文件夹上右击,选择添加一个接口,命名为 IProductsRepository

namespace SportStore.Domain.Abstract  

{  

    public interface IProductRepository  

    {  

        IEnumerable<Product> Products { get; }  

    }  

}  

       

口使用了 IEnumerable<T> 接口去获取一个Product对象,我们没有告诉它去哪或怎么样去取得数据,一个使用 IProductsRepository 接口的类能够取得Product 对象,而不需要知道它们从哪来或被谁传递,这就是 repository设计模式的本质。接下来我们就通过添加一些特性到我们代码中,去再次拜访一下这个接口。

     

7.2.2 创建模仿存储库 #

构建一个Mock Repository

现在我们已经定义了一个 abstract interface, 我们能够实现这个持久化机制并且挂接到数据库,不过这是不是现在要做的,为了能够启动这个项目的其他部分,现在我们要创建一个 IProductsRepository 接口的 Mock 实现,我们需要在我们的 SportsStore.WebUI 工程的 NinjectControllerFactory 类的 AddBindings 方法中去做这件事。

       

using System;  

using System.Collections.Generic;  

using System.Linq;  

using System.Web;  

using System.Web.Mvc;  

using System.Web.Routing;  

using Moq;  

using Ninject;  

using SportStore.Domain.Abstract;  

using SportStore.Domain.Entities;  

        

namespace SportStore.WebUI.Infrastructure  

{  

   /// <summary>  

    /// 工厂类  

   /// </summary>  

    public class NinjectControllerFactory : DefaultControllerFactory  

    {  

        private IKernel ninjectKernel;  

        

        public NinjectControllerFactory()  

        {  

            ninjectKernel = new StandardKernel();  

            AddBindings();  

        }  

        

        protected override IController GetControllerInstance(RequestContext  

            requestContext, Type controllerType)  

        {  

        

            return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);  

        }  

        

        private void AddBindings()  

        {  

            //告诉Moq想使用哪种模仿对象  

            Mock<IProductRepository> mock = new Mock<IProductRepository>();  

            //Setup 给模仿对象添加一个方法  

            //Returns 调用模仿方法时 Moq 返回的结果  

            mock.Setup(m => m.Products).Returns(new List<Product> {  

                new Product { Name = "Football", Price = 25 },  

                new Product { Name = "Surf board", Price = 179 },  

                new Product { Name = "Running shoes", Price = 95 }  

                });  

            //ToConstant 表示,应该将服务绑定到指定的常数值。  

            ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object);  

            //put bindings here  

        }  

    }  

}  

       

无论 IProductsRepository 在哪获得了一个请求, 我们都需要 Ninject 去返回同样的 mock 对象,这就是 为什么我们使用 ToConstant 方法的原因。

...

ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object);

       

7.3 显示产品列表 #

       

7.3.1 添加控制器 #

已经做了这么久,我们还没有看到任何可视化的效果,这对于有些心急的朋友来说是不公平的,看不见有任何成绩出来,将会打击我们做项目的信心,这对开发团队是很不利的事情,现在就让我们添加一个Controller SportsStore.WebUI 工程中,选择添加控制器,命名为 ProductController,确保模板选型为空,如下图:

       

       

接下来,你要删除VS自动为你添加的代码,并用如下代码代替:

using System;  

using System.Collections.Generic;  

using System.Linq;  

using System.Web;  

using System.Web.Mvc;  

using SportStore.Domain.Abstract;  

        

namespace SportStore.WebUI.Controllers  

{  

    public class ProductController : Controller  

    {  

        private IProductRepository repository;  

        public ProductController(IProductRepository productRepository)  

        {  

            this.repository = productRepository;  

        }  

        

        public ViewResult List()  

        {  

            return View(repository.Products);  

        }  

    }  

}  

       

7.3.2 添加视图 #

现在要做的是添加一个View,在 List 方法上右击并选择添加View,如图:

       

这里请注意了,在模型类的下拉列表中,你并不能找到 IEnumerable<SportsStore.Domain.Entities.Product> 项,你需要手工输入它。然后,点击添加按钮,创建View。

       

渲染View数据

@model IEnumerable<SportsStore.Domain.Entities.Product>  

         

@{  

    ViewBag.Title = "Products";  

}  

@foreach (var p in Model) {  

<div class="item">  

        <h3>@p.Name</h3>  

        @p.Description  

        <h4>@p.Price.ToString("c")</h4>  

</div>  

}  

       

我们改变一下这个页的标题,注意这里我们不需要使用 Razor text 或者 @:elements 去展示数据,因为每行内容都是一个 HTML 元素.

       

7.3.3 设置默认路由 #

       

现在我们需要去做的,就是告诉MVC框架,当一个请求到达时,我们的网站要映射到ProductController类的List 活动方法,这需要去修改App_Start/RouteConfig.cs 文件的 RegisterRoutes 方法,

       

routes.MapRoute(  

                name: "Default",  

                url: "{controller}/{action}/{id}",  

                defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }  

            );  

       

完成修改后,运行你的应用,你将看到如下画面:

    

      

作者:【唐】三三

出处:https://www.cnblogs.com/tangge/p/6351221.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   【唐】三三  阅读(1463)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2011-01-26 奇怪了,为什么“语句未结束”
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示