zoukankan      html  css  js  c++  java
  • Web API中使用Dependency Resolver

     

    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
  • 相关阅读:
    用make编译openCV报错:ts_gtest.cpp:(.text._ZN7testing8internal2RED2Ev+0xf): undefined reference to 'regfreeA'
    Makefile:160: recipe for target 'all' failed (Ubuntu 16.06 + Opencv3.2)解决办法
    Linux常用命令汇总
    深度图像检测算法总结与对比(4)
    深度图像检测算法总结与对比(3)
    深度图像检测算法总结与对比(2)
    深度图像检测算法总结与对比(1)
    Caffe SSD的resize过程解析
    caffe 生成检测框并绘图
    Caffe中deploy.prototxt 和 train_val.prototxt 区别
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3463457.html
Copyright © 2011-2022 走看看