丹尼大叔

数学专业毕业,爱上编程的大叔,兴趣广泛。使用博客园这个平台分享我工作和业余的学习内容,以编程交友。有朋自远方来,不亦乐乎。

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

摘要:

下面的几篇文章介绍如何使用Ninject创建不同类型的应用系统。包括:

  • Windows Form应用系统
  • ASP.NET MVC应用系统
  • ASP.NET Web Form应用系统

尽管对于不同类型的应用系统,Ninject向应用组件注入依赖项的方式是相同的。但是根据不同应用系统架构不同,创建这些应用系统是不同的。一些新的框架例如ASP.NET MVC被设计成支持DI的,然而一些旧的框架例如ASP.NET是不支持所有DI模式。

前面已经介绍了Ninject提供的大多数功能,下面我们将在一个工程里应用这些功能。我们将实现一些应用,每一个应用都包含一个数据访问层,一个业务层,一个表现层,前面两层将在所有应用中共享。

程序下载

准备工作

1. 在网上下载Northwind数据库,并Restore或Attach到本地数据库。

2. 用Visual Studio 2015创建空解决方案Demo.Northwind。

3. 在解决方案Demo.Northwind里创建数据访问层工程:Demo.Northwind.Core。

在工程Demo.Northwind.Core内,用NuGet Manager添加引用EntityFramework和Ninject。

 

 在工程Demo.Northwind.Core内添加如下文件/文件夹。

Customer.cs:

 1 namespace Demo.Northwind.Core.Model
 2 {
 3     public class Customer
 4     {
 5         public string CustomerID { get; set; }
 6 
 7         public string CompanyName { get; set; }
 8 
 9         public string City { get; set; }
10 
11         public string PostalCode { get; set; }
12 
13         public string Phone { get; set; }
14     }
15 }

ICustomerRepository.cs:

 1 using Demo.Northwind.Core.Model;
 2 using System.Collections.Generic;
 3 
 4 namespace Demo.Northwind.Core.Interface
 5 {
 6     public interface ICustomerRepository
 7     {
 8         IEnumerable<Customer> GetAll();
 9 
10         Customer Get(string customerID);
11 
12         void Add(Customer customer);
13     }
14 }

NorthwindContext.cs:

 1 using Demo.Northwind.Core.Model;
 2 using System.Data.Entity;
 3 
 4 namespace Demo.Northwind.Core.SqlDataAccess
 5 {
 6     public class NorthwindContext : DbContext
 7     {
 8         public NorthwindContext() { }
 9 
10         public DbSet<Customer> Customers { get; set; }
11     }
12 }

SqlCustomerRepository.cs:

 1 using System.Collections.Generic;
 2 using Demo.Northwind.Core.Interface;
 3 using Demo.Northwind.Core.Model;
 4 
 5 namespace Demo.Northwind.Core.SqlDataAccess
 6 {
 7     public class SqlCustomerRepository : ICustomerRepository
 8     {
 9         private readonly NorthwindContext _context;
10 
11         public SqlCustomerRepository()
12         {
13             _context = new NorthwindContext();
14         }
15 
16         public void Add(Customer customer)
17         {
18             _context.Customers.Add(customer);
19             _context.SaveChanges();
20         }
21 
22         public Customer Get(string customerID)
23         {
24             return _context.Customers.Find(customerID);
25         }
26 
27         public IEnumerable<Customer> GetAll()
28         {
29             return _context.Customers;
30         }
31     }
32 }

创建工程Demo.Northwind.Winforms

Windows Forms是实现DI的一个最直接的应用系统类型。像Console应用程序一样,它不需要特别的Ninject配置。在Program类里的Main方法注册依赖项,框架里的组件例如Form类不需要一个无参数的构造函数,这使得实现构造函数注入变得很简单。

1. 在工程Demo.Northwind.Winforms内使用NutGet Manager添加如下引用:

2. 在工程Demo.Northwind.Winforms内添加到Demo.Northwind.Core的引用。

修改App.config,添加数据库连接字符串:

<connectionStrings>
    <add name="NorthwindContext" providerName="System.Data.SqlClient" connectionString="Data Source=localhost;Initial Catalog=NORTHWND;Integrated Security=True" />
  </connectionStrings>

3. 在MainForm里添加一个DataGrid控件,一个BindingSource控件。绑定DataGrid控件的数据源到BindingSource控件。

代码:

 1 using Demo.Northwind.Core.Interface;
 2 using Demo.Northwind.Core.Model;
 3 using System;
 4 using System.Linq;
 5 using System.Windows.Forms;
 6 
 7 namespace Demo.Northwind.Winforms
 8 {
 9     public partial class MainForm : Form
10     {
11         private readonly ICustomerRepository _repository;
12 
13         public MainForm(ICustomerRepository repository)
14         {
15             this._repository = repository;
16             InitializeComponent();
17         }
18 
19         private void MainForm_Load(object sender, EventArgs e)
20         {
21             LoadCustomers();
22         }
23 
24         private void LoadCustomers()
25         {
26             var customers = _repository.GetAll();
27             customerBindingSource.DataSource = customers.ToList<Customer>();
28         }
29     }
30 }

ICustomerRepository是这个类唯一的依赖项,在构造函数内引入和注入。

4. 既然MainForm的构造函数注入了一个ICustomerRepository对象,需要在Ninject中完成依赖注入,并使用kernel.Get<CustomerForm>()得到MainForm窗口对象,修改Program.cs:

 1 using System;
 2 using System.Windows.Forms;
 3 using Ninject;
 4 using Ninject.Extensions.Conventions;
 5 
 6 namespace Demo.Northwind.Winforms
 7 {
 8     static class Program
 9     {
10         /// <summary>
11         /// The main entry point for the application.
12         /// </summary>
13         [STAThread]
14         static void Main()
15         {
16             Application.EnableVisualStyles();
17             Application.SetCompatibleTextRenderingDefault(false);
18 
19             using (var kernel = new StandardKernel())
20             {
21                 kernel.Bind(x => x.FromAssembliesMatching("Demo.Northwind.*")
22                     .SelectAllClasses()
23                     .BindAllInterfaces());
24 
25                 var mainForm = kernel.Get<MainForm>();
26                 Application.Run(mainForm);
27             }
28         }
29     }
30 }

5. 如果要在MainForm窗口上加一个“Create”按钮,点击按钮打开一个CustomerForm窗口用来添加新Customer并保存到数据库。CustomerForm窗口类也应该在构造函数中注入一个ICustomerRepository对象。

新建Windows Form:CustomerForm。

 

代码:

 1 using Demo.Northwind.Core.Interface;
 2 using Demo.Northwind.Core.Model;
 3 using System;
 4 using System.Windows.Forms;
 5 
 6 namespace Demo.Northwind.Winforms
 7 {
 8     public partial class CustomerForm : Form
 9     {
10         private readonly ICustomerRepository repository;
11 
12         public CustomerForm(ICustomerRepository repository)
13         {
14             this.repository = repository;
15             InitializeComponent();
16             customerBindingSource.Add(new Customer());
17         }
18 
19         private void saveButton_Click(object sender, EventArgs e)
20         {
21             customerBindingSource.EndEdit();
22             var customer = customerBindingSource.Current as Customer;
23             repository.Add(customer);
24             this.DialogResult = DialogResult.OK;
25         }
26 
27         private void closeButton_Click(object sender, EventArgs e)
28         {
29             this.DialogResult = DialogResult.Cancel;
30         }
31     }
32 }

6. 在MainForm.cs中添加Create按钮事件:createButton_Click:

1         private void createButton_Click(object sender, EventArgs e)
2         {
3             
4         }

问题来了,CustomerForm窗口类只有一个注入ICustomerRepository对象的构造函数,不能使用new无参数的构造函数创建CustomerForm窗口类对象,也不能在MainForm窗口类里再新创建一个kernal对象,使用Get方法得到CustomerForm对象。

因此,我们怎么办呢?这个时候应该使用Ninject动态工厂。多亏了Ninject工厂功能,我们只需要简单地定义如下的接口:

1 using System.Windows.Forms;
2 
3 namespace Demo.Northwind.Winforms
4 {
5     public interface IFormFactory
6     {
7         T Create<T>() where T : Form;
8     }
9 }

在MainForm类里添加IFormFactory对象:

private readonly IFormFactory _formFactory;

修改MainForm类createButton_Click事件:

1         private void createButton_Click(object sender, EventArgs e)
2         {
3             var customerForm = _formFactory.Create<CustomerForm>();
4             if (customerForm.ShowDialog(this) == DialogResult.OK)
5             {
6                 LoadCustomers();
7             }
8         }

修改MainForm类构造函数,添加IFormFactory对象注入:

1         public MainForm(ICustomerRepository repository, IFormFactory formFactory)
2         {
3             this._repository = repository;
4             this._formFactory = formFactory;
5             InitializeComponent();
6         }

最后是在Program类的Main方法里添加注册我们的动态工厂服务:

1             kernel.Bind(x => x.FromThisAssembly()
2                 .SelectAllInterfaces()
3                 .EndingWith("Factory")
4                 .BindToFactory()
5                 .Configure(c => c.InSingletonScope()));

 运行系统,测试系统运行情况。

posted on 2017-01-25 11:56  丹尼大叔  阅读(836)  评论(0编辑  收藏  举报