在MVC中使用泛型仓储模式和依赖注入实现增删查改

标签:

原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pattern-and-dep/

系列目录:

这篇文章,我将介绍如何在MVC项目中,使用泛型仓储模式和依赖注入实现增删查改。

这篇文章的章节如下:

1.介绍【Introduction】

2.依赖倒置原则(DIP)【Dependency Inversion Principle】

a.真实的例子【Real-Life Example】

b.实际不使用依赖倒置(DIP)的例子【Practical Example without DIP】

c.实际使用依赖倒置(DIP)的例子【Practical Example with DIP】

3.控制反转(IOC)模式【Inversion of Control (IoC) Pattern

4.依赖注入(Dependency Injection)【DI】

a.紧耦合【Tight Coupling】

b.松耦合【Loose Coupling】

5.依赖注入的容器【Dependency Injection (DI) Container】

6.程序增删查改的设计步骤【CRUD operations Application Design】

a.在程序中定义实体【Define Entities in Application】

b.定义数据上下文【Define Context Class】

c.定义映射实体类【Define Mapping of Entities】

d.创建泛型仓储【Create Generic Repository】

e.创建服务来对用户表进行操作【Create Service for User Operations】

7.在MVC程序中使用IOC和DI【An MVC Application Using the IoC and DI】

a.引入Ninject依赖注入容器【Ninject Dependency Injection Container】

b.用于增删查改的Model和控制器【CRUD Operations Model and Controller】

c.create/Edit视图【reate / Edit User View】

d.User List视图【User List View】

e.User Detail视图【User Detail View】

f.Delete User视图【Delete User】

8.总结【Conclusion】

9.下载【Download】

介绍

A software developer writes a lot of code that is tightly coupled and when complexity grows the code will eventuallydeteriorateintospaghetticode,in other words application design being a bad design. A bad design that has one of the following causes.

deteriorate [英 [d?‘t??r??re?t] 美 [d?‘t?r??ret] vi. 恶化,变坏vt. 恶化]

spaghetti 【英 [sp?‘get?] 美 [sp?‘ɡ?ti]n. 意大利式细面条】

翻译:一个软件开发者写出了很多紧耦合的代码,然而当代码变的很复杂的时候,他写的代码就会恶化成意大利面条(不堪一击),换句话说程序就变成了一个不好的设计,一个不好的设计是由下面几种因素导致的:

1.Rigid: A design is rigid if it cannot be easily changed. A single change is heavily dependent on another module so this change causes a cascade of changes that couldn‘t be predicted,the impact of change could not be estimated.

2.Fragile: A simple change to one part of the application leads to failures in another part of it that appears completely unrelated. Fixing those problems leads to even more problems.

3.Immobile: When the desirable parts of the design are highly dependent upon other details that are not desired and that is why one part of the application could not be used in another application.

Rigid 【英 [‘r?d??d] 美 [‘r?d??d] adj. 严格的;僵硬的,死板的;坚硬的;精确的】

Fragile 【英 [‘fræd?a?l] 美 [‘fræd??l]adj. 脆的;易碎的】

Immobile 【英 [?‘m??ba?l] 美 [?‘mobl]adj. 固定的;稳定的;不变的】

翻译:

1.死板的:如果设计是死板的,那么想要改变就很难了。一个小小的改变就会牵制很多其他的模块,所以这样的改变就会导致一连串不能预期的改变,并且这个改变所带来的影响是不能预估的。

2.易碎的:程序中一个简单的改变,就会导致其他不想关的部分完全瘫痪。修复这些问题甚至会导致更多的问题。

3.固定的:当程序设计中的比较好的部分组件紧紧耦合,其他我们不想提取出来的组件的时候,这个时候这个设计比较好的组件就很难重用到其他的项目中了。

The Dependency Inversion Principle is a solution for all these causes,that‘s why in this article I explain it. This article basically focuses on DIP,IoC,DI and DI containers so before diving into these,I just want to provide a small introduction in this section.

翻译:依赖注入原则就是解决上面这些问题的一个很好的解决方案。这也是我为什么要在这篇文章中详细解释的原因。这篇文章基础性了讲解依赖倒置原则,控制反转容器和依赖注入,所以在讲解这些之前,我打算先来一个简单的介绍。


The Dependency Inversion Principle (DIP) is a software design principle that is the last principle of SOLID while Inversion of Control (IoC) is a software design pattern. Here I used two terms,one is a principle and the other is a pattern. So what is the basic difference between these?

依赖倒置原则是设计原则中最后一个。然后控制反转是软件的设计模式。这里我使用这两个术语,一个是设计原则另外一个是设计模式。那么他们之间基本的区别是什么呢?

1. Software Design Principle: Software Design Principles represent a set of guidelines that help us to avoid having a bad design. These are less about specific languages or paradigms and more generally "Don‘t Repeat Yourself" (DRY);    the DRY principle is true for all programming.

软件设计原则:软件设计原则也就是一系列帮助我们避免不好的软件设计方针。设计原则,很少是关联到具体的编程语言或者编程范式的,更多的是关系到“不要重复你自己”,软件设计原则对所有的语言编程都是同样有效的。

2. Software Design Pattern: Software Design Patterns are a general reusable solution to a commonly occurring problem within a given context in software design. These are common solutions for object-oriented programming      problems. Like the Singleton Pattern and Factory Pattern.

软件设计模式:软件设计模式:软件设计模式通常是给出,在既定的环境中普遍存在的问题的,一个可以重用的解决方案。软件设计模式是解决在面向对象编程过程中出现的问题的一个很通用的解决方案,例如:单例模式和工厂模式。

依赖倒置原则

It is the fifth principle of SOLID where “D” stands for Dependency Inversion Principle. Its main goal is decoupling software modules,in other words software design should be loosely coupled instead of tightly coupled.

依赖倒置原则是设计原则中的第五个,D代表依赖倒置原则。它的主要目标是去除软件设计模块之间的耦合性,换句话说软件设计,应该是松耦合的而不是紧耦合的。

The principle states:【依赖倒置原则的特征】
1.High-level modules should not depend upon low-level modules. Both should depend upon abstractions.【高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象层。】
2.Abstractions should not depend upon details. Details should depend upon abstractions.【抽象层不应该依赖于具像层,具像层应该依赖于抽象层。】
In short the higher-level module defines an interface and lower-level module implements that interface. To explain this sentence we use a real-life example.【换句话说,高层次的模块定义了一个接口,然后低层次的模块实现了这个接口,为了解释这个场景我使用了一个真实的例子。】

真实的例子

Suppose you are sitting on your desk. Your desk has some gadgets,like your development machine (LCD Monitor or Laptop) and mobile phone. The LCD Monitor has a cable that connects from the electric port (power cable) and the same as the mobile phone that also has a charging cable that also connects to an electric port. You could see that both devices connect from the electric port so the question occurs of who defined the port,your device or the cable? You will say that the devices define the port,in other words we don‘t purchase devices depending on port while the port is designed dependent on devices and the cable is just an interface that connects both devices and the port so you could say that a high-level module doesn‘t depend on the low-level module but both should be dependent on abstraction.

gadgets 【美 [gæ,d??ts]n. 小配件;小工具(gadget的复数)】

翻译:假想你正坐在办公桌上,你的桌上有一些零件,例如你的开发机器(液晶显示器或者笔记本电脑)和手机。液晶显示器有一个电缆连接到了插板上,并且手机有一根充电线同样连接到了插板上。你可以看到现在两个设备都连到了这个插板的端口上,那么问题出来了,谁定义了这个端口呢,你的设备还是这个电缆线呢?你可能会说,是这些设备定义了这个端口,换句话说,我们不根据端口买这些设备,并且端口的设计是独立于设备的。并且电缆线仅仅是一个连接设备和端口的接口,所以你可以说一个高层次的模块不能依赖于低层次的模块,但是高层次模块和低层次模块都应该依赖于抽象模块。

实际不使用依赖倒置(DIP)的例子

To understand DIP,we use an example that explains how an error log can manage an application. There are two types of log management,the first one is via text file and the other is by using the event viewer. We create a high-level Operation class for error log entry. We create two interfaces,one is IEventViewerLogger and the other is IFileLogger interface. The IEventViewerLogger interface is implemented by the EventViewerLogger class while the IFileLogger interface is implemented by the FileLogger class.

为了理解依赖倒置,我们使用了一个例子来解释:程序中错误日志怎么管理程序。这里有两种类型的日志系统,第一个是通过文本文件记录,另外一个是使用事件查看器。我们为错误日志实体创建一个高层次的操作类,然后创建两个接口,一个是IEventViewerLogger,另外一个是IFileLogger,EventViewerLogger类实现IEventViewerLogger接口,FileLogger类实现IFileLogger接口。

The preceding Figure 1.2 shows that a high-level Operation class depends on the interface. We create an instance of each interface in this class and assign an appropriate object to each instance and use the operation accordingly. This means that a high-level module Operation class depends on the low-level module such as interfaces. Now suppose we want to add a new logger,such as a Database logger. Then we need to add a new interface and that‘s why the Operation class needs to care for all the interfaces and that‘s a violation of the Dependency Inversion Principle.

violation【英 [va??‘le??n] 美 [,va??‘le??n]n. 违反;妨碍,侵害;违背;强奸】

下图中,显示了一个高层次的操作类依赖于接口ILogger,我们在这个高层次的操作类中创建了接口了每个接口的实例【实例接口中定义的成员】,并且根据操作分配合适的对象给每个实例,这样就意味着高层次的模块操作类依赖于低层次模块,例如接口。现在假设,我们想要添加一个新的Logger,例如一个Database Logger,这个时候,我们就需要添加一个新接口,这也是为什么,这个操作类需要考虑到所有的接口,并且这样违背了依赖倒置的原则。

实际使用依赖倒置(DIP)的例子【Practical Example with DIP】

DIP states that a high-level module should not depend on a low-level module,both should be dependent on abstraction. To implement this principle we create an ILogger interface that is defined by a high-level module,in other words by an operation class and implemented by low-level modules,both EventViewerLogger and FileLogger classes. So when we add a new Logger,such as a database logger,then we don‘t need to update the Operation class.

依赖倒置原则声明:一个高级模块不应该依赖于一个低级模块,而是高级模块和低级模块都应该依赖于一个抽象层。为了实现这个依赖倒置原则,我们创建一个高级模块定义的ILogger接口,换句话说,这个Ilogger接口被一个操作类定义,被低级模块(EventViewerLogger和FileLogger类)实现。所以,当我们添加一个新的Logger的时候,例如database Logger,这个时候,我们就不用去更新这个操作类了。

It‘s a basic introduction to the Dependency Inversion Principle. If you are looking for code for this example then you can visit:Constructor Dependency Injection Pattern Implementation in C#. As I mention in this article that the software design principle is a guideline,in other words DIP doesn‘t tell us how to solve the preceding problem. If we want to understand how to solve the preceding problem then we need to follow a software design pattern and move onto Inversion of Control.

这是一个基本的介绍依赖倒置原则的文章,如果你想这个例子的话,你可以访问:Constructor Dependency Injection Pattern Implementation in C#.正如我在这篇文章说到的,软件设计原则是一个指导方针,换句话说,依赖倒置原则并不会告诉我们怎么去解决前面提到的问题。如果我们想要理解,怎么去解决前面遇到的问题,我们需要去看下软件设计模式,顺便看看控制反转。

控制反转(IOC)模式【Inversion of Control (IoC) Pattern】

DIP is a software designprinciplethat defines a guideline to solve a problem while IoC is a software designpatternthat defines how to solve the problem. In other words the IoC is the pattern by which we can practically implement DIP in software development. Let‘s see an example.

依赖倒置原则是软件设计的原则,它定义了一个指导方针,帮助我们去解决问题。然而IOC是软件设计模式,IOC帮助我们怎么去解决问题。换句话说,IOC是模式,通过它我们能够在软件开发中实现依赖倒置原则。我们来看一个例子吧。

In the previous error logger example,we define interfaces and implement them in classes. DIP states that a High-level Module should not be depend on a low-level module,that means we define the interface according to a high-level module Operation Class and implemented on a low-level module classes. The IoC is inverting the control of something switching control. In other words an outside module or class is responsible for creating an object of the class instead of directly creating the object of the low-level module class in the high-level module class so we can say that an IoC is an abstraction on which both high-level and low-level modules depend and it inverts the control flow.

invert【[?n‘v??t] 美 [‘?nv?t]vt. 使…转化;使…颠倒;使…反转;使…前后倒置n. 颠倒的事物;倒置物;倒悬者adj. 转化的】

在前面的错误日志的例子中,我们定义了接口,并在类中实现了接口,依赖倒置原则声称:一个高层级的模块不应该依赖于低层级的模块,这也就是说,我们根据高层次的操作类来定义这个接口,然后在低层次的类中实现这个接口。IOC是控制反转的开关。换句话说一个外在的模块或者一个类是用来创建类的对象的,而不是直接在高层次的模块类中创建低层次的类的对象。所以我们可以说,IOC就是一个抽象层,不仅仅高级模块还有低级模块都依赖于它,IOC使控制发生了反转。

In short we can say that IoC is used to invert the control flow of the application and an application module interacts with another module via interface and application classes object are created from one class.

简而言之,我们可以说,IOC是用来反转程序的控制流,并且程序的模块和其他模块的交互是通过接口,和其他类中创建的类的对象来实现的。

Dependency Injection (DI)--依赖注入

Dependency Injection (DI) is a type of IoC,it is a pattern where objects are not responsible for creating their own dependencies. Dependency injection is a way to remove hard-coded dependencies among objects,making it easier to replace an object‘s dependencies,either for testing (using mock objects in unit test) or to change run-time behaviour.

翻译:依赖注入是控制反转的一种,它是一种设计模式:对象不负责创建自己的依赖。依赖注入是移除对象之间硬编码依赖的一种方式。使对象的依赖能够更容易的被替换,或者说为了更方便测试,或者改变对象运行的时候的行为。

Before understanding Dependency Injection,you should be familiar with the two concepts of Object Oriented Programming,one is tight coupling and another is loose coupling,so let‘s see each one by one.

理解依赖注入之前,你应该要很熟悉面向对象编程中的两个概念,一个是紧耦合,另外一个是松耦合,我们来一个一个的看吧:

Tight Coupling:When a class is dependent on a concrete dependency,it is said to be tightly coupled to that class. A tightly coupled object is dependent on another object; that means changing one object in a tightly coupled application often requires changes to a number of other objects. It is not difficult when an application is small but in an enterprise level application,it is too difficult to make the changes.

翻译:紧耦合:当一个类依赖于一个具体的依赖,也就是说这个类,是紧密耦合的类。一个紧耦合对象依赖于另外一个对象,这意味着改变紧耦合程序中的一个对象,通常需要改变很多其他对象的部分代码,当应用程序比较小的时候,还不是很难,但是如果应用程序是企业级很大的时候,这样就变得很难修改了。

Loose Coupling:It means two objects are independent and an object can use another object without being dependent on it. It is a design goal that seeks to reduce the inter-dependencies among components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.

翻译:松耦合:这意味着两个对象是相互独立的,并且一个对象使用另外一个对象而不必依赖于它。松耦合是程序设计的目标,意在寻求减少系统组件之间的内在的相互依赖,并且当我们改变其中一个组件代码的时候,减少,需要去修改其他组件代码的风险。

Now in short,Dependency Injection is a pattern that makes objects loosely coupled instead of tightly coupled. Generally we create a concrete class object in the class we require the object and bind it in the dependent class but DI is a pattern where we create a concrete class object outside this high-level module or dependent class.

翻译:现在简而言之,就是依赖注入是一个设计模式,它能够使对象之间成为松耦合,代替原来对象之间的紧耦合。通常,我们在类中创建一个具体的类的对象的时候,我们需要这个对象,捆绑在这个类中,但是依赖注入设计模式下,我们创建一个类的具体对象,在这个高级模块或者这个类之外,而不必捆绑在这个类中。

There are three types of dependency injections:

  1. Constructor Dependency Injection
  2. Setter Dependency Injection
  3. Interface Dependency Injection

翻译:这里有三种类型的依赖注入:

1.构造函数的依赖注入

2.属性依赖注入

3.接口依赖注入

In this article we will use Constructor Dependency Injection. This is the most commonly used Dependency Injection Pattern in Object Oriented Programming. The Constructor Dependency Injection uses a parameter to inject dependencies so there is normally one parameterized constructor always. So in this constructor dependency,the object has no default constructor and you need to pass specified values at the time of creation to initiate the object. You can say that your design is loosely coupled with the use of constructor dependency injection.

翻译:在这篇文章中,我将会使用构造函数注入的方式,这是在面向对象编程中,使用的最多的依赖注入方式。构造函数依赖注入,通过使用一个参数来注入依赖,所以通常构造函数都会有一个参数,因此在构造函数依赖中,对象没有了默认的构造函数,你需要在初始化对象的时候,传递一个明确的值。这时候,你可以说,使用构造函数依赖的话,你的设计就是是松耦合的了。

Dependency Injection (DI) Container【依赖注入容器】

The Dependency Injection Container is a framework to create dependencies and inject them automatically when required. It automatically creates objects based on requests and injects them when required. It helps us split our application into a collection of loosely-coupled,highly-cohesive pieces and then glue them back together in a flexible manner. By DI container,our code will become easier to write,reuse,test and modify. In this article we will use a Niject DI Container.

翻译:依赖注入容器是一个创建依赖的框架,当需要的时候,容器就会自动的注入依赖。它会基于请求,自动地创建对象,并且当需要依赖的时候,自动注入依赖。它会帮助我们,将程序拆分成松耦合,高内聚的零件,并以灵活的方式,将这些零件重新粘合在一起。通过依赖注入容器,我们的代码将会变得越来越容易写,越来越容易测试和修改。这篇文章中我将会使用Niject 依赖注入容器。

好了,到此为止,理论介绍完了,开始实践吧:

CRUD operations Application Design【增删查改的应用程序设计】

We create four projects in a solution to implement DIP with generic repository pattern. These are:

我们将会创建四个项目并使用泛型仓储模式,来实现依赖倒置原则,他们是:

  1. Ioc.Entities (class library)
  2. Ioc.Data (class library)
  3. Ioc.Service (class library)
  4. Ioc.Web (web application)

首先明确引用关系:Ioc.Data添加Ioc.Entiies引用,Ioc.Service添加Ioc.Entities引用和Ioc.Data引用,最后Ioc.Web添加Ioc.Service和Ioc.Entities引用。

这样我们就搭建好了基本的框架了。接下来就是开发我们的实体层了。

在这篇文章中,我将会使用EF Code-First方式,来开发引用程序。实体层【Ioc.Entities】中,我们将会创建三个实体,一个是BaseEntity,一个是User实体,另外一个是UserProfile实体,BaseEntity实体类中有一些公共的属性,另外两个实体将会继承BaseEntity实体类。下面实体层的代码:

BaseEntity实体类:

using System;  System.Collections.Generic;  System.Linq;  System.Text;  System.Threading.Tasks; namespace Ioc.Entities { public abstract class BaseEntity { /// <summary>
        /// Id编号 </summary>
        int Id { get; set; }  添加时间 public DateTime AddedDate {  修改时间 public DateTime ModifiedDate {  IP地址 string IP { ; } } }
BaseEntity

User实体和UserProfile实体之间是一对一的关系,一个用户只有一个UserProfile

User实体:

 Ioc.Entities.User {  User:BaseEntity { <summary>
        用户名 </summary>
       string UserName {  电子邮件 string Email {  密码 string Password {  导航属性--UserProfile virtual UserProfile UserProfile { ; } } }
User

UserProfile实体:

 UserProfile:BaseEntity { string FirstName { string LastName {  住址 string Address {  导航属性--User virtual User User { ; } } }
UserProfile

实体层的代码到此就写完了,我们看下实体层的结构:

现在开始数据层的开发,因为我们使用EF,所以在Ioc.Data和Ioc.Service以及Ioc.Web项目都引入EF。

先来定义数据上下文接口:

IDbContext接口:

 Ioc.Entities;  System.Data.Entity;  Ioc.Data { public  interface IDbContext {  泛型返回值类型IDbSet<TEntity>方法Set,并且TEntity要继承BaseEntity <typeparam name="TEntity"></typeparam>
        <returns></returns>
        IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity;  保存 <returns></returns>
        int SaveChanges(); } }
IDbContext

IocDbContext数据上下文类:

 System.Data.Entity.ModelConfiguration;  System.Reflection; <summary>
     数据上下文类,要继承DbContext类 </summary>
    IocDbContext:DbContext,IDbContext { public IocDbContext() : base("name=DbConnectionstring) { }  重写DbContext类的OnModelCreating方法 <param name="modelBuilder"></param>
       protected override void OnModelCreating(DbModelBuilder modelBuilder) { var typesToRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(type => !String.IsNullOrEmpty(type.Namespace)) .Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typesToRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } base.OnModelCreating(modelBuilder); }  IocDbContext实现接口IDbContext中的 Set() 方法 <typeparam name="TEntity"></typeparam>
       <returns></returns>
       new IDbSet<TEntity> Set<TEntity>()  TEntity : Entities.BaseEntity { return base.Set<TEntity>(); //throw new NotImplementedException();可以看出来,接口的默认实现没有实现
 } } }
IocDbContext

Ioc.Data的配置文件中,需要配置数据库连接字符串:

<connectionStrings>
    <add name=DbConnectionstring" connectionString=server=.;database=IocDB;uid=sa;pwd=Password_1" providerName=System.Data.SqlClient"/>
  </connectionStrings>

这些配置完了,之后,就是实体的映射类了。还是在Ioc.Data项目中:

UserMap实体类:

 Ioc.Entities.User;  Ioc.Data.Mapping.User {  实体映射类,需要继承EntityTypeConfiguration类 </summary>
    class UserMap : EntityTypeConfiguration<Ioc.Entities.User.User> {  UserMap() { key 
           HasKey(t => t.Id); properties 
           Property(t => t.UserName).IsRequired(); Property(t => t.Email).IsRequired(); Property(t => t.Password).IsRequired(); Property(t => t.AddedDate).IsRequired(); Property(t => t.ModifiedDate).IsRequired(); Property(t => t.IP); table 
           ToTable(Users); } } }
UserMap

UserProfileMap实体类:

 UserProfileMap实体映射类 ,需要继承EntityTypeConfiguration类 class UserProfileMap:EntityTypeConfiguration<UserProfile> UserProfileMap() { properties 
           Property(t => t.FirstName).IsRequired().HasMaxLength(100).HasColumnType(nvarchar); Property(t => t.LastName).HasMaxLength(); Property(t => t.Address).HasColumnType(); Property(t =>UserProfiles); relation 
           HasRequired(t => t.User).WithRequiredDependent(u => u.UserProfile); } } }
UserProfileMap

至此实体映射类写完了。现在我们继续开发,写泛型仓储模式,关于泛型仓储模式的介绍,请看这个系列前面的文章的介绍,这里就不再罗嗦了。

我们在Ioc.Data项目中,创建一个泛型仓储接口。

IRepository接口

 泛型仓储接口 <typeparam name="T"></typeparam>
   interface IRepository<T> where T:BaseEntity  类型参数和接口名称之间没有任何符号,where关键字和类型参数之间,有一个空格。
 泛型方法,通过id获取实体 <param name="id"></param>
       <returns></returns>
       T GetById(object id);  泛型方法--添加实体 <param name="model"></param>
        Insert(T model);  泛型方法,更新实体  Update(T model);  泛型方法--删除实体  Delete(T model);  只读Table </summary>
       IQueryable<T> Table { get; } } }
Irepository

接着创建泛型仓储类,实现这个泛型接口。

 System.Data.Entity.Validation;  泛型仓储类,实现泛型仓储接口。 <typeparam name="T"></typeparam>
    class Repository<T> : IRepository<T> where T : BaseEntity  约束在最后面。
private readonly IocDbContext _context; private IDbSet<T> _entities; /// 
         Repository(IocDbContext context) { this._context = context; } public IDbSet<T> Entities { if (_entities == null) { _entities = _context.Set<T>(); } return _entities; } }  实现泛型接口中的IQueryable<T>类型的 Table属性  标记为virtual是为了可以重写它 virtual IQueryable<T> Table { this.Entities; } } public T GetById( id) { .Entities.Find(id); throw new NotImplementedException();
 }  Insert(T model) { tryif(model==) { throw new ArgumentNullException(model); } else.Entities.Add(model); ._context.SaveChanges(); } } catch(DbEntityValidationException ex)DbEntityValidationException从这个类中获取错误信息
var msg=string.Empty; var errorList  ex.EntityValidationErrors) { var item  errorList.ValidationErrors) { msg+=string.Format(Property:{0} Error:{1}",item.PropertyName,item.ErrorMessage)+Environment.NewLine; } } var fail=new Exception(msg,ex); throw fail; }  Update(T model) { model为空,抛空异常
                if (model == 直接保存了
                    catch (DbEntityValidationException ex) { var msg = string.Empty;记录错误信息
                Property:{0},Error:{1}创建一个异常实例,把错误信息传递进去
                var fail =  Delete(T model) { entity.Entities.Remove(model); ._context.SaveChanges(); }  (DbEntityValidationException dbEx) { var validationErrors  dbEx.EntityValidationErrors) { var validationError  validationErrors.ValidationErrors) { msg += Environment.NewLine + Property: {0} Error: {1},validationError.PropertyName,validationError.ErrorMessage); } }  fail;  throw new NotImplementedException();
 } } } }
Repository

好吧,至此,我们的数据访问层,也就是Ioc.Data就开发完毕了,我们来看下这个层的结构:

为了,实现依赖倒置原则,我们创建了一个Ioc.Service层,这个层负责与用户层【UI】,和数据访问层【Ioc.Data】进行通信。因为,依赖倒置原则声明:高级的模块不能依赖于低级的模块,所以我们在Ioc.Service项目中创建一个IUserService接口,负责和UI层的交互【增删查改】,下面是IUserService接口的代码:

IUserService接口代码:

 Ioc.Service {  IUserService {  获取所有用户 <returns></returns>
        IQueryable<User> GetUsers();  通过Id获取用户 <param name="id"></param>
        <returns></returns>
        User GetUserById(long 新增User <param name="model"></param>
         InsertUser(User model);  更新User  UpdateUser(User model);  删除User  DeleteUser(User model); } }
IUserService

接着就是创建用户操作类,继承IUserService接口,来做增删查改了。

UserService类的代码:

 Ioc.Data;  UserService:IUserService { private IRepository<User> userRepository; private IRepository<UserProfile> userProfileRepository;  构造函数注入 <param name="userRepository"></param>
       <param name="userProfileRepository"></param>
       public UserService(IRepository<User> userRepository,IRepository<UserProfile> userProfileRepository) { this.userRepository =this.userProfileRepository = userProfileRepository; } public IQueryable<User> GetUsers() { .userRepository.Table; 接口方法的默认实现,是抛异常
public User GetUserById( userRepository.GetById(id);  InsertUser(User model) { userRepository.Insert(model);  UpdateUser(User model) { userRepository.Update(model);  DeleteUser(User model) { userRepository.Delete(model);删除用户
           userProfileRepository.Delete(model.UserProfile);删除用户详情  } } }
UserService

好了,到此为止,我们的服务层也开发完了,我们看下这个层的结构:

现在就是我们的Ui层了,也就是Ioc.Web,既然文章开头已经说了,要做依赖注入,那么现在就是重头戏了,我们使用Niject注入容器。

The Ninject is a lightweight dependency injection framework for .NET applications. It helps us split our application into a collection of loosely-coupled,highly-cohesive pieces and then glue them back together in a flexible manner. By using Ninject to support our application‘s architecture,test and modify. You can learn more about it from:http://www.ninject.org/

翻译:Ninject是一个轻量级的依赖注入.net框架.它帮助我们,把程序拆分成松耦合,高内聚的块,然后又以灵活的方式,把它们组合在一起。通过使用Ninject我们的程序框架,将会变得很容易扩展,测试和修改,你可以上这个网站了解更多关于Ninject的知识。http://www.ninject.org/

引入Ninject。

引入Ninject.MVC5之后,我们程序中就有了下面的引用:

并且在App_Start文件夹下生成了一个类:

然后我们写注入代码。

注意:1.按理说,Ioc.Web不用引入Ioc.Data项目的引用,但这里配置依赖注入,就还是需要添加Ioc.Data的引用了。

2.并且Ioc.Web项目也要引入EF,配置文件中也要配置连接字符串。

自动生成的NinjectWebCommon类代码:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Ioc.Web.App_Start.NinjectWebCommon),Start)] [assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(Stop)] Ioc.Web.App_Start { System.Web; Microsoft.Web.Infrastructure.DynamicModuleHelper; Ninject; Ninject.Web.Common; Ioc.Service; static NinjectWebCommon { readonly Bootstrapper bootstrapper = Bootstrapper(); Starts the application Start() { DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule)); DynamicModuleUtility.RegisterModule((NinjectHttpModule)); bootstrapper.Initialize(CreateKernel); } Stops the application. Stop() { bootstrapper.ShutDown(); } Creates the kernel that will manage your application. <returns>The created kernel.</returns> static IKernel CreateKernel() { var kernel = StandardKernel(); { kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => Bootstrapper().Kernel); kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); RegisterServices(kernel); kernel; } { kernel.Dispose(); ; } } Load your modules or register your services here! <param name="kernel">The kernel.</param> RegisterServices(IKernel kernel) { 这里面写我们的注入代码 Bind方法要绑定的服务, To方法指定实现的类 kernel.Bind<IDbContext>().To<IocDbContext>().InRequestScope(); 泛型类型配置麻烦点 kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope(); kernel.Bind<IUserService>().To<UserService>().InRequestScope(); } } }

好了,到此为止,我们的程序,大部分都完成了,主要的逻辑。

现在我们来创建一个ViewModel类,用于操作。

UserModel类:

 System.ComponentModel.DataAnnotations;  Ioc.Web.Models {  UserModel { public Int64 ID { ; } [Display(Name = First NameLast NameUser NameAdded Date; } } }
View Code

最后就是控制器中的代码实现,和视图了,快要大功告成了。

 Ioc.Web.Models;  System.Web.Mvc;  Ioc.Web.Controllers {  UserController : Controller { private IUserService userService; <param name="userService"></param>
         UserController(IUserService userService) { this.userService = userService; }  ActionResult Index() { IEnumerable<UserModel> users = userService.GetUsers().Select(u =>  UserModel { FirstName = u.UserProfile.FirstName,LastName = u.UserProfile.LastName,Email = u.Email,Address = u.UserProfile.Address,ID = u.Id });  View(users); } [HttpGet] public ActionResult CreateEditUser(int? id) { UserModel model =  UserModel(); if (id.HasValue && id != 0) { User userEntity = userService.GetUserById(id.Value); model.FirstName = userEntity.UserProfile.FirstName; model.LastName = userEntity.UserProfile.LastName; model.Address = userEntity.UserProfile.Address; model.Email = userEntity.Email; model.UserName = userEntity.UserName; model.Password = userEntity.Password; }  View(model); } [HttpPost]  ActionResult CreateEditUser(UserModel model) { if (model.ID == ) { Ioc.Entities.User.User userEntity =  User { UserName = model.UserName,0)"> model.Email,Password = model.Password,AddedDate = DateTime.UtcNow,ModifiedDate = Request.UserHostAddress,UserProfile =  UserProfile { FirstName = model.FirstName,0)"> model.LastName,0)"> model.Address,0)"> Request.UserHostAddress } }; userService.InsertUser(userEntity); if (userEntity.Id > return RedirectToAction(index); } }  { Ioc.Entities.User.User userEntity = userService.GetUserById(model.ID); userEntity.UserName = model.UserName; userEntity.Email = model.Email; userEntity.Password = model.Password; userEntity.ModifiedDate = DateTime.UtcNow; userEntity.IP = Request.UserHostAddress; userEntity.UserProfile.FirstName = model.FirstName; userEntity.UserProfile.LastName = model.LastName; userEntity.UserProfile.Address = model.Address; userEntity.UserProfile.ModifiedDate = DateTime.UtcNow; userEntity.UserProfile.IP = Request.UserHostAddress; userService.UpdateUser(userEntity);  View(model); } public ActionResult DetailUser() { Ioc.Entities.User.User userEntity = userService.GetUserById(id.Value);  model.ID = userEntity.ID; 
                model.FirstName = userEntity.Email; model.AddedDate = userEntity.AddedDate; model.UserName = userEntity.UserName; } public ActionResult DeleteUser(if (id !=  userService.GetUserById(id); model.FirstName = id,FormCollection collection) {  userService.GetUserById(id); userService.DeleteUser(userEntity); Index View(); }  View(); } } } }
控制器代码

创建和编辑视图:

@model Ioc.Web.Models.UserModel @{ ViewBag.Title = Create Edit User; } <div class=book-example panel panel-primary">
    <div panel-heading panel-head">Add / Edit User</div>
    <div panel-body"> @using (Html.BeginForm()) { <div form-horizontal">
                <div form-group @Html.LabelFor(model => model.FirstName,255)">new { @class = col-lg-2 control-label }) <div col-lg-9 @Html.TextBoxFor(model => model.FirstName,0)">form-control }) </div>
                </div>
                <div  @Html.LabelFor(model => model.LastName,0)"> @Html.TextBoxFor(model => model.LastName,0)"> @Html.LabelFor(model => model.Email,0)"> @Html.TextBoxFor(model => model.Email,0)"> @Html.LabelFor(model => model.UserName,0)"> @Html.TextBoxFor(model => model.UserName,0)"> @Html.LabelFor(model => model.Password,0)"> @Html.PasswordFor(model => model.Password,0)"> @Html.LabelFor(model => model.Address,0)"> @Html.TextBoxFor(model => model.Address,0)">">
                    <div "></div>
                    <div col-lg-3 @Html.ActionLink(Back to Listnull,0)">btn btn-default }) <button btn btn-success" id=btnSubmit" type=submit Submit </button>
                    </div>
                </div>
            </div> } </div>
</div>  
View Code

Index视图:

@{ ViewBag.Title = ; } @model IEnumerable<Ioc.Web.Models.UserModel>

<div ">Users Listing</div>
    <div ">
        <a id=createEditBookModal" href=@Url.Action("CreateEditUser)" ">
            <span glyphicon glyphicon-plus"></span> User </a>

        <table table" style=margin: 4px">
            <tr>
                <th> @Html.DisplayName(Name) </th>
                <th> @Html.DisplayNameFor(model => model.Email) </th>
                <th> model.Address) </th>
                <th> Action </th>
                <th></th>
            </tr> @foreach ( Model) { <tr>
                    <td> @Html.DisplayFor(modelItem => item.FirstName) @Html.DisplayFor(modelItem => item.LastName) </td>
                    <td> @Html.DisplayFor(modelItem => item.Email) </td>
                    <td> item.Address) </td>
                    <td>EditCreateEditUsernew { id = item.ID },0)"> }) @Html.ActionLink(DetailsDetailUserbtn btn-primaryDeleteDeleteUserbtn btn-danger }) </td>
                </tr> } </table>
    </div>
</div>  
View Code

Delete视图:

Delete User">Delete User</div>
    <div ">
        <h3>Are you sure you want to delete this?</h3>
        <h1>@ViewBag.ErrorMessage</h1>
        <div ">
            <div  @Html.DisplayFor(model => model.FirstName,0)"> }) </div>
            </div>

            <div  @Html.DisplayFor(model => model.LastName,0)"> @Html.DisplayFor(model => model.UserName,0)"> @Html.DisplayFor(model => model.Address,0)"> }) </div>
            </div>col-lg-2">
                        <input type=" value=" /> }) </div>
                </div> } </div>
    </div>
</div>
  
View Code

detail视图:

User Detail">User Detail</div>
    <div ">
        <div  @Html.DisplayFor(model => model.Email,0)"> @Html.LabelFor(model => model.AddedDate,0)"> @Html.DisplayFor(model => model.AddedDate,255)">new { id = ViewContext.RouteData.Values[id"] },63); line-height:30px"> 效果图:

好了,到此为止,这个系列的文章就学完了,欢迎大家提意见。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结