上一篇 中将项目的基本骨架搭起来能正常跑通,这一篇将讲到,如何通过autofac将DbContext和model进行解耦,只用添加model,而不用在DbContext中添加DbSet。

在这里就不详细讲autofac是干什么用的了,简单说下autofac。

1.autofac可替换net core自带的DI IOC,用来扩展。

2.autofac可提供Aop,具体实现在博客园有很多示例。

3.autofac的几个生命周期用法:InstancePerDependency 每次都创建一个对象 ,SingleInstance 每次都是同一个对象,InstancePerLifetimeScope 同一个生命周期生成的对象是同一个。

  接下来,我们需要在启动项目上通过nuget安装两个Package:Autofac、Autofac.Extensions.DependencyInjection。

因为autofac是通过接口来进行注入的,因此我们需要创建对应的基层接口用来注入。在basic项目通过nuget安装Autofac.Extensions.DependencyInjection、,

  然后中添加 Dependency 文件夹来存放基层接口,添加IOC容器接口:IIocManager,代码如下:

using System;
using Autofac;
using Autofac.Core; namespace DemoFrame_Basic.Dependency
{
/// <summary>
/// IOC容器接口
/// </summary>
public interface IIocManager
{
IContainer Container { get; } bool IsRegistered(Type serviceType, ILifetimeScope scope = null);
object Resolve(Type type, ILifetimeScope scope = null);
T Resolve<T>(string key = "", ILifetimeScope scope = null) where T : class;
T Resolve<T>(params Parameter[] parameters) where T : class;
T[] ResolveAll<T>(string key = "", ILifetimeScope scope = null);
object ResolveOptional(Type serviceType, ILifetimeScope scope = null);
object ResolveUnregistered(Type type, ILifetimeScope scope = null);
T ResolveUnregistered<T>(ILifetimeScope scope = null) where T : class;
ILifetimeScope Scope();
bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance);
}
}

-IOC容器接口

  再添加一个数据库基础接口:IEntityBase

    /// <summary>
/// 数据库基础接口
/// </summary>
public interface IEntityBase
{
}

-数据库基础接口

  IIocManager的实现类:IocManager

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Autofac;
using Autofac.Core;
using Autofac.Core.Lifetime;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel; namespace DemoFrame_Basic.Dependency
{
/// <summary>
/// Container manager
/// </summary>
public class IocManager : IIocManager
{
private IContainer _container; public static IocManager Instance { get { return SingletonInstance; } }
private static readonly IocManager SingletonInstance = new IocManager(); /// <summary>
/// Ioc容器初始化
/// </summary>
/// <param name="config"></param>
/// <returns></returns>
public IServiceProvider Initialize(IServiceCollection services)
{ //.InstancePerDependency() //每次都创建一个对象
//.SingleInstance() //每次都是同一个对象
//.InstancePerLifetimeScope() //同一个生命周期生成的对象是同一个 var builder = new ContainerBuilder();
builder.RegisterInstance(Instance).As<IIocManager>().SingleInstance();
//所有程序集 和程序集下类型
var deps = DependencyContext.Default;
var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系统程序集、Nuget下载包
var listAllType = new List<Type>();
foreach (var lib in libs)
{
try
{
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
listAllType.AddRange(assembly.GetTypes().Where(type => type != null));
}
catch { }
} //注册IEntityBase实现类
var entityBaseType = typeof(IEntityBase);
var arrEntityBaseType = listAllType.Where(t => entityBaseType.IsAssignableFrom(t) && t != entityBaseType).ToArray();
builder.RegisterTypes(arrEntityBaseType)
.AsImplementedInterfaces()
.SingleInstance()
.PropertiesAutowired(); foreach (var type in arrEntityBaseType)
{
if (type.IsClass && !type.IsAbstract && !type.BaseType.IsInterface && type.BaseType != typeof(object))
{
builder.RegisterType(type).As(type.BaseType)
.SingleInstance()
.PropertiesAutowired();
}
} //注册controller实现类 让Controller能被找到
var controller = typeof(ControllerBase);
var arrcontrollerType = listAllType.Where(t => controller.IsAssignableFrom(t) && t != controller).ToArray();
builder.RegisterTypes(arrcontrollerType)
.AsImplementedInterfaces()
.SingleInstance()
.PropertiesAutowired(); foreach (var type in arrcontrollerType)
{
if (type.IsClass && !type.IsAbstract && !type.BaseType.IsInterface && type.BaseType != typeof(object))
{
builder.RegisterType(type).AsSelf();
}
} builder.Populate(services);
_container = builder.Build();
return new AutofacServiceProvider(_container);
} /// <summary>
/// Gets a container
/// </summary>
public virtual IContainer Container
{
get
{
return _container;
}
} /// <summary>
/// Resolve
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="key">key</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Resolved service</returns>
public virtual T Resolve<T>(string key = "", ILifetimeScope scope = null) where T : class
{
if (scope == null)
{
//no scope specified
scope = Scope();
}
if (string.IsNullOrEmpty(key))
{
return scope.Resolve<T>();
}
return scope.ResolveKeyed<T>(key);
} /// <summary>
/// Resolve
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="key">key</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Resolved service</returns>
public virtual T Resolve<T>(params Parameter[] parameters) where T : class
{
var scope = Scope();
return scope.Resolve<T>(parameters);
} /// <summary>
/// Resolve
/// </summary>
/// <param name="type">Type</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Resolved service</returns>
public virtual object Resolve(Type type, ILifetimeScope scope = null)
{
if (scope == null)
{
//no scope specified
scope = Scope();
}
return scope.Resolve(type);
} /// <summary>
/// Resolve all
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="key">key</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Resolved services</returns>
public virtual T[] ResolveAll<T>(string key = "", ILifetimeScope scope = null)
{
if (scope == null)
{
//no scope specified
scope = Scope();
}
if (string.IsNullOrEmpty(key))
{
return scope.Resolve<IEnumerable<T>>().ToArray();
}
return scope.ResolveKeyed<IEnumerable<T>>(key).ToArray();
} /// <summary>
/// Resolve unregistered service
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Resolved service</returns>
public virtual T ResolveUnregistered<T>(ILifetimeScope scope = null) where T : class
{
return ResolveUnregistered(typeof(T), scope) as T;
} /// <summary>
/// Resolve unregistered service
/// </summary>
/// <param name="type">Type</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Resolved service</returns>
public virtual object ResolveUnregistered(Type type, ILifetimeScope scope = null)
{
if (scope == null)
{
//no scope specified
scope = Scope();
}
var constructors = type.GetConstructors();
foreach (var constructor in constructors)
{
try
{
var parameters = constructor.GetParameters();
var parameterInstances = new List<object>();
foreach (var parameter in parameters)
{
var service = Resolve(parameter.ParameterType, scope);
if (service == null) throw new Exception("Unknown dependency");
parameterInstances.Add(service);
}
return Activator.CreateInstance(type, parameterInstances.ToArray());
}
catch (Exception)
{ }
}
throw new Exception("No constructor was found that had all the dependencies satisfied.");
} /// <summary>
/// Try to resolve srevice
/// </summary>
/// <param name="serviceType">Type</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <param name="instance">Resolved service</param>
/// <returns>Value indicating whether service has been successfully resolved</returns>
public virtual bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance)
{
if (scope == null)
{
//no scope specified
scope = Scope();
}
return scope.TryResolve(serviceType, out instance);
} /// <summary>
/// Check whether some service is registered (can be resolved)
/// </summary>
/// <param name="serviceType">Type</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Result</returns>
public virtual bool IsRegistered(Type serviceType, ILifetimeScope scope = null)
{
if (scope == null)
{
//no scope specified
scope = Scope();
}
return scope.IsRegistered(serviceType);
} /// <summary>
/// Resolve optional
/// </summary>
/// <param name="serviceType">Type</param>
/// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
/// <returns>Resolved service</returns>
public virtual object ResolveOptional(Type serviceType, ILifetimeScope scope = null)
{
if (scope == null)
{
//no scope specified
scope = Scope();
}
return scope.ResolveOptional(serviceType);
} /// <summary>
/// Get current scope
/// </summary>
/// <returns>Scope</returns>
public virtual ILifetimeScope Scope()
{
try
{
//when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
return Container.BeginLifetimeScope();
}
catch (Exception)
{
//we can get an exception here if RequestLifetimeScope is already disposed
//for example, requested in or after "Application_EndRequest" handler
//but note that usually it should never happen //when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
return Container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
}
}
}
}

-Container manager

  在这里添加完以后,我们需要将自带的DI容器给替换成现在使用的autofac,

  在启动项目的Startup文件中更改,最终代码如下:

        public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>()); services.AddDbContext<DemoDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"))); return IocManager.Instance.Initialize(services);
}

-ConfigureServices

  为了方便使用,在CoreMvc项目中添加DemoWeb的类来存放一些系统数据:

using DemoFrame_Basic.Dependency;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System.Linq; namespace DemoFrame_CoreMvc
{
public class DemoWeb
{
private static IHttpContextAccessor _httpContextAccessor; /// <summary>
/// Configure
/// </summary>
/// <param name="httpContextAccessor"></param>
public static void Configure(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
} /// <summary>
/// 当前请求HttpContext
/// </summary>
public static HttpContext HttpContext
{
get => _httpContextAccessor.HttpContext;
set => _httpContextAccessor.HttpContext = value;
} /// <summary>
/// IocManager
/// </summary>
public static IIocManager IocManager { get; set; } /// <summary>
/// Environment
/// </summary>
public static IHostingEnvironment Environment { get; set; } /// <summary>
/// Configuration
/// </summary>
public static IConfiguration Configuration { get; set; } /// <summary>
/// MemoryCache
/// </summary>
public static IMemoryCache MemoryCache { get; set; } /// <summary>
/// 获取当前请求客户端IP
/// </summary>
/// <returns></returns>
public static string GetClientIp()
{
var ip = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault()?.Split(',')[].Trim();
if (string.IsNullOrEmpty(ip))
{
ip = HttpContext.Connection.RemoteIpAddress.ToString();
}
return ip;
}
}
}

  Startup的完整代码如下:

public class Startup
{
public Startup(IConfiguration configuration)
{
DemoWeb.Configuration = configuration;
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>()); services.AddDbContext<DemoDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"))); return IocManager.Instance.Initialize(services);
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
DemoWeb.IocManager = app.ApplicationServices.GetService<IIocManager>();
DemoWeb.Environment = env;
try//注意这里在本地开发允许时会重置数据库,并清空所有数据,如不需要请注释
{
if (env.IsDevelopment())
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
var dbContent = serviceScope.ServiceProvider.GetService<DemoDbContext>();
//CheckMigrations(dbContent);
var database = serviceScope.ServiceProvider.GetService<DemoDbContext>().Database;
database.EnsureDeleted();
database.EnsureCreated();
}
}
}
catch (Exception ex)
{
//LogHelper.Logger.Error(ex, "Failed to migrate or seed database");
}
DemoWeb.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());//允许跨域
app.UseHttpsRedirection();
app.UseMvc();
} }

-Startup

  在这么多的配置都完成了的情况下,我们该去实现mode与DbContext的解耦操作了。那么该如何做呢?

  废话不多说了,直接上代码,在数据库上下文DemoDbContext中将之前的DbSet删掉,更改如下:

  !!!先将之前的model都继承 IEntityBase 接口。这样在模型生成时才能生成到数据库!!!

    /// <summary>
/// 数据库上下文
/// </summary>
public class DemoDbContext : DbContext
{
public DemoDbContext(DbContextOptions<DemoDbContext> options)
: base(options)
{ } #region IOC得到所有实体
private readonly IEntityBase[] _entitys = DemoWeb.IocManager.ResolveAll<IEntityBase>();
#endregion protected override void OnModelCreating(ModelBuilder modelBuilder)
{
if (_entitys == null)
{
return;
}
foreach (var entity in _entitys)
{
modelBuilder.Model.AddEntityType(entity.GetType());
}
}
}

-数据库上下文

  在使用数据库上下文是,使用Set<T>方法设置需要使用的的类

  在下一篇中将介绍如何使用基类controller来统一前后端交互数据,统一使用一个模型进行返回。

  有需要源码的可通过此 GitHub链接拉取 觉得还可以的给个 start 哦,谢谢!

从零开始搭建前后端分离的NetCore(EF Core CodeFirst+Au)+Vue的项目框架之二autofac解耦的更多相关文章

  1. 【手摸手,带你搭建前后端分离商城系统】02 VUE-CLI 脚手架生成基本项目,axios配置请求、解决跨域问题

    [手摸手,带你搭建前后端分离商城系统]02 VUE-CLI 脚手架生成基本项目,axios配置请求.解决跨域问题. 回顾一下上一节我们学习到的内容.已经将一个 usm_admin 后台用户 表的基本增 ...

  2. Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之二 || 后端项目搭建

    本文梯子 前言 1..net core 框架性能测试 2..net core 执行过程 3.中间件执行过程 4.AOP切面 5.整体框架结构与数据库表UML 一.创建第一个Core 1.SDK 安装 ...

  3. 从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之四Nlog记录日志至数据库

    为什么要进行日志记录呢?为什么要存至数据库呢?只能说日志记录是每个系统都应当有的. 好的日志记录方式可以提供我们足够多定位问题的依据.查找系统或软件或项目的错误或异常记录.程序在运行时就像一个机器人, ...

  4. 利用grunt-contrib-connect和grunt-connect-proxy搭建前后端分离的开发环境

    前后端分离这个词一点都不新鲜,完全的前后端分离在岗位协作方面,前端不写任何后台,后台不写任何页面,双方通过接口传递数据完成软件的各个功能实现.此种情况下,前后端的项目都独立开发和独立部署,在开发期间有 ...

  5. List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac

    List多个字段标识过滤 class Program{  public static void Main(string[] args) { List<T> list = new List& ...

  6. 【手摸手,带你搭建前后端分离商城系统】01 搭建基本代码框架、生成一个基本API

    [手摸手,带你搭建前后端分离商城系统]01 搭建基本代码框架.生成一个基本API 通过本教程的学习,将带你从零搭建一个商城系统. 当然,这个商城涵盖了很多流行的知识点和技术核心 我可以学习到什么? S ...

  7. 【手摸手,带你搭建前后端分离商城系统】03 整合Spring Security token 实现方案,完成主业务登录

    [手摸手,带你搭建前后端分离商城系统]03 整合Spring Security token 实现方案,完成主业务登录 上节里面,我们已经将基本的前端 VUE + Element UI 整合到了一起.并 ...

  8. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之七 || API项目整体搭建 6.2 轻量级ORM

    本文梯子 本文3.0版本文章 前言 零.今天完成的蓝色部分 0.创建实体模型与数据库 1.实体模型 2.创建数据库 一.在 IRepository 层设计接口 二.在 Repository 层实现相应 ...

  9. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之六 || API项目整体搭建 6.1 仓储+服务+抽象接口模式

    本文梯子 本文3.0版本文章 前言 零.完成图中的粉色部分 2019-08-30:关于仓储的相关话题 一.创建实体Model数据层 二.设计仓储接口与其实现类 三.设计服务接口与其实现类 四.创建 C ...

随机推荐

  1. jmeter_遍历转换浮点时间戳

    概述 近期帮朋友解决了一个浮点时间戳转换的问题,在这里记录一下. 具体场景是有一个十位浮点时间戳的list,需要遍历转换为当前的标准时间. list如下: 实现步骤 实现步骤其实很简单,只需要一个fo ...

  2. 个人永久性免费-Excel催化剂功能第38波-比Vlookup更好用的查找引用函数

    谈起Excel的函数,有一个函数生来自带明星光环,在表哥表姐群体中无人不知,介绍它的教程更是铺天盖地,此乃VLOOKUP函数也.今天Excel催化剂在这里冒着被火喷的风险,大胆地宣布一个比VLOOKU ...

  3. 创建RDD

    RDD创建 在Spark中创建RDD的创建方式大概可以分为三种:从集合中创建RDD:从外部存储创建RDD:从其他RDD创建. 由一个已经存在的Scala集合创建,集合并行化,而从集合中创建RDD,Sp ...

  4. 【HDOJ】2104 hide handkerchief

    Problem Description The Children’s Day has passed for some days .Has you remembered something happen ...

  5. .NetCore下ES查询驱动 PlainElastic .Net 升级官方驱动 Elasticsearch .Net

    1.背景 由于历史原因,笔者所在的公司原有的ES查询驱动采用的是 PlainElastic.Net, 经过询问原来是之前PlainElastic.Net在园子里文档较多,上手比较容易,所以最初作者选用 ...

  6. k8s1.9.0安装--基础集群部署

    二.基础集群部署 - kubernetes-simple 1. 部署ETCD(主节点) 1.1 简介 kubernetes需要存储很多东西,像它本身的节点信息,组件信息,还有通过kubernetes运 ...

  7. JVM执行原理

    ,Java是一种技术,它由四方面组成:Java编程语言.Java类文件格式.Java虚拟机和Java应用程序接口(Java API).它们的关系如下图所示: 运行期环境代表着Java平台,开发人员编写 ...

  8. Linux零拷贝技术,看完这篇文章就懂了

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫. 本文讲解 ...

  9. CoreCLR Host源码分析(C++)

    废话不多说,直接上源码: 1.在托管程序集里面执行方法 HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId,//通过CreateAppDomai ...

  10. Redis优化建议

    优化的一些建议 1.尽量使用短的key 当然在精简的同时,不要完了key的"见名知意".对于value有些也可精简,比如性别使用0.1. 2.避免使用keys * keys *, ...