基于.NET Core 3.1 网站开发和部署的方法
一、准备开发环境
1.主要开发工具的选择
- vscode
- .NETCorecommand-lineinterface(CLI)tools
- Dbeaver
这里选择vscode+.netcorecli是因为不管在Windows还是Linux和Mac上都能使用这一套工具,而且命令行工具也非常强大。
2.vscode安装C#插件
在vscode插件市场中搜索安装即可
新手还可以去这里了解vscode的强大之处
3.安装数据库
这里使用Centos7,因为.NETCore3.1只支持7及以上版本
配置网络
nmcliconn nmcliconnaddifnameens34con-nameens34typeenthernetautoconnectyesip4192.168.30.110/24
安装mariadb-server
使用XShell连接服务器
cd/etc/yum.repos.d/ mkdirbak mvCen*./bak/ curl-o/etc/yum.repos.d/CentOS-Base.repohttp://mirrors.aliyun.com/repo/Centos-7.repo yuminstallmariadb-server.x86_64
启动服务
systemctlenablemariadb.service systemctlstartmariadb.service systemctlstatusmariadb
执行安全加强脚本
mysql_secure_installation
创建数据库并授权访问帐号
MariaDB[(none)]>createdatabaseHotelWebDbdefaultcharsetutf8collateutf8_general_ci; MariaDB[(none)]>grantallonHotelWebDb.*tosa@'192.168.30.%'identifiedby'110'; MariaDB[(none)]>showdatabases; +--------------------+ |Database| +--------------------+ |information_schema| |HotelWebDb| |mysql| |performance_schema| +--------------------+ 4rowsinset(0.00sec)
4.使用Dbeaver连接数据库创建数据表和测试数据
--管理员登录表 CREATETABLEifnotEXISTSSysAdmins ( LoginIdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, LoginNameVARCHAR(20)NOTNULL, LoginPwdVARCHAR(20)NOTNULL )engine=innodbDEFAULTcharset=utf8; ALTERTABLESysAdminsAUTO_INCREMENT=10000; --新闻分类表 CREATETABLEifnotEXISTSNewsCategory ( CategoryIdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, CategoryNameVARCHAR(20)NOTNULL )engine=innodbDEFAULTcharset=utf8; --新闻表 CREATETABLEifnotEXISTSNews ( IdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, NewsTitleVARCHAR(100), NewsContentTEXT, PublishTimeTIMESTAMPDEFAULTnow(), CategoryIdINTUNSIGNED, FOREIGNKEY(CategoryId)REFERENCESNewsCategory(CategoryId) )engine=innodbDEFAULTcharset=utf8; ALTERTABLENewsAUTO_INCREMENT=1000; --菜品分类表 CREATETABLEifnotEXISTSDishCategory ( CategoryIdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, CategoryNameVARCHAR(20) )engine=innodbDEFAULTcharset=utf8; --菜品表 CREATETABLEifnotEXISTSDishes ( IdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, DishNameVARCHAR(100), UnitPriceNUMERIC(18,2), CategoryIdINTUNSIGNED, FOREIGNKEY(CategoryId)REFERENCESDishCategory(CategoryId) )engine=innodbDEFAULTcharset=utf8; ALTERTABLEDishesAUTO_INCREMENT=10000; --菜品预订表 CREATETABLEifnotEXISTSDishBook ( IdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, HotelNameVARCHAR(50), ConsumeTimedatetime, ConsumePersonsINTUNSIGNED, RoomTypeVARCHAR(20), CustomerPhoneVARCHAR(20), CustomerNameVARCHAR(20), CustomerEmailVARCHAR(100), CommentsVARCHAR(500), BookTimeTIMESTAMPDEFAULTnow(), BookStatusINTDEFAULT0--(0表示未审核,1表示审核通过,2表示消费完成,-1表示撤销订单) )engine=innodbDEFAULTcharset=utf8; ALTERTABLEDishBookAUTO_INCREMENT=1000; --招聘信息表 CREATETABLEifnotEXISTSRecruitment ( PostIdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, PostNameNVARCHAR(100), PostTypeCHAR(4),--(全职或兼职) WorkPlaceNVARCHAR(50), PostDescTEXT, PostRequireTEXT, ExperienceNVARCHAR(100), EduBackgroundNVARCHAR(100), RequireCountINT, PublishTimeTIMESTAMPDEFAULTnow(), ManagerVARCHAR(20), PhoneNumberVARCHAR(20), EmailVARCHAR(100) )engine=innodbDEFAULTcharset=utf8; ALTERTABLERecruitmentAUTO_INCREMENT=100000; --投诉建议表 CREATETABLEifnotEXISTSSuggestion ( IdINTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, CustomerNameVARCHAR(20), ConsumeDescTEXT, SuggestionDescTEXT, SuggestionTimeTIMESTAMPDEFAULTnow(), PhoneNumberVARCHAR(20), EmailVARCHAR(20), StatusIdINTDEFAULT0--(0:未受理;1:已经受理) )engine=innodbDEFAULTcharset=utf8; ALTERTABLESuggestionAUTO_INCREMENT=10000;
创建测试数据
--插入测试数据 --管理员信息 insertintoSysAdmins(LoginPwd,LoginName)values('123456','李浩'); insertintoSysAdmins(LoginPwd,LoginName)values('123456','赵雪伶'); --新闻分类 insertintoNewsCategory(CategoryName)values('公司新闻'); insertintoNewsCategory(CategoryName)values('社会新闻'); --菜品分类 insertintoDishCategory(CategoryName)values('川菜'); insertintoDishCategory(CategoryName)values('湘菜'); insertintoDishCategory(CategoryName)values('鲁菜'); insertintoDishCategory(CategoryName)values('海鲜类'); insertintoDishCategory(CategoryName)values('其他'); --新闻 insertintoNews(NewsTitle,NewsContent,CategoryId)values('迎接十一海鲜大促销','最新鲜的鱼类全面上市,欢迎新老顾客品尝。',1); insertintoNews(NewsTitle,NewsContent,CategoryId)values('本店正在热招加盟商','如果您愿意在酒店行业有所突破,请加入我们。',1); insertintoNews(NewsTitle,NewsContent,CategoryId)values('互联网的消费正在兴起','网上购物已经成为人们生活必不可少的一部分。',2); insertintoNews(NewsTitle,NewsContent,CategoryId)values('本店正在热招加盟商','如果您愿意在酒店行业有所突破,请加入我们。',1); insertintoNews(NewsTitle,NewsContent,CategoryId)values('互联网的消费正在兴起','网上购物已经成为人们生活必不可少的一部分。',2); --菜品信息 insertintoDishes(DishName,UnitPrice,CategoryId)values('水煮鱼',50,1); insertintoDishes(DishName,UnitPrice,CategoryId)values('回锅肉',85,1); insertintoDishes(DishName,UnitPrice,CategoryId)values('剁椒鱼头',75,2); insertintoDishes(DishName,UnitPrice,CategoryId)values('红椒腊牛肉',40,2); insertintoDishes(DishName,UnitPrice,CategoryId)values('糖醋鲤鱼',70,3); insertintoDishes(DishName,UnitPrice,CategoryId)values('玉记扒鸡',60,3); insertintoDishes(DishName,UnitPrice,CategoryId)values('汤爆双脆',90,3); insertintoDishes(DishName,UnitPrice,CategoryId)values('赤贝',80,4); --预定信息 insertintoDishBook(HotelName,ConsumeTime,ConsumePersons,RoomType,CustomerName,CustomerPhone,CustomerEmail,Comments) values('天津南开店','2014-09-1112:30',5,'包间','李丽','13589011222','lilivip@163.com','希望房间敞亮些'); insertintoDishBook(HotelName,ConsumeTime,ConsumePersons,RoomType,CustomerName,CustomerPhone,CustomerEmail,Comments) values('天津和平店','2014-10-1114:30',5,'包间','王鑫新','13889018888','wangxinxin@qq.com','希望房间安静些'); insertintoDishBook(HotelName,ConsumeTime,ConsumePersons,RoomType,CustomerName,CustomerPhone,CustomerEmail,Comments) values('北京朝阳点','2014-12-1017:30',5,'散座','刘花雨','13689011999','liuhuayu@126.com','房间靠里面点儿'); --招聘信息 insertintoRecruitment(PostName,PostType,WorkPlace,PostDesc,PostRequire,Experience,EduBackground,RequireCount,Manager,PhoneNumber,Email) values('大堂经理','全职','天津','负责一层楼的管理','要求具备该职位3年以上经营管理经验','3年','本科',2,'李超阳','15689011231','lichaoyang@hyl.com'); insertintoRecruitment(PostName,PostType,WorkPlace,PostDesc,PostRequire,Experience,EduBackground,RequireCount,Manager,PhoneNumber,Email) values('接待员','全职','北京','负责客户的接待礼仪','要求具备该职位1年以上经验','1年','高中',5,'李超阳','15689011231','lichaoyang@hyl.com'); insertintoRecruitment(PostName,PostType,WorkPlace,PostDesc,PostRequire,Experience,EduBackground,RequireCount,Manager,PhoneNumber,Email) values('总经理助理','全职','天津','负责日常的文秘工作','要求具备该职位3年以上经营管理经验','3年','本科',1,'李超阳','15689011231','lichaoyang@hyl.com'); --投诉建议 insertintoSuggestion(CustomerName,ConsumeDesc,SuggestionDesc,PhoneNumber,Email) values('杜小杰','在该店举行一次婚礼','感觉总体服务不到位,菜品味道没有以前的好。','15687423456','duxiaojie@qq.com'); insertintoSuggestion(CustomerName,ConsumeDesc,SuggestionDesc,PhoneNumber,Email) values('柳钢','在本店聚会一次','感觉上菜有点慢,希望后续改进。','15686623456','liugang@qq.com');
二、搭建项目框架
1.使用vscode创建一个mvc项目
进入vscode,打开终端创建项目的根目录
快捷键:Ctrl+`
创建项目根目录
D:\dotnet_core>mkdirHotelWebMVC D:\dotnet_core>dir 驱动器D中的卷是补充 卷的序列号是0004-524D D:\dotnet_core的目录 2019/12/1009:33. 2019/12/1009:33 .. 2019/08/3016:31 .vscode 2018/05/0720:25 helloworld 2019/12/1009:33 HotelWebMVC 2019/12/0920:22 netcore_mvc
安装.NETCoreSDK
下载地址: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>dotnetnew--help 用法:new[选项] 选项: -h,--helpDisplayshelpforthiscommand. -l,--listListstemplatescontainingthespecifiedname.Ifnonameisspecified,listsalltemplates. -n,--nameThenamefortheoutputbeingcreated.Ifnonameisspecified,thenameofthecurrentdirectoryisused. -o,--outputLocationtoplacethegeneratedoutput. -i,--installInstallsasourceoratemplatepack. -u,--uninstallUninstallsasourceoratemplatepack. --nuget-sourceSpecifiesaNuGetsourcetouseduringinstall. --typeFilterstemplatesbasedonavailabletypes.Predefinedvaluesare"project","item"or"other". --dry-runDisplaysasummaryofwhatwouldhappenifthegivencommandlinewererunifitwouldresultinatemplatecreation. --forceForcescontenttobegeneratedevenifitwouldchangeexistingfiles. -lang,--languageFilterstemplatesbasedonlanguageandspecifiesthelanguageofthetemplatetocreate. --update-checkCheckthecurrentlyinstalledtemplatepacksforupdates. --update-applyCheckthecurrentlyinstalledtemplatepacksforupdate,andinstalltheupdates.
创建项目
比如添加解决方案
D:\dotnet_core\HotelWebMVC>dotnetsln./HotelWebMVC.slnaddDAL\DAL.csproj 已将项目“DAL\DAL.csproj”添加到解决方案中。 D:\dotnet_core\HotelWebMVC>dotnetsln./HotelWebMVC.slnaddBLL\BLL.csproj 已将项目“BLL\BLL.csproj”添加到解决方案中。 D:\dotnet_core\HotelWebMVC>dotnetslnlist 项目 -- HotelWebMVC\HotelWebMVC.csproj Models\Models.csproj DAL\DAL.csproj BLL\BLL.csproj
添加启动项目和类库项目之间的引用
Models-->DAL
D:\dotnet_core\HotelWebMVC\DAL>dotnetaddreference..\Models\Models.csproj 已将引用“..\Models\Models.csproj”添加到项目。
DAL—>BLL
D:\dotnet_core\HotelWebMVC\DAL>dotnetadd..\bll\BLL.csprojreference.\DAL.csproj 已将引用“..\DAL\DAL.csproj”添加到项目。
HotelWebMVC-->BLL
D:\dotnet_core\HotelWebMVC\DAL>dotnetadd..\HotelWebMVC\HotelWebMVC.csprojreference..\bll\BLL.csproj 已将引用“..\bll\BLL.csproj”添加到项目。
2.生成Model
①使用EFCore生成模型
DBFirst模式
全局安装ef工具
dotnettoolinstall--globaldotnet-ef
测试工具是否安装成功
D:\dotnet_core\HotelWebMVC>dotnetef _/\__ ---==/\\ ______|.\|\ |__||__||)\\\ |_||_|\_/|//|\\ |___||_|/\\\/\\ EntityFrameworkCore.NETCommand-lineTools3.1.0 Usage:dotnetef[options][command] Options: --versionShowversioninformation -h|--helpShowhelpinformation -v|--verboseShowverboseoutput. --no-colorDon'tcolorizeoutput. --prefix-outputPrefixoutputwithlevel. Commands: databaseCommandstomanagethedatabase. dbcontextCommandstomanageDbContexttypes. migrationsCommandstomanagemigrations. Use"dotnetef[command]--help"formoreinformationaboutacommand.
只要看到有这个独角兽就代表安装成功了。
添加需要的NuGet包
dotnetaddpackageMicrosoft.EntityFrameworkCore.Design dotnetaddpackagePomelo.EntityFrameworkCore.MySql
使用EF工具
查看帮助
D:\dotnet_core\HotelWebMVC\DAL>dotnetefdbcontextscaffold--help Usage:dotnetefdbcontextscaffold[arguments][options] Arguments:Theconnectionstringtothedatabase. Theprovidertouse.(E.g.Microsoft.EntityFrameworkCore.SqlServer) Options: -d|--data-annotationsUseattributestoconfigurethemodel(wherepossible).Ifomitted,onlythefluentAPIisused. -c|--context ThenameoftheDbContext. --context-dir ThedirectorytoputDbContextfilein.Pathsarerelativetotheprojectdirectory. -f|--forceOverwriteexistingfiles. -o|--output-dir Thedirectorytoputfilesin.Pathsarerelativetotheprojectdirectory. --schema ...Theschemasoftablestogenerateentitytypesfor. -t|--table ...Thetablestogenerateentitytypesfor. --use-database-namesUsetableandcolumnnamesdirectlyfromthedatabase. --jsonShowJSONoutput. -p|--project Theprojecttouse. -s|--startup-project Thestartupprojecttouse. --framework Thetargetframework. --configuration Theconfigurationtouse. --runtime Theruntimetouse. --msbuildprojectextensionspath TheMSBuildprojectextensionspath.Defaultsto"obj". --no-buildDon'tbuildtheproject.Onlyusethiswhenthebuildisup-to-date. -h|--helpShowhelpinformation -v|--verboseShowverboseoutput. --no-colorDon'tcolorizeoutput. --prefix-outputPrefixoutputwithlevel.
连接数据库生成模型数据
D:\dotnet_core\HotelWebMVC\DAL>dotnetefdbcontextscaffold"Server=192.168.30.110,3306;DataBase=HotelWebDb;User=sa;Pwd=110;""Pomelo.EntityFrameworkCore.MySql"-s..\HotelWebMVC\HotelWebMVC.csproj Buildstarted... Buildsucceeded.
修改在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文件获取连接字符串
publicvoidConfigureServices(IServiceCollectionservices) { services.AddControllersWithViews(); stringconnString=Configuration.GetConnectionString("HotelWeb"); services.AddDbContext(options=>options.UseMySql(connString,x=>x.ServerVersion("5.5.64-mariadb"))); }
最后DbContenxt类中配置就可以删除了
移动DAL生成的实体类到Models模块
修改实体类中的命名空间
②另一种使用ADO.NET实现
不是这次的重点,所以略过。
三、编写Model部分的代码
1.编写一个简单的Helper类
usingMicrosoft.EntityFrameworkCore; namespaceDAL { classEFCoreHelper { privateDbContextdbContext=null; publicEFCoreHelper(DbContextcontext) { this.dbContext=context; } //////添加实体 /// ///publicintAdd (Tentity)whereT:class { dbContext.Entry(entity).State=EntityState.Added; returndbContext.SaveChanges(); } /// ///修改实体的全部属性 /// ///publicintModify (Tentity)whereT:class { dbContext.Entry(entity).State=EntityState.Modified; returndbContext.SaveChanges(); } /// ///删除实体 /// ///publicintDelete (Tentity)whereT:class { dbContext.Entry(entity).State=EntityState.Deleted; returndbContext.SaveChanges(); } } }
2.完成新闻后台数据访问类
数据访问类
usingSystem; usingSystem.Linq; usingSystem.Collections.Generic; usingModels; namespaceDAL { publicclassNewsService { privateEFCoreHelperhelper=newEFCoreHelper(newHotelWebDbContext()); //////添加新闻 /// ////// publicintAddNews(Newsnews)=>helper.Add(news); /// ///修改新闻 /// ////// publicintModifyNews(Newsnews)=>helper.Modify(news); /// ///删除新闻 /// ////// publicintDeleteNews(stringnewssId) { Newsnews=newNews(){Id=Convert.ToUInt32(newssId)}; returnhelper.Delete(news); } /// ///获取指定数量的新闻列表 /// ////// publicList GetNews(intcount) { using(HotelWebDbContextdbContext=newHotelWebDbContext()) { return(fromnindbContext.Newsorderbyn.PublishTimedescendingselectn).Take(count).ToList(); } } /// ///根据ID获取新闻信息 /// ////// publicNewsGetNewsById(stringnewssId) { uintid=Convert.ToUInt32(newssId); using(HotelWebDbContextdbContext=newHotelWebDbContext()) { return(fromnindbContext.Newswheren.Id==idselectn).FirstOrDefault(); } } /// ///获取所有的新闻分类 /// ///publicList GetCategories() { using(HotelWebDbContextdbContext=newHotelWebDbContext()) { return(fromcindbContext.NewsCategoryselectc).ToList(); } } } }
业务逻辑部分
usingSystem.Collections.Generic; usingDAL; usingModels; namespaceBLL { publicclassNewsManager { privateNewsServiceobjService=newNewsService(); //////添加新闻 /// ////// publicintAddNews(Newsnews)=>objService.AddNews(news); /// ///修改新闻 /// ////// publicintModifyNews(Newsnews)=>objService.ModifyNews(news); /// ///删除新闻 /// ////// publicintDeleteNews(stringnewssId)=>objService.DeleteNews(newssId); /// ///获取指定数量的新闻列表 /// ////// publicList GetNews(intcount)=>objService.GetNews(count); /// ///根据ID获取新闻信息 /// ////// publicNewsGetNewsById(stringnewssId)=>objService.GetNewsById(newssId); /// ///获取所有的新闻分类 /// ///publicList GetCategories()=>objService.GetCategories(); } }
3.添加一个控制台项目用来测试
添加需要的引用
dotnetaddpackageMicrosoft.EntityFrameworkCore.Design dotnetaddpackagePomelo.EntityFrameworkCore.MySql
DbContext中的数据库连接字符串添加回去
protectedoverridevoidOnConfiguring(DbContextOptionsBuilderoptionsBuilder) { if(!optionsBuilder.IsConfigured) { optionsBuilder.UseMySql("Server=192.168.30.110;DataBase=HotelWebDb;User=sa;Pwd=110;",x=>x.ServerVersion("5.5.64-mariadb")); } }
编写测试代码
Newsnews=newNews() { NewsContent="你好这是一个测试新闻内容", NewsTitle="测试新闻", CategoryId=1 }; Console.WriteLine(objNews.AddNews(news));
启动调试
选择启动项目有两种方法
①通过solutionexplorer插件选择
{ "name":".NETCoreLaunch(console)", "type":"coreclr", "request":"launch", "preLaunchTask":"build", "program":"${workspaceFolder}/UnitTestPro/bin/Debug/netcoreapp3.1/UnitTestPro.dll", "args":[], "cwd":"${workspaceFolder}", "stopAtEntry":false, "console":"internalConsole" },
结果查验
结果符合预期
注意事项
修改新闻调用的方法不支持部分属性修改,如果对象属性不设置,那么没有设置的字段被设置为空。
后面有字段部分修改的方法。
Newsnews=newNews() { Id=1008, NewsContent="修改新闻的内容", NewsTitle="这是被修改的新闻标题", }; Console.WriteLine(objNews.ModifyNews(news));
4.编写菜品预订
5.编写招聘
6.编写投诉和建议
7.管理员登录
类似不再贴代码
四、前端UI实现
1.完成前端Html代码的编写
不多说
2.完成MVC项目中控制器和视图的文件添加
这个只能手动添加,不像VS有模板可用
3.复制网站的静态资源
asp.netcore网站静态资源都是放在wwwroot目录的,并且文件名一般是小写。
4.在视图中引用资源
MVC框架可以直接识别在wwwroot中的静态资源,不用写显示的写出目录名。
5.编写动作方法
publicIActionResultIndex() { returnView(); }
6.添加视图
7.启动调试
首页效果图
8.视图与控制器之间传递数据
使用ViewData
视图的网页标题可以使用这种方式传递
publicIActionResultIndex() { ViewData["title"]="好运来酒店"; ViewBag.list=newNewsManager().GetNews(4); returnView(); }
视图中引用数据
@ViewData["title"]-舒适快捷经济
使用ViewBag
这是所谓的动态类型,直接无中生有造一个属性
ViewBag.list=newNewsManager().GetNews(4);
视图中引用
@foreach(Newsitemin@ViewBag.list){@item.NewsTitle