zoukankan      html  css  js  c++  java
  • angular4和asp.net core 2 web api

    angular4和asp.net core 2 web api

    这是一篇学习笔记. angular 5 正式版都快出了, 不过主要是性能升级.

    我认为angular 4还是很适合企业的, 就像.net一样.

    我用的是windows 10

    安装工具:

    git for windows: 官网很慢, 所以找一个镜像站下载: https://github.com/waylau/git-for-win, 淘宝镜像的速度还是蛮快的:

    安装的时候, 建议选择这个, 会添加很多命令行工具: 

    nodejs: 去官网下载就行: https://nodejs.org/en/

    正常安装即可. npm的版本不要低于5.0吧:

    angular-cli, 官网: https://github.com/angular/angular-cli

    npm install -g @angular/cli

    visual studio codehttps://code.visualstudio.com/

    and visual studio 2017 of course.

    建立angular项目

    进入命令行在某个地方执行命令:

    ng new client-panel

    这就会建立一个client-panel文件夹, 里面是该项目的文件, 然后它会立即执行npm install命令(这里不要使用淘宝的cnpm进行安装, 有bug), 稍等一会就会结束.

    使用vscode打开该目录, 然后在vscode里面打开terminal:

    terminal默认的可能是powershell, 如果你感觉powershell有点慢的话, 可以换成bash(安装git时候带的)或者windows command line等.

    第一次打开terminal的时候, vscode上方会提示你配置terminal, 这时就可以更换默认的terminal. 否则的话, 你可以点击菜单file-reference-settings, 自己选择一个terminal应用:

    同样可以安装几个vscode的插件:

    然后试运行一下项目, 在terminal执行 ng serve, 如果没问题的话, 大概是这样: 

    浏览器运行: http://localhost:4200

    安装bootstrap4等:

    安装bootstrap4, tether, jquery等:

    npm install bootstrap@4.0.0-beta.2 tether jquery --save

    安装成功后, 打开 .angular-cli.json, 把相关的css和js添加进去:

    然后在运行试试 ng serve, 刷新:

    字体已经改变, bootstrap起作用了.

    建立Components

    建立dashboard:

    terminal执行

    ng g component components/dashboard

    执行成功后会生成4个文件:

    并且会自动在app.module.ts里面声明:

    建立其他 components:

    复制代码
    ng g component components/clients
    ng g component components/clientDetails
    ng g component components/addClient
    ng g component components/editClient
    ng g component components/navbar
    ng g component components/sidebar
    ng g component components/login
    ng g component components/register
    ng g component components/settings
    ng g component components/pageNotFound
    复制代码

    建立Route路由

    复制代码
    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    
    import { AppComponent } from './app.component';
    import { DashboardComponent } from './components/dashboard/dashboard.component';
    import { ClientsComponent } from './components/clients/clients.component';
    import { ClientDetailsComponent } from './components/client-details/client-details.component';
    import { AddClientComponent } from './components/add-client/add-client.component';
    import { EditClientComponent } from './components/edit-client/edit-client.component';
    import { NavbarComponent } from './components/navbar/navbar.component';
    import { SidebarComponent } from './components/sidebar/sidebar.component';
    import { LoginComponent } from './components/login/login.component';
    import { RegisterComponent } from './components/register/register.component';
    import { SettingsComponent } from './components/settings/settings.component';
    import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
    
    const appRoutes: Routes = [
      { path: '', component: DashboardComponent },
      { path: 'register', component: RegisterComponent },
      { path: 'login', component: LoginComponent }
    ];
    
    @NgModule({
      declarations: [
        AppComponent,
        DashboardComponent,
        ClientsComponent,
        ClientDetailsComponent,
        AddClientComponent,
        EditClientComponent,
        NavbarComponent,
        SidebarComponent,
        LoginComponent,
        RegisterComponent,
        SettingsComponent,
        PageNotFoundComponent
      ],
      imports: [
        BrowserModule,
        RouterModule.forRoot(appRoutes)
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    复制代码

    添加router-outlet:

    打开app.component.html, 清空内容, 添加一个div(可以输入div.container然后按tab健):

    <div class="container">
      <router-outlet></router-outlet>
    </div>

    现在刷新浏览器, 大约这样:

    添加navbar:

    修改navbar.component.html:

    复制代码
    <nav class="navbar navbar-expand-md navbar-light bg-light">
      <div class="container">
        <a class="navbar-brand" href="#">Client Panel</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault"
          aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
    
        <div class="collapse navbar-collapse" id="navbarsExampleDefault">
          <ul class="navbar-nav mr-auto">
            <li class="nav-item">
              <a class="nav-link" href="#" routerLink="/">Dashboard </a>
            </li>
          </ul>
          <ul class="navbar-nav ml-auto">
            <li class="nav-item">
              <a class="nav-link" href="#" routerLink="/register">Register </a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#" routerLink="/login">Login </a>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    复制代码

    修改app.component.html:

    <app-navbar></app-navbar>
    <div class="container">
      <router-outlet></router-outlet>
    </div>

    运行:

    建立Service

    建立一个client.service:

    ng g service services/client

    然后在app.module.ts添加引用:

    // Services Imports
    import { ClientService } from "./services/client.service";

    并添加在providers里:

      providers: [
        ClientService
      ],

    前端先暂时到这, 现在开始搞后端 web api.

    建立asp.net core 2.0 的 Web api项目

    web api项目源码: https://github.com/solenovex/asp.net-core-2.0-web-api-boilerplate

    项目列表如图:

    AspNetIdentityAuthorizationServer是一个单独的authorization server, 这里暂时还没用到, 它的端口是5000, 默认不启动.

    CoreApi.Infrastructure 里面有一些基类和接口, 还放了一个公共的工具类等.

    CoreApi.Models就是 models/entities

    CoreApi.DataContext 里面就是DbContext相关的

    CoreApi.Repositories 里面是Repositories

    CoreApi.Services 里面就是各种services

    CoreApi.ViewModels 里面就是各种ViewModels或者叫Dtos

    CoreApi.Web是web启动项目.

    SharedSettings是横跨authorization server和 web api的一些公共设置.

    上面说的这些都没什么用, 下面开始建立Client的api.

    建立Client Model(或者叫Entity)

    在CoreApi.Models建立文件夹Angular, 然后建立Client.cs:

    复制代码
    using CoreApi.Infrastructure.Features.Common;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Metadata.Builders;
    
    namespace CoreApi.Models.Angular
    {
        public class Client : EntityBase
        {
            public decimal Balance { get; set; }
            public string Email { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Phone { get; set; }
        }
    
        public class ClientConfiguration : EntityBaseConfiguration<Client>
        {
            public override void ConfigureDerived(EntityTypeBuilder<Client> builder)
            {
                builder.Property(x => x.Balance).HasColumnType("decimal(18,2)");
                builder.Property(x => x.Email).IsRequired().HasMaxLength(100);
                builder.Property(x => x.FirstName).IsRequired().HasMaxLength(50);
                builder.Property(x => x.LastName).IsRequired().HasMaxLength(50);
                builder.Property(x => x.Phone).HasMaxLength(50);
            }
        }
    }
    复制代码

    其中父类EntityBase里面含有一些通用属性,Id, CreateUser, UpdateUser, CreateTime, UpdateTime, LastAction, 这些是我公司做项目必须的, 你们随意.

    下面ClientConfiguration是针对Client的fluent api配置类. 他的父类EntityBaseConfiguration实现了EF的IEntityTypeConfiguration接口, 并在父类里面针对EntityBase那些属性使用fluent api做了限制:

    复制代码
    namespace CoreApi.Infrastructure.Features.Common
    {
        public abstract class EntityBaseConfiguration<T> : IEntityTypeConfiguration<T> where T : EntityBase
        {
            public virtual void Configure(EntityTypeBuilder<T> builder)
            {
                builder.HasKey(e => e.Id);
                builder.Property(x => x.CreateTime).IsRequired();
                builder.Property(x => x.UpdateTime).IsRequired();
                builder.Property(x => x.CreateUser).IsRequired().HasMaxLength(50);
                builder.Property(x => x.UpdateUser).IsRequired().HasMaxLength(50);
                builder.Property(x => x.LastAction).IsRequired().HasMaxLength(50);
    
                ConfigureDerived(builder);
            }
    
            public abstract void ConfigureDerived(EntityTypeBuilder<T> b);
        }
    }
    复制代码

    弄完Model和它的配置之后, 就添加到DbContext里面. 打开CoreApi.DataContext的CoreContext, 添加Model和配置:

    复制代码
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.HasDefaultSchema(AppSettings.DefaultSchema);
    
                modelBuilder.ApplyConfiguration(new UploadedFileConfiguration());
                modelBuilder.ApplyConfiguration(new ClientConfiguration());
            }
    复制代码
            public DbSet<UploadedFile> UploadedFiles { get; set; }
            public DbSet<Client> Clients { get; set; }

    然后建立ClientRepository

    在CoreApi.Repositories里面建立Angular目录, 建立ClientRepository.cs:

    复制代码
    namespace CoreApi.Repositories.Angular
    {
        public interface IClientRepository : IEntityBaseRepository<Client> { }
    
        public class ClientRepository : EntityBaseRepository<Client>, IClientRepository
        {
            public ClientRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
            {
            }
        }
    }
    复制代码

    图省事, 我把repository和它的interface放在一个文件了.

    IEntityBaseRepository<T>定义了一些常用的方法:

    复制代码
    namespace CoreApi.DataContext.Infrastructure
    {
        public interface IEntityBaseRepository<T> where T : class, IEntityBase, new()
        {
            IQueryable<T> All { get; }
            IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties);
    
            int Count();
            Task<int> CountAsync();
            T GetSingle(int id);
            Task<T> GetSingleAsync(int id);
            T GetSingle(Expression<Func<T, bool>> predicate);
            Task<T> GetSingleAsync(Expression<Func<T, bool>> predicate);
            T GetSingle(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties);
            Task<T> GetSingleAsync(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties);
            IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
            void Add(T entity);
            void Update(T entity);
            void Delete(T entity);
            void DeleteWhere(Expression<Func<T, bool>> predicate);
            void AddRange(IEnumerable<T> entities);
            void DeleteRange(IEnumerable<T> entities);
            void Attach(T entity);
            void AttachRange(IEnumerable<T> entities);
            void Detach(T entity);
            void DetachRange(IEnumerable<T> entities);
            void AttachAsModified(T entity);
        }
    }
    复制代码

    EntityBaseRepository<T>是它的实现:

    复制代码
    namespace CoreApi.DataContext.Infrastructure
    {
        public class EntityBaseRepository<T> : IEntityBaseRepository<T>
            where T : class, IEntityBase, new()
        {
            #region Properties
            protected CoreContext Context { get; }
    
            public EntityBaseRepository(IUnitOfWork unitOfWork)
            {
                Context = unitOfWork as CoreContext;
            }
            #endregion
    
            public virtual IQueryable<T> All => Context.Set<T>();
    
            public virtual IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties)
            {
                IQueryable<T> query = Context.Set<T>();
                foreach (var includeProperty in includeProperties)
                {
                    query = query.Include(includeProperty);
                }
                return query;
            }
    
            public virtual int Count()
            {
                return Context.Set<T>().Count();
            }
    
            public async Task<int> CountAsync()
            {
                return await Context.Set<T>().CountAsync();
            }
    
            public T GetSingle(int id)
            {
                return Context.Set<T>().FirstOrDefault(x => x.Id == id);
            }
    
            public async Task<T> GetSingleAsync(int id)
            {
                return await Context.Set<T>().FirstOrDefaultAsync(x => x.Id == id);
            }
    
            public T GetSingle(Expression<Func<T, bool>> predicate)
            {
                return Context.Set<T>().FirstOrDefault(predicate);
            }
    
            public async Task<T> GetSingleAsync(Expression<Func<T, bool>> predicate)
            {
                return await Context.Set<T>().FirstOrDefaultAsync(predicate);
            }
    
            public T GetSingle(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties)
            {
                IQueryable<T> query = Context.Set<T>();
                foreach (var includeProperty in includeProperties)
                {
                    query = query.Include(includeProperty);
                }
                return query.Where(predicate).FirstOrDefault();
            }
    
            public async Task<T> GetSingleAsync(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties)
            {
                IQueryable<T> query = Context.Set<T>();
                foreach (var includeProperty in includeProperties)
                {
                    query = query.Include(includeProperty);
                }
    
                return await query.Where(predicate).FirstOrDefaultAsync();
            }
    
            public virtual IQueryable<T> FindBy(Expression<Func<T, bool>> predicate)
            {
                return Context.Set<T>().Where(predicate);
            }
    
            public virtual void Add(T entity)
            {
                Context.Set<T>().Add(entity);
            }
    
            public virtual void Update(T entity)
            {
                EntityEntry<T> dbEntityEntry = Context.Entry(entity);
                dbEntityEntry.State = EntityState.Modified;
    
                dbEntityEntry.Property(x => x.Id).IsModified = false;
                dbEntityEntry.Property(x => x.CreateUser).IsModified = false;
                dbEntityEntry.Property(x => x.CreateTime).IsModified = false;
            }
    
            public virtual void Delete(T entity)
            {
                Context.Set<T>().Remove(entity);
            }
    
            public virtual void AddRange(IEnumerable<T> entities)
            {
                Context.Set<T>().AddRange(entities);
            }
    
            public virtual void DeleteRange(IEnumerable<T> entities)
            {
                foreach (var entity in entities)
                {
                    Context.Set<T>().Remove(entity);
                }
            }
    
            public virtual void DeleteWhere(Expression<Func<T, bool>> predicate)
            {
                IEnumerable<T> entities = Context.Set<T>().Where(predicate);
    
                foreach (var entity in entities)
                {
                    Context.Entry<T>(entity).State = EntityState.Deleted;
                }
            }
            public void Attach(T entity)
            {
                Context.Set<T>().Attach(entity);
            }
    
            public void AttachRange(IEnumerable<T> entities)
            {
                foreach (var entity in entities)
                {
                    Attach(entity);
                }
            }
    
            public void Detach(T entity)
            {
                Context.Entry<T>(entity).State = EntityState.Detached;
            }
    
            public void DetachRange(IEnumerable<T> entities)
            {
                foreach (var entity in entities)
                {
                    Detach(entity);
                }
            }
    
            public void AttachAsModified(T entity)
            {
                Attach(entity);
                Update(entity);
            }
            
        }
    }
    复制代码

    建立Client的ViewModels

    在CoreApi.ViewModels建立Angular文件夹, 分别针对查询, 新增, 修改建立3个ViewModel(Dto):

    ClientViewModel:

    复制代码
    namespace CoreApi.ViewModels.Angular
    {
        public class ClientViewModel : EntityBase
        {
            public decimal Balance { get; set; }
            public string Email { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Phone { get; set; }
        }
    }
    复制代码

    ClientCreationViewModel:

    复制代码
    namespace CoreApi.ViewModels.Angular
    {
        public class ClientCreationViewModel
        {
            public decimal Balance { get; set; }
            
            [Required]
            [MaxLength(100)]
            public string Email { get; set; }
            
            [Required]
            [MaxLength(50)]
            public string FirstName { get; set; }
            
            [Required]
            [MaxLength(50)]
            public string LastName { get; set; }
    
            [Required]
            [MaxLength(50)]
            public string Phone { get; set; }
        }
    }
    复制代码

    ClientModificationViewModel:

    复制代码
    namespace CoreApi.ViewModels.Angular
    {
        public class ClientModificationViewModel
        {
            public decimal Balance { get; set; }
    
            [Required]
            [MaxLength(100)]
            public string Email { get; set; }
    
            [Required]
            [MaxLength(50)]
            public string FirstName { get; set; }
    
            [Required]
            [MaxLength(50)]
            public string LastName { get; set; }
    
            [Required]
            [MaxLength(50)]
            public string Phone { get; set; }
        }
    }
    复制代码

    配置AutoMapper

    针对Client和它的Viewmodels, 分别从两个方向进行配置:

    DomainToViewModelMappingProfile:

    复制代码
    namespace CoreApi.Web.MyConfigurations
    {
        public class DomainToViewModelMappingProfile : Profile
        {
            public override string ProfileName => "DomainToViewModelMappings";
    
            public DomainToViewModelMappingProfile()
            {
                CreateMap<UploadedFile, UploadedFileViewModel>();
                CreateMap<Client, ClientViewModel>();
                CreateMap<Client, ClientModificationViewModel>();
            }
        }
    }
    复制代码

    ViewModelToDomainMappingProfile:

    复制代码
    namespace CoreApi.Web.MyConfigurations
    {
        public class ViewModelToDomainMappingProfile : Profile
        {
            public override string ProfileName => "ViewModelToDomainMappings";
    
            public ViewModelToDomainMappingProfile()
            {
                CreateMap<UploadedFileViewModel, UploadedFile>();
                CreateMap<ClientViewModel, Client>();
                CreateMap<ClientCreationViewModel, Client>();
                CreateMap<ClientModificationViewModel, Client>();
            }
        }
    }
    复制代码

    注册Repository的DI:

    在web项目的StartUp.cs的ConfigureServices里面为ClientRepository注册DI:

    services.AddScoped<IClientRepository, ClientRepository>();

    建立Controller

    在controllers目录建立Angular/ClientController.cs:

    复制代码
    namespace CoreApi.Web.Controllers.Angular
    {
        [Route("api/[controller]")]
        public class ClientController : BaseController<ClientController>
        {
            private readonly IClientRepository _clientRepository;
            public ClientController(ICoreService<ClientController> coreService,
                IClientRepository clientRepository) : base(coreService)
            {
                _clientRepository = clientRepository;
            }
    
            [HttpGet]
            public async Task<IActionResult> GetAll()
            {
                var items = await _clientRepository.All.ToListAsync();
                var results = Mapper.Map<IEnumerable<ClientViewModel>>(items);
                return Ok(results);
            }
    
            [HttpGet]
            [Route("{id}", Name = "GetClient")]
            public async Task<IActionResult> Get(int id)
            {
                var item = await _clientRepository.GetSingleAsync(id);
                if (item == null)
                {
                    return NotFound();
                }
                var result = Mapper.Map<ClientViewModel>(item);
                return Ok(result);
            }
    
            [HttpPost]
            public async Task<IActionResult> Post([FromBody] ClientCreationViewModel clientVm)
            {
                if (clientVm == null)
                {
                    return BadRequest();
                }
    
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                var newItem = Mapper.Map<Client>(clientVm);
                newItem.SetCreation(UserName);
                _clientRepository.Add(newItem);
                if (!await UnitOfWork.SaveAsync())
                {
                    return StatusCode(500, "保存客户时出错");
                }
    
                var vm = Mapper.Map<ClientViewModel>(newItem);
    
                return CreatedAtRoute("GetClient", new { id = vm.Id }, vm);
            }
    
            [HttpPut("{id}")]
            public async Task<IActionResult> Put(int id, [FromBody] ClientModificationViewModel clientVm)
            {
                if (clientVm == null)
                {
                    return BadRequest();
                }
    
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
                var dbItem = await _clientRepository.GetSingleAsync(id);
                if (dbItem == null)
                {
                    return NotFound();
                }
                Mapper.Map(clientVm, dbItem);
                dbItem.SetModification(UserName);
                _clientRepository.Update(dbItem);
                if (!await UnitOfWork.SaveAsync())
                {
                    return StatusCode(500, "保存客户时出错");
                }
    
                return NoContent();
            }
    
            [HttpPatch("{id}")]
            public async Task<IActionResult> Patch(int id, [FromBody] JsonPatchDocument<ClientModificationViewModel> patchDoc)
            {
                if (patchDoc == null)
                {
                    return BadRequest();
                }
                var dbItem = await _clientRepository.GetSingleAsync(id);
                if (dbItem == null)
                {
                    return NotFound();
                }
                var toPatchVm = Mapper.Map<ClientModificationViewModel>(dbItem);
                patchDoc.ApplyTo(toPatchVm, ModelState);
    
                TryValidateModel(toPatchVm);
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                Mapper.Map(toPatchVm, dbItem);
    
                if (!await UnitOfWork.SaveAsync())
                {
                    return StatusCode(500, "更新的时候出错");
                }
    
                return NoContent();
            }
    
            [HttpDelete("{id}")]
            public async Task<IActionResult> Delete(int id)
            {
                var model = await _clientRepository.GetSingleAsync(id);
                if (model == null)
                {
                    return NotFound();
                }
                _clientRepository.Delete(model);
                if (!await UnitOfWork.SaveAsync())
                {
                    return StatusCode(500, "删除的时候出错");
                }
                return NoContent();
            }
        }
    }
    复制代码

    首先, Controller继承了ControllerBase这个类, ControllerBase是自己写的类, 里面可以放置一些公用的方法或属性, 目前里面的东西都没用:

    复制代码
    namespace CoreApi.Web.Controllers.Bases
    {
        public abstract class BaseController<T> : Controller
        {
            protected readonly IUnitOfWork UnitOfWork;
            protected readonly ILogger<T> Logger;
            protected readonly IFileProvider FileProvider;
            protected readonly ICoreService<T> CoreService;
    
            protected BaseController(ICoreService<T> coreService)
            {
                CoreService = coreService;
                UnitOfWork = coreService.UnitOfWork;
                Logger = coreService.Logger;
                FileProvider = coreService.FileProvider;
            }
    
            #region Current Information
    
            protected DateTime Now => DateTime.Now;
            protected string UserName => User.Identity.Name ?? "Anonymous";
    
            #endregion
    
        }
    }
    复制代码

    由于父类构造函数依赖的类太多了, 所以我建立了一个CoreService, 里面包含着这些依赖, 然后用一个变量就注入进去了, 这种写法不一定正确:

    复制代码
    public interface ICoreService<out T> : IDisposable
        {
            IUnitOfWork UnitOfWork { get; }
            ILogger<T> Logger { get; }
            IFileProvider FileProvider { get; }
        }
    复制代码

    Controller里面的方法应该都能看明白吧. 需要提一下的是UnitOfWork. 

    Unit Of Work

    我才用的是UnitOfWork和Repository模式, 多个Repository挂起的数据库操作, 可以使用一个UnitOfWork一次性提交.

    由于DBContext已经实现了UnitOfWork模式, 所以可以直接在Controller里面使用DbContext, 但是我还是做了一个接口 IUnitOfWork:

    复制代码
    namespace CoreApi.DataContext.Infrastructure
    {
        public interface IUnitOfWork: IDisposable
        {
            int SaveChanges();
            int SaveChanges(bool acceptAllChangesOnSuccess);
            Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken));
            Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
    
            bool Save();
            bool Save(bool acceptAllChangesOnSuccess);
            Task<bool> SaveAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken));
            Task<bool> SaveAsync(CancellationToken cancellationToken = default(CancellationToken));
        }
    }
    复制代码

    里面前4个方法就是DbContext内置的方法, 后面4个方法可有可无, 就是上面4个方法的简单变形.

    看一下CoreContext:

    复制代码
    namespace CoreApi.DataContext.Core
    {
        public class CoreContext : DbContext, IUnitOfWork
        {
            public CoreContext(DbContextOptions<CoreContext> options)
                : base(options)
            {
            }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.HasDefaultSchema(AppSettings.DefaultSchema);
    
                modelBuilder.ApplyConfiguration(new UploadedFileConfiguration());
                modelBuilder.ApplyConfiguration(new ClientConfiguration());
            }
    
            public DbSet<UploadedFile> UploadedFiles { get; set; }
            public DbSet<Client> Clients { get; set; }
    
            public bool Save()
            {
                return SaveChanges() >= 0;
            }
    
            public bool Save(bool acceptAllChangesOnSuccess)
            {
                return SaveChanges(acceptAllChangesOnSuccess) >= 0;
            }
    
            public async Task<bool> SaveAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
            {
                return await SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken) >= 0;
            }
    
            public async Task<bool> SaveAsync(CancellationToken cancellationToken = default(CancellationToken))
            {
                return await SaveChangesAsync(cancellationToken) >= 0;
            }
        }
    }
    复制代码

    差不多了, 开始

    迁移数据库

    在Package Manager Console分别执行 Add-Migration XXX和 Update-database命令.

    注意这个时候 解决方案的启动项目必须是Web项目, 如果设置了多个启动项目, 迁移命令会不太好用.

    然后运行一下: 选择CoreApi.Web而不是IISExpress, 这样的话端口应该是 http://localhost:5001/api/values

    到Swagger里简单测试下

    然后进入swagger简单测试一下ClientController: http://localhost:5001/swagger/

    先添加数据 POST:

    先点击右侧, 然后会把数据的json模板复制到左边的框里, 然后修改值, 然后点击try It out, 结果如下:

    然后两个Get, Delete, Put您都应该会测试.

    这里试一下 Patch:

    再查询一下, 应该没有什么问题.

    先写到这, 明天就能差不多写完了吧.

  • 相关阅读:
    微信红包限额提升方法
    微信从业人员推荐阅读的100本经典图书
    微信裂变红包
    微信公众平台开发最佳实践(第2版)
    微信公众平台开发(108) 微信摇一摇
    微信支付样例
    微信行业解决方案
    牛逼顿
    微信支付开发(4) 扫码支付模式二
    微信公众平台开发(107) 分享到朋友圈和发送给好友
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/7764883.html
Copyright © 2011-2022 走看看