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

上一篇 中将项目的基本骨架搭起来能正常跑通,这一篇将讲到,如何通过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(‘,‘)[0].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来统一前后端交互数据,统一使用一个模型进行返回。

  有需要源码的在下方评论或私信~给我的SVN访客账户密码下载,代码未放在GitHub上。

原文地址:https://www.cnblogs.com/levywang/p/coreframe_2.html

时间: 2024-10-12 20:08:00

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

从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之七使用JWT生成Token(个人见解)

在 上一篇中讲到了在NetCore项目中如何进行全局的请求模型验证,只要在请求模型中加了验证特性,接口使用时只用将数据拿来使用,而不用去关系数据是否符合业务需求. 这篇中将讲些个人对于JWT的看法和使用,在网上也能找到很多相关资料和如何使用,基本都是直接嵌到  Startup 类中来单独使用.而博主是将jwt当做一个验证方法来使用.使用起来更加方便,并且在做验证时也更加的灵活. 1.什么是JWT? Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON

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

前后端分离这个词一点都不新鲜,完全的前后端分离在岗位协作方面,前端不写任何后台,后台不写任何页面,双方通过接口传递数据完成软件的各个功能实现.此种情况下,前后端的项目都独立开发和独立部署,在开发期间有2个问题不可避免:第一是前端调用后台接口时的跨域问题(因为前后端分开部署):第二是前端脱离后台服务后无法独立运行.本文总结最近一个项目的工作经验,介绍利用grunt-contrib-connect和grunt-connect-proxy搭建前后端分离的开发环境的实践过程,希望能对你有所帮助. 注:

从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十七 ║Vue基础:给博客首页加花样(二)

回顾 今天来晚辣,给公司做了一个小项目,一个瀑布流+动态视频控制的DEMO,有需要的可以联系我,公司的项目就不对外展示了(一个后端程序员真的要干前端了哈哈哈). 书接上文,昨天正式的开始了Vue的代码的学习,简单的通过一些假的数据来展示了下个人博客的首页列表,不知道大家是否还记得昨天讲的什么,如果不太清楚呢,可以再回顾下<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十七 ║Vue基础:使用Vue.js 来画博客首页(一)>,我们主要说到了,Vue的核心语法是什么,MVVM

ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目

 一.前言 这几年前端的发展速度就像坐上了火箭,各种的框架一个接一个的出现,需要学习的东西越来越多,分工也越来越细,作为一个 .NET Web 程序猿,多了解了解行业的发展,让自己扩展出新的技能树,对自己的职业发展还是很有帮助的.毕竟,现在都快到9102年了,如果你还是只会 Web Form,或许还是能找到很多的工作机会,可是,这真的不再适应未来的发展了.如果你准备继续在 .NET 平台下进行开发,适时开始拥抱开源,拥抱 ASP.NET Core,即使,现在工作中可能用不到. 雪崩发生时,没有一

前后端分离开发,基于SpringMVC符合Restful API风格Maven项目实战(附完整Demo)!

摘要: 本人在前辈<从MVC到前后端分离(REST-个人也认为是目前比较流行和比较好的方式)>一文的基础上,实现了一个基于Spring的符合REST风格的完整Demo,具有MVC分层结构并实现前后端分离,该项目体现了一个具有REST风格项目的基本特征,即具有统一响应结构. 前后台数据流转机制(HTTP消息与Java对象的互相转化机制).统一的异常处理机制.参数验证机制.Cors跨域请求机制以及鉴权机制.此外,该项目的完整源码可移步到我的Github参考:RestSpringMVCDemo.喜欢

node+mysql+vue 搭建前后端分离基础框架

话不多说直接上 1.安装node,通过express.生成node项目.搭建链接 http://www.expressjs.com.cn/starter/generator.html: 2安装vue 前端项目. 3.配置vue 跨域问题,找到vue里面config里的index文件.配置proxyTable 原文地址:https://www.cnblogs.com/chen527/p/11442588.html

关于使用vue搭建前后端分离的项目,部署过程遇到的问题

1.首先应该有三个端口号:app前端.网页前端.后台接口  后台接口有很多,但是会映射到zuul上,保证他的端口号是对外开放的,其他不被占用就行 2.pc前端访问后台路径 他的baseUrl是每一次请求的基础路径,需要写服务器后台对外开放的ip和端口号,tomcat部署前端服务也得需要另一个端口号 3.然后发现他的静态资源都访问不到,可以看我的另一篇博客  https://www.cnblogs.com/vv-lilu/p/11106894.html 4.使用vue-lic3搭建的手机端框架,静

从零开始搭建django前后端分离项目 系列一(技术选型)

前言 最近公司要求基于公司的hadoop平台做一个关于电信移动网络的数据分析平台,整个项目需求大体分为四大功能模块:数据挖掘分析.报表数据查询.GIS地理化展示.任务监控管理.由于页面功能较复杂,所以采用前后端分离方式开发.前端采用webpack+vue+vue-router+axios技术栈,后端用django进行开发.从搭建到上线,整个项目前前后后花了差不多一个月时间,中途也遇到一些问题,不过还好都解决了.由于是个人项目,所以我打算把源码贡献出来大家一起讨论学习. 源代码 https://g

[原创]基于VueJs的前后端分离框架搭建之完全攻略

首先请原谅本文标题取的有点大,但并非为了哗众取宠.本文取这个标题主要有3个原因,这也是写作本文的初衷: (1)目前国内几乎搜索不到全面讲解如何搭建前后端分离框架的文章,讲前后端分离框架思想的就更少了,而笔者希望在本文中能够全面.详细地阐述我们团队在前后端分离的摸索中所得到的搭建思路.最佳实践以及架构思想: (2)我们团队所搭建的前后端分离框架,并非只是将网上传播的知识碎片简单拼装,而是一开始就从全局出发,按照整个系统对前后端分离框架的最高期望进行设计,到目前为止,可以说我们的框架完全实现了对我们