asp.net core2.1+EFCore + MVC開發留言管理項目實戰(一)


  好久沒寫隨筆了,主要是因為近一個月趕項目。近期翻了翻前程無憂,發現招聘要求使用.net core的公司越來越多,不得不感嘆一下.net 發展,有今天的局面離不開微軟粑粑的大力開源。正好自己最近也在接觸學習.net core,這里打算開兩三期記錄一下這個小demo的開發過程,后續會附錄上源代碼。

  首先介紹下項目背景,本人使用的開發工具是vs2017 社區免費版,服務器是騰訊雲低配版服務器(Ubuntu16.04  64位,個人隨便搭建個環境玩玩,低配版跑的windows很卡,只能用linux),.net core sdk是2.1.400,web服務器采用jexus5.8.2(一開始是采用nginx,由於.netcore 運行需要前台運行,並且在關閉ssh連接之后會自動斷開,因此采用jexus),數據庫采用mysql。項目實現了兩個小模塊(增刪查改),分別是分類管理和文章管理,由於是demo項目,諸位看官請勿太過計較= =||。

  首先是項目結構,項目采用EFCore Code first模式,分為實體、倉庫、Service接口、Application(service實現)和WebApp(UI)。實體層包括了實體和倉庫接口,倉庫層包括了Dbcontext和倉庫實現(簡單寫了個BaseRepository實現),Service接口層包括了業務接口以及dto,Application層是service業務接口的實現(相關的業務邏輯寫在這層)。如下圖:

    

  先看看startup

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Ye.BoardMessage.Repository;
using Ye.BoardMessage.Entity.IRepositories;
using Ye.BoardMessage.Service;
using Ye.BoardMessage.Application;
using Microsoft.AspNetCore.Authentication.Cookies;

namespace Ye.BoardMessage.WebApp
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //DbContext
            services.AddDbContext<BoardMessageDbContext>((provider, builder) =>
            {
                builder.UseMySql(Configuration.GetConnectionString("DefaultConnection"), b =>
                {
                    b.CommandTimeout(10);
                });
            });
           //服務注入
            services.AddLogging();
            services.Add(new ServiceDescriptor(typeof(DbContext), typeof(BoardMessageDbContext), ServiceLifetime.Scoped));
            services.Add(new ServiceDescriptor(typeof(ICategoryRepository), typeof(CategoryRepository), ServiceLifetime.Scoped));
            services.Add(new ServiceDescriptor(typeof(IMsgArticleRepository), typeof(MsgArticleRepository), ServiceLifetime.Scoped));
            services.Add(new ServiceDescriptor(typeof(IAppUserRepository), typeof(AppUserRepository),ServiceLifetime.Scoped));
            services.Add(new ServiceDescriptor(typeof(ICategoryService), typeof(CategoryService), ServiceLifetime.Scoped));
            services.Add(new ServiceDescriptor(typeof(IMsgArticleService), typeof(MsgArticleService), ServiceLifetime.Scoped));
            services.Add(new ServiceDescriptor(typeof(IAppUserService), typeof(AppUserService), ServiceLifetime.Scoped));

            //https://www.cnblogs.com/oorz/p/8617530.html cookie授權登錄參考
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,options =>
                {
                    options.Cookie.HttpOnly = true;
                    options.Cookie.Expiration = TimeSpan.FromMinutes(30);
                    // If the LoginPath isn't set, ASP.NET Core defaults 
                    // the path to /Account/Login.
                    options.LoginPath = "/Account/Login";
                    options.Cookie.Name = CookieAuthenticationDefaults.AuthenticationScheme;
                });
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            
            app.UseStaticFiles();
            app.UseCookiePolicy();
            
            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

  然后是DbContext以及相關的Entity和EntityMap

  1、DbContext實現

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Text;
using Ye.BoardMessage.Repository.EntityMaps;

namespace Ye.BoardMessage.Repository
{
    public class BoardMessageDbContext : DbContext
    {
        public BoardMessageDbContext() : base()
        {
        }

        public BoardMessageDbContext(DbContextOptions<BoardMessageDbContext> options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new CategoryEntityMap());
            modelBuilder.ApplyConfiguration(new MsgArticleEntityMap());
            modelBuilder.ApplyConfiguration(new AppUserEntityMap());
            base.OnModelCreating(modelBuilder);
        }
    }
}

  2、Entity,這里因為Entity比較多,因此只選取一個來做介紹,這個是留言的實體

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace Ye.BoardMessage.Entity
{
    public class MsgArticleEntity
    {
        public int Id { get; set; }

        public string Title { get; set; }

        public string Author { get; set; }

        public DateTime CreatedTime { get; set; }

        public string MsgContent { get; set; }

        public int CategoryId { get; set; }
        
        public CategoryEntity Category { get; set; }
    }
}

  3、EntityMap,同樣因為Map比較多,只選取一個來做介紹,留言實體映射

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using Ye.BoardMessage.Entity;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Ye.BoardMessage.Repository.EntityMaps
{
    public class MsgArticleEntityMap : IEntityTypeConfiguration<MsgArticleEntity>
    {
        public void Configure(EntityTypeBuilder<MsgArticleEntity> builder)
        {
            builder.ToTable("messagearticle");
            builder.HasKey(t => t.Id);
            builder.Property(t => t.Id).HasColumnName("Id");
            builder.Property(t => t.Author).HasColumnName("Author").IsRequired().HasMaxLength(30);
            builder.Property(t => t.CategoryId).HasColumnName("CategoryId").IsRequired();
            builder.Property(t => t.CreatedTime).HasColumnName("CreatedTime").IsRequired();
            builder.Property(t => t.MsgContent).HasColumnName("MsgContent").IsRequired().HasMaxLength(500);
            
            builder.HasOne<CategoryEntity>(t => t.Category)
                .WithMany(p => p.Articles).HasForeignKey(p => p.CategoryId).IsRequired();
        }
    }
}

  總的來說,EFCore相比EntityFramework,API方面略有改變,大體用法還是一致的,另外asp.net core自帶了服務注入,這個非常方便。EFCore一對多的配置有所改變,這里踩了個小坑的,參閱了網上不少資料才填完(感謝發達的網絡- -b)。這個系列的第一篇介紹完畢,下一篇將介紹使用cookie登錄驗證以及BaseRepository。代碼后續會貼出來,各位看官莫急。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM