Try   HackMD

MVC程式開發筆記

2017-10-3

基礎筆記

SQLExpress 家庭用

(localdb)\MSSQLLocalDB

Database First, How To Connect MVC to Database

  1. Models (rightClick) > 新增 ADO.NET 實體資料模型
  2. 從資料庫產生
  3. 新增連結 (hqssql****t)
  4. 選取資料表
  5. 完成

Unobtrusive jqueryval

  1. 加入section scripts
@section scripts{ @Scripts.Render("~/bundles/jqueryval") }
  1. 加入Html Helper, input 必須使用helper 否則必須自打data-val
@Html.ValidationMessageFor(model => model.FacetItem.FacetOrder)
  1. 一併顯示使用
@Html.ValidationSummary()

多對多關係,加入Checkbox處理呈現與修改

Controller 端

// GET: /Employee/Edit/5 public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } auth_employee emp = db.auth_employee .Include(i => i.auth_EmployeeGroup) .Where(i => i.Id == id) .Single(); GetAllRole(emp); if (emp == null) { return HttpNotFound(); } ViewBag.allCheckbox = db.auth_group.ToList(); return View(emp); }

輔助程式,邏輯重點取得所有的角色類型構成ViewModel存入ViewBag

private void GetAllRole(auth_employee emp) { var auth_groupTable = db.auth_group; var empOwnRole = new HashSet<int>( emp.auth_EmployeeGroup.Select(c => c.groupId)); var viewModel = new List<groupViewModel>(); foreach (var row in auth_groupTable) { viewModel.Add(new groupViewModel { groupId = row.groupId, roleName = row.groupName, isOwn = empOwnRole.Contains(row.groupId)}); ViewBag.roles = viewModel; } }

利用TryUpdateModel來更新模型,但尚未處理被塞入資料的問題。

// POST: /Employee/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(int? Id, string[] selectedRole) { var emp = db.auth_employee .Include(j => j.auth_EmployeeGroup) .Where(j => j.Id == Id) .Single(); if (TryUpdateModel(emp)) { UpdateEmployeeRoles(selectedRole, emp); db.Entry(emp).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } else { // error; } return View(emp); }

輔助程式,讀入checkBox構成的字串陣列,迭代所有的角色如果符合字串陣列的加入emp的屬性。

private void UpdateEmployeeRoles(string[] selectedRole, auth_employee emp) { if (selectedRole == null) { emp.auth_EmployeeGroup = new List<auth_EmployeeGroup>(); return; } // Edit 勾選的角色 var selectedRoleHS = new HashSet<string>(selectedRole); // 員工擁有的角色 var empRoles = new HashSet<int> (emp.auth_EmployeeGroup.Select(c => c.groupId)); emp.auth_EmployeeGroup = new List<auth_EmployeeGroup>(); // 迭代所有的角色 foreach (var role in db.auth_group) { if (selectedRoleHS.Contains(role.groupId.ToString())) { emp.auth_EmployeeGroup.Add( new auth_EmployeeGroup { groupId = role.groupId, employeeId = emp.Id }); } } }

View端

<div class="form-group"> <label class="control-label col-md-2">具備角色</label> <div class="col-md-10"> @using sideMenu.Models; @{ List<sideMenu.ViewModel.groupViewModel> roles = ViewBag.roles; foreach (var role in roles) { <input type="checkbox" name="selectedRole" value="@role.groupId" @(Html.Raw(role.isOwn ? "checked=\"checked\"" : ""))> @role.groupId @: @role.roleName </input> <br/> } } </div> </div>

MVC 調用 Process / python script

using System.Diagnostics; public ActionResult Eng() { String Command = "python C:\\users\\631469\\create.py"; ProcessStartInfo ProcessInfo; // /C 關閉結束後關閉console /K 結束後保留console ProcessInfo = new ProcessStartInfo("cmd.exe", "/C " + Command); ProcessInfo.CreateNoWindow = true; ProcessInfo.UseShellExecute = true; var p = Process.Start(ProcessInfo); p.Close(); return View(); }

Model Partial Class

Models Directory / classNamePartial.cs

[MetadataType(typeof(anyClassName))] public partial class originalClassName { } public class anyClassName { [Required] [Display(Name = "partialName")] public string property { get; set; } }

edmx / classNamePartial.cs

pulibc originalClassName { public string property { get; set; } }

排序ParentId 與其 Child附加其下

public ActionResult Index(int? projectId) { ViewBag.projectId = projectId; var cases = db.Case .Include(i => i.Department) .Include(i => i.Project); // 判別是否有輸入專案Id // TODO: 判斷是否擁有權限存取 if (projectId == null) { return RedirectToAction("Index", "Project"); } else { var parentCases = from c in db.Case where c.projectId == projectId && c.caseParentId == null select c; var sortCase = parentCases.ToList(); var Childcases = from c in db.Case where c.projectId == projectId && c.caseParentId != null select c; foreach (var item in Childcases) { var parentIndex = sortCase.FindIndex( ite => ite.caseId == item.caseParentId); sortCase.Insert(parentIndex + 1, item); } @ViewBag.projectName = db.Project.Find(projectId).projectName; return View(sortCase); } }

Razor

MVC View Intellisense 錯誤修復

在View > Web.Config 新增此段

<system.web> <compilation> <assemblies> <add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> </assemblies> </compilation> </system.web> <!-- Before end of configuration </configuration> -->

factorType 版本必須維持5.0

<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

如何擴充 Html Helper

  1. 新增資料夾 Extentions (非Convention)
  2. 加入HtmlHelperExtetion.cs (非Convention)
  3. 示範程式碼, Html.Submit 可以製造一顆input tag submit
namespace System.Web.Mvc.Html { public static MvcHtmlString Submit(this HtmlHelper htmlHelper) { var tag = new TagBuilder("input"); tag.Attributes.Add("type", "submit"); tag.Attributes.Add("value", "送出"); var html = tag.ToString(); return MvcHtmlString.Create(html); } }
@Html.DropDownListFor(x => x.caseId, (IEnumerable<SelectListItem>)ViewBag.caseId, new { @class = "form-control"})

EditorFor Complex Situation (Value, placeholder)

@Html.EditorFor(model => model.FacetItem.FacetOrder, new { htmlAttributes = new { @class = "form-control", @Value = value, placeholder = "構面順序" } } )

EditorFor With Class (form-control)

@Html.EditorFor(model => model.Accumulated, new { htmlAttributes = new { @class = "form-control" } })

日期格式 Decorator, Format Attribute

[DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public System.DateTime projectDateEnd { get; set; }

Session

System.Web.HttpContext.Current.Session[""]

唯讀 Texbox

@Html.TextBoxFor(model => model.CheckPointName, new { @class = "form-control", @readonly = true})
@Html.DropDownListFor(model => model.CheckPointName, new { @class = "form-control", @disabled = true})

檔案 Size Convert

@functions { static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; public string SizeSuffix(Int64 value, int decimalPlaces = 1) { if (value < 0) { return "-" + SizeSuffix(-value); } if (value == 0) { return "0.0 bytes"; } // mag is 0 for bytes, 1 for KB, 2, for MB, etc. int mag = (int)Math.Log(value, 1024); // 1L << (mag * 10) == 2 ^ (10 * mag) // [i.e. the number of bytes in the unit corresponding to mag] decimal adjustedSize = (decimal)value / (1L << (mag * 10)); // make adjustment when the value is large enough that // it would round up to 1000 or more if (Math.Round(adjustedSize, decimalPlaces) >= 1000) { mag += 1; adjustedSize /= 1024; } return string.Format("{0:n" + decimalPlaces + "} {1}", adjustedSize, SizeSuffixes[mag]); } }

鑲嵌其他 Action Partial Result

# Controller public ActionResult Simple() { return PartialView(); } # View @Html.Action("Simple", "ControllerName")

Nuget 系列

Install-Package jQuery -Version 3.1.1 Install-Package Microsoft.AspNet.Mvc -Version 5.2.3 Install-Package EntityFramework -Version 6.0.0

PageList 示例

Web.config

<system.web.webPages.razor> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="PagedList" /> <add namespace="PagedList.Mvc" /> </namespaces> </pages> </system.web.webPages.razor>

Controller

public ActionResult Index(int? page) { var project = db.project; project = project.OrderBy(i => i.ProjectId); int pageSize = 2; // 每頁顯示筆數 int pageNumber = (page ?? 1); pageNumber = (pageNumber > (project.ToList().Count / pageSize + 1)) ? 1 : pageNumber; return View(project.ToPagedList(pageNumber, pageSize));

View 引入model方式 與 表頭顯示技巧

@model PagedList.IPagedList<Models.project> <th> @Html.DisplayNameFor(model => model.FirstOrDefault().ProjectId) </th>

分頁顯示

第 @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) 頁 共 @Model.PageCount 頁 @Html.PagedListPager(Model, page => Url.Action("Index", new { page }))

Controller

Model Binding 多重物件拋接

Object Class

Class person{
 string name {get; set;}
 int age {get; set;}
}

Controller

public ActionResult method(IList<person> per){
    ...
}

View

<input type="text" name="per[0].name" value=""/> <input type="text" name="per[0].age" value=""/>

View name 迭代一定要從0開始

TryUpdate

[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(int Id, FormCollection FromValue) { Product product = db.Product .Where(p => p.Id.Equals(Id)) .FirstOrDefault(); if (TryUpdateModel( product, //要更新的對象 "", //ViewModel的前置詞 FromValue.AllKeys, //代入的更新資料會自動綁定 new string[] { "ModifyUid" })) //要排除綁定的對象 { db.SaveChanges(); return RedirectToAction("Index"); } return View(product); }

TryUpdate ViewModel

https://dotblogs.com.tw/jasonyah/2013/05/11/103443

SelectList <專門>

ViewBag 塞入 SelectList

ViewBag.UnitSelect = new SelectList(db.Wtp_Unit, "UnitId", "UnitName");

View 顯示 SelectList

//DropDownList @Html.DropDownList ( "inputName", (IEnumerable<SelectListItem>)ViewBag.UnitSelect, "請選擇", new { @class = "form-control" } ) //DropDownListFor @Html.DropDownListFor ( x => x.InputName, (IEnumerable<SelectListItem>)ViewBag.EmpselectList, "請選擇", new { @class = "form-control" } )

自造 SelectList

var selectList = new List<SelectListItem> { }; foreach (var item in itemList) { selectList.Add ( new SelectListItem() { Text = item, Value = (int)item } ); } return selectList;

Enum 轉 selectList

var RoleList = Enum.GetValues(typeof(ROLE)) .Cast<ROLE>() .Select(v => new SelectListItem{ Text = v.ToString(), Value = ((int)v).ToString()}) .ToList();

RouteDate 取得Controller 與 Action

View

@ (ViewContext.RouteData.Values["action"]); @ (ViewContext.RouteData.Values["controller"]);

Controller

var currentAction = RouteData.Values["action"]; var currentController = RouteData.Values["controlller"];

Ajax

@Ajax.ActionLink("顯示文字", "ActionName", new {routeValue = "value"}, new AjaxOptions { HttpMethod = "GET", UpdateTargetId = "divMessage", InsertionMode = InsertionMode.Repalce })

AjaxHelper BeginForm

@using (Ajax.BegingForm("ActionName", new AjaxOptions{ HttpMethod = "GET", UpdateTargetId = "divMessage", InsertionMode = InsertionMode.Replace })) { <input type="text" name="routeValue" value="value" /> <input type="submit" /> }

jQuery Ajax

後端回傳Json 匿名類型串列示例

// JSON Practice public ActionResult GetJson() { var empList = new[] { new { empName = "", empId = "" } }.ToList(); foreach (var emp in db.Wtp_Employee) { if (emp.Title == "副總經理") { empList.Add( new { empName = emp.EmployeeName, empId = emp.EmployeeId }); } } return Json(empList.Skip(1), JsonRequestBehavior.AllowGet); }

ajax Function

public ActionResult JsonData(string id, string name){ var data = new {empId = id, EmpName = name, Age = 25}; return Json(data, JsonRequestBehavior.AllowGet); } ~/home/jsondata/100?name=marry
public ActionResult JsonData(string id, string name) { if (Request.IsAjaxRequest()){ var data = new {empId = id, EmpName = name, Age =25}; return Json(data, JsonRequestBehavior.AllowGet); } return View(); }
$(function(){ $("#button1").click(function(){ $.ajax({ type: "GET", url: "JsonData", data: "id=1&name=mary", success: function(data) { //data用於接住回傳值 console.log(data); $("#result").text(data.EmpName); } }); }); });

Confirm Delete Alert

以下範例結合 SweetAlert2 與 Ajax

$('#closeCase').click(function () { var caseId = $(this).attr("data-closeId"); swal({ title: '您確定要結案嗎?', text: " 確定結案後便無法再作意見編輯與檔案上傳", type: 'question', showCancelButton: true, confirmButtonColor: '#DD6B55', cancelButtonColor: '#aaa', confirmButtonText: '確認結案', cancelButtonText: '取消', allowEnterKey: false }).then(function () { $.ajax({ url: "@Url.Action("Close", "Do", null)", type: "POST", data: { id: caseId }, dataType: "Json", success: function (data) { swal("結案", "結案完成!", "success"); toDetach.remove(); }, error: function (xhr, ajaxOptions, thrownError) { swal("結案過程發生錯誤!", "請稍後再次執行", "error"); } }); // end of ajax }); // end of then }); // end of jQuery

SweetAlert2 ==Refrence==

JSON

存取 local json file

using System.IO; using Newtonsoft.Json; public static List<AuthMember> readJson() { var r = new List<AuthMember>{}; using (var sr = new StreamReader( System.Web.HttpContext.Current.Server.MapPath("~/App_Data/member.json"))) { r = JsonConvert.DeserializeObject<List<AuthMember>>(sr.ReadToEnd()); } return r; }