zoukankan      html  css  js  c++  java
  • [外包]!采用asp.net core 快速构建小型创业公司后台管理系统(一.项目简介)

    今天给大家分享一下采用asp.net core 快速构建小型创业公司后台管理系统,该项目是我给一个朋友做的,将要用到公司项目,今天分享出来权限管理模块喜欢的朋友可以试用用一下。

    项目不是一个什么新项目,也没有用到什么牛逼的东西,但里面融入了我用asp.net core构建管理系统的思考,可以说是思想的结合体。

    该项目的权限模块我已经放到了Liinu上,项目预览地址:http://xingchenbeta.52expo.top/Welcome 账户:admin 密码:123456

    接下来再说一下该项目基本点:

    • 项目采用Asp.Net Core2.1+EF Core构建后台服务
    • 项目前端使用BootStrap+Angular1.x构建管理系统前端
    • 数据库采用MySql 5.7.24
    • 部署环境在CentOS 7.4上
    • 项目中用到Redis
    • 用到Quartz

    接下来在上一张项目图片:

    项目基本完成功能点有:

    • 角色管理(curd)
    • 角色授权
    • 后台用户管理(crud)
    • 代码动态生成权限

    废话就说这么多吧,接下来我就从头开始介绍这个项目。

     一.项目基本组成介绍

    项目成员就这么多,大家看着名字可能很眼熟,其实我只接用了DDD的名字而已。

    除去单元测试,项目分为五部分:API,WebSite,Domain,Infrastuctrue,Applicaiton

    Api 主要用来给我们的移动端兄弟们提供api支持

    Website里面呢就是我们的后台管理系统

    Domain里面我放的是数据库实体模型,识图模型,枚举类,服务接口约束,以及必要的核心东西

    Infrastructure里面我放着部分Domain接口的实现,数据库上下文,三方,工具类,一些拓展方法,等基础构造

    Application里面放着Domain接口的实现,这里我主要放自己需要写的服务,也可以称之为业务逻辑

    二.抽丝剥茧,看看具体怎么实现

    1,设计好数据库(我们还是采用db frist的思想,因为我觉得code frist开发的有点慢,并不是说code frist不好!),在Domain项目引入支持mysql的nuget包

    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.2" />

      生成实体类

    ## dbfrist 数据库迁移命令

    Scaffold-DbContext "Server=host;Database=RestApi;User=root;Password=xx.;" "Pomelo.EntityFrameworkCore.MySql" -Force -OutputDir Entitys

      如图

      

      把context从实体中拉出来,放到infrastructure里,在Infrastructure里创建context文件夹

      

    2. 在Domain 创建Repositorys文件夹

      

      IDbRepository封装装ef数据仓储接口

      

    /// <summary>
        /// 封装装ef数据仓储接口
        /// </summary>
        public interface IDbRepository<TContext> where TContext:dbcontext
        {
            /// <summary>
            /// get <see cref="!:TSource" /> from raw sql query
            /// the TSource must in database or <see cref="T:Microsoft.EntityFrameworkCore.DbContext" />
            /// </summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="sql"></param>
            /// <param name="parameters"></param>
            /// <returns></returns>
            IQueryable<TSource> FromSql<TSource>(string sql, params object[] parameters) where TSource : class;
    
            /// <summary>get single or default TSource</summary>
            /// <typeparam name="TSource">entity</typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            TSource Single<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class;
    
            /// <summary>get first or default TSource</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            TSource First<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class;
    
            /// <summary>select entity by conditions</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            IQueryable<TSource> Where<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class;
    
            /// <summary>counting the entity's count under this condition</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            int Count<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class;
    
            /// <summary>return the query</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <returns></returns>
            IQueryable<TSource> Query<TSource>() where TSource : class;
    
            /// <summary>check the condition</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            bool Exists<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class;
    
            /// <summary>paging the query</summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="query"></param>
            /// <param name="pageIndex">page index</param>
            /// <param name="pageSize">page size </param>
            /// <param name="count">total row record count</param>
            /// <returns></returns>
            IQueryable<T> Pages<T>(IQueryable<T> query, int pageIndex, int pageSize, out int count) where T : class;
    
            /// <summary>paging the query</summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="pageIndex">page index</param>
            /// <param name="pageSize">page size </param>
            /// <param name="count">total row record count</param>
            /// <returns></returns>
            IQueryable<T> Pages<T>(int pageIndex, int pageSize, out int count) where T : class;
    
            /// <summary>
            /// 分页
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="query"></param>
            /// <param name="pageIndex"></param>
            /// <param name="pageSize"></param>
            /// <param name="count">总条数</param>
            /// <param name="pageCount">页数</param>
            /// <returns></returns>
            IQueryable<T> Pages<T>(IQueryable<T> query, int pageIndex, int pageSize, out int count, out int pageCount) where T : class;
            /// <summary>save all the changes add, update, delete</summary>
            void Save();
    
            /// <summary>add entity to context or database</summary>
            /// <param name="entity"></param>
            /// <param name="save">save the add and all changes before this to database</param>
            void Add(object entity, bool save = false);
    
            /// <summary>update entity to context or database</summary>
            /// <param name="entity"></param>
            /// <param name="save">save the update and all changes before this to database</param>
            void Update(object entity, bool save = false);
    
            /// <summary>update entitys to context or database</summary>
            /// <param name="list"></param>
            /// <param name="save">save the updates and all changes before this to database</param>
            void Update(IEnumerable<object> list, bool save = false);
    
            /// <summary>delete entity from context or database</summary>
            /// <param name="entity"></param>
            /// <param name="save">save the delete and all changes before this to database</param>
            void Delete(object entity, bool save = false);
    
            /// <summary>delete entitys from context or database</summary>
            /// <param name="list"></param>
            /// <param name="save">save the deletes and all changes before this to database</param>
            void Delete(IEnumerable<object> list, bool save = false);
        }

      在Infrastructure里创建Repositorys,DbRepository类实现了IDbRepository,封装泛型仓储 依赖接口 DbContext约束

      

      

    /// <summary>
        /// 封装泛型仓储 依赖接口 DbContext约束
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        public class DbRepository<TContext> : IDbRepository where TContext : DbContext
        {
            private TContext _context;
    
            protected virtual TContext DataContext
            {
                get
                {
                    if ((object)this._context == null)
                        this._context = ServiceCollectionExtension.New<TContext>();
                    return this._context;
                }
            }
    
            /// <summary>
            /// get <see cref="!:TSource" /> from raw sql query
            /// the TSource must in database or <see cref="T:Microsoft.EntityFrameworkCore.DbContext" />
            /// </summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="sql"></param>
            /// <param name="parameters"></param>
            /// <returns></returns>
            public IQueryable<TSource> FromSql<TSource>(string sql, params object[] parameters) where TSource : class
            {
                return this.DataContext.Set<TSource>().FromSql<TSource>((RawSqlString)sql, parameters);
            }
    
            /// <summary>get single or default TSource</summary>
            /// <typeparam name="TSource">entity</typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            public TSource Single<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
            {
                if (predicate == null)
                    return this.DataContext.Set<TSource>().SingleOrDefault<TSource>();
                return this.DataContext.Set<TSource>().SingleOrDefault<TSource>(predicate);
            }
    
            /// <summary>get first or default TSource</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            public TSource First<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
            {
                if (predicate == null)
                    return this.DataContext.Set<TSource>().FirstOrDefault<TSource>();
                return this.DataContext.Set<TSource>().FirstOrDefault<TSource>(predicate);
            }
    
            /// <summary>select entity by conditions</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            public IQueryable<TSource> Where<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
            {
                if (predicate == null)
                    return this.DataContext.Set<TSource>().AsQueryable<TSource>();
                return this.DataContext.Set<TSource>().Where<TSource>(predicate);
            }
    
            /// <summary>counting the entity's count under this condition</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            public int Count<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
            {
                if (predicate == null)
                    return this.DataContext.Set<TSource>().Count<TSource>();
                return this.DataContext.Set<TSource>().Count<TSource>(predicate);
            }
    
            /// <summary>return the query</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <returns></returns>
            public IQueryable<TSource> Query<TSource>() where TSource : class
            {
                return (IQueryable<TSource>)this.DataContext.Set<TSource>();
            }
    
            /// <summary>check the condition</summary>
            /// <typeparam name="TSource"></typeparam>
            /// <param name="predicate"></param>
            /// <returns></returns>
            public bool Exists<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
            {
                if (predicate == null)
                    return this.DataContext.Set<TSource>().Any<TSource>();
                return this.DataContext.Set<TSource>().Any<TSource>(predicate);
            }
    
            /// <summary>paging the query</summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="query"></param>
            /// <param name="pageIndex">page index</param>
            /// <param name="pageSize">page size </param>
            /// <param name="count">total row record count</param>
            /// <returns></returns>
            public IQueryable<T> Pages<T>(IQueryable<T> query, int pageIndex, int pageSize, out int count) where T : class
            {
                if (pageIndex < 1)
                    pageIndex = 1;
                if (pageSize < 1)
                    pageSize = 10;
                count = query.Count<T>();
                query = query.Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
                return query;
            }
    
            /// <summary>paging the query</summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="pageIndex">page index</param>
            /// <param name="pageSize">page size </param>
            /// <param name="count">total row record count</param>
            /// <returns></returns>
            public IQueryable<T> Pages<T>(int pageIndex, int pageSize, out int count) where T : class
            {
                if (pageIndex < 1)
                    pageIndex = 1;
                if (pageSize < 1)
                    pageSize = 10;
                var source = this.DataContext.Set<T>().AsQueryable<T>();
                count = source.Count<T>();
                return source.Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
            }
            /// <summary>
            /// 分页
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="query"></param>
            /// <param name="pageIndex"></param>
            /// <param name="pageSize"></param>
            /// <param name="count"></param>
            /// <param name="pageCount"></param>
            /// <returns></returns>
            public IQueryable<T> Pages<T>(IQueryable<T> query, int pageIndex, int pageSize, out int count, out int pageCount) where T : class
            {
                if (pageIndex < 1)
                {
                    pageIndex = 1;
                }
                if (pageSize < 1)
                {
                    pageSize = 10;
                }
                if (pageSize > 100)
                {
                    pageSize = 100;
                }
                count = query.Count();
                pageCount = count / pageSize;
                if ((decimal)pageCount < (decimal)count / (decimal)pageSize)
                {
                    pageCount++;
                }
                query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
                return query;
            }
    
    
            /// <summary>save all the changes add, update, delete</summary>
            public void Save()
            {
                this.DataContext.SaveChanges();
            }
    
            /// <summary>add entity to context or database</summary>
            /// <param name="entity"></param>
            /// <param name="save">save the add and all changes before this to database</param>
            public void Add(object entity, bool save = false)
            {
                this.DataContext.Add(entity);
                if (!save)
                    return;
                this.Save();
            }
    
            /// <summary>update entity to context or database</summary>
            /// <param name="entity"></param>
            /// <param name="save">save the update and all changes before this to database</param>
            public void Update(object entity, bool save = false)
            {
                this.DataContext.Update(entity);
                if (!save)
                    return;
                this.Save();
            }
    
            /// <summary>update entitys to context or database</summary>
            /// <param name="list"></param>
            /// <param name="save">save the updates and all changes before this to database</param>
            public void Update(IEnumerable<object> list, bool save = false)
            {
                this.DataContext.UpdateRange(list);
                if (!save)
                    return;
                this.Save();
            }
    
            /// <summary>delete entity from context or database</summary>
            /// <param name="entity"></param>
            /// <param name="save">save the delete and all changes before this to database</param>
            public void Delete(object entity, bool save = false)
            {
                this.DataContext.Remove(entity);
                if (!save)
                    return;
                this.Save();
            }
    
            /// <summary>delete entitys from context or database</summary>
            /// <param name="list"></param>
            /// <param name="save">save the deletes and all changes before this to database</param>
            public void Delete(IEnumerable<object> list, bool save = false)
            {
                this.DataContext.RemoveRange(list);
                if (!save)
                    return;
                this.Save();
            }
        }
    View Code

      需要注意的地方我说一下

      

    public class DbRepository<TContext> : IDbRepository<TContext> where TContext : DbContext
        {
            private TContext _context;
    
            protected virtual TContext DataContext
            {
                get
                {
                    if ((object)this._context == null)
                        this._context = ServiceCollectionExtension.New<TContext>();
                    return this._context;
                }
            }
    }

      

      ServiceCollectionExtension.New<TContext>()是我写的一个服务拓展,可以创建出一个TContext类型的实体,当然我们可以把这个DbRepository放到Application
      这样Repository这块东西就只是Domain和Application通过接口之间的约束了

      3.简要说一下
    ServiceCollectionExtension里的东西

      

      这个拓展我写到了Infrastructure里,主要用来做服务注册用的,他非常重要非常重要非常重要,代码我这里分享一下。

    public static class ServiceCollectionExtension
        {
            private static IHttpContextAccessor _httpContextAccessor;
    
            private static IServiceProvider _serviceProvider;
            /// <summary>
            /// cerf weige
            /// </summary>
            private static IDataProtector Protector => ServiceProvider.GetDataProtector("AspNetCore", Array.Empty<string>());
    
    
            /// <summary>
            /// 注册常用服务
            /// </summary>
            /// <param name="service"></param>
            public static IServiceCollection AddRegisterContainer(this IServiceCollection services)
            {
                //注入httpContextAccessor
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                //注入配置文件获取服务
                services.AddSingleton<IConfigGeter, ConfigGeter>();
                return services;
            }
    
            //
            /// <summary>
            /// 创建自定义AddMvc
            /// </summary>
            /// <param name="services"></param>
            /// <param name="mvcOptions"></param>
            /// <returns></returns>
            public static IMvcBuilder AddMvcCustomer(this IServiceCollection services, Action<MvcApplicationOptions> mvcOptions = null)
            {
                ServiceCollectionDescriptorExtensions.Replace(services, ServiceDescriptor.Singleton<IFilterProvider, MvcFilterProvider>());
    
                var result= services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddJsonOptions(_mvcJsonOptions =>
                {
                    _mvcJsonOptions.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                    _mvcJsonOptions.SerializerSettings.DateFormatString = "yyyy-MM-d HH:mm";
                    _mvcJsonOptions.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
                    _mvcJsonOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    _mvcJsonOptions.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                });
    
                services.AddAuthentication(options => options.AddScheme<MvcCookieAuthenticationHandler>(TbConstant.WEBSITE_AUTHENTICATION_SCHEME, TbConstant.WEBSITE_AUTHENTICATION_SCHEME));
                
                services.BuildServiceProvider().RegisterServiceProvider();
                return result;
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="services"></param>
            /// <returns></returns>
            public static IServiceCollection AddAuthorizedFilter<T>(this IServiceCollection services) where T : class, IAuthorizationFilter
            {
                services.AddTransient<IAuthorizationFilter, T>();
                return services;
            }
            /// <summary>
            /// 创建服务提供者
            /// </summary>
            /// <param name="serviceProvider"></param>
            /// <returns></returns>
            public static IServiceProvider RegisterServiceProvider(this IServiceProvider serviceProvider)
            {
                _serviceProvider = serviceProvider ?? throw new MvcException("IServiceProvider serviceProvider canot be null");
                _httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
                return serviceProvider;
            }
    
            /// <summary>
            /// 
            /// </summary>
            public static IServiceProvider ServiceProvider
            {
                get
                {
                    if (_serviceProvider == null)
                    {
                        return _httpContextAccessor.HttpContext.RequestServices;
                    }
                    return _serviceProvider;//_httpContextAccessor.HttpContext.RequestServices;
                }
            }
    
            public static HttpContext HttpContext => _httpContextAccessor?.HttpContext;
    
    
            public static object New(Type type)
            {
                return ActivatorUtilities.CreateInstance(ServiceProvider, type, Array.Empty<object>());
            }
    
            public static T New<T>()
            {
                return ActivatorUtilities.CreateInstance<T>(ServiceProvider, Array.Empty<object>());
            }
    
            public static T Get<T>()
            {
                T val;
                try
                {
                    val = ActivatorUtilities.GetServiceOrCreateInstance<T>(ServiceProvider);
                }
                catch (Exception ex)
                {
                    try
                    {
                        val = ServiceProvider.GetService<T>();
                    }
                    catch (Exception ex2)
                    {
                        try
                        {
                            val = default(T);
                        }
                        catch (Exception ex3)
                        {
                            throw new MvcException($"ex0={ex.Message}; ex1={ex2.Message}; ex2={ex3.Message};");
                        }
                    }
                }
                if (val != null)
                {
                    return val;
                }
                return default(T);
            }
    
            public static object Get(Type type)
            {
                try
                {
                    return ActivatorUtilities.GetServiceOrCreateInstance(ServiceProvider, type);
                }
                catch
                {
                    object service = ServiceProvider.GetService(type);
                    if (service == null)
                    {
                        return null;
                    }
                    return service;
                }
            }
    
            /// <summary>
            /// base 64/256解密
            /// </summary>
            /// <param name="plaintext">密文</param>
            /// <returns></returns>
            public static string Decrypt(string plaintext)
            {
                IDataProtector protector = Protector;
                if (protector is Base256DataProtector)
                {
                    return (protector as Base256DataProtector).Unprotect(plaintext, true);
                }
                return protector.Unprotect(plaintext);
            }
    
            /// <summary>
            /// base64/256加密
            /// </summary>
            /// <param name="plaintext">明文</param>
            /// <returns></returns>
            public static string Encrypt(string plaintext)
            {
                IDataProtector protector = Protector;
                if (protector is Base256DataProtector)
                {
                    return (protector as Base256DataProtector).Protect(plaintext, true);
                }
                return protector.Protect(plaintext);
            }
    
            #endregion
    
            public static IServiceCollection AddTestIdentityServer(this IServiceCollection services)
            {
                services.AddIdentityServer()
                    .AddDeveloperSigningCredential()
                    .AddInMemoryApiResources(Auth.Config.GetApiResources())
                    .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
                    .AddInMemoryClients(Auth.Config.GetClients())
                    .AddTestUsers(Auth.Config.GetUsers());
                return services;
            }
    
            public static IServiceCollection AddTestAuthentication(this IServiceCollection services)
            {
                services.AddAuthentication("Bearer")
                    .AddIdentityServerAuthentication(options =>
                    {
                        options.Authority = ConfigLocator.Instance["ApplicationUrl"];
                        options.RequireHttpsMetadata = false;
                        options.ApiName = "banbrickcustomer";
                    });
                return services;
            }
        }
    View Code

      4.写自己具体的服务

      

      AccountService实现了接口IAccountService

      5.在StartUp里注入服务

      

      6.在控制器里使用

      

      这样就大体上从上到下,梳理了一下这个项目

    三.下期分享

      这个项目下期准备继续讲一下里面的

    • BaseController里分装的奥妙
    • 配置文件读取强类型Model
    • Redis如何更好灵活的配置

    
    


  • 相关阅读:
    编程自学网站
    SQL中Case语句用法
    SQL 综合应用(1.创建临时表,为后续查询所用) 实例_(学生,课程表,选修表)
    SQL 存储过程(学生,课程表,选修表)
    测试角度看公司流程规范对比后篇
    自动化测试技巧之图片验证
    QTP连载四:神一样的参数化方式?
    自动化测试之控件点击
    自动化测试技巧之结果验证
    自动化测试开展的条件
  • 原文地址:https://www.cnblogs.com/gdsblog/p/10001879.html
Copyright © 2011-2022 走看看