Web API中使用Dependency Resolver

前言

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html

本文主要来介绍在Asp.Net Web API使用Web API的Decpendency Resolver在控制器中如何注入依赖。

本文使用VS2013。本文的示例代码下载链接为http://pan.baidu.com/s/1BvFTs

为什么要使用Dependency Resolver

一个dependency 其实就是一个对象或者另外一个对象需要的一个接口。例如,在Asp.Net Web API 2第二课——CRUD操作 http://www.cnblogs.com/aehyok/p/3434578.html中,我们定义了一个ProductsController的类,这个类需要一个IProductRepository 的实例,这个实现看起来像这样:

public class ProductsController : ApiController
{
private static IProductRepository repository = new ProductRepository(); // Controller methods not shown.
}

这不是最好的设计,因为对于调用创建的ProductRepository 是通过在控制器中硬编码的方式实现的。如果要使用IProductRepository的不同实例,我们将需要在ProductRepository中改变代码。如果ProductsController不依赖于任何具体实例的IProductRepository那会是比较好的。

Dependency injection解决了这个问题。在Dependency injection中,对象是不会负责创建自己的依赖项的。相反,当你创建一个对象,注入这个依赖的时候是通过构造函数参数或者setter方法。

这里是ProductsController中修改后的实现代码:

public class ProductsController : ApiController
{
private readonly IProductRepository repository; public ProductsController(IProductRepository repository)
{
if (repository == null)
{
throw new ArgumentNullException("repository");
}
this.repository = repository;
}

这样是比较好的。现在可以切换到另外一个IProductRepository 的实例,而不用触及到ProductsController的实现。

但是,在Asp.Net Web API中,你不能直接的创建一个控制器。相反,这个框架给你创建一个控制器,而且它并不知道IProductRepository 的相关信息。这个框架也只能通过调用无参数的构造函数来创建你的控制器。

就在这个时候dependency resolver来了。dependency resolver的工作就是创建这个框架所需要的对象,包含congtrollers对象。通过提供一个自定义的dependency resolver,你可以代表框架来创建控制器实例。

一个简单的dependency resolver

下面的代码展示了一个简单的dependency resolver。这个代码主要只是展示了在Web API中依赖注入如何工作的。之后,我们将看到怎样来合并一个Ioc的容器。

class SimpleContainer : IDependencyResolver
{
static readonly IProductRepository respository = new ProductRepository(); public IDependencyScope BeginScope()
{
// This example does not support child scopes, so we simply return 'this'.
return this;
} public object GetService(Type serviceType)
{
if (serviceType == typeof(ProductsController))
{
return new ProductsController(respository);
}
else
{
return null;
}
} public IEnumerable<object> GetServices(Type serviceType)
{
return new List<object>();
} public void Dispose()
{
// When BeginScope returns 'this', the Dispose method must be a no-op.
}
}

一个 dependency resolver实现了这个IDependencyResolver 接口。这个IDependencyResolver  接口继承了另外的两个接口IDependencyScope 、IDisposable。

namespace System.Web.Http.Dependencies
{
public interface IDependencyResolver : IDependencyScope, IDisposable
{
IDependencyScope BeginScope();
} public interface IDependencyScope : IDisposable
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
}

IDependencyScope 接口定义了两个方法:

  • GetService: 创建一个指定类型的实例
  • GetServices: 创建一个指定类型的集合对象

对于控制器,这个框架调用 GetService来获得控制器的单个实例。这就是我们简单的容器创建控制器和注入repository

对于你的dependency resolver不处理的任何类型,GetService 会返回null,GetServices 也会返回一个空的集合对象,尤其是,别抛出一个未知类型的异常。

这个IDependencyResolver 接口继承了IDependencyScope ,添加了一个方法:

  • BeginScope: 创建一个嵌套的范围

之后,我们将来讨论嵌套的范围内如何来管理我们对象的生命周期。现在,BeginScope 方法的实现我们简单的返回一个this。

Setting the Dependency Resolver

现在在Web API全局配置对象中来设置Dependency Resolver。

主要是在Global.asax这个文件当中。然后在Application_Start 方法中,将GlobalConfiguration.Configuration.DependencyResolver设置为你的Dependency Reslover。

public class WebApiApplication : System.Web.HttpApplication
{
void ConfigureApi(HttpConfiguration config)
{
config.DependencyResolver = new SimpleContainer();
} protected void Application_Start()
{
ConfigureApi(GlobalConfiguration.Configuration); // ...
}
}

那么现在你可以正常运行程序了。

范围和对象声明周期

控制器被创建的每个请求。为了帮助管理对象的声明周期,IDependencyResolver 使用了IDisposable接口。被添加到HttpConfiguration 上的dependency resolver对象拥有全局的范围。当框架创建一个新的控制器实例的时候,它调用IDependencyResolver.BeginScope。这个方法返回一个IDependencyScope 。这个框架在IDependencyScope 上调用GetService 去获得这个控制器。当框架处理完这个请求的时候,它在子范围中调用Dispose 。你能通过Dispose 方法来释放控制器的依赖。

Dependency Injection with IoC Containers

一个Ioc容器就是一个软件组件,它负责创建依赖。Ioc容器为依赖注入提供公共的框架。如果你使用一个Ioc容器,你不需要在代码中直接连同对象,几个开源的.Net Ioc容器是可以利用的,例如Autofac, Castle Windsor, Ninject, Spring.NET, StructureMap 等等。

下面的例子我们来使用Unity,这个Ioc容器是由Microsoft patterns & practices开发的。

namespace ProductStore
{
using System;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Dependencies;
using Microsoft.Practices.Unity; class ScopeContainer : IDependencyScope
{
protected IUnityContainer container; public ScopeContainer(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
} public object GetService(Type serviceType)
{
if (container.IsRegistered(serviceType))
{
return container.Resolve(serviceType);
}
else
{
return null;
}
} public IEnumerable<object> GetServices(Type serviceType)
{
if (container.IsRegistered(serviceType))
{
return container.ResolveAll(serviceType);
}
else
{
return new List<object>();
}
} public void Dispose()
{
container.Dispose();
}
} class IoCContainer : ScopeContainer, IDependencyResolver
{
public IoCContainer(IUnityContainer container)
: base(container)
{
} public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new ScopeContainer(child);
}
}
}

这个ScopeContainer 类实现了IDependencyScope 代表了一个子范围。这个IoCContainer 类实现了全局范围内的依赖解析。并在BeginScope 方法中创建一个新的ScopeContainer对象。这个Unity 容器也有一个子容器的概念。因为我们可以用Unity 的子容器来初始化ScopeContainer 。这个ScopeContainer.Dispose方法释放了Unity的子容器。

下面的代码用Unity注册了controller和repository,然后设置Dependency resolver.

void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterType<ProductsController>();
unity.RegisterType<IProductRepository, ProductRepository>(
new HierarchicalLifetimeManager());
config.DependencyResolver = new IoCContainer(unity);
}

每次HTTP请求的时候Web API 控制器被创建,然后请求被处理之后控制器被释放。

现在同样可以运行了。

总结

对依赖注入的研究,还没有那么深入,只知道简单的怎么用。

对于文中

    public IDependencyScope BeginScope()
{
// This example does not support child scopes, so we simply return 'this'.
return this;
}

如果不适用this,那么其他还可以使用什么,还有待进一步的深入。之后自己还要对依赖Unity的依赖注入进行研究。不过感觉好像没MEF那么好用。

本文的参考链接为http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

本文以同步到Web API系列导航中 http://www.cnblogs.com/aehyok/p/3446289.html

本文的示例代码下载链接为http://pan.baidu.com/s/1BvFTs

 
 

入门级:怎么使用C#进行套接字编程(二)

 

入门级:怎么使用C#进行套接字编程(一)

原文地址如下

C# Server Socket program

C# Client Socket program

代码环境:VS2010+Win8.1企业评估版+Framework4.0

C#套接字编程由两部分组成。

1、C#服务端套接字程序
2、C#客户端套接字程序

服务端套接字编程

这里的服务端套接字程序是基于c#的控制台程序,实际上该程序作为一个服务端监听客户端的请求。这里我们为服务端套接字指定了端口号8888,他是C#类TcpListener的一个实例,通过该实例调用start()方法。

1
2
TcpListener serverSocket = new TcpListener(8888);
serverSocket.Start();

下一步就是创建一个无限循环来监听客户端那边的请求。当服务端套接字接受来自客户端的请求的时候,他会从网络流里读取数据,也会向网络流里写入他对客户端的响应。从下面的C#程序里你会了解如何使用C#创建一个服务端套接字程序。创建一个新的控制台程序项目并将下面的源码放进项目里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
TcpListener serverSocket = new TcpListener(8888);
int requestCount = 0;
TcpClient clientSocket = default(TcpClient);
serverSocket.Start();
Console.WriteLine(" >> Server Started");
clientSocket = serverSocket.AcceptTcpClient();
Console.WriteLine(" >> Accept connection from client");
requestCount = 0;
 
while ((true))
{
    try
    {
        requestCount = requestCount + 1;
        NetworkStream networkStream = clientSocket.GetStream();
        //为什么是65536,因为ReceiveBufferSize大小是65536,设置其大小时未起到作用
        //暂时就先用其默认大小
        byte[] bytesFrom = new byte[65536];
        networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
        string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
        dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$"));
        Console.WriteLine(" >> Data from client - " + dataFromClient);
        string serverResponse = "Server response " + Convert.ToString(requestCount);
        Byte[] sendBytes = Encoding.ASCII.GetBytes(serverResponse);
        networkStream.Write(sendBytes, 0, sendBytes.Length);
        networkStream.Flush();
        Console.WriteLine(" >> " + serverResponse);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}
 
clientSocket.Close();
serverSocket.Stop();
Console.WriteLine(" >> exit");
Console.ReadLine();

客户端套接字编程
C#客户端套接字编程是C#套接字编程的第二部分。该客户端套接字程序是基于窗体应用程序的。客户端连接到服务端套接字程序的端口8888上,因为服务端和客户端运行在同一台机器上,所以我们给出IP地址(主机名)为127.0.0.1。

1
clientSocket.Connect("127.0.0.1", 8888);

当C#客户端程序启动时,他将连接服务端套接字程序并开始从网络流里读取数据和向网络流里写入数据。启动客户端程序时你会获得一个消息提示“客户端已启动”。当你按下客户端窗体底部的按钮时,他将向服务端发送一个消息并且接收来自服务端的响应。

程序使用:

先启动服务器端如图:

再启动客户端如图:

点击底部的button按钮即可通信。

demo下载

快快乐乐敲代码,做一个专业的码农!
 
标签: socket

Web API中使用Dependency Resolver的更多相关文章

  1. Asp.Net Web API 2第十一课——在Web API中使用Dependency Resolver

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文主要来介绍在Asp.N ...

  2. 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建

    目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...

  3. ASP.NET Web API 中的返回数据格式以及依赖注入

    本篇涉及ASP.NET Web API中的返回数据合适和依赖注入. 获取数据 public IEnumerable<Food> Get() { var results = reop.Get ...

  4. Entity Framework 6 Recipes 2nd Edition(9-3)译->找出Web API中发生了什么变化

    9-3. 找出Web API中发生了什么变化 问题 想通过基于REST的Web API服务对数据库进行插入,删除和修改对象图,而不必为每个实体类编写单独的更新方法. 此外, 用EF6的Code Fri ...

  5. ASP.NET Web API中的Controller

    虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...

  6. Web APi 2.0优点和特点?在Web APi中如何启动Session状态?

    前言 曾几何时,微软基于Web服务技术给出最流行的基于XML且以扩展名为.asmx结尾的Web Service,此服务在.NET Framework中风靡一时同时也被.NET业界同仁所青睐,几年后在此 ...

  7. 在ASP.NET Web API中使用OData

    http://www.alixixi.com/program/a/2015063094986.shtml 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在A ...

  8. Web Api中的get传值和post传值

    GET 方式 get方式传参 我们一般用于获取数据做条件筛选,也就是 “查” 1.无参 var look = function () { $.ajax({ type: "GET", ...

  9. WEB API 中HTTP的get、post、put,delete 请求方式

    一.WEB API 中HTTP 请求方式的四个主要方法 (GET, PUT, POST, DELETE), 按照下列方式映射为 CURD 操作: 1.POST 用于新建资源,服务端在指定的URI 上创 ...

随机推荐

  1. linux终奌站 信息 格式 更改 /etc/bashrc

    gedit /etc/bashrc shell环境下默认的特殊符号意义: \d :代表日期,格式为weekday month date,比如:"Sun Sep 18" \H :完整 ...

  2. react学习笔记2--练习Demos

    准备工作 # 0.react核心库 <script src="../build/react.js"></script> # 将JSX 语法转为 JavaSc ...

  3. EF调用sp,EF自动生成返回类型

    在sp中添加下面的红色部分,就是执行sp时的返回类型,后面在EF中添加该sp后,EF会在DBContext文件中,自动生成调用该sp的代码,包括返回类型等,如下: public virtual Obj ...

  4. 我的MYSQL学习心得(三)

    原文:我的MYSQL学习心得(三) 我的MYSQL学习心得(三) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(四) 我的MYSQL学习心得(五) 我的MYSQL ...

  5. 一个奇怪的注意事项TNS-12545 TNS-12560 TNS-00515

    近来的reportDB无法从一开始就与系统收听,比较奇怪的现象. 由于server有听众的一个实例上正常启动,这是不是从开始监听器的实例手动启动是正常的.所以写下来未能找到离奇写的原因. 1.故障现象 ...

  6. EF中的transaction的使用范例

    注意一点: 在EF中使用事物后,对于一个新增的model,在saveChanges后,可以得到该实体的自增ID,但在提交事物之前, 该数据并没有真正的新增到DB中,但此时可以得到model新增的自增I ...

  7. poj 3744 Scout YYF I (可能性DP+矩阵高速功率)

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5062   Accepted: 1370 Description YYF i ...

  8. 【转】Java 工程师成神之路

    一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http://i ...

  9. CSharp设计模式读书笔记(19):备忘录模式(学习难度:★★☆☆☆,使用频率:★★☆☆☆)

    备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态.它是一种对象行为型模式,其别名为Tok ...

  10. Java8的日期和时间的库20经常使用的演示样本

    除了lambda表达,stream以及从一些小的改进,Java 8还推出了新的日期和时间API,在本教程中,我们将展示通过几个简单的任务来学习如何使用示例Java 8这组API.Java至今.日历和时 ...