参考【ASP.NET Core跨平台开发从入门到实战 [张剑桥].pdf】从零搭建.net core项目(名称叫NetNote),又踩了很多坑,趁着有印象记下:html
一、选用的是最简单最空的项目,说是WebApplication,实际和控制台同样了,只有最基本的Starup.cs、Program.cs,以及几个json,其它全没有。这种最好,一个个往上搭,看须要什么东西前端
二、看有些core源码没有再分一层数据层出来,直接在控制器搞定。我仍是按习惯把默认的改成NetNote.UI,再建一个类库,叫NetNote.DAL数据库
一下没注意,选类库的时候,仍是选了上面的.net Standard,结果代码都写好了,发现是不能CodeFirst仍是什么的,总之提示不是core项目,报错。仔细一看,原来新建项目时下面还有专门的.net core 类库。json
再建个core类库,把代码剪切过来,把旧的删了,再改文件夹名称、改解决方案里文件夹名称,正常了浏览器
三、照着教程先来DAL层,要装Framework.Core.SQLServer、Framework.Core.Tools,好久以前(去年?前年?)还据说ef core支持很差,如今应该很成熟了app
四、照着把DAL层的实体类、接口、接口实现仓储建好,要在UI层配置,教程里都建了接口,平时工做都没先定义接口再作增删改查,致使叫法不统一,好比有的叫Update,有的叫Save,但也不是很影响就是了,都有代码提示。框架
五、坑都在这里踩了,重点说一下异步
public void ConfigureServices(IServiceCollection services) { string connection = @"Server=.;Database=Note;UID=sa;PWD=XXX;"; services.AddDbContext<NoteContext>(options => options.UseSqlServer(connection)); services.AddScoped<INoteRepository, NoteRepository>(); services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //app.Run(async (context) => //{ // await context.Response.WriteAsync("Hello World!"); //}); app.UseMvcWithDefaultRoute(); }
仓储层建好后要在ConfigureServices配置async
一开始MVC不识别,即浏览器访问不了(由于是彻底空的项目),要配置services.AddMvc(),并在Configure里配置默认路由。这个弄了半天,觉得都底层默认支持原始路由。post
MVC配置后仍没法用,全部页面均为Hello World,原来是初始代码里有这么一句(上面注释了的),全部输出均为Hello World了
六、好不容易UI层弄好了,要CodeFirst生成数据库,死活不行,一开始说要装Core Tools,还有个什么东西忘了,由于我是空项目一个个往里装所需插件的。装完后仍是不行,最后用Package Manager又能够了
会多一个这样的文件夹出来,查网上资料好像也是说若是要直接用dotnet ef迁移,要提早把这个迁移文件夹及内容配好。用PM的会帮咱们配
平时都是DBFirst,没用过CodeFirst,恰好尝试下
七、总体项目文件夹以下:
教程是另弄了个ViewModel来和实体对应,JAVA也基本是这样,在数据库实体以外再弄一个VO来对应。我一直以为很麻烦、不必。
若是字段有所不一样还好,若是是彻底同样的,何须这样再来一遍?退一步说真要这样弄个实体,好歹也用反射什么的自动赋值吧
这个以前有和水平较高的大佬讨论过,也网上看过,说是为了避免暴露数据库内部结构,那若是不想暴露,好歹ViewModel要取彻底不一样的才有意义吧,并且数据库字段名给别人知道了也没什么特别要紧。
还有种说法是为了避免因数据库结构而改变前端什么的,也不对啊,数据库若是变了,前端模型也得跟着变,代码也得跟着变,都是要一条龙的
这个可能就和先接口再实现同样吧,是一种规范,大项目要这样约束好,平时小项目感受是没关系,既不要接口,也不要对应UI实体类,节省时间,也不会带来什么后遗症
八、顺便说下,core都是用这种异步写法了,虽然说小项目也是效率看不出来,但养成习惯就好,毕竟是底层更高效的,写了也不吃亏
主要是方法上用asyn Task,内部代码用await,其它没什么区别
public async Task<IActionResult> Index() { List<Note> notes = await noteRepository.ListAsync(); return View(notes); }
九、控制器上都这样用注入了,原先公司用的是在Base里用单例工厂,感受是同样用,就是不用实例化就能调后台呗,不是一回事?
private INoteRepository noteRepository; public NoteController(INoteRepository diNoteRepository) { noteRepository = diNoteRepository; }
公司目前是这样,单例的工厂提早备好服务,哪里要用直接用就能够,也是无需再实例化,这个单例和注入的区别,还要再研究下基础知识才行
public class BaseController : Controller {protected EntityRepositoryService ucEntity = UserCenterFactory.EntityRepositoryService; protected SqlRepositoryService ucSql = UserCenterFactory.SqlRepositoryService;
=================
十、TagHelpers的坑。。。照着教程用 <a asp-action="Add">添加Note</a> ,但解析出来,竟然就是原本来本的 <a asp-action="Add">添加Note</a> 这种html,为何不翻译成a标签的href之类的呢?
找了半天,原来仍是由于新建的是空项目的缘由,默认会自带个_ViewImports.cshtml,里面就一句话
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
手动在视图页面上面加了这个就行了
十一、还有个坑,教程上漏写了一个普通视图的控制器入口,我还觉得框架底层又有什么新写法,直接兼容页面和提交呢(或仍是我哪里没配对?)
public IActionResult Add() { return View(); } [HttpPost] public async Task<IActionResult> Add(NoteModel nmModel) { if (!ModelState.IsValid) { return BadRequest(ModelState); } await noteRepository.AddAsync(new Note { Title = nmModel.Title, Content = nmModel.Content, Create = DateTime.Now }); return RedirectToAction("Index"); }
教程里面是没有上面普通的public IActionResult Add(){return View()} 的,只有下面post的保存方法,我就看了半天,那Add页面是怎么展现的呢?原先只有接收post啊。
也不知是真支持这样写,但须要另外配(或框架哪里有处理),仍是真漏了,反正我加上普通的方法让它返回到页面就能够了
十二、外键
平时EF从没用过外键,不方便,网上也建议不要用外键,数据库只作好存储的事,不要搭上业务。
教程里这样写,试了会报错,建表是会自动建外键,但新增时,只增了一张表,另张表没处理,是外键会自动处理?感受是须要手动加一句吧,两张表都要保存,否则外键的那张表怎么知道要存什么数据。
去掉了外键,单表保存正常,这本教程感受源码直接拿来上机会有些问题,恰好在排查问题时能加深理解