上一篇 中将项目的基本骨架搭起来能正常跑通,这一篇将讲到,如何通过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. CF543B Destroying Roads 题解

    看到没有题解就贡献一波呗 分析: 这题其实就是想让我们求一个图中两条最短路的最短(好把更多的边删掉). 我们先考虑一条最短路,别问我我怎么会的显然,就是s和t跑个最短路再用n-就行. 然后就是两条喽! ...

  2. 小埋的Dancing Line之旅:比赛题解&热身题题解

    答疑帖: 赞助团队:UMR IT Team和洛谷大佬栖息地 赛后题解:更新了那两道练手题的题解 赛时公告,不过一些通知也可能在团队宣言里发出 如果各位发现重题,请将你认为重复的题目链接连同这次比赛的题 ...

  3. 渐进式web应用开发---promise式数据库(五)

    在前面的一篇文章中,我们已经实现了使用indexedDB实现ajax本地数据存储的功能,详情,请看这篇文章.现在我们需要把上面的一篇文章中的代码使用promise结构来重构下.我们为什么需要使用pro ...

  4. 个人永久性免费-Excel催化剂功能第39波-DotNet版的正则处理函数

    在很久之前已经开发过的一些自定义函数,未能有详细的讲解,接下来几波中着重对之前开发过的自定义函数进行详细讲解及示例说明,希望能够帮助到普通用户们能顺利使用,此篇介绍为正则表达式函数. 文章出处说明 原 ...

  5. Excel催化剂开源第21波-使用Advanced Installer打包VSTO几个注意问题

    STO项目开发完毕完,最终需要分发给用户,需要Excel催化剂用的是Clickonce发布方式,但也面临到部分用户环境要求太高,设置过程太繁锁,而要求有一些简单的安装方式,用打包工具将其打包为一个EX ...

  6. 《VR入门系列教程》之3---运动追踪与输入设备

    运动追踪设备    第二种可以使人脑相信它真实处于虚拟世界的关键技术就是运动追踪技术,它可以通过追踪头部的运动状态实时更新渲染的场景.这与我们在真实世界中观看周围非常类似.    高速的惯性测量单元( ...

  7. 装饰器和"开放-封闭"原则

    装饰器和"开放-封闭"原则 "开放-封闭"原则 软件开发中的"开放-封闭"原则,它规定已经实现的功能代码不应该被修改,但可以被扩展,即: 封 ...

  8. SSM整合环境搭建demo

    1.项目目录结构 2.项目中用的jar包 3.web.xml(其中主要配置spring与springmvc) <?xml version="1.0" encoding=&qu ...

  9. PC端触底效果反复触发的解决方案

    最近在做一个PC端的项目,要求是在滑动到页面的底部的时候就动态的加载下一页的数据,代码实现思路如下: 首先,我们需要知道浏览器中有三个高度,分别是屏幕高度(outerHeight),文档容器高度(in ...

  10. 用wxpy管理微信公众号,并利用微信获取自己的开源数据。

    之前了解到itchat 乃至于 wxpy时 是利用tuling聊天机器人的接口.调用接口并保存双方的问答结果可以作为自己的问答词库的一个数据库累计.这些数据可以用于自己训练. 而最近希望获取一些语音资 ...