版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
附錄A外文翻譯—原文部分文章來源:NateBarbettiniTheLittleASP.NETCoreBook[Z]ADDINCNKISM.UserStyleCreateacontrollerTherearealreadyafewcontrollersintheproject'sControllersdirectory,includingtheHomeControllerthatrendersthedefaultwelcomescreenyouseewhenyouvisithttp://localhost:5000.Youcanignorethesecontrollersfornow.Createanewcontrollerfortheto-dolistfunctionality,calledTodoController,andaddthefollowingcode:Controllers/TodoController.csusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading.Tasks;usingMicrosoft.AspNetCore.Mvc;namespaceAspNetCoreTodo.Controllers{publicclassTodoController:Controller{//Actionsgohere}}Routesthatarehandledbycontrollersarecalledactions,andarerepresentedbymethodsinthecontrollerclass.Forexample,theHomeControllerincludesthreeactionmethods(Index,About,andContact)whicharemappedbyASP.NETCoretotheserouteURLs:localhost:5000/Home->Index()localhost:5000/Home/About->About()localhost:5000/Home/Contact->Contact()Thereareanumberofconventions(commonpatterns)usedbyASP.NETCore,suchasthepatternthatFooControllerbecomes/Foo,andtheIndexactionnamecanbeleftoutoftheURL.Youcancustomizethisbehaviorifyou'dlike,butfornow,we'llsticktothedefaultconventions.AddanewactioncalledIndextotheTodoController,replacingthe//Actionsgoherecomment:publicclassTodoController:Controller{publicIActionResultIndex(){//Getto-doitemsfromdatabase//Putitemsintoamodel//Renderviewusingthemodel}}Actionmethodscanreturnviews,JSONdata,orHTTPstatuscodeslike200OKand404NotFound.TheIActionResultreturntypegivesyoutheflexibilitytoreturnanyofthesefromtheaction.It'sabestpracticetokeepcontrollersaslightweightaspossible.Inthiscase,thecontrollerwillberesponsibleforgettingtheto-doitemsfromthedatabase,puttingthoseitemsintoamodeltheviewcanunderstand,andsendingtheviewbacktotheuser'sbrowser.Beforeyoucanwritetherestofthecontrollercode,youneedtocreateamodelandaview.CreatemodelsTherearetwoseparatemodelclassesthatneedtobecreated:amodelthatrepresentsato-doitemstoredinthedatabase(sometimescalledanentity),andthemodelthatwillbecombinedwithaview(theMVinMVC)andsentbacktotheuser'sbrowser.Becausebothofthemcanbereferredtoas"models",I'llrefertothelatterasaviewmodel.First,createaclasscalledTodoItemintheModelsdirectory:Models/TodoItem.csusingSystem;usingSystem.ComponentModel.DataAnnotations;namespaceAspNetCoreTodo.Models{publicclassTodoItem{publicGuidId{get;set;}publicboolIsDone{get;set;}[Required]publicstringTitle{get;set;}publicDateTimeOffset?DueAt{get;set;}}}Thisclassdefineswhatthedatabasewillneedtostoreforeachto-doitem:anID,atitleorname,whethertheitemiscomplete,andwhattheduedateis.Eachlinedefinesapropertyoftheclass:TheIdpropertyisaguid,oragloballyuniqueidentifier.Guids(orGUIDs)arelongstringsoflettersandnumbers,like43ec09f2-7f70-4f4b-9559-65011d5781bb.Becauseguidsarerandomandareextremelyunlikelytobeaccidentallyduplicated,theyarecommonlyusedasuniqueIDs.Youcouldalsouseanumber(integer)asadatabaseentityID,butyou'dneedtoconfigureyourdatabasetoalwaysincrementthenumberwhennewrowsareaddedtothedatabase.Guidsaregeneratedrandomly,soyoudon'thavetoworryaboutauto-incrementing.TheIsDonepropertyisaboolean(true/falsevalue).Bydefault,itwillbefalseforallnewitems.Lateryou'llusewritecodetoswitchthispropertytotruewhentheuserclicksanitem'scheckboxintheview.TheTitlepropertyisastring(textvalue).Thiswillholdthenameordescriptionoftheto-doitem.The[Required]attributetellsASP.NETCorethatthisstringcan'tbenullorempty.TheDueAtpropertyisaDateTimeOffset,whichisaC#typethatstoresadate/timestampalongwithatimezoneoffsetfromUTC.Storingthedate,time,andtimezoneoffsettogethermakesiteasytorenderdatesaccuratelyonsystemsindifferenttimezones.Noticethe?questionmarkaftertheDateTimeOffsettype?ThatmarkstheDueAtpropertyasnullable,oroptional.Ifthe?wasn'tincluded,everyto-doitemwouldneedtohaveaduedate.TheIdandIsDonepropertiesaren'tmarkedasnullable,sotheyarerequiredandwillalwayshaveavalue(oradefaultvalue).StringsinC#arealwaysnullable,sothere'snoneedtomarktheTitlepropertyasnullable.C#stringscanbenull,empty,orcontaintext.Eachpropertyisfollowedbyget;set;,whichisashorthandwayofsayingthepropertyisread/write(or,moretechnically,ithasagetterandsettermethods).Atthispoint,itdoesn'tmatterwhattheunderlyingdatabasetechnologyis.ItcouldbeSQLServer,MySQL,MongoDB,Redis,orsomethingmoreexotic.ThismodeldefineswhatthedatabaseroworentrywilllooklikeinC#soyoudon'thavetoworryaboutthelow-leveldatabasestuffinyourcode.Thissimplestyleofmodelissometimescalleda"plainoldC#object"orPOCO.TheviewmodelOften,themodel(entity)youstoreinthedatabaseissimilarbutnotexactlythesameasthemodelyouwanttouseinMVC(theviewmodel).Inthiscase,theTodoItemmodelrepresentsasingleiteminthedatabase,buttheviewmightneedtodisplaytwo,ten,orahundredto-doitems(dependingonhowbadlytheuserisprocrastinating).Becauseofthis,theviewmodelshouldbeaseparateclassthatholdsanarrayofTodoItems:Models/TodoViewModel.csnamespaceAspNetCoreTodo.Models{publicclassTodoViewModel{publicTodoItem[]Items{get;set;}}}Nowthatyouhavesomemodels,it'stimetocreateaviewthatwilltakeaTodoViewModelandrendertherightHTMLtoshowtheusertheirto-dolist.CreateaviewViewsinASP.NETCorearebuiltusingtheRazortemplatinglanguage,whichcombinesHTMLandC#code.(Ifyou'vewrittenpagesusingHandlebarsmoustaches,ERBinRubyonRails,orThymeleafinJava,you'vealreadygotthebasicidea.)MostviewcodeisjustHTML,withtheoccasionalC#statementaddedintopulldataoutoftheviewmodelandturnitintotextorHTML.TheC#statementsareprefixedwiththe@symbol.TheviewrenderedbytheIndexactionoftheTodoControllerneedstotakethedataintheviewmodel(asequenceofto-doitems)anddisplayitinanicetablefortheuser.Byconvention,viewsareplacedintheViewsdirectory,inasubdirectorycorrespondingtothecontrollername.Thefilenameoftheviewisthenameoftheactionwitha.cshtmlextension.CreateaTododirectoryinsidetheViewsdirectory,andaddthisfile:Views/Todo/Index.cshtml@modelTodoViewModel@{ViewData["Title"]="Manageyourtodolist";}<divclass="panelpanel-defaulttodo-panel"><divclass="panel-heading">@ViewData["Title"]</div><tableclass="tabletable-hover"><thead><tr><td>✔</td><td>Item</td><td>Due</td></tr></thead>@foreach(variteminModel.Items){<tr><td><inputtype="checkbox"class="done-checkbox"></td><td>@item.Title</td><td>@item.DueAt</td></tr>}</table><divclass="panel-footeradd-item-form"><!--TODO:Additemform--></div></div>Attheverytopofthefile,the@modeldirectivetellsRazorwhichmodeltoexpectthisviewtobeboundto.ThemodelisaccessedthroughtheModelproperty.Assumingthereareanyto-doitemsinModel.Items,theforeachstatementwillloopovereachto-doitemandrenderatablerow(<tr>element)containingtheitem'snameandduedate.Acheckboxisalsorenderedthatwilllettheusermarktheitemascomplete.ThelayoutfileYoumightbewonderingwheretherestoftheHTMLis:whataboutthe<body>tag,ortheheaderandfooterofthepage?ASP.NETCoreusesalayoutviewthatdefinesthebasestructurethateveryotherviewisrenderedinsideof.It'sstoredinViews/Shared/_Layout.cshtml.ThedefaultASP.NETCoretemplateincludesBootstrapandjQueryinthislayoutfile,soyoucanquicklycreateawebapplication.Ofcourse,youcanuseyourownCSSandJavaScriptlibrariesifyou'dlike.CustomizingthestylesheetThedefaulttemplatealsoincludesastylesheetwithsomebasicCSSrules.Thestylesheetisstoredinthewwwroot/cssdirectory.AddafewnewCSSstylerulestothebottomofthesite.cssfile:wwwroot/css/site.cssdiv.todo-panel{margin-top:15px;}tabletr.done{text-decoration:line-through;color:#888;}YoucanuseCSSruleslikethesetocompletelycustomizehowyourpageslookandfeel.ASP.NETCoreandRazorcandomuchmore,suchaspartialviewsandserver-renderedviewcomponents,butasimplelayoutandviewisallyouneedfornow.TheofficialASP.NETCoredocumentation(at)containsanumberofexamplesifyou'dliketolearnmore.AddaserviceclassYou'vecreatedamodel,aview,andacontroller.Beforeyouusethemodelandviewinthecontroller,youalsoneedtowritecodethatwillgettheuser'sto-doitemsfromadatabase.Youcouldwritethisdatabasecodedirectlyinthecontroller,butit'sabetterpracticetokeepyourcodeseparate.Why?Inabig,real-worldapplication,you'llhavetojugglemanyconcerns:Renderingviewsandhandlingincomingdata:thisiswhatyourcontrolleralreadydoes.Performingbusinesslogic,orcodeandlogicthat'srelatedtothepurposeand"business"ofyourapplication.Inato-dolistapplication,businesslogicmeansdecisionslikesettingadefaultduedateonnewtasks,oronlydisplayingtasksthatareincomplete.Otherexamplesofbusinesslogicincludecalculatingatotalcostbasedonproductpricesandtaxrates,orcheckingwhetheraplayerhasenoughpointstolevelupinagame.Savingandretrievingitemsfromadatabase.Again,it'spossibletodoallofthesethingsinasingle,massivecontroller,butthatquicklybecomestoohardtomanageandtest.Instead,it'scommontoseeapplicationssplitupintotwo,three,ormore"layers"ortiersthateachhandleone(andonlyone)concern.Thishelpskeepthecontrollersassimpleaspossible,andmakesiteasiertotestandchangethebusinesslogicanddatabasecodelater.Separatingyourapplicationthiswayissometimescalledamulti-tierorn-tierarchitecture.Insomecases,thetiers(layers)areisolatedincompletelyseparateprojects,butothertimesitjustreferstohowtheclassesareorganizedandused.Theimportantthingisthinkingabouthowtosplityourapplicationintomanageablepieces,andavoidhavingcontrollersorbloatedclassesthattrytodoeverything.Forthisproject,you'llusetwoapplicationlayers:apresentationlayermadeupofthecontrollersandviewsthatinteractwiththeuser,andaservicelayerthatcontainsbusinesslogicanddatabasecode.Thepresentationlayeralreadyexists,sothenextstepistobuildaservicethathandlesto-dobusinesslogicandsavesto-doitemstoadatabase.Mostlargerprojectsusea3-tierarchitecture:apresentationlayer,aservicelogiclayer,andadatarepositorylayer.Arepositoryisaclassthat'sonlyfocusedondatabasecode(nobusinesslogic).Inthisapplication,you'llcombinetheseintoasingleservicelayerforsimplicity,butfeelfreetoexperimentwithdifferentwaysofarchitectingthecode.CreateaninterfaceTheC#languageincludestheconceptofinterfaces,wherethedefinitionofanobject'smethodsandpropertiesisseparatefromtheclassthatactuallycontainsthecodeforthosemethodsandproperties.Interfacesmakeiteasytokeepyourclassesdecoupledandeasytotest,asyou'llseehere(andlaterintheAutomatedtestingchapter).You'lluseaninterfacetorepresenttheservicethatcaninteractwithto-doitemsinthedatabase.Byconvention,interfacesareprefixedwith"I".CreateanewfileintheServicesdirectory:Services/ITodoItemService.csusingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;usingAspNetCoreTodo.Models;namespaceAspNetCoreTodo.Services{publicinterfaceITodoItemService{Task<TodoItem[]>GetIncompleteItemsAsync();}}NotethatthenamespaceofthisfileisAspNetCoreTodo.Services.Namespacesareawaytoorganize.NETcodefiles,andit'scustomaryforthenamespacetofollowthedirectorythefileisstoredin(AspNetCoreTodo.ServicesforfilesintheServicesdirectory,andsoon).Becausethisfile(intheAspNetCoreTodo.Servicesnamespace)referencestheTodoItemclass(intheAspNetCoreTodo.Modelsnamespace),itneedstoincludeausingstatementatthetopofthefiletoimportthatnamespace.Withouttheusingstatement,you'llseeanerrorlike:Thetypeornamespacename'TodoItem'couldnotbefound(areyoumissingausingdirectiveoranassemblyreference?)Sincethisisaninterface,thereisn'tanyactualcodehere,justthedefinition(ormethodsignature)oftheGetIncompleteItemsAsyncmethod.ThismethodrequiresnoparametersandreturnsaTask<TodoItem[]>.Ifthissyntaxlooksconfusing,think:"aTaskthatcontainsanarrayofTodoItems".TheTasktypeissimilartoafutureorapromise,andit'susedherebecausethismethodwillbeasynchronous.Inotherwords,themethodmaynotbeabletoreturnthelistofto-doitemsrightawaybecauseitneedstogotalktothedatabasefirst.(Moreonthislater.)CreatetheserviceclassNowthattheinterfaceisdefined,you'rereadytocreatetheactualserviceclass.I'llcoverdatabasecodeindepthintheUseadatabasechapter,sofornowyou'lljustfakeitandalwaysreturntwohard-codeditems:Services/FakeTodoItemService.csusingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;usingAspNetCoreTodo.Models;namespaceAspNetCoreTodo.Services{publicclassFakeTodoItemService:ITodoItemService{publicTask<TodoItem[]>GetIncompleteItemsAsync(){varitem1=newTodoItem{Title="LearnASP.NETCore",DueAt=DateTimeOffset.Now.AddDays(1)};varitem2=newTodoItem{Title="Buildawesomeapps",DueAt=DateTimeOffset.Now.AddDays(2)};returnTask.FromResult(new[]{item1,item2});}}}ThisFakeTodoItemServiceimplementstheITodoItemServiceinterfacebutalwaysreturnsthesamearrayoftwoTodoItems.You'llusethistotestthecontrollerandview,andthenaddrealdatabasecodeinUseadatabase.UsedependencyinjectionBackintheTodoController,addsomecodetoworkwiththeITodoItemService:publicclassTodoController:Controller{privatereadonlyITodoItemService_todoItemService;publicTodoController(ITodoItemServicetodoItemService){_todoItemService=todoItemService;}publicIActionResultIndex(){//Getto-doitemsfromdatabase//Putitemsintoamodel//Passtheviewtoamodelandrender}}SinceITodoItemServiceisintheServicesnamespace,you'llalsoneedtoaddausingstatementatthetop:usingAspNetCoreTodo.Services;ThefirstlineoftheclassdeclaresaprivatevariabletoholdareferencetotheITodoItemService.ThisvariableletsyouusetheservicefromtheIndexactionmethodlater(you'llseehowinaminute).ThepublicTodoController(ITodoItemServicetodoItemService)linedefinesaconstructorfortheclass.Theconstructorisaspecialmethodthatiscalledwhenyouwanttocreateanewinstanceofaclass(theTodoControllerclass,inthiscase).ByaddinganITodoItemServiceparametertotheconstructor,you'vedeclaredthatinordertocreatetheTodoController,you'llneedtoprovideanobjectthatmatchestheITodoItemServiceinterface.Interfacesareawesomebecausetheyhelpdecouple(separate)thelogicofyourapplication.SincethecontrollerdependsontheITodoItemServiceinterface,andnotonanyspecificclass,itdoesn'tknoworcarewhichclassit'sactuallygiven.ItcouldbetheFakeTodoItemService,adifferentonethattalkstoalivedatabase,orsomethingelse!Aslongasitmatchestheinterface,thecontrollercanuseit.Thismakesitreallyeasytotestpartsofyourapplicationseparately.I'llcovertestingindetailintheAutomatedtestingchapter.NowyoucanfinallyusetheITodoItemService(viatheprivatevariableyoudeclared)inyouractionmethodtogetto-doitemsfromtheservicelayer:publicIActionResultIndex(){varitems=await_todoItemService.GetIncompleteItemsAsync();//...}RememberthattheGetIncompleteItemsAsyncmethodreturnedaTask<TodoItem[]>?ReturningaTaskmeansthatthemethodwon'tnecessarilyhavearesultrightaway,butyoucanusetheawaitkeywordtomakesureyourcodewaitsuntiltheresultisreadybeforecontinuingon.TheTaskpatterniscommonwhenyourcodecallsouttoadatabaseoranAPIservice,becauseitwon'tbeabletoreturnarealresultuntilthedatabase(ornetwork)responds.Ifyou'veusedpromisesorcallbacksinJavaScriptorotherlanguages,Taskisthesameidea:thepromisethattherewillbearesult-sometimeinthefuture.Ifyou'vehadtodealwith"callbackhell"inolderJavaScriptcode,you'reinluck.Dealingwithasynchronouscodein.NETismucheasierthankstothemagicoftheawaitkeyword!awaitletsyourcodepauseonanasyncoperation,andthenpickupwhereitleftoffwhentheunderlyingdatabaseornetworkrequestfinishes.Inthemeantime,yourapplicationisn'tblocked,becauseitcanprocessotherrequestsasneeded.Thispatternissimplebuttakesalittlegettingusedto,sodon'tworryifthisdoesn'tmakesenserightaway.Justkeepfollowingalong!TheonlycatchisthatyouneedtoupdatetheIndexmethodsignaturetoreturnaTask<IActionResult>insteadofjustIActionResult,andmarkitasasync:publicasyncTask<IActionResult>Index(){varitems=await_todoItemService.GetIncompleteItemsAsync();//Putitemsintoamodel//Passtheviewtoamodelandrender}You'realmostthere!You'vemadetheTodoControllerdependontheITodoItemServiceinterface,butyouhaven'tyettoldASP.NETCorethatyouwanttheFakeTodoItemServicetobetheactualservicethat'susedunderthehood.ItmightseemobviousrightnowsinceyouonlyhaveoneclassthatimplementsITodoItemService,butlateryou'llhavemultipleclassesthatimplementthesameinterface,sobeingexplicitisnecessary.Declaring(or"wiringup")whichconcreteclasstouseforeachinterfaceisdoneintheConfigureServicesmethodoftheStartupclass.Rightnow,itlookssomethinglikethis:Startup.cspublicvoidConfigureServices(IServiceCollectionservices){//(...somecode)services.AddMvc();}ThejoboftheConfigureServicesmethodisaddingthingstotheservicecontainer,orthecollectionofservicesthatASP.NETCoreknowsabout.Theservices.AddMvclineaddstheservicesthattheinternalASP.NETCoresystemsneed(asanexperiment,trycommentingoutthisline).AnyotherservicesyouwanttouseinyourapplicationmustbeaddedtotheservicecontainerhereinConfigureServices.AddthefollowinglineanywhereinsidetheConfigureServicesmethod:services.AddSingleton<ITodoItemService,FakeTodoItemService>();ThislinetellsASP.NETCoretousetheFakeTodoItemServicewhenevertheITodoItemServiceinterfaceisrequestedinaconstructor(oranywhereelse).AddSingletonaddsyourservicetotheservicecontainerasasingleton.ThismeansthatonlyonecopyoftheFakeTodoItemServiceiscreated,andit'sreusedwhenevertheserviceisrequested.Later,whenyouwriteadifferentserviceclassthattalkstoadatabase,you'lluseadifferentapproach(calledscoped)instead.I'llexplainwhyintheUseadatabasechapter.That'sit!WhenarequestcomesinandisroutedtotheTodoController,ASP.NETCorewilllookattheavailableservicesandautomaticallysupplytheFakeTodoItemServicewhenthecontrollerasksforanITodoItemService.Becausetheservicesare"injected"fromtheservicecontainer,thispatterniscalleddependencyinjection.FinishthecontrollerThelaststepistofinishthecontrollercode.Thecontrollernowhasalistofto-doitemsfromtheservicelayer,anditneedstoputthoseitemsintoaTodoViewModelandbindthatmodeltotheviewyoucreatedearlier:Controllers/TodoController.cspublicasyncTask<IActionResult>Index(){varitems=await_todoItemService.GetIncompleteItemsAsync();varmodel=newTodoViewModel(){Items=items};returnView(model);}Ifyouhaven'talready,makesuretheseusingstatementsareatthetopofthefile:usingAspNetCoreTodo.Services;usingAspNetCoreTodo.Models;Ifyou'reusingVisualStudioorVisualStudioCode,theeditorwillsuggesttheseusingstatementswhenyouputyourcursoronaredsquigglyline.TestitoutTostarttheapplication,pressF5(ifyou'reusingVisualStudioorVisualStudioCode),orjusttypedotnetrunintheterminal.Ifthecodecompileswithouterrors,theserverwillstartuponport5000bydefault.Ifyourwebbrowserdidn'topenautomatically,openitandnavigatetohttp://localhost:5000/todo.You'llseetheviewyoucreated,withthedatapulledfromyourfakedatabase(fornow).Althoughit'spossibletogodirectlytohttp://localhost:5000/todo,itwouldbenicertoaddanitemcalledMyto-dostothenavbar.Todothis,youcaneditthesharedlayoutfile.UpdatethelayoutThelayoutfileatViews/Shared/_Layout.cshtmlcontainsthe"base"HTMLforeachview.Thisincludesthenavbar,whichisrenderedatthetopofeachpage.Toaddanewitemtothenavbar,findtheHTMLcodefortheexistingnavbaritems:Views/Shared/_Layout.cshtml<ulclass="navnavbar-nav"><li><aasp-area=""asp-controller="Home"asp-action="Index">Home</a></li><li><aasp-area=""asp-controller="Home"asp-action="About">About</a></li><li><aasp-area=""asp-controller="Home"asp-action="Contact">Contact</a></li></ul>AddyourownitemthatpointstotheTodocontrollerinsteadofHome:<li><aasp-controller="Todo"asp-action="Index">Myto-dos</a></li>Theasp-controllerandasp-actionattributesonthe<a>elementarecalledtaghelpers.Beforetheviewisrendered,ASP.NETCorereplacesthesetaghelperswithrealHTMLattributes.Inthiscase,aURLtothe/Todo/Indexrouteisgeneratedandaddedtothe<a>elementasanhrefattribute.Thismeansyoudon'thavetohard-codetheroutetotheTodoController.Instead,ASP.NETCoregeneratesitforyouautomatically.Ifyou'veusedRazorinASP.NET4.x,you'llnoticesomesyntaxchanges.Insteadofusing@Html.ActionLink()togeneratealinktoanaction,taghelpersarenowtherecommendedwaytocreatelinksinyourviews.Taghelpersareusefulforforms,too(you'llseewhyinalaterchapter).Youcanlearnaboutothertaghelpersinthedocumentationat.附錄B外文翻譯—譯文部分創(chuàng)建控制器在項目的Controllers目錄里,已經預置了幾個控制器,其中有渲染默認歡迎頁的HomeController,就是你訪問http://localhost:5000看到的那個頁面。暫時不用管這些控制器。給待辦清單功能創(chuàng)建一個新的控制器,取名叫TodoController,并添加如下代碼:Controllers/TodoController.csusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading.Tasks;usingMicrosoft.AspNetCore.Mvc;namespaceAspNetCoreTodo.Controllers{publicclassTodoController:Controller{//在這里添加Actions}}由控制器本身處理的路由叫action,在控制器類里用方法表示。比如,HomeController包含三個action方法(Index,About,和Contact),由ASP.NETCore分別映射到如下的URL:localhost:5000/Home->Index()localhost:5000/Home/About->About()localhost:5000/Home/Contact->Contact()ASP.NETCore中有幾個慣例(常見的模式),比如這個FooController映射到/Foo的模式,還有Index的action名可以在URL里省略。如果你有需要,可以自定義這些行為,不過就目前的情況,讓我們暫且遵循這些慣例。在TodoController里,添加一個名為Index的action,把那句//Actionsgohere注釋替換掉:publicclassTodoController:Controller{publicIActionResultIndex(){//從數(shù)據(jù)庫獲取to-do條目//把條目置于model中//使用model渲染視圖}}一個action方法可以返回視圖、JSON數(shù)據(jù),或者200OK和404NotFound之類的狀態(tài)碼。返回類型IActionResult給了你足夠的靈活性,以返回上面提到的任意一個。使控制器盡可能保持輕量化,是一個良好的習慣。在當前的情形里,這個控制器應該僅僅完成這些事情:從數(shù)據(jù)庫取出待辦事項的記錄,把這些事項包裝在一個可用于視圖的模型中,并把這個視圖發(fā)送到用戶的瀏覽器。繼續(xù)編碼這個控制器之前,你需要創(chuàng)建模型和視圖。創(chuàng)建模型我們需要創(chuàng)建兩個獨立的模型類:一個模型表示保存在數(shù)據(jù)庫里的條目(有時候也稱為一個記錄(entity)),另一個模型將與視圖結合(MVC里的MV)發(fā)送到用戶的瀏覽器。因為他們都可以被稱為模型,我將稱后者為視圖模型(viewmodel)。首先,在Models目錄下,創(chuàng)建一個名為TodoItem的類:Models/TodoItem.csusingSystem;namespaceAspNetCoreTodo.Models{publicclassTodoItem{publicGuidId{get;set;}publicboolIsDone{get;set;}publicstringTitle{get;set;}publicDateTimeOffset?DueAt{get;set;}}}這個類定義了每個待辦事項都要保存的內容:一個ID、一個標題或者名稱、該事項是否已經完成,以及截至日期是什么時候。每行定義了這個類的一個屬性:Id屬性是一個guid,或者說是全局(globally)唯一(unique)標識符(identifier).Guid(或者GUID)是一個由字母和數(shù)字組成的長長的字符串,看起來是這樣的43ec09f2-7f70-4f4b-9559-65011d5781bb。因為guid是隨機的,并極少會有重復值,所以常被用作唯一標識。你也可以用數(shù)字(整形integer)作為數(shù)據(jù)庫記錄的標識,但你需要在數(shù)據(jù)庫里配置,以便這個數(shù)字在添加新條目的時候始終增長。因為Guid是隨機生產的,所以就你不必再擔心這個自增的問題了。IsDone屬性是一個布爾值(值為true/false)。默認情況下,所有新建條目的該值為false。你后面會編寫代碼,在用戶在視圖里點擊某個條目的復選框時,修改這個屬性為true。Title屬性是一個字符串,用于保存待辦事項的名稱或者簡述。DueAt屬性是一個DateTimeOffset,C#用于這種類型保存一個日期/時間的戳記和一個與UTC偏移量表示的時區(qū)。把時期、時間和時區(qū)一起保存,有助于在不同時區(qū)的系統(tǒng)上準確地顯示時間。看到DateTimeOffset類型后面那個問號?了嗎?它表示DueAt屬性可空(nullable),或者說是可選的。如果不加這個?,每個待辦事項都必須帶有一個截止日期。Id和IsDone屬性沒有標記為可空,所以是必須的,并可以確保始終有值(或者是一個缺省值)。C#里的字符串總是可空的,所以沒必要給Title屬性添加可空標記。C#字符串可以沒有值,也可以是空白字符串或者包含任意文本。每個屬性后面都跟著get;set;,這是個簡寫,表示該屬性可讀/可寫(read/write)(或者,更確切地說,它有getter和setter方法各一個)?,F(xiàn)在,暫且不必關心底層數(shù)據(jù)庫采用的是哪種實現(xiàn)。它可以是SQLServer,MySQL,MongoDB,Redis,或者什么其它稀奇古怪的玩意兒。這個模型定義了數(shù)據(jù)庫里的行或者記錄在C#里看起來是什么樣的,所以你無須在代碼層面擔心數(shù)據(jù)庫層面的東西。這種模型簡單的風格被稱為“樸實可愛的C#對象(plainoldC#object)”或者POCO。視圖模型通常,你保存在數(shù)據(jù)庫里的模型(實體),跟你在MVC里用的模型(視圖模型)非常相似,但又不盡相同。在現(xiàn)在的情形下,TodoItem模型代表單一的一個數(shù)據(jù)庫里的條目,而視圖則需要展示兩個、十個,甚至是一百個待辦事項(取決于用戶拖延癥的病情輕重)。因此,視圖模型應該是一個獨立的類,里面包含著一個TodoItem的數(shù)組:Models/TodoViewModel.csnamespaceAspNetCoreTodo.Models{publicclassTodoViewModel{publicTodoItem[]Items{get;set;}}}好了,現(xiàn)在模型也有了,是時候創(chuàng)建一個接收TodoViewModel并以HTML向用戶展示待辦事項列表的視圖了。創(chuàng)建視圖ASP.NETCore里的視圖使用Razor模板語言編寫,這種模板語言混合了HTML和C#的代碼。(如果你在JavaScript下用Jade、Pug或者Handlebarsmoustaches,在RubyonRails下用ERB,在Java下用Thymeleaf寫過頁面,那你就已經了解其基本概念了.)絕大多數(shù)視圖代碼就是HTML,偶爾摻雜一點C#語句,用以從視圖模型里抽取數(shù)據(jù)并轉換為文本或者HTML。這些C#語句以符號@作為前綴。由TodoController中的actionIndex生成的視圖,需要從視圖模型(一個待辦事項的數(shù)組)獲取數(shù)據(jù),并用一個適當?shù)谋砀裾故窘o用戶。按規(guī)定,視圖要置于Views目錄里,在一個與所屬控制器同名的子目錄下。視圖文件的文件名就是action的名字加上一個.cshtml擴展名。Views/Todo/Index.cshtml@modelTodoViewModel@{ViewDa
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《少兒理財活動案例》課件
- 單位管理制度集粹選集【人力資源管理】十篇
- 單位管理制度匯編大全【人事管理篇】
- 單位管理制度合并選集人員管理篇
- 《巫婆的暑假》課件
- 單位管理制度分享大合集【人員管理篇】十篇
- 單位管理制度范例匯編【人員管理】十篇
- 單位管理制度呈現(xiàn)大全【人員管理篇】
- 《行政職業(yè)能力測驗》2022年公務員考試民和回族土族自治縣預測試題含解析
- 《基層干部管理》課件
- 駕駛員資格申請表
- Module 6 Unit1 Can I have some sweets (說課稿)外研版(三起)英語四年級上冊
- 主要負責人重大隱患帶隊檢查表
- 《建筑施工模板安全技術規(guī)范》(JGJ 162-2008)
- 菜品作業(yè)指導書-06
- 小學勞動教育調查報告
- 電動叉車控制系統(tǒng)詳解帶電路圖
- JGJ-16--民用建筑電氣設計規(guī)范
- 義務教育數(shù)學課程標準(2022年版)
- 倉央嘉措詩全集
- 海洛斯操作手冊(說明書)
評論
0/150
提交評論