C50108
Search…
2019/0613/MVC Part2 PhotoSharing ViewModel & ErrorHandle

寫完CreateComment 與 delete
符合UX 調整 View 跟 controller

//step 4 建立討論主題與回覆功能
//step 4.1 建立CreateComment Action(Get及Post)
//step 4.2 建立CreateComment View(Empty-Without Model)
//step 4.3 在CreateComment View建立回覆表單
//step 4.4 在CreateComment View建立"回討論主題列表" ActionLink
//step 4.5 在Index View建立"回覆" ActionLink
//step 4.6 在Display View建立"回覆" ActionLink
//step 4.7 將CreateComment Action加入mode參數
//step 4.8 將"回覆" ActionLink加入mode參數(Index View)
//step 4.9 改寫CreateComment Action return時的判斷
//step 4.10 測試
//step 5 建立刪除回覆功能
//step 5.1 建立Delete Action
//step 5.2 在Index View建立"刪除" ActionLink
//step 5.3 在Display View建立"刪除" ActionLink
//step 5.4 測試

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Net;
using PhotoSharing.DB_EntitySQL.Models;
namespace PhotoSharing.ViewModel.Controllers
{
//step 1.4 建立VMPhotoCommentsController
public class VMPhotoCommentsController : Controller
{
PhotoSharingEntities db = new PhotoSharingEntities();
// GET: VMPhotoComments
//step 2.1 建立Index Action
public ActionResult Index(int id=1)
{
PhotoComments pc = new PhotoComments()
{
photos = db.Photos.ToList(),
comments = db.Comments.Where(p => p.PhotoID == id).ToList()
};
ViewBag.PID = id;
ViewBag.PTitle = db.Photos.Where(p => p.PhotoID == id).FirstOrDefault().Title;
return View(pc);
}
//step 3.1 建立Display Action
public ActionResult Display(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
PhotoComments pc = new PhotoComments()
{
photos = db.Photos.Where(p => p.PhotoID == id).ToList(),
comments = db.Comments.Where(p => p.PhotoID == id).ToList()
};
ViewBag.PID = id;
//ViewBag.PTitle = db.Photos.Where(p => p.PhotoID == id).FirstOrDefault().Title;
return View(pc);
}
//step 4.1 建立CreateComment Action(Get及Post)
//step 4.7 將CreateComment Action加入mode參數
public ActionResult CreateComment(int? id, int mode)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ViewBag.PhotoID = id;
ViewBag.Mode = mode;
return View();
}
//step 4.1 建立CreateComment Action(Get及Post)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateComment(Comments comment,int mode)
{
db.Comments.Add(comment);
db.SaveChanges();
//step 4.9 改寫CreateComment Action 口eturn時的判斷
if (mode == 2)
return RedirectToAction("Display", new { id = comment.PhotoID });
return RedirectToAction("Index",new{id=comment.PhotoID });
}
}
}

@*//step 2.2 建立Index View(Empty-Without Model)*@
@model PhotoSharing.ViewModel.PhotoComments
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div class="row">
<div class="col-xs-3">
@*//step 2.3 建立討論主題列表*@
<h4>討論主題列表</h4>
@foreach (var item in Model.photos)
{
<h4>@Html.ActionLink(item.PhotoID + "." + item.Title, "Index", new { id = item.PhotoID })</h4>
}
</div>
<div class="col-xs-9">
@*//step 2.4 建立回覆列表*@
<h2>@ViewBag.PTitle</h2>
@if (Model.comments.Count == 0)
{
<h4>尚無任何回覆</h4>
<p>
@*//step 4.5 在Index View建立"回覆" ActionLink*@
@*//step 4.8 將"回覆" ActionLink加入mode參數(Index與Display View)*@
@Html.ActionLink("回覆留言", "CreateComment", new { id = ViewBag.PID, mode = 1 })
</p>
}
else
{
<p>
@*//step 4.5 在Index View建立"回覆" ActionLink*@
@*//step 4.8 將"回覆" ActionLink加入mode參數(Index與Display View)*@
@Html.ActionLink("回覆留言", "CreateComment", new { id = ViewBag.PID, mode = 1 }) |
@*//step 3.5 在Index View建立"詳細資料" ActionLink*@
@Html.ActionLink("詳細資料", "Display", new { id = ViewBag.PID })
</p>
<table class="table">
<tr>
<th>
Subject
</th>
<th>
Body
</th>
<th>
UserName
</th>
</tr>
@foreach (var item in Model.comments)
{
<tr>
<td>
@item.Subject
</td>
<td>
@item.Body
</td>
<td>
@item.UserName
</td>
</tr>
}
</table>
}
</div>
</div>
@*@Html.ActionLink("Edit", "Edit", new { id = item.CommentID }) |
@Html.ActionLink("Details", "Details", new { id = item.CommentID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.CommentID })*@

@*//step 3.2 建立Display View(Empty-Without Model)*@
@model PhotoSharing.ViewModel.PhotoComments
@{
ViewBag.Title = "Display";
}
@*//step 3.3 建立討論主題顯示區*@
<div class="row well">
<div class="col-xs-12">
<h2>@Model.photos[0].Title</h2>
<p>@Model.photos[0].Description</p>
<p>建立人:@Model.photos[0].UserName</p>
<p>建立日期:@Model.photos[0].CreatedDate</p>
@*//step 4.6 在Display View建立"回覆" ActionLink*@
<p class="text-right">
@Html.ActionLink("回覆", "CreateComment", new { id = ViewBag.PID, mode = 2 })
</p>
</div>
</div>
<hr />
@*//step 3.4 建立回覆列表顯示區*@
<div class="row">
<div class="col-lg-offset-2 col-xs-8">
@if (Model.comments.Count == 0)
{
<h4>尚無任何回覆</h4>
}
else
{
foreach (var item in Model.comments)
{
<div class="row table-bordered">
<div class="col-xs-12">
<h3>@item.Subject</h3>
<p>@item.Body</p>
<p class="text-right">建立人:@item.UserName</p>
</div>
</div>
<hr />
}
}
</div>
</div>
@*//step 3.6 在Display View建立"回討論主題列表" ActionLink*@
@Html.ActionLink("回留言列表", "Index", new { id = ViewBag.PID })

@{
ViewBag.Title = "CreateComment";
}
<h2>回覆留言</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken();
<p>
<label for="Subject">回覆主題:</label>
<input id="Subject" name="Subject" type="text" />
</p>
<p>
<label for="Body">回覆內容:</label>
<textarea id="Body" name="Body" rows="5" cols="30"></textarea>
</p>
<p>
<label for="UserName">回覆人名稱:</label>
<input id="UserName" name="UserName" type="text" />
</p>
<input id="PhotoID" name="PhotoID" type="hidden" value="@ViewBag.PhotoID" />
<input id="mode" name="mode" type="hidden" value="@ViewBag.Mode" />
<p>
<input id="Submit1" type="submit" value="確定送出" class="btn btn-default" />
</p>
}

//4.1建立ExceptionDemo Action引發錯誤
//4.2替ExceptionDemo Action建立View並測試
//4.3在Web.Config啟用自訂錯誤 <customErrors mode = "On" />
//4.4再測試一次ExceptionDemo View(會把錯誤導向Error.cshtml)
//4.5 建立SlideShow Action並自訂NotImplementedException錯誤
//4.6 替SlideShow Action建立View並測試(仍會把錯誤導向Error.cshtml)
//4.7 在Shared目錄建立ExceptionError View
// 在ExceptionError.cshtml使用System.Web.Mvc.HandleErrorInfo 取出ControllerName,ActionName及Exception.Message屬性
//4.8 在global.asax註冊使用GlobalFilterCollection(Web Application層級)
//4.8-1其實在FilterConfig.cs裡已經被註冊使用GlobalFilterCollection,因此預預都會導到Error.cshtml
//在global.asax裡若把GlobalFilters.Filters.Add(new HandleErrorAttribute() { View = "ExceptionError" })
//寫法GlobalFilterCollection之前,則會用GlobalFilterCollection,若寫在之後,則會用
//GlobalFilters.Filters.Add(new HandleErrorAttribute() { View = "ExceptionError" })
//4.9 改寫在Shared目錄裡的Error View(已存在,可直接修改內容)
//4.9-1 在Error.cshtml使用System.Web.Mvc.HandleErrorInfo 取出ControllerName,ActionName及Exception.Message屬性
//4.9-2 使用System.Web.Mvc.HandleErrorInfo
// @model System.Web.Mvc.HandleErrorInfo
//4.9-3取出ControllerName,ActionName及Exception.Message屬性*@
// <fieldset>
// <legend>HandleErrorInfo</legend>
// Controller: @Model.ControllerName<br />
// Action: @Model.ActionName<br />
// Message: @Model.Exception.Message
// </fieldset>
//4.10 在PhotoController加入 [HandleError(View = "Error")]屬性(Controller層級,會覆蓋Global層級)
// 若只加[HandleError],沒指定View的話,不管Global設定什麼,都會導到預設
//4.11 在Web.config設計400與404錯誤的重新導向
//<httpErrors errorMode = "Custom" >
// <remove statusCode="400"/>
// <remove statusCode = "404" />
// <error statusCode="400" path="/400.html" responseMode="ExecuteURL"/>
// <error statusCode = "404" path="/404.html" responseMode="ExecuteURL"/>
//</httpErrors>
400錯誤 還沒到 通訊端就處理掉了 IIS處理
Webconfig 如果沒有設定組態就會繼承 IIS處理機制
還有別種類型的 如 發生例外
好的網站不能讓USER看到系統錯誤
接著我們要來自訂錯誤
首先要到 Webconfig 啟用自訂錯誤
<cutomErrors mode=”RemoteOnly”

<?xml version="1.0" encoding="utf-8"?>
<!--
如需如何設定 ASP.NET 應用程式的詳細資訊,請瀏覽
https://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="ConnectionString" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\PhotoSharing.mdf;Integrated Security=True" providerName="System.Data.SqlClient" />
<add name="PhotoSharingEntities" connectionString="metadata=res://*/DB_EntitySQL.Models.PhotoComments.csdl|res://*/DB_EntitySQL.Models.PhotoComments.ssdl|res://*/DB_EntitySQL.Models.PhotoComments.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=(LocalDB)\MSSQLLocalDB;attachdbfilename=|DataDirectory|\PhotoSharing.mdf;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" /></connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1" />
<httpModules>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
</httpModules>
<!--//4.3在Web.Config啟用自訂錯誤-->
<customErrors mode="On">
</customErrors>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" />
<bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.1" newVersion="4.0.2.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" />
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.4.0" newVersion="5.2.4.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.webServer>
<!--//4.11 在Web.config設計400與404錯誤的重新導向-->
<httpErrors errorMode="Custom">
<remove statusCode="404" />
<remove statusCode="400" />
<error statusCode="404" path="404.html" />
<error statusCode="400" path="404.html" />
</httpErrors>
<modules>
<remove name="TelemetryCorrelationHttpModule" />
<add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" preCondition="integratedMode,managedHandler" />
<remove name="ApplicationInsightsWebTracking" />
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
</compilers>
</system.codedom>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
寫一個正式的控制
首先 先寫一個會觸發錯誤的acction
PhotosController.cs -> ExceptionDemo()

//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的功能還沒有做好哦!!!");
}
接著講解了一下運作方式(錯誤機制的觸發) 等等會實際更改
Global.asax.cs
Filters.webconfig

先寫 Error.cshtml

@*<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width" />
<title>忙碌中</title>
</head>
<body>
<hgroup>
<h1>伺服器忙碌中...</h1>
<h2>伺服器忙碌中,請稍後再試。</h2>
</hgroup>
</body>
</html>*@
@model System.Web.Mvc.HandleErrorInfo
@{
}
<h1>伺服器忙碌中...</h1>
<h2>伺服器忙碌中,請稍後再試。</h2>
<fieldset>
<legend>錯誤資訊</legend>
ControllerName:@Model.ControllerName<br />
ActionName:@Model.ActionName<br />
Exception:@Model.Exception.GetType().ToString()<br />
Message:@Model.Exception.Message<br />
</fieldset>
帶值近來讓開發人員看得值
要帶一個 model System.Web.Mvc.HandleErrorInfo
才能帶到錯誤訊息
但通常這個不能給人看到

所以改成有兩頁預設頁 ( 2 error
ExceptionError.cshtml

@model System.Web.Mvc.HandleErrorInfo
@{
ViewBag.Title = "ExceptionError";
}
<h1>Message:@Model.Exception.Message</h1>
要去修改 filterConfig.cs

例如去
Global.asax.cs 伺服器層級的組態定義
Habdleerrorattribute view = ???
這樣就會在這邊先導到新的那頁錯誤
Global.asax.cs
Filterconfig
都有寫的時候 ( 都有註冊時
會以 filterconfig 為主 類似 css 層級 越精緻 且 執行的時間後面

註冊成 controller 或 action 層級的 即可
所以到 controller 裡面 的action[handleerror(view=”視圖名稱”)]
大部分頁面都要 就註冊 filterconfig
少數的 就註冊 action 層級的
整個 controller 的就寫在 controller 正向負向表列
接著新增了一個 httperror.cshtml

@{
ViewBag.Title = "HttpError";
}
<video id="v" controls="controls" style="width:1000px;" autoplay="autoplay">
<source src="~/Images/404.mp4" type="video/mp4" />
</video>
<script>
var v = document.getElementById("v");
v.play();
</script>
伺服器層級的錯誤400系列 一定要定義在 web.config
剛剛的問題 站食用根目錄的就好 找不出來
步驟在 photoscontroller
忘記這天的狀況,因為晚上有上在職班的課所以沒有很早走在趕專案進度,
結尾亂亂的忘記老師到底在哪時結尾
以上如果看不懂 或是有些頁面不知道就看老師步驟

//4.1建立ExceptionDemo Action引發錯誤
//4.2替ExceptionDemo Action建立View並測試
//4.3在Web.Config啟用自訂錯誤 <customErrors mode = "On" />
//4.4再測試一次ExceptionDemo View(會把錯誤導向Error.cshtml)
//4.5 建立SlideShow Action並自訂NotImplementedException錯誤
//4.6 替SlideShow Action建立View並測試(仍會把錯誤導向Error.cshtml)
//4.7 在Shared目錄建立ExceptionError View
// 在ExceptionError.cshtml使用System.Web.Mvc.HandleErrorInfo 取出ControllerName,ActionName及Exception.Message屬性
//4.8 在global.asax註冊使用GlobalFilterCollection(Web Application層級)
//4.8-1其實在FilterConfig.cs裡已經被註冊使用GlobalFilterCollection,因此預預都會導到Error.cshtml
//在global.asax裡若把GlobalFilters.Filters.Add(new HandleErrorAttribute() { View = "ExceptionError" })
//寫法GlobalFilterCollection之前,則會用GlobalFilterCollection,若寫在之後,則會用
//GlobalFilters.Filters.Add(new HandleErrorAttribute() { View = "ExceptionError" })
//4.9 改寫在Shared目錄裡的Error View(已存在,可直接修改內容)
//4.9-1 在Error.cshtml使用System.Web.Mvc.HandleErrorInfo 取出ControllerName,ActionName及Exception.Message屬性
//4.9-2 使用System.Web.Mvc.HandleErrorInfo
// @model System.Web.Mvc.HandleErrorInfo
//4.9-3取出ControllerName,ActionName及Exception.Message屬性*@
// <fieldset>
// <legend>HandleErrorInfo</legend>
// Controller: @Model.ControllerName<br />
// Action: @Model.ActionName<br />
// Message: @Model.Exception.Message
// </fieldset>
//4.10 在PhotoController加入 [HandleError(View = "Error")]屬性(Controller層級,會覆蓋Global層級)
// 若只加[HandleError],沒指定View的話,不管Global設定什麼,都會導到預設
//4.11 在Web.config設計400與404錯誤的重新導向
//<httpErrors errorMode = "Custom" >
// <remove statusCode="400"/>
// <remove statusCode = "404" />
// <error statusCode="400" path="/400.html" responseMode="ExecuteURL"/>
// <error statusCode = "404" path="/404.html" responseMode="ExecuteURL"/>
//</httpErrors>
Copy link
On this page
#接續07_ViewModel
#08_ErrorHandle 錯誤處理機制
RemoteOnly 遠端自訂錯誤 近端系統錯誤
自訂開發人員例外錯誤訊息
自訂400系列錯誤訊息
##不同層級去阻擋跑出錯誤訊息
##那如果要讓兩個錯誤不同錯誤頁面那該怎辦 ?