# 2019/0618/MVC Part2 PhotoSharing Route & Sitemap & \_LayOut & AJAX

今日 倒數第二次 MVC課程

今日會把Part2 結束

\#09\_Route\_Sitemap&#x20;( Route )
---------------

兩個重點

一個是路由

![](/files/-LiBQiCNGCzfc8cGukE6)

![](/files/-LiBQnaXgxBMn0PCFf2N)

預設長這樣

接著我們自己定義一個

沒放在大括弧 { } 就要完全一樣照打不會自動去找

有點類似 donaname

可以讓懂得人也看不出你網站結構

網址沒有再分大小寫

Constraints 約束 ( 正負向表列

### ##Expration expression&#xD;

Regular Expression

{% embed url="<https://www.google.com/search?rlz=1C1GCEU_zh-TWTW835TW836&ei=uzcIXZ-LCseC8gW0qrHwBw&q=expression+%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E6%98%AF&oq=expression+%E6%AD%A3%E8%A6%8F%E8%A1%A8%E9%81%94%E6%98%AF&gs_l=psy-ab.3..33i160.3625.6602..6889...0.0..0.115.959.15j1......0....1..gws-wiz.......0i5i30j0i30j0i8i30.BxbkU-D0mjs>" %}

^開頭$結尾

\[ ] 或

在 \[ ] 內多一個^是負向表列

### ##接著要把url改為自訂的相對應內容&#xD;

例如留言的url為留言的title

首先啟用自訂action 方法

再到controller 新增action 專門服務它

寫自訂

Find 只能找 key

所以要用where

如果title一樣怎辦 ， 結果說機率太小所以沒處理

記得要啟用 \[Route(@”photo/title/{title}”)]

#### ###Chrome 如果 url 有特殊符號 就是被編碼掉了 如空白就是%&#xD;

SEO 排名會比較前面

以上為路游的介紹

#### ###App\_Start/RouteConfig.cs&#xD;

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace PhotoSharing
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            ///////////////////////////////
            //5.1-3 在\App_Start\RouteConfig.cs啟用自訂ACTION 路由==> routes.MapMvcAttributeRoutes();
            //啟用自訂Action當作路由方法
            routes.MapMvcAttributeRoutes();

            /////////////////////
            routes.MapRoute(
                name: "PhotoRoute",
                url: "photos/{id}",
                defaults: new { controller = "Photos", action = "Display" }
                //constraints: new { id=@"^[1-3]$"}
                );



            /////////////////////////
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

```

#### ###Controller&#xD;s/PhotosController.cs

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PhotoSharing.Models;
using PhotoSharing.DAL;
using System.Net;


namespace PhotoSharing.Controllers
{
    
    public class PhotosController : Controller
    {
        //2.2建立Data Context 來自 Photo Model 的 PhotoSharingContext 
        PhotoSharingContext context = new PhotoSharingContext();

        // GET: Photos
        //2.3-1 Index()回傳Photo
      
        public ActionResult Index()
        {
            ViewBag.Date = DateTime.Now;  //用ViewBag帶入今日日期
            return View(context.Photos.ToList());
        }

        //2.3-2 Display(int id) 透過id參數回傳Photo,若找不到回傳HttpNotFound()helper
       
        public ActionResult Display(int? id)
        {
            ViewData["Date"] = DateTime.Now; //用ViewData帶入今日日期
            if (id==null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            Photo photo = context.Photos.Find(id);
            if(photo==null)
            {
                return HttpNotFound("abcde");
            }

            return View("Display", photo);
        }
        //2.3-7 建立GetImage(int id)回傳File(photo.PhotoFile, photo.ImageMimeType)
        //這不是View()Helper的ActionResult, 這是File()helper
        public FileContentResult GetImage(int id)
        {
            Photo photo = context.Photos.Find(id);
            return File(photo.PhotoFile, photo.ImageMimeType);
        }

        //2.3-3 GET:Create() 產生新增Photo作業,並回傳 new Photo()並產生CreatedDate屬性值= DateTime.Today
        public ActionResult Create()
        {
            Photo newPhoto = new Photo();
            newPhoto.CreatedDate = DateTime.Today;
            
            return View("Create",newPhoto);
        }
        //2.3-4 Post:Create(Photo photo, HttpPostedFileBase image),使用HTTP POST,執行新增Photo回存作業,回傳RedirectToAction()helper
        //      如果ModelState.IsValid==false,回傳Photo給View, 反之執行新增Photo回存作業
        //      photo.ImageMimeType = image.ContentType;
        //      photo.PhotoFile = new byte[image.ContentLength];
        //      image.InputStream.Read(photo.PhotoFile, 0, image.ContentLength);
        [HttpPost,ValidateAntiForgeryToken]
        public ActionResult Create(Photo photo,HttpPostedFileBase image)
        {
            photo.CreatedDate = DateTime.Today;
            if(ModelState.IsValid)
            {
                //有post照片才做照片上傳的處理
                if (image!=null)
                {
                    photo.ImageMimeType = image.ContentType;  //抓照片型態
                    photo.PhotoFile = new byte[image.ContentLength];  //取得上傳照片的大小再轉byte陣列
                    image.InputStream.Read(photo.PhotoFile, 0, image.ContentLength);
                }
                context.Photos.Add(photo);
                context.SaveChanges();
                return RedirectToAction("Index");

            }
            else
            {
                return View("Create", photo);
            }


            
        }
        //2.3-5 Get:Delete(int id)產生刪除Photo作業,並回傳Photo(),若找不到回傳HttpNotFound()helper
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            Photo photo = context.Photos.Find(id);
            if (photo == null)
            {
                return HttpNotFound();
            }

            return View("Delete", photo);
        }
        //2.3-6 Post:建立DeleteConfirmed(int id)使用[ActionName("Delete")]屬性,透過HTTP POST,執行刪除Photo回存作業.回傳RedirectToAction()helper
        [HttpPost,ValidateAntiForgeryToken]
        [ActionName("Delete")]
        public ActionResult DeleteConfirmed(int? id)
        {
            Photo photo = context.Photos.Find(id);
            context.Photos.Remove(photo);
            context.SaveChanges();
            return RedirectToAction("Index");
        }

        //3.13-3 在PhotoController中的_PhotoGallery Action上標註排除使用Filter
        [ValueReporter(IsCheck=false)]
        //3.6.在PhotoController.cs建立[ChildActionOnly] _PhotoGallery action,用於Partial View
        public ActionResult _PhotoGallery(int number=0)
        {
            List<Photo> photos;
            if (number == 0)
            {
                //Lambda
                photos = context.Photos.OrderByDescending(p => p.CreatedDate).ThenBy(p => p.PhotoID).ToList();

                //LINQ
                //photos = (from p in context.Photos
                //          orderby p.CreatedDate descending, p.PhotoID ascending
                //          select p).ToList();

                //SQL
                //Select * from photo
                //order by CreatedDate desc,p.PhotoID
            }
            else
            {
                photos = context.Photos.OrderByDescending(p => p.CreatedDate).ThenBy(p => p.PhotoID).Take(number).ToList();

                //LINQ
                //photos = (from p in context.Photos
                //          orderby p.CreatedDate descending, p.PhotoID ascending
                //          select p).Take(number).ToList();


                //SQL
                //Select top 2 * from photo
                //order by CreatedDate desc,p.PhotoID

            }

            return PartialView("_PhotoGallery", photos);


        }

        //4.1建立ExceptionDemo Action引發錯誤
        //[HandleError(View="ExceptionError")]
        public ActionResult ExceptionDemo()
        {
            int i = 0;

            int j = 10 / i;

            return View();
        }
        //4.5建立SlideShow Action並自訂NotImplementedException錯誤
        [HandleError(View="ExceptionError")]
        public ActionResult SliderShow()
        {
            throw new NotImplementedException("這一個SliderShow的功能還沒有做好哦!!!");
        }

        //5.1-2 建立自訂路由的ACTION:DisplayByTitle(PhotoController.cs)
        [Route(@"photo/title/{title}")]
        public ActionResult DisplayByTitle(string title)
        {
            if (title == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            Photo photo = context.Photos.Where(p=>p.Title==title).FirstOrDefault();

            if(photo==null)
            {
                return HttpNotFound("abcde");
            }

            return View("Display", photo);
        }


    }
}

```

#### ###老師步驟&#xD;

```
//5.1   設定自訂路由
//5.1-1 在\App_Start\RouteConfig.cs自訂photo路由PhotoRoute
//5.1-1.1 測試
//5.1-1.2 測試後加上下段,將constraints限制存取的id導到錯誤處理頁面
//<customErrors mode = "On" >
//    < error statusCode="404" redirect="/404.html" />
//</customErrors>

//5.1-2 建立自訂路由的ACTION:DisplayByTitle(PhotoController.cs)
//5.1-3 在\App_Start\RouteConfig.cs啟用自訂ACTION 路由==> routes.MapMvcAttributeRoutes();
//5.1-3.1 測試
//5.1-4 在_PhtotGallery PartialView加上@Html.ActionLink("詳細資料byTitle", "DisplayByTitle", new { Title = item.Title })
//5.1-4.1 測試

//5.2   加入Navigation
//5.2.1 NuGet下載MvcSiteMapProvider.MVC5
// ********需先把EntityFramework降版至6.1.3再安裝MvcSiteMapProvider.MVC5，裝完後根目錄下會有sitemap檔
//5.2-2 自訂mvcSiteMapNode(Mvc.sitemap檔)
//5.2-3 顯示Menu及SiteMapPath(Photo\Index.cshtml)
```

## #09\_Route\_Sitemap ( Sitemap )

下個例子要講layout

Navbar

有很多個做法 老師介紹他覺得還不錯的

Sitemap 在 webform 有控制項

但在mvc首先要安裝插鍵

但要先把entityframework 降版 6.1.3

寫mvc要知道有些功能通常都有元件

Mvc sitemap provider 可以只裝mvc5的版本

把它當像是webform裡面的sitemap來用就好

一個xml檔案

接著做個簡單的例子

#### ###Mvc.sitemap&#xD;

```
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0"
            xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">

  <mvcSiteMapNode title="Home" controller="Home" action="Index">
    
    <mvcSiteMapNode title="All Photos" controller="Photos" action="Index"/>
    <mvcSiteMapNode title="Create Photos" controller="Photos" action="Create"/>
    <mvcSiteMapNode title="ExceptionDemo" controller="Photos" action="ExceptionDemo"/>
    <mvcSiteMapNode title="SliderShow" controller="Photos" action="SliderShow"/>
  </mvcSiteMapNode>

</mvcSiteMap>
```

有層級關係

指定controllername跟actionname

這個講完後會補充 error hander 時提到的slider showS

做好後

現在先讀出來

到 views -> photos -> index.cshtml

@Html.mvcsitemap().menu()

@Html.mvcsitemap().sitemappath()

有bug 沒解決 下課休息

剛剛的問題是發生在Routerconfig 錯了

400 request 就錯了

![](/files/-LiBXJcjKULoorkKOwIJ)

直接打/photos不帶任何參數就可以

![](/files/-LiBXC4LWMVJg1uj8P1U)

url沒有分大小寫

所以要自訂自己的router 千萬不要跟 controllername一樣不然就沒意義

等等在 layout 解決

Navbar 其實就是用 ul 實現的所以現在就先用 ul 做

@Menu 後面的參數 多載很多 必須要知道到底在調整啥

現在先以 (三參數做示範

開始節點&#x20;

子節點

階層調整成需求的 就可以上 class&#x20;

這個sitemap先壓縮起來這其實只是鋪耿要給layout用的

下午例子要去layout跟menu一起講

下午還要講 ajax ??&#x20;

#### ###Mvc.sitemap&#xD;

#### ###Views/photos/index.cshtml&#xD;

```

@{
    ViewBag.Title = "討論區";
}
<div>

    選單:@Html.MvcSiteMap().Menu(false,false,false)

    目前所在位置:@Html.MvcSiteMap().SiteMapPath()


    <h2>討論區</h2>
    <hr />
    <p>@Html.ActionLink("新增留言", "Create")</p>

    @Html.Action("_PhotoGallery", "Photos")

</div>



```

#### ###老師步驟&#xD;

```
//5.1   設定自訂路由
//5.1-1 在\App_Start\RouteConfig.cs自訂photo路由PhotoRoute
//5.1-1.1 測試
//5.1-1.2 測試後加上下段,將constraints限制存取的id導到錯誤處理頁面
//<customErrors mode = "On" >
//    < error statusCode="404" redirect="/404.html" />
//</customErrors>

//5.1-2 建立自訂路由的ACTION:DisplayByTitle(PhotoController.cs)
//5.1-3 在\App_Start\RouteConfig.cs啟用自訂ACTION 路由==> routes.MapMvcAttributeRoutes();
//5.1-3.1 測試
//5.1-4 在_PhtotGallery PartialView加上@Html.ActionLink("詳細資料byTitle", "DisplayByTitle", new { Title = item.Title })
//5.1-4.1 測試

//5.2   加入Navigation
//5.2.1 NuGet下載MvcSiteMapProvider.MVC5
// ********需先把EntityFramework降版至6.1.3再安裝MvcSiteMapProvider.MVC5，裝完後根目錄下會有sitemap檔
//5.2-2 自訂mvcSiteMapNode(Mvc.sitemap檔)
//5.2-3 顯示Menu及SiteMapPath(Photo\Index.cshtml)
```

Layout 相當於 webform 的 masterpage

\#10\_LayOut

Shared 是大家都要用到的東西就會放在這

Partialview

錯誤頁面 等等 …

\_有底線的沒辦法直接存取

所有的 View都在 @RenderBody() 裡面

接著真正的做一個空的 \_layout

ViewBag.Title 通常表示那個 view 的資訊

Bundle 在講 ??

@styles.Render

用html5語意標籤來寫可以增加 seo 排名

接著調整樣式 利用 bs 3

重點來了

要把 @Html.ActionLink 改為 @sitemap

這時候問題來了 ul 如果用 sitemap 並沒辦法套用 class

那就要用 jq dom 塞 … ( 如果不是預設的內容就要用 jq 塞

接著測試 新增 TestBoostrap.cshtml

@{Layout=”\_MainLayout.cshtml”}

各自view所做的樣式修改

最好是留在各自的view內

然後利用@section CSS{\<style>\</style>}

到原本的layout內利用

@RenderSection(“CSS”,false)

@RenderSection(“Script”,false)

false不需要每一個view都有那個區塊

### ##指定預設\_Layout ( 正負面表列&#xD;

#### ###Views/\_ViewStart.cshtml&#xD;

```
@{
    //Layout = "~/Views/Shared/_Layout.cshtml";
    Layout = "~/Views/Shared/_MainLayout.cshtml";
}
```

#### ###View/Shared/\_MainLayout.cshtml&#xD;

```
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    @*//6.1-1-1<title>@ViewBag.Title</title>*@
    <title>@ViewBag.Title | 高屏澎東分署股份有限公司</title>

    @*//6.1-1-1<title>@ViewBag.Title</title>*@
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    @*6.2.4 將自訂CSS Section插入Layout*@
    <link href="~/Content/Site.css" rel="stylesheet" />
    @RenderSection("CSS", false)

</head>
<body>
    @*//6.1-1-2  製作<header> </header>裡的Navbar*@
    <header>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a href="#" class="navbar-brand">WDA</a>
                    @*@Html.ActionLink("應用程式名稱", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })*@
                </div>
                <div class="navbar-collapse collapse">
                    @*<ul class="nav navbar-nav">
                            <li>@Html.ActionLink("首頁", "Index", "Home")</li>
                            <li>@Html.ActionLink("關於", "About", "Home")</li>
                            <li>@Html.ActionLink("連絡人", "Contact", "Home")</li>
                            <li>@Html.ActionLink("討論區", "Index", "Photos")</li>
                        </ul>*@

                    @Html.MvcSiteMap().Menu()

                </div>
            </div>
        </div>
    </header>
    @*6.1-1-3...........................................*@
    <section class="container body-content">
        @RenderBody()

    </section>
    @*6.1-1-4............................................*@
    <footer class="container">
        <hr />
        <p>目前所在位置:@Html.MvcSiteMap().SiteMapPath()</p>
        <p>&copy; @DateTime.Now.Year - 高屏澎東分署股份有限公司</p>
    </footer>


    @*6.2.3 在layout View(Shared\_MainLayout.cshtml)使用BootStrap/Jquery JS*@
    <script src="~/Scripts/jquery-3.3.1.min.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
    @*6.2.5 將自訂Scripts Section插入Layout*@
    @*//6.5.3 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>*@
    @RenderSection("Script", false)
    <script>
        //6.5.2 更新(Shared\_MainLayout.cshtml), 加入JQUERY, 產生 < ul id = "menu" class="nav navbar-nav" >
        $('#menu').addClass('nav navbar-nav');
        $('#menu').append('<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>');

    </script>
</body>
</html>

```

#### ###老師步驟&#xD;

```
//6.1   建立layout
//6.1-1 建立layout View(Shared\_MainLayout.cshtml)
//      Templete:empty(without model)
//      不要勾選Use a Layout Page
//      修改內容(可參考_Layout.cshtml)
//6.1-1-1  <title>@ViewBag.Title</title>
//6.1-1-2  製作<header> </header>裡的Navbar 
//6.1-1-3  <section>@RenderBody()</section>
//6.1-1-4  <footer>@Html.MvcSiteMap().SiteMapPath()</footer>

//6.1-2 (_ViewStart.cshtml)設定預設的Layout
//6.1-3 註解（photo/index.cshtml）原本 5.2-3的Menu及SiteMapPath

//6.2.1 *Manage NuGet Package 加入BootStrap & Jquery(已存在則省略)
//6.2.2 在layout View(Shared\_MainLayout.cshtml)使用BootStrap CSS
//      在<Head>標籤內加入
//                 1.<link href="~/Content/bootstrap.min.css" rel="stylesheet" />

//6.2.3 在layout View(Shared\_MainLayout.cshtml)使用BootStrap/Jquery JS
//      在</Body>標籤前加入
//                 1.<script src="~/Scripts/jquery-3.1.1.min.js"></script>
//                 2.<script src="~/Scripts/bootstrap.min.js"></script>

//6.2.4 將自訂css Section插入Layout(Shared\_MainLayout.cshtml)
//      在<Head>標籤內加入(6.2.2的後面)
//      @RenderSection("CSS", false)

//6.2.5 將自訂Scripts Section插入Layout(Shared\_MainLayout.cshtml)
//      在</body>標籤上一行加入
//      @RenderSection("Scripts", false)

//6.3-1 加入TestBootStrap Action
//6.3.2 在Photos裡建立Bootstrap View:TestBootStrap.cshtml,使用Bootstrap Grid System
//      Template:Empty (without model)
//      勾選Use a Layout Page
//      選擇_MainLayout.cshtml為主版
//      修改內容
//6.3.3 在TestBootStrap.cshtml View中定義Section
//      @section CSS{.......}


//6.4.1 更新Create View,使用Bootstrap Form/Button
//6.4.2 更新Create View,自訂SCRIPT,使用@section
//       @section Scripts{.......}

//6.5.1 更新(Shared\_MainLayout.cshtml),SiteMap使用Bootstrap Navbar
//6.5.2 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<ul id="menu" class="nav navbar-nav">
//6.5.3 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>


```

\#11AJAX

#### 如果沒有像Webform AJAX控制項時的用法&#xD;

{% embed url="<https://www.google.com/search?q=Ajax&rlz=1C1GCEU_zh-TWTW835TW836&oq=Ajax&aqs=chrome..69i57j69i61j69i65l2j69i60.500j0j7&sourceid=chrome&ie=UTF-8>" %}

&#x20;**AJAX**即“Asynchronous JavaScript and XML”（非同步的JavaScript與XML技術），指的是一套综合了多項技術的瀏覽器端網頁開發技術。

一個crud 通常就是一個 controller

那我們就新增一個 commentController

該using的 + dbcontext

#### &#xD;###Controller&#xD;s/commentController&#xD;.cs

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PhotoSharing.DAL;
using PhotoSharing.Models;


namespace PhotoSharing.Controllers
{
    public class CommentController : Controller
    {
        //7.2-1 宣告PhotoSharingContext()並在建構式建構DBContext物件
        PhotoSharingContext context = new PhotoSharingContext();

        //7.2-2 加入_CommentsForPhoto Action
        [ChildActionOnly]//無法在瀏覽器上用URL存取此action
        public ActionResult _CommentsForPhoto(int PhotoID)
        {
            var comments = from c in context.Comments
                           where c.PhotoID == PhotoID
                           select c;
            //為了在View裡取得PhotoID的值所以先存在ViewBag裡
            ViewBag.PhotoID = PhotoID;

            return PartialView(comments.ToList());
        }

        //7.5-1 加入_Create Action
        public ActionResult _Create(int PhotoID)
        {
            Comment newComment = new Comment();
            newComment.PhotoID = PhotoID;

            ViewBag.PhotoID = PhotoID;

            return PartialView("_CreateAComment");
        }

        //7.6-1 在CommentController加入_CommentsForPhoto POST Action
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult _CommentsForPhoto(Comment comment, int PhotoID)
        {
            context.Comments.Add(comment);
            context.SaveChanges();

            var comments = from c in context.Comments
                           where c.PhotoID == PhotoID
                           select c;
            //7.6-1 在CommentController加入_CommentsForPhoto POST Action(第二個畫面)
            ViewBag.PhotoID = PhotoID;

            return PartialView("_CommentsForPhoto", comments.ToList());
        }

        //7.8-1加入CommentControl的Delete ACTION
        public ActionResult Delete(int id)
        {
            Comment comment = context.Comments.Find(id);

            context.Comments.Remove(comment);
            context.SaveChanges();
        

            return RedirectToAction("Display","Photos",new { id=comment.PhotoID});
        }


    }
}
```

增加一個 partialview

在上面加上 \[childactiononly]

不直接回應瀏覽器要求

如果直接在url key 會顯示此動作只能由子要求存取

查詢帶參數到partialview

這樣 這個 partialview 就做好了

接著新增partialview的檢視  create as a partialview

#### &#xD;###Views/Shared/\_CommentsForPhoto.cshtml

```
@model IEnumerable<PhotoSharing.Models.Comment>

@using (Ajax.BeginForm("_CommentsForPhoto",new { PhotoID=ViewBag.PhotoID},new AjaxOptions {UpdateTargetId= "comments-tool",HttpMethod="Post" }))
{
<div id="comments-tool">
    <div class="well">
        @* 7.6-4 加入_Create Action********************************************** *@
        @*Action Name是_Create才對!!*@
        @Html.Action("_Create", "Comment", new { PhotoID = ViewBag.PhotoID })


        @foreach (var item in Model)
        {
            @*7.3 在/Shared/_CommentsForPhoto.cshtml加入IEnumerable<T>及foreach (var item in Model){}*@
        <div class="panel panel-warning">
            <div class="panel-heading">
                <h4>@item.Subject</h4>
            </div>
            <div class="panel-body">
                <p>@item.Body</p>
                <p class="text-right">
                    回覆人:@item.UserName
                </p>
            </div>
            @*//7-8-2 在_CommentsForPhoto.cshtml加入Delete連結*@
            <div class="panel-footer">
                @Html.ActionLink("刪除回覆","Delete",new { id=item.CommentID},new { @class="btn btn-danger", onclick="return confirm('確定刪除嗎??')"})
            </div>
        </div>
        }
    </div>
</div>
}
```

用 foreach 讀出來

接著去修改 Display.cshtml的 partialview鏈結&#x20;

以上為顯示的部分

修改這些是為了 等等 的 ajax

### ##接著要安裝Ajax的插件

Microsoft.jquery.unobtrusive.ajax

![](/files/-LiBbzzHILPSqWx-k3v-)

這個是用後端然後可以寫前端的套件

Include script jquery.unobtrusive-ajax.js

#### ###Views/Shared/\_MainLayout.cshtml

```
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    @*//6.1-1-1<title>@ViewBag.Title</title>*@
    <title>@ViewBag.Title | 高屏澎東分署股份有限公司</title>

    @*//6.1-1-1<title>@ViewBag.Title</title>*@
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    @*6.2.4 將自訂CSS Section插入Layout*@
    <link href="~/Content/Site.css" rel="stylesheet" />
    @RenderSection("CSS", false)

</head>
<body>
    @*//6.1-1-2  製作<header> </header>裡的Navbar*@
    <header>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a href="#" class="navbar-brand">WDA</a>
                    @*@Html.ActionLink("應用程式名稱", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })*@
                </div>
                <div class="navbar-collapse collapse">
                    @*<ul class="nav navbar-nav">
                            <li>@Html.ActionLink("首頁", "Index", "Home")</li>
                            <li>@Html.ActionLink("關於", "About", "Home")</li>
                            <li>@Html.ActionLink("連絡人", "Contact", "Home")</li>
                            <li>@Html.ActionLink("討論區", "Index", "Photos")</li>
                        </ul>*@

                    @Html.MvcSiteMap().Menu()

                </div>
            </div>
        </div>
    </header>
    @*6.1-1-3...........................................*@
    <section class="container body-content">
        @RenderBody()

    </section>
    @*6.1-1-4............................................*@
    <footer class="container">
        <hr />
        <p>目前所在位置:@Html.MvcSiteMap().SiteMapPath()</p>
        <p>&copy; @DateTime.Now.Year - 高屏澎東分署股份有限公司</p>
    </footer>


    @*6.2.3 在layout View(Shared\_MainLayout.cshtml)使用BootStrap/Jquery JS*@
    <script src="~/Scripts/jquery-3.3.1.min.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>

    @*6.2.5 將自訂Scripts Section插入Layout*@
    @*//6.5.3 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>*@
    @RenderSection("Script", false)
    <script>
        //6.5.2 更新(Shared\_MainLayout.cshtml), 加入JQUERY, 產生 < ul id = "menu" class="nav navbar-nav" >
        $('#menu').addClass('nav navbar-nav');
        $('#menu').append('<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>');

    </script>
</body>
</html>

```

接著回到 commentcontroller.cs

新增一個 \_Create的partialview

一樣查詢

為了區別viewname可以跟action不同名稱

Return 時 雙引號 “partialview名稱”&#x20;

接著新增檢視 記得要把VIEW名稱改為“partialview名稱”

接著到 shared \_createacomment.cshtml (要做表單 ?

### Partialview 階層&#xD;

display

\_commentsForPhoto.cshtml&#x20;

\_createacomment.cshtml   (後悔了 改為範本 讓它直接蓋過去

#### &#xD;###\_createacomment.cshtml

```
@model PhotoSharing.Models.Comment


@Html.AntiForgeryToken()
@*7.6-2 _CreateAComment.cshtml加入Html Helper 及 class屬性*@
<div class="form-horizontal">
    <h4>Comment</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(model => model.Subject, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Subject, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Subject, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Body, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Body, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Body, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
        </div>
    </div>



    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>


```

要幫整個\_commentsForPhoto.cshtml 套上form

而且要用 ajax的方法

@using (Ajax.BeginForm(“\_createacomment.cshtml”,new{PhotoID=}, AjaxOptions局部區塊ID…)

AjaxOptions {UpdateTargetId=局部區塊ID,送出去的方法}

再回到 CommentController.cs 新增 \[HttpPost]\_CommentsForPhoto 多載(不同參數不同傳送方法)

把資料讀出來在塞回 同一頁 自己

```
@using (Ajax.BeginForm("_CommentsForPhoto",new { PhotoID=ViewBag.PhotoID},new AjaxOptions {UpdateTargetId= "comments-tool",HttpMethod="Post" }))
{Formcontent}
```

測試

剛剛用範本產生的部分有錯 削掉就成功了

#### ###老師步驟

```
//7 用ajax的方式來實現回覆留言的功能

//7.1 加入CommentController(Mvc5 Controller-Empty)
//   在CommentController加入_Create Action
//   在_CreateAComment View使用AJAX


//7.2 加入CommentController(Mvc5 Controller-Empty)
//7.2-1 宣告PhotoSharingContext()並在建構式建構DBContext物件
//7.2-2 加入_CommentsForPhoto Action
//7.2-3 加入_CommentsForPhoto Action的Partial View
//      使用Scaffold template:Empty
//      Model Class:Comment (PhotoSharing.Models)
//      Data Context Class:PhotoSharingContext (PhotoSharing.DAL)
//      勾選Create as a partial view核取方塊
//7.2-4 將_CommentsForPhoto.cshtml移至Shared目錄

//
//7.3 在/Shared/_CommentsForPhoto.cshtml加入IEnumerable<T>及foreach (var item in Model){}

//7.4 在/Photo/Display View加入@Html.Action("_CommentsForPhoto", "Comment", new { PhotoID = Model.PhotoID })

//可先測試一下在Display中是否能正常顯示回覆留言的PartialView


// 使用NuGet安裝套件 
// 1.*Jquery(如果需要)
// 2.Microsoft.jQuery.Unobtrusive.Ajax

//7.5-1 加入_Create Action

//7.5-2 加入_Create Action的_CreateAComment View
//      使用Scaffold template:Empty
//      Model Class:Comment (PhotoSharing.Models)
//      Data Context Class:PhotoSharingContext (PhotoSharing.DAL)
//      勾選Create as a partial view核取方塊

//7.5-3 將_CreateAComment.cshtml移至Shared目錄
// GET: /Comment/_Create. A Partial View for displaying the create comment tool as a AJAX partial page update

//7.6-1 在CommentController加入_CommentsForPhoto POST Action

//7.6-2 /Shared/_CreateAComment.cshtml加入Html Helper 及 class屬性

//7.6-3 /Shared/_CommentsForPhoto.cshtml使用Ajax.BeginForm

//7.6-4 /Shared/_CommentsForPhoto.cshtml加入@Html.Action("_Create", "Comment", new { PhotoID = ViewBag.PhotoId })
//      透過@Html.Action加入_CreateAComment Partial View

//7.7 在_MainLayout.cshtml加入SCRIPT
//7.7-1 加入*jquery-3.1.1.min.js(如果需要的話)(注意:不可用jquery-1.XXX版本)

//7.7-2 *****加入jquery.unobtrusive-ajax.min.js*****這個一定要記得安裝啊!!!!!!

//到這裡可以先測試一下在Display中是否能以Ajax方式新增留言

//7.8 加入CommentControl的Delete ACTION

//7.8-1加入CommentControl的Delete ACTION

//7-8-2 在_CommentsForPhoto.cshtml加入Delete連結

//7-9 測試:http://localhost:3395/Photo/Display/1
```

結果ajax的地方沒有錄影錄到 …

### ##補充功能 刪除&#xD;

Panel-footer

有登入還可以判斷登入狀態

下一個 actionlink

要帶參數 然後 帶 class 帶 onclick

接著到 controller 寫刪除的 action

到此 MVC Part2告一個段落 ， 可以拿它來應用很多地方

接下來會介紹一些跟專案本身進度沒關聯性

如 Include bundle ?&#x20;

狀態管理 viewbag viewdata session


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://johch3n611u.gitbook.io/c50108/ju-li-cheng-bei/201906/2019-0625.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
