适用Zero版本:ASP.NET Core & Angular 2+ (aspnet-zero-core-3.1.0)。

该版本官方有两个solution文件夹:Angular(前端) 和 aspnet-core(后台服务)。

在开始以下步骤之前需要能够成功发布程序,对于后台服务只要能运行即可,如有报错可根据提示安装需要的插件。Angular 则比较麻烦,装的东西较多,官方建议用yarn,这个要下载,顺藤摸瓜都安装完即可。

我没有改解决方案名称,仍用的默认solution的名称MyCompanyName.AbpZeroTemplate,所以下面有的文件名跟官网的phonebook示例文档有区别。

修改1版将aspnet-core后台服务project和Angular前端project的步骤分类,这样不需要跳跃性的操作,阅读操作效率更高。本文仅谈实操,不详细解释理论性的东西,因为本文观点认为,实操没问题了,初学者的信心就有了,理解仅仅是时间问题。

一、aspnet-core后台Project步骤如下:

1、 src/***.core/***CoreModule.cs文件中临时禁用多租户。

[DependsOn(typeof(AbpZeroCoreModule))]
public class PhoneBookCoreModule : AbpModule
{
public override void PreInitialize()
{
//some other code... //Enable this line to create a multi-tenant application.
Configuration.MultiTenancy.IsEnabled = false; //some other code...
}
}

2、src/***.core/Localization/AbpZeroTemplate/AbpZeroTemplate.xml (默认的英文字体)中加入代码。如有对应中文,可在对应的中文文件中加入中文名称。其他语言中没加的都默认用英文的。

<text name="PhoneBook">Phone Book</text> 

3、创建实体类person。在.Core内新建文件夹People,然后在People文件夹内新建如下Person.cs类。

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Abp.Domain.Entities.Auditing; namespace Acme.PhoneBook.People
{
[Table("PbPersons")]
public class Person : FullAuditedEntity
{
public const int MaxNameLength = 32;
public const int MaxSurnameLength = 32;
public const int MaxEmailAddressLength = 255; [Required]
[MaxLength(MaxNameLength)]
public virtual string Name { get; set; } [Required]
[MaxLength(MaxSurnameLength)]
public virtual string Surname { get; set; } [MaxLength(MaxEmailAddressLength)]
public virtual string EmailAddress { get; set; }
}
}

4、在.EntityFramework内的****DbContext.cs文件增加如下黄色标记代码。

public class ******DbContext : AbpZeroDbContext<Tenant, Role, User>
{
public virtual IDbSet<Person> Persons { get; set; } //...other code
}

5、用EntityFramework的code first迁移功能更新数据库创建PdPersons表。

在windows command prompt 命令行工具定位到.EntityFramework文件夹。输入:“dotnet ef migrations add "Added_Persons_Table”并回车。

这会在Migrations文件夹中增加一个***Added_Persons_Table.cs类。然后在命令行中输入:“dotnet ef database update”命令,即可在数据库中生成新表。

我在执行这步的时候报错了。提示C:\Program Files\dotnet\shared\Microsoft.NETCore.App 目录里没有1.1.0版本的。原来是我没安装command line版的

.net core 1.1 sdk.官网直接下载即可下载地址:https://www.microsoft.com/net/core#windowscmd 。安装好即可成功更新数据库。

6、为新创建的PdPersons表造点初始数据。

在.EntityFramework空间内的Migrations/seed/host 内新建InitialPeopleCreator.cs类

类代码:

using System.Linq;
using Acme.PhoneBook.EntityFramework;
using Acme.PhoneBook.People; namespace Acme.PhoneBook.Migrations.Seed.Host
{
public class InitialPeopleCreator
{
private readonly PhoneBookDbContext _context; public InitialPeopleCreator(PhoneBookDbContext context)
{
_context = context;
} public void Create()
{
var douglas = _context.Persons.FirstOrDefault(p => p.EmailAddress == "douglas.adams@fortytwo.com");
if (douglas == null)
{
_context.Persons.Add(
new Person
{
Name = "Douglas",
Surname = "Adams",
EmailAddress = "douglas.adams@fortytwo.com"
});
} var asimov = _context.Persons.FirstOrDefault(p => p.EmailAddress == "isaac.asimov@foundation.org");
if (asimov == null)
{
_context.Persons.Add(
new Person
{
Name = "Isaac",
Surname = "Asimov",
EmailAddress = "isaac.asimov@foundation.org"
});
}
}
}
}  

7、在.EntityFramework空间内的Migrations/seed/host 内的InitialHostDbBuilder.cs类里新增如下黄色标记代码。

public class InitialHostDbBuilder
{
//existing codes... public void Create()
{
//existing code...
new InitialPeopleCreator(_context).Create(); _context.SaveChanges();
}
}

然后在命令行中执行代码:“dotnet ef database update ” 即可。查看PdPersons表里已有数据。

8、创建person应用程序服务-----------新建一个接口类。

应用程序服务对应.Application空间,在MyCompanyName.AbpZeroTemplate.Application下面建立文件夹People。

然后在People文件夹中新建IPersonAppService.cs接口类.代码如下:

using Abp.Application.Services;
using Abp.Application.Services.Dto; namespace Acme.PhoneBook.People
{
public interface IPersonAppService : IApplicationService
{
ListResultDto<PersonListDto> GetPeople(GetPeopleInput input);
}
}

9、在People文件夹下面再建立一个文件夹Dto,然后在此新建PersonListDto.cs文件。代码如下:

using Abp.Application.Services.Dto;
using Abp.AutoMapper; namespace MyCompanyName.AbpZeroTemplate.People.Dto
{
[AutoMapFrom(typeof(Person))]
public class PersonListDto : FullAuditedEntityDto
{
public string Name { get; set; } public string Surname { get; set; } public string EmailAddress { get; set; } } public class GetPeopleInput
{
public string Filter { get; set; }
} }

10、在Pepole文件夹下再建立一个PersonAppService.cs文件。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using MyCompanyName.AbpZeroTemplate.People.Dto; namespace MyCompanyName.AbpZeroTemplate.People
{
public class PersonAppService:AbpZeroTemplateAppServiceBase,IPersonAppService
{
private readonly IRepository<Person> _personRepository; public PersonAppService(IRepository<Person> personRepository)
{
_personRepository = personRepository;
} public async Task CreatePerson(CreatePersonInput input)
{
var person = input.MapTo<Person>();
await _personRepository.InsertAsync(person);
} public ListResultDto<PersonListDto> GetPeople(GetPeopleInput input)
{
var persons = _personRepository
.GetAll()
.WhereIf(
!input.Filter.IsNullOrEmpty(),
p => p.Name.Contains(input.Filter) ||
p.Surname.Contains(input.Filter) ||
p.EmailAddress.Contains(input.Filter)
)
.OrderBy(p => p.Name)
.ThenBy(p => p.Surname)
.ToList(); return new ListResultDto<PersonListDto>(persons.MapTo<List<PersonListDto>>());
}
} }

11、增加Person。

首先再IpersonAppService.cs文件里新增如下代码:

Task CreatePerson(CreatePersonInput input);

然后在Dto文件内新增类CreatePersonInput.cs类,代码如下:

using Abp.AutoMapper;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks; namespace MyCompanyName.AbpZeroTemplate.People.Dto
{
[AutoMapTo(typeof(Person))]
public class CreatePersonInput
{
[Required]
[MaxLength(Person.MaxNameLength)]
public string Name { get; set; } [Required]
[MaxLength(Person.MaxSurnameLength)]
public string Surname { get; set; } [EmailAddress]
[MaxLength(Person.MaxEmailAddressLength)]
public string EmailAddress { get; set; }
} }

12、允许创建person对象的授权。

首先加入允许进入phonebook页的授权。在src/***.core/Authorization/AppPermissions.cs文件中加入常量定义:

public const string Pages_Tenant_PhoneBook = "Pages.Tenant.PhoneBook";

在src/MyCompanyName.AbpZeroTemplate.Application/People里的PersonAppService.cs里加入如下黄色标记代码:

[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook)]
public class PersonAppService : PhoneBookAppServiceBase, IPersonAppService
{
//...
}

在src/***.core/Authorization/AppAuthorizationProvider.cs类中定义许可,代码如下:

var phoneBook = pages.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook, L("PhoneBook"), multiTenancySides: MultiTenancySides.Tenant);
phoneBook.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson, L("CreateNewPerson"), multiTenancySides: MultiTenancySides.Tenant);

在同目录下的AppPermissions.cs文件中加入常量定义:

public const string Pages_Tenant_PhoneBook_CreatePerson = "Pages.Tenant.PhoneBook.CreatePerson";

13、增加ABP授权属性。

在src/MyCompanyName.AbpZeroTemplate.Application/People里的PersonAppService.cs文件中增加属性标记代码如下

[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson)]
public async Task CreatePerson(CreatePersonInput input)
{
//...
}

14、删除person实体对象。

在IPersonAppService.cs文件中增加代码:

Task DeletePerson(EntityDto input);

在PersonAppService.cs文件中增加代码:

[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson)]
public async Task DeletePerson(EntityDto input)
{
await _personRepository.DeleteAsync(input.Id);
}

另外提醒一下, 要跟创建person的权限设置一样在AppPermissions.cs文件中定义常量Pages_Tenant_PhoneBook_DeletePerson,

且在src/***.core/Authorization/AppAuthorizationProvider.cs类中定义许可,代码如下:

phoneBook.DeleteChildPermission(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson, L("DeletePerson"), multiTenancySides: MultiTenancySides.Tenant);

以后这类增删查改不再赘述权限功能的实现。

15、创建Phone 实体。

在src/*******.core下创建Phone.cs类代码如下

[Table("PbPhones")]
public class Phone : CreationAuditedEntity<long>
{
public const int MaxNumberLength = ; [ForeignKey("PersonId")]
public virtual Person Person { get; set; }
public virtual int PersonId { get; set; } [Required]
public virtual PhoneType Type { get; set; } [Required]
[MaxLength(MaxNumberLength)]
public virtual string Number { get; set; }
}

16、在Person.cs中增加phones字段。

[Table("PbPersons")]
public class Person : FullAuditedEntity
{
//...other properties public virtual ICollection<Phone> Phones { get; set; }
}

17、在.core下增加PhoneType.cs类

public enum PhoneType : byte
{
Mobile,
Home,
Business
}

18、在Entity Framework下的AbpZeroTemplateDbContext.cs增加代码

public virtual IDbSet<Phone> Phones { get; set; }

且用命令行命令:dotnet ef migrations add "Added_Phone"  增加数据库phone表的迁移类。

然后更新数据库,该部分类似操作在上文已有介绍,不赘述。

该部分未完成待续。。。

19、

20、

二、Angular前端Project步骤如下:

1、增加一个新的菜单项。app\shared\layout\side-bar.component.ts (展开side-bar.component.html文件)在dashboard下面加入如下代码
  new SideBarMenuItem("PhoneBook", null, "icon-notebook", "/app/main/phonebook")

2、app\main\main-routing.module.ts  文件中加路由

{ path: 'dashboard', component: DashboardComponent, data: { permission: 'Pages.Tenant.Dashboard' } },

{ path: 'phonebook', component: PhoneBookComponent }

此时phoneBookComponent报错,先忽略不管。

3、在app/main中新建一个phonebook文件夹并创建phonebook.component.ts文件,代码如下:

import { Component, Injector } from '@angular/core';
import { AppComponentBase } from '@shared/common/app-component-base';
import { appModuleAnimation } from '@shared/animations/routerTransition'; @Component({
templateUrl: './phonebook.component.html',
animations: [appModuleAnimation()]
})
export class PhoneBookComponent extends AppComponentBase { constructor(
injector: Injector
) {
super(injector);
} }

4、解决第2步的报错问题。在main-routing.module.ts加入import代码:

import { PhoneBookComponent } from './phonebook/phonebook.component';

5、在app/main/phonebook中新建 phonebook.component.html文件,代码如下:

<div [@routerTransition]>
<div class="row margin-bottom-5">
<div class="col-xs-12">
<div class="page-head">
<div class="page-title">
<h1>
<span>{{l("PhoneBook")}}</span>
</h1>
</div>
</div>
</div>
</div> <div class="portlet light margin-bottom-0">
<div class="portlet-body"> <p>PHONE BOOK CONTENT COMES HERE!</p> </div>
</div>
</div>

6、在app/main/main.module.ts文件中添加下面有黄色标记的代码。

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; import { ModalModule, TabsModule, TooltipModule } from 'ng2-bootstrap'; import { UtilsModule } from '@shared/utils/utils.module'
import { AppCommonModule } from '@app/shared/common/app-common.module' import { MainRoutingModule } from './main-routing.module'
import { MainComponent } from './main.component'
import { DashboardComponent } from './dashboard/dashboard.component';
import { PhoneBookComponent } from './phonebook/phonebook.component'; @NgModule({
imports: [
BrowserModule,
CommonModule,
FormsModule, ModalModule.forRoot(),
TabsModule.forRoot(),
TooltipModule.forRoot(), UtilsModule,
AppCommonModule, MainRoutingModule
],
declarations: [
MainComponent,
DashboardComponent,
PhoneBookComponent
]
})
export class MainModule { }

保存后刷新前端页面点击phone book后可出来如下页面。

7、更新服务端后台服务(后台新增功能代码时执行)。 在dos命令行工具里先定位到angular所在目录路径,然后输入命令:nswag/refresh.bat 执行更新命令。

8、获取person列表。

首先在 shared/service-proxies/service-proxy.module.ts文件中的对应地方加入如下代码:

ApiServiceProxies.PersonServiceProxy

修改phonebook.component.ts里的代码如下面的黄色标记处所示:

import { Component, Injector, OnInit } from '@angular/core';
import { AppComponentBase } from '@shared/common/app-component-base';
import { appModuleAnimation } from '@shared/animations/routerTransition';
import { PersonServiceProxy, PersonListDto, ListResultDtoOfPersonListDto } from '@shared/service-proxies/service-proxies'; @Component({
templateUrl: './phonebook.component.html',
animations: [appModuleAnimation()]
})
export class PhoneBookComponent extends AppComponentBase implements OnInit { people: PersonListDto[] = [];
filter: string = ''; constructor(
injector: Injector,
private _personService: PersonServiceProxy
) {
super(injector);
} ngOnInit(): void {
this.getPeople();
} getPeople(): void {
this._personService.getPeople(this.filter).subscribe((result) => {
this.people = result.items;
});
}
}

再替换phonebook.component.html的 <p>PHONE BOOK CONTENT COMES HERE!</p>代码为下面的黄色标记代码:

<div [@routerTransition]>
<div class="row margin-bottom-5">
<div class="col-xs-12">
<div class="page-head">
<div class="page-title">
<h1>
<span>{{l("PhoneBook")}}</span>
</h1>
</div>
</div>
</div>
</div> <div class="portlet light margin-bottom-0">
<div class="portlet-body"> <h3>{{l("AllPeople")}}</h3> <div class="list-group">
<a *ngFor="let person of people" href="javascript:;" class="list-group-item">
<h4 class="list-group-item-heading">
{{person.name + ' ' + person.surname}}
</h4>
<p class="list-group-item-text">
{{person.emailAddress}}
</p>
</a>
</div> </div>
</div>
</div>

刷新页面

9、新建一个person对象。

首先在phonebook文件夹内创建一个组件create-person-modal.component.ts文件。代码如下:

import { Component, ViewChild, Injector, ElementRef, Output, EventEmitter } from '@angular/core';
import { ModalDirective } from 'ng2-bootstrap';
import { PersonServiceProxy, CreatePersonInput } from '@shared/service-proxies/service-proxies';
import { AppComponentBase } from '@shared/common/app-component-base'; @Component({
selector: 'createPersonModal',
templateUrl: './create-person-modal.component.html'
})
export class CreatePersonModalComponent extends AppComponentBase { @Output() modalSave: EventEmitter<any> = new EventEmitter<any>(); @ViewChild('modal') modal: ModalDirective;
@ViewChild('nameInput') nameInput: ElementRef; person: CreatePersonInput; active: boolean = false;
saving: boolean = false; constructor(
injector: Injector,
private _personService: PersonServiceProxy
) {
super(injector);
} show(): void {
this.active = true;
this.person = new CreatePersonInput();
this.modal.show();
} onShown(): void {
$(this.nameInput.nativeElement).focus();
} save(): void {
this.saving = true;
this._personService.createPerson(this.person)
.finally(() => this.saving = false)
.subscribe(() => {
this.notify.info(this.l('SavedSuccessfully'));
this.close();
this.modalSave.emit(this.person);
});
} close(): void {
this.modal.hide();
this.active = false;
}
}

然后创建同名的html文件 create-person-modal.component.html,代码如下:

<div bsModal #modal="bs-modal" (onShown)="onShown()" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true" [config]="{backdrop: 'static'}">
<div class="modal-dialog">
<div class="modal-content">
<form *ngIf="active" #personForm="ngForm" novalidate (ngSubmit)="save()">
<div class="modal-header">
<button type="button" class="close" (click)="close()" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">
<span>{{l("CreateNewPerson")}}</span>
</h4>
</div>
<div class="modal-body"> <div class="form-group form-md-line-input form-md-floating-label no-hint">
<input #nameInput class="form-control" type="text" name="name" [(ngModel)]="person.name" required maxlength="32">
<label>{{l("Name")}}</label>
</div> <div class="form-group form-md-line-input form-md-floating-label no-hint">
<input class="form-control" type="email" name="surname" [(ngModel)]="person.surname" required maxlength="32">
<label>{{l("Surname")}}</label>
</div> <div class="form-group form-md-line-input form-md-floating-label no-hint">
<input class="form-control" type="email" name="emailAddress" [(ngModel)]="person.emailAddress" required maxlength="255" pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,})+$"> <label>{{l("EmailAddress")}}</label>
</div> </div>
<div class="modal-footer">
<button [disabled]="saving" type="button" class="btn btn-default" (click)="close()">{{l("Cancel")}}</button>
<button type="submit" class="btn btn-primary blue" [disabled]="!personForm.form.valid" [buttonBusy]="saving" [busyText]="l('SavingWithThreeDot')"><i class="fa fa-save"></i> <span>{{l("Save")}}</span></button>
</div>
</form>
</div>
</div>
</div>

接着在main.module.ts类里加入如下黄色标记代码:

...previous imports
import { CreatePersonModalComponent } from './phonebook/create-person-modal.component'; @NgModule({
imports: [
...existing module imports...
],
declarations: [
MainComponent,
DashboardComponent,
PhoneBookComponent,
CreatePersonModalComponent
]
})
export class MainModule { }

最后,在phonebook.component.html文件里加入如下黄色标记代码:

<div [@routerTransition]>
<div class="row margin-bottom-5">
<div class="col-xs-6">
<div class="page-head">
<div class="page-title">
<h1>
<span>{{l("PhoneBook")}}</span>
</h1>
</div>
</div>
</div>
<div class="col-xs-6 text-right">
<button class="btn btn-primary blue" (click)="createPersonModal.show()"><i class="fa fa-plus"></i> {{l("CreateNewPerson")}}</button>
</div>
</div> <div class="portlet light margin-bottom-0">
<div class="portlet-body"> <h3>{{l("AllPeople")}}</h3> <div class="list-group">
<a *ngFor="let person of people" href="javascript:;" class="list-group-item">
<h4 class="list-group-item-heading">
{{person.name + ' ' + person.surname}}
</h4>
<p class="list-group-item-text">
{{person.emailAddress}}
</p>
</a>
</div> </div>
</div>
<createPersonModal #createPersonModal (modalSave)="getPeople()"></createPersonModal>
</div>

10、隐藏未授权的button按钮。

打开phonebook.component.html文件。在button处加入下面的黄色标记代码:

<button *ngIf="isGranted('Pages.Tenant.PhoneBook.CreatePerson')" class="btn btn-primary blue" (click)="createPersonModal.show()"><i class="fa fa-plus"></i> {{l("CreateNewPerson")}}</button>

11、删除peson对象。

修改phonebook.component.html文件,增加如下黄色标记处代码:

...
<h3>{{l("AllPeople")}}</h3> <div class="list-group">
<a *ngFor="let person of people" href="javascript:;" class="list-group-item">
<h4 class="list-group-item-heading">
{{person.name + ' ' + person.surname}}
<button (click)="deletePerson(person)" title="{{l('Delete')}}" class="btn btn-circle btn-icon-only red delete-person" href="javascript:;">
<i class="icon-trash"></i>
</button>
</h4>
<p class="list-group-item-text">
{{person.emailAddress}}
</p>
</a>
</div>
...

12、使用LESS样式将按钮移至右边。

在phonebook文件夹下创建phonebook.component.less样式文件,代码如下:

.list-group-item-heading {
button.delete-person {
float: right;
}
}

在 phonebook.component.ts 文件中引入样式文件,代码如黄色标记:

@Component({
templateUrl: './phonebook.component.html',
styleUrls: ['./phonebook.component.less'],
animations: [appModuleAnimation()]
})

13、在phonebook.component.ts内添加删除功能代码:

deletePerson(person: PersonListDto): void {
this.message.confirm(
this.l('AreYouSureToDeleteThePerson', person.name),
isConfirmed => {
if (isConfirmed) {
this._personService.deletePerson(person.id).subscribe(() => {
this.notify.info(this.l('SuccessfullyDeleted'));
_.remove(this.people, person);
});
}
}
);
}

并且在@Component标记前增加引入代码:

import * as _ from 'lodash';

14、

15、

16、

未完待续。。。

Asp.net Zero 应用实战-官方示例PhoneBook学习1_修改1版的更多相关文章

  1. Asp.net Zero 应用实战-官方示例PhoneBook学习1

    适用Zero版本:ASP.NET Core & Angular 2+ (aspnet-zero-core-3.1.0). 该版本官方有两个solution文件夹:Angular(前端) 和 a ...

  2. gRPC官方快速上手学习笔记(c#版)

    上手前准备工作 支持操作系统:windows.OS X.Linux.实例采用.net..net core sdk. The .NET Core SDK command line tools. The ...

  3. Asp.Net Core 项目实战之权限管理系统(0) 无中生有

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  4. Asp.Net Core 项目实战之权限管理系统(6) 功能管理

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  5. 【无私分享:ASP.NET CORE 项目实战(第十四章)】图形验证码的实现

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 很长时间没有来更新博客了,一是,最近有些忙,二是,Core也是一直在摸索中,其实已经完成了一个框架了,并且正在准备在生产环境中 ...

  6. 【无私分享:ASP.NET CORE 项目实战(第十三章)】Asp.net Core 使用MyCat分布式数据库,实现读写分离

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 MyCat2.0版本很快就发布了,关于MyCat的动态和一些问题,大家可以加一下MyCat的官方QQ群:106088787.我 ...

  7. 【无私分享:ASP.NET CORE 项目实战(第十二章)】添加对SqlServer、MySql、Oracle的支持

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 增加对多数据库的支持,并不是意味着同时对多种数据库操作,当然,后面,我们会尝试同时对多种数据库操作,这可能需要多个上下文,暂且 ...

  8. 【无私分享:ASP.NET CORE 项目实战(第十一章)】Asp.net Core 缓存 MemoryCache 和 Redis

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitHub上下载了十几个源码参考, Memory 和 Redis 终于写出一个 ...

  9. 【无私分享:ASP.NET CORE 项目实战(第七章)】文件操作 FileHelper

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在程序设计中,我们很多情况下,会用到对文件的操作,在 上一个系列 中,我们有很多文件基本操作的示例,在Core中有一些改变,主 ...

随机推荐

  1. django之关联field 描述子

    """Accessors for related objects. When a field defines a relation between two models, ...

  2. Java数据类型(Primivite 和引用数据类型!)

    一.byte(8位)  short(16位)  int(32位) long(64位) float(32位) double(64位) boolean(Java虚拟机决定)  true 或者false! ...

  3. nginx stream module on mt7621(newifi3 d2) with openwrt 18.06.2

    因为需要使用nginx的stream模块,专门编译了一个nginx安装包,适用于openwrt 18.06.2版本,mt7621平台 顺便记录一下编译的笔记: 1.修改feeds/packages/n ...

  4. KeyValuePair 和 Dictionary 的关系和区别

    KeyValuePair 和 Dictionary 的关系 1.KeyValuePair      a.KeyValuePair 是一个结构体(struct):     b.KeyValuePair  ...

  5. html注册栏网页练习代码

    html body>     <form action="#" method="get">         <div>       ...

  6. RPC web service

    ---------------------------------------------------------------------------------------------------- ...

  7. VS2019正式版注册码秘钥

    Visual Studio 2019 EnterpriseBF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 ProfessionalNYWVH-HT4X ...

  8. java获取request中的参数、java解析URL问号后的参数

    java获取request中的参数.java解析URL问号后的参数.有时候我们需要从request中获取参数,或者获取拼接在Url后面的参数,有时候一个一个去拿有点麻烦,一起拿出来放在一个map里面需 ...

  9. 随select动,将value值显示在后面的input里

    <!doctype html><html lang="en"> <head> <meta charset="UTF-8" ...

  10. Freemarker 对于数字的循环

    Freemarker 对于数字的循环 格式:[#list count.. as i] ${i} [/#list] ******************************************* ...