当前位置 博文首页 > 基于.NET Core 3.1 网站开发和部署的方法
这里选择vscode + .net core cli 是因为不管在Windows还是Linux和Mac上都能使用这一套工具,而且命令行工具也非常强大。
在vscode插件市场中搜索安装即可
新手还可以去这里了解vscode的强大之处
这里使用Centos7,因为.NET Core 3.1只支持7及以上版本
配置网络
nmcli conn nmcli conn add ifname ens34 con-name ens34 type enthernet autoconnect yes ip4 192.168.30.110/24
安装mariadb-server
使用XShell连接服务器
cd /etc/yum.repos.d/ mkdir bak mv Cen* ./bak/ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo yum install mariadb-server.x86_64
启动服务
systemctl enable mariadb.service systemctl start mariadb.service systemctl status mariadb
执行安全加强脚本
mysql_secure_installation
创建数据库并授权访问帐号
MariaDB [(none)]> create database HotelWebDb default charset utf8 collate utf8_general_ci; MariaDB [(none)]> grant all on HotelWebDb.* to sa@'192.168.30.%' identified by '110'; MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | HotelWebDb | | mysql | | performance_schema | +--------------------+ 4 rows in set (0.00 sec)
编写Sql脚本
-- 管理员登录表 CREATE TABLE if not EXISTS SysAdmins ( LoginId INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, LoginName VARCHAR(20) NOT NULL, LoginPwd VARCHAR(20) NOT NULL )engine=innodb DEFAULT charset=utf8; ALTER TABLE SysAdmins AUTO_INCREMENT=10000; -- 新闻分类表 CREATE TABLE if not EXISTS NewsCategory ( CategoryId INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, CategoryName VARCHAR(20) NOT NULL )engine=innodb DEFAULT charset=utf8; -- 新闻表 CREATE TABLE if not EXISTS News ( Id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, NewsTitle VARCHAR(100), NewsContent TEXT, PublishTime TIMESTAMP DEFAULT now(), CategoryId INT UNSIGNED , FOREIGN KEY(CategoryId) REFERENCES NewsCategory (CategoryId) )engine=innodb DEFAULT charset=utf8; ALTER TABLE News AUTO_INCREMENT=1000; -- 菜品分类表 CREATE TABLE if not EXISTS DishCategory ( CategoryId INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, CategoryName VARCHAR(20) )engine=innodb DEFAULT charset=utf8; -- 菜品表 CREATE TABLE if not EXISTS Dishes ( Id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, DishName VARCHAR(100), UnitPrice NUMERIC(18, 2), CategoryId INT UNSIGNED, FOREIGN KEY(CategoryId) REFERENCES DishCategory (CategoryId) )engine=innodb DEFAULT charset=utf8; ALTER TABLE Dishes AUTO_INCREMENT=10000; -- 菜品预订表 CREATE TABLE if not EXISTS DishBook ( Id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, HotelName VARCHAR(50), ConsumeTime datetime, ConsumePersons INT UNSIGNED, RoomType VARCHAR(20), CustomerPhone VARCHAR(20), CustomerName VARCHAR(20), CustomerEmail VARCHAR(100), Comments VARCHAR(500), BookTime TIMESTAMP DEFAULT now(), BookStatus INT DEFAULT 0 -- ( 0 表示未审核,1 表示审核通过,2 表示消费完成,-1 表示撤销订单) )engine=innodb DEFAULT charset=utf8; ALTER TABLE DishBook AUTO_INCREMENT=1000; -- 招聘信息表 CREATE TABLE if not EXISTS Recruitment ( PostId INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, PostName NVARCHAR(100), PostType CHAR(4), -- (全职或兼职) WorkPlace NVARCHAR(50), PostDesc TEXT, PostRequire TEXT, Experience NVARCHAR(100), EduBackground NVARCHAR(100), RequireCount INT, PublishTime TIMESTAMP DEFAULT now(), Manager VARCHAR(20), PhoneNumber VARCHAR(20), Email VARCHAR(100) )engine=innodb DEFAULT charset=utf8; ALTER TABLE Recruitment AUTO_INCREMENT=100000; -- 投诉建议表 CREATE TABLE if not EXISTS Suggestion ( Id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, CustomerName VARCHAR(20), ConsumeDesc TEXT, SuggestionDesc TEXT, SuggestionTime TIMESTAMP DEFAULT now(), PhoneNumber VARCHAR(20), Email VARCHAR(20), StatusId INT DEFAULT 0 -- (0:未受理;1:已经受理) )engine=innodb DEFAULT charset=utf8; ALTER TABLE Suggestion AUTO_INCREMENT=10000;
创建测试数据
-- 插入测试数据 -- 管理员信息 insert into SysAdmins(LoginPwd,LoginName)values('123456','李浩'); insert into SysAdmins(LoginPwd,LoginName)values('123456','赵雪伶'); -- 新闻分类 insert into NewsCategory(CategoryName)values('公司新闻'); insert into NewsCategory(CategoryName)values('社会新闻'); -- 菜品分类 insert into DishCategory(CategoryName)values('川菜'); insert into DishCategory(CategoryName)values('湘菜'); insert into DishCategory(CategoryName)values('鲁菜'); insert into DishCategory(CategoryName)values('海鲜类'); insert into DishCategory(CategoryName)values('其他'); -- 新闻 insert into News(NewsTitle,NewsContent,CategoryId)values('迎接十一海鲜大促销','最新鲜的鱼类全面上市,欢迎新老顾客品尝。',1); insert into News(NewsTitle,NewsContent,CategoryId)values('本店正在热招加盟商','如果您愿意在酒店行业有所突破,请加入我们。',1); insert into News(NewsTitle,NewsContent,CategoryId)values('互联网的消费正在兴起','网上购物已经成为人们生活必不可少的一部分。',2); insert into News(NewsTitle,NewsContent,CategoryId)values('本店正在热招加盟商','如果您愿意在酒店行业有所突破,请加入我们。',1); insert into News(NewsTitle,NewsContent,CategoryId)values('互联网的消费正在兴起','网上购物已经成为人们生活必不可少的一部分。',2); -- 菜品信息 insert into Dishes(DishName,UnitPrice,CategoryId)values('水煮鱼',50,1); insert into Dishes(DishName,UnitPrice,CategoryId)values('回锅肉',85,1); insert into Dishes(DishName,UnitPrice,CategoryId)values('剁椒鱼头',75,2); insert into Dishes(DishName,UnitPrice,CategoryId)values('红椒腊牛肉',40,2); insert into Dishes(DishName,UnitPrice,CategoryId)values('糖醋鲤鱼',70,3); insert into Dishes(DishName,UnitPrice,CategoryId)values('玉记扒鸡',60,3); insert into Dishes(DishName,UnitPrice,CategoryId)values('汤爆双脆',90,3); insert into Dishes(DishName,UnitPrice,CategoryId)values('赤贝',80,4); -- 预定信息 insert into DishBook(HotelName,ConsumeTime,ConsumePersons,RoomType,CustomerName,CustomerPhone,CustomerEmail,Comments) values('天津南开店','2014-09-11 12:30',5,'包间','李丽','13589011222','lilivip@163.com','希望房间敞亮些'); insert into DishBook(HotelName,ConsumeTime,ConsumePersons,RoomType,CustomerName,CustomerPhone,CustomerEmail,Comments) values('天津和平店','2014-10-11 14:30',5,'包间','王鑫新','13889018888','wangxinxin@qq.com','希望房间安静些'); insert into DishBook(HotelName,ConsumeTime,ConsumePersons,RoomType,CustomerName,CustomerPhone,CustomerEmail,Comments) values('北京朝阳点','2014-12-10 17:30',5,'散座','刘花雨','13689011999','liuhuayu@126.com','房间靠里面点儿'); -- 招聘信息 insert into Recruitment(PostName,PostType,WorkPlace,PostDesc,PostRequire,Experience,EduBackground,RequireCount,Manager,PhoneNumber,Email) values('大堂经理','全职','天津','负责一层楼的管理','要求具备该职位3年以上经营管理经验','3年','本科',2,'李超阳','15689011231','lichaoyang@hyl.com'); insert into Recruitment(PostName,PostType,WorkPlace,PostDesc,PostRequire,Experience,EduBackground,RequireCount,Manager,PhoneNumber,Email) values('接待员','全职','北京','负责客户的接待礼仪','要求具备该职位1年以上经验','1年','高中',5,'李超阳','15689011231','lichaoyang@hyl.com'); insert into Recruitment(PostName,PostType,WorkPlace,PostDesc,PostRequire,Experience,EduBackground,RequireCount,Manager,PhoneNumber,Email) values('总经理助理','全职','天津','负责日常的文秘工作','要求具备该职位3年以上经营管理经验','3年','本科',1,'李超阳','15689011231','lichaoyang@hyl.com'); -- 投诉建议 insert into Suggestion(CustomerName,ConsumeDesc,SuggestionDesc,PhoneNumber,Email) values('杜小杰','在该店举行一次婚礼','感觉总体服务不到位,菜品味道没有以前的好。','15687423456','duxiaojie@qq.com'); insert into Suggestion(CustomerName,ConsumeDesc,SuggestionDesc,PhoneNumber,Email) values('柳钢','在本店聚会一次','感觉上菜有点慢,希望后续改进。','15686623456','liugang@qq.com');
进入vscode,打开终端创建项目的根目录
快捷键:Ctrl + `
创建项目根目录
D:\dotnet_core>mkdir HotelWebMVC D:\dotnet_core>dir 驱动器 D 中的卷是 补充 卷的序列号是 0004-524D D:\dotnet_core 的目录 2019/12/10 09:33 <DIR> . 2019/12/10 09:33 <DIR> .. 2019/08/30 16:31 <DIR> .vscode 2018/05/07 20:25 <DIR> helloworld 2019/12/10 09:33 <DIR> HotelWebMVC 2019/12/09 20:22 <DIR> netcore_mvc
安装 .NET Core SDK
下载地址:https://dotnet.microsoft.com/download
查看微软的教程:https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-3.1&tabs=visual-studio-code
查看命令帮助
D:\dotnet_core\HotelWebMVC>dotnet new --help 用法: new [选项] 选项: -h, --help Displays help for this command. -l, --list Lists templates containing the specified name. If no name is specified, lists all templates. -n, --name The name for the output being created. If no name is specified, the name of the current directory is used. -o, --output Location to place the generated output. -i, --install Installs a source or a template pack. -u, --uninstall Uninstalls a source or a template pack. --nuget-source Specifies a NuGet source to use during install. --type Filters templates based on available types. Predefined values are "project", "item" or "other". --dry-run Displays a summary of what would happen if the given command line were run if it would result in a template creation. --force Forces content to be generated even if it would change existing files. -lang, --language Filters templates based on language and specifies the language of the template to create. --update-check Check the currently installed template packs for updates. --update-apply Check the currently installed template packs for update, and install the updates.
创建项目
以上操作都是可以使用命令完成
比如添加解决方案
D:\dotnet_core\HotelWebMVC>dotnet sln ./HotelWebMVC.sln add DAL\DAL.csproj 已将项目“DAL\DAL.csproj”添加到解决方案中。 D:\dotnet_core\HotelWebMVC>dotnet sln ./HotelWebMVC.sln add BLL\BLL.csproj 已将项目“BLL\BLL.csproj”添加到解决方案中。 D:\dotnet_core\HotelWebMVC>dotnet sln list 项目 -- HotelWebMVC\HotelWebMVC.csproj Models\Models.csproj DAL\DAL.csproj BLL\BLL.csproj
添加启动项目和类库项目之间的引用
Models -->DAL
D:\dotnet_core\HotelWebMVC\DAL>dotnet add reference ..\Models\Models.csproj 已将引用“..\Models\Models.csproj”添加到项目。
DAL —> BLL
D:\dotnet_core\HotelWebMVC\DAL>dotnet add ..\bll\BLL.csproj reference .\DAL.csproj 已将引用“..\DAL\DAL.csproj”添加到项目。
HotelWebMVC --> BLL
D:\dotnet_core\HotelWebMVC\DAL>dotnet add ..\HotelWebMVC\HotelWebMVC.csproj reference ..\bll\BLL.csproj 已将引用“..\bll\BLL.csproj”添加到项目。
① 使用EF Core 生成模型
DB First模式
全局安装ef工具
dotnet tool install --global dotnet-ef
测试工具是否安装成功
D:\dotnet_core\HotelWebMVC>dotnet ef _/\__ ---==/ \\ ___ ___ |. \|\ | __|| __| | ) \\\ | _| | _| \_/ | //|\\ |___||_| / \\\/\\ Entity Framework Core .NET Command-line Tools 3.1.0 Usage: dotnet ef [options] [command] Options: --version Show version information -h|--help Show help information -v|--verbose Show verbose output. --no-color Don't colorize output. --prefix-output Prefix output with level. Commands: database Commands to manage the database. dbcontext Commands to manage DbContext types. migrations Commands to manage migrations. Use "dotnet ef [command] --help" for more information about a command.
只要看到有这个独角兽就代表安装成功了。
添加需要的NuGet包
dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Pomelo.EntityFrameworkCore.MySql
使用EF工具
查看帮助
D:\dotnet_core\HotelWebMVC\DAL>dotnet ef dbcontext scaffold --help Usage: dotnet ef dbcontext scaffold [arguments] [options] Arguments: <CONNECTION> The connection string to the database. <PROVIDER> The provider to use. (E.g. Microsoft.EntityFrameworkCore.SqlServer) Options: -d|--data-annotations Use attributes to configure the model (where possible). If omitted, only the fluent API is used. -c|--context <NAME> The name of the DbContext. --context-dir <PATH> The directory to put DbContext file in. Paths are relative to the project directory. -f|--force Overwrite existing files. -o|--output-dir <PATH> The directory to put files in. Paths are relative to the project directory. --schema <SCHEMA_NAME>... The schemas of tables to generate entity types for. -t|--table <TABLE_NAME>... The tables to generate entity types for. --use-database-names Use table and column names directly from the database. --json Show JSON output. -p|--project <PROJECT> The project to use. -s|--startup-project <PROJECT> The startup project to use. --framework <FRAMEWORK> The target framework. --configuration <CONFIGURATION> The configuration to use. --runtime <RUNTIME_IDENTIFIER> The runtime to use. --msbuildprojectextensionspath <PATH> The MSBuild project extensions path. Defaults to "obj". --no-build Don't build the project. Only use this when the build is up-to-date. -h|--help Show help information -v|--verbose Show verbose output. --no-color Don't colorize output. --prefix-output Prefix output with level.
连接数据库生成模型数据
D:\dotnet_core\HotelWebMVC\DAL>dotnet ef dbcontext scaffold "Server=192.168.30.110,3306;DataBase=HotelWebDb;User=sa;Pwd=110;" "Pomelo.EntityFrameworkCore.MySql" -s ..\HotelWebMVC\HotelWebMVC.csproj Build started... Build succeeded.
修改连接字符串的位置
修改在appsettings.json文件中添加连接字符串
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "ConnectionStrings":{ "HotelWeb":"Server=192.168.30.110,3306;DataBase=HotelWebDb;User=sa;Pwd=110;" } }
然后在Sartup.cs文件获取连接字符串
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); string connString=Configuration.GetConnectionString("HotelWeb"); services.AddDbContext<DAL.HotelWebDbContext>(options=>options.UseMySql(connString, x => x.ServerVersion("5.5.64-mariadb"))); }
最后DbContenxt类中配置就可以删除了
移动DAL生成的实体类到Models模块
修改实体类中的命名空间
② 另一种使用ADO.NET实现
不是这次的重点,所以略过。
1.编写一个简单的Helper类
using Microsoft.EntityFrameworkCore; namespace DAL { class EFCoreHelper { private DbContext dbContext = null; public EFCoreHelper(DbContext context) { this.dbContext = context; } /// <summary> /// 添加实体 /// </summary> /// <typeparam name="T"></typeparam> public int Add<T>(T entity) where T : class { dbContext.Entry(entity).State=EntityState.Added; return dbContext.SaveChanges(); } /// <summary> /// 修改实体的全部属性 /// </summary> /// <typeparam name="T"></typeparam> public int Modify<T>(T entity) where T:class { dbContext.Entry(entity).State=EntityState.Modified; return dbContext.SaveChanges(); } /// <summary> /// 删除实体 /// </summary> /// <typeparam name="T"></typeparam> public int Delete<T>(T entity) where T:class { dbContext.Entry(entity).State=EntityState.Deleted; return dbContext.SaveChanges(); } } }
2.完成新闻后台数据访问类
数据访问类
using System; using System.Linq; using System.Collections.Generic; using Models; namespace DAL { public class NewsService { private EFCoreHelper helper = new EFCoreHelper(new HotelWebDbContext()); /// <summary> /// 添加新闻 /// </summary> /// <param name="news"></param> /// <returns></returns> public int AddNews(News news) => helper.Add(news); /// <summary> /// 修改新闻 /// </summary> /// <param name="news"></param> /// <returns></returns> public int ModifyNews(News news) => helper.Modify(news); /// <summary> /// 删除新闻 /// </summary> /// <param name="newssId"></param> /// <returns></returns> public int DeleteNews(string newssId) { News news = new News() { Id = Convert.ToUInt32(newssId) }; return helper.Delete(news); } /// <summary> /// 获取指定数量的新闻列表 /// </summary> /// <param name="count"></param> /// <returns></returns> public List<News> GetNews(int count) { using (HotelWebDbContext dbContext = new HotelWebDbContext()) { return (from n in dbContext.News orderby n.PublishTime descending select n).Take(count).ToList(); } } /// <summary> /// 根据ID获取新闻信息 /// </summary> /// <param name="newssId"></param> /// <returns></returns> public News GetNewsById(string newssId) { uint id = Convert.ToUInt32(newssId); using (HotelWebDbContext dbContext = new HotelWebDbContext()) { return (from n in dbContext.News where n.Id == id select n).FirstOrDefault(); } } /// <summary> /// 获取所有的新闻分类 /// </summary> /// <returns></returns> public List<NewsCategory> GetCategories() { using (HotelWebDbContext dbContext = new HotelWebDbContext()) { return (from c in dbContext.NewsCategory select c).ToList(); } } } }
业务逻辑部分
using System.Collections.Generic; using DAL; using Models; namespace BLL { public class NewsManager { private NewsService objService=new NewsService(); /// <summary> /// 添加新闻 /// </summary> /// <param name="news"></param> /// <returns></returns> public int AddNews(News news) => objService.AddNews(news); /// <summary> /// 修改新闻 /// </summary> /// <param name="news"></param> /// <returns></returns> public int ModifyNews(News news) => objService.ModifyNews(news); /// <summary> /// 删除新闻 /// </summary> /// <param name="newssId"></param> /// <returns></returns> public int DeleteNews(string newssId) => objService.DeleteNews(newssId); /// <summary> /// 获取指定数量的新闻列表 /// </summary> /// <param name="count"></param> /// <returns></returns> public List<News> GetNews(int count) => objService.GetNews(count); /// <summary> /// 根据ID获取新闻信息 /// </summary> /// <param name="newssId"></param> /// <returns></returns> public News GetNewsById(string newssId) => objService.GetNewsById(newssId); /// <summary> /// 获取所有的新闻分类 /// </summary> /// <returns></returns> public List<NewsCategory> GetCategories() => objService.GetCategories(); } }
3.添加一个控制台项目用来测试
添加需要的引用
dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Pomelo.EntityFrameworkCore.MySql
DbContext中的数据库连接字符串添加回去
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if(!optionsBuilder.IsConfigured) { optionsBuilder.UseMySql("Server=192.168.30.110;DataBase=HotelWebDb;User=sa;Pwd=110;",x => x.ServerVersion("5.5.64-mariadb")); } }
编写测试代码
News news=new News() { NewsContent="你好这是一个测试新闻内容", NewsTitle="测试新闻", CategoryId=1 }; Console.WriteLine(objNews.AddNews(news));
启动调试
选择启动项目有两种方法
①通过solution explorer 插件选择
②通过配置launch.json 文件启动
然后修改启动程序入口就可以了
{ "name": ".NET Core Launch (console)", "type": "coreclr", "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/UnitTestPro/bin/Debug/netcoreapp3.1/UnitTestPro.dll", "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, "console": "internalConsole" },
还要修改task文件,否则测试项目中新加的代码不能被执行。
结果查验
结果符合预期
注意事项
修改新闻调用的方法不支持部分属性修改,如果对象属性不设置,那么没有设置的字段被设置为空。
后面有字段部分修改的方法。
News news=new News() { Id=1008, NewsContent="修改新闻的内容", NewsTitle="这是被修改的新闻标题", }; Console.WriteLine(objNews.ModifyNews(news));
4.编写菜品预订
5.编写招聘
6.编写投诉和建议
7.管理员登录
类似不再贴代码
1.完成前端Html代码的编写
不多说
2.完成MVC项目中控制器和视图的文件添加
这个只能手动添加,不像VS有模板可用
3.复制网站的静态资源
asp.net core 网站静态资源都是放在wwwroot目录的,并且文件名一般是小写。
4.在视图中引用资源
MVC框架可以直接识别在wwwroot中的静态资源,不用写显示的写出目录名。
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" /> <link rel="stylesheet" href="~/css/site.css" rel="external nofollow" rel="external nofollow" />
5.编写动作方法
public IActionResult Index() { return View(); }
6.添加视图
7.启动调试
首页效果图
8.视图与控制器之间传递数据
使用ViewData
视图的网页标题可以使用这种方式传递
public IActionResult Index() { ViewData["title"]="好运来酒店"; ViewBag.list=new NewsManager().GetNews(4); return View(); }
视图中引用数据
<!doctype html> <html lang="zh"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" /> <link rel="stylesheet" href="~/css/site.css" rel="external nofollow" rel="external nofollow" /> <title>@ViewData["title"]-舒适快捷经济</title> </head>
使用ViewBag
这是所谓的动态类型,直接无中生有造一个属性
ViewBag.list=new NewsManager().GetNews(4);
视图中引用
@foreach (News item in @ViewBag.list) { <div class="d-flex flex-row justify-content-between newslist"> <div class="p-2"> <a href="/News/NewsDetail?id=@item.Id" rel="external nofollow" rel="external nofollow" >@item.NewsTitle</a> </div> <div class="p-2"> @item.PublishTime.ToShortDateString() </div> </div>
使用viewmodel
控制器中使用View的重载方法传递viewmodel
public IActionResult Index() { ViewData["title"]="好运来酒店"; return View(new NewsManager().GetNews(4)); }
视图中先声明后使用
Specify a model using the @model directive. Use the model with @Model:
@model list<News> ... @foreach (News item in @Model) { <div class="d-flex flex-row justify-content-between newslist"> <div class="p-2"> <a href="/News/NewsDetail?id=@item.Id" rel="external nofollow" rel="external nofollow" >@item.NewsTitle</a> </div> <div class="p-2"> @item.PublishTime.ToShortDateString() </div> </div>