• ASPNET5的依赖注入


    ASP.NET5设计的时候就是以DI为基础的,它可以利用内建的框架在Startup类的方法中,把依赖注入进去。应用服务也可以被配置的注入。默认的服务容器提供一些基本的功能,它并不打算代替现代主流的DI框架。

    1. 什么是Dependency Injection?

    DI的概念相信大家已经了解了,不了解的可以查一下资料。我们来讲一讲ASP.NET 5内建的DI容器。

    ASP.NET5包含一个简单的内建容器,它的表现形式是IServiceProvider接口, 默认支持构造函数的注入,ASP.NET通过它注入相关的服务类。ASP.NET的容器引用的类型,在它里面叫做服务,在下面的内容当中,服务就当然于ASP.NET Ioc容器当中管理的类型。你可以通过Startup类中的CongureServices注入内建的服务。

    2. 构架提供的服务

    Startup类中的ConfigureServices方法定义了应用程序需要的服务,像Entity Framework, MVC等,它由IServiceCollection的扩展方法来添加. 例如:

    public void ConfigureServices(IServiceCollection services)

    {

      services.AddEntityFramework().AddSqlServer().AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

      services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

          servies.AddMvc();

          services.AddTransient<IEmailSender, AuthMessageSender>();

      services.AddTransient<ISmsSender, AuthMessageSender>();

    }

    3. 注册你自己的服务

    上面的代码当中:

    services.AddTransient<IEmailSender, AuthMessageSender>();

    services.AddTransient<ISmsSender, AuthMessageSender>();

    AddTransient方法用来添加抽象类型到具体的类型映射,并且申明了它的生命周期,在你注册服务时,选择合适的对象生命周期很重要。

    我们来看一个例子:

    public class CharactersController : Controller

    {

      private readonly ICharacterRepository _characterRepository;

      public CharactersController(ICharacterRepository characterRepository)

      {

        _characterRepository = characterRepository;

      }

      public IActionResult Index()

      {

        var characters = _characterRepository.ListAll();

        return View(characters);

      }

    }

    public interface ICharacterRepository

    {

       IEnumberable<Character> ListAll();

    }

    public class CharacterRepository : ICharacterRepository

    {

      private readonly ApplicationDbContext _dbContext;

      public CharacterRepository(ApplicationDbContext dbContext)

      {

        _dbContext = dbContext;

      }

      public IEnumerable<Character> ListAll()

      {

        return _dbContext.Characters.AsEnumberable();

      }

    }

    注意CharacterRepository的构造函数当中需要一个ApplicationDbContext,像它这样的注入方式并不常见,在每个申请当中,容器负责提供每一个对象的具体依赖对象。

    在这个例子当中,ICharacterRepository和ApplicationDbContext都必须在ConfigureServices当中被注册。

    services.AddEntityFramework().AddSqlServer().AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration["Data:DefaultCOnnection:ConnectionString"]));

    services.AddScoped<ICharacterRepository, CharacterRepository>();

    EntityFramework context 应该被以Scoped的生命周期增加到容器当中,Repositories用到EntityFramework, 所以它应该使用同一个生命周期。

    4. 服务的生命周期和注册选项

    ASP.NET 服务可以配置对象的生命周期如下所示:

    Transient

      它是意思每个请求都创建一个新的对象,这个适合轻量的,无状态的服务。

    Scoped

      每个申请只创建一个对象。

    Singleton

      它是在首次被申请调用时创建一次, 以后所有的请求都会被重用,如果你的应用程序需要单例,推荐使用些方法,而不要自己实现单例模式。

    Instance

      它与Singleton相似 ,唯一的区别是,Instance在ConfigureServices的时候就创建了,而Singleton要在第一次请求的时候才创建。

    5. 请求的服务和应用服务

    ASP.NET当中服务在HttpContext的ApplicationServices和RequestServices中能够得到

    RequestServices里的服务是配置和请求你的应用程序的一部分,ApplicationServices里的服务是被限制在应用程序启动的时候的服务,任何Scoped的应用程序都能在RequestServices得到,但是在ApplicationServices里得不到。当你的对象申明依赖时,这些依赖在RequestServices里能够得到,在ApplicationServices里得不到,

    一般地,你不需要直接用这些属性,而可以通过构造函数注入。

    6. 用DI设计你的服务

    你应该用DI来设计你的应用,不要用函数状态的静态方法调用,或者直接地实例化你的服务。用DI ,你的类比较小,而且是灵活的,可测试的。

    当你一个类依赖很多的时候,你就要意识到是否违反了单一职责原则。你可以重构你的代码,把一些依赖移到其它的新类当中。注意在你Controler 类当中应该注意在UI上面,因此你的业务逻辑和数据访问通过UI的职责的分来被相应地合理分开。

    当用到数据访问时,你可以注入EntityFramework的DbContext类型到你的controllers里面,不过首先你要确保EF在Startup类中被配置了,然而,避免在UI里直接使用DbContext, 你应该把它放到抽象当中去,例如Repository的接口中去。这样可以减少你的应用和数据的耦合。也能使你的应用程序可以很容易地被测试。

    7 替代默认的服务容器

    在ASP.NET当中,你可以很容易地替代内建的服务容器,在ConfigureServices方法当中一般返回void, 但是如果它返回IServiceProvider, 一个不同的容器可以被返回,我们以autofac为例。

    首选,你必须在project.json加如下的配置:

    "dependencies":{

      "Autofac": "4.0.0-beta8",

      "Autofac.Framework.DependencyInjection": "4.0.0-beta8"

    },

    接下来,改写ConfigureServices

    public IServiceProvider ConfigureServices(IServiceCollection services)

    {

      services.AddMvc();

      

      // Add Autofac

      var containerBuilder = new ContainerBuilder();

      containerBuilder.RegisterModule<DefaultModule>();

      containerBuilder.Populate(services);

      var container = containerBuilder.Build();

      return container.Resolve<IServiceProvider>();

    }

    最后,配置Autofac在DefaultModule里面

    public class DefaultModule : Module

    {

      protected override void Load(ContainerBuilder builder)

      {

        builder.RegisterType<CharacterRepository>.As<ICharacterRepository>();

      }

    }

    现在,Autoface被用来生成你的服务在DI里面。

    ASP.NET 5/DNX Containers

    Autofac.Dnx     http://autofac.org

    StructureMap.Dnx   http://structuremap.github.io

    8. 建议

    * DI用于复杂的依赖,控制器、服务、仓储等

    * 不要直接利用DI存储数据和配置

    * 不要静态地访问服务

    * 不要在应用程序当中手动使用服务定位

    * 不要静态地访问HttpContext

    记住,不要把DI和static/global对应混用,否则你就感觉不到DI的好处了

  • 相关阅读:
    javaScript 基础知识汇总(六)
    javaScript 基础知识汇总(五)
    javaScript 基础知识汇总(四)
    WPF — Grid布局中行的高度和列的高度值定义的三种形式
    C# — 用递归实现斐波拉契数列的第n项
    C# — ref参数、params参数、out参数详解
    Android apk反编译教程
    WPF学习资源
    C# — 通过点击回车执行任务
    C# — MvvMLight框架入门资源
  • 原文地址:https://www.cnblogs.com/superkklot/p/5055685.html
Copyright © 2020-2023  润新知