繼上次的ASP.NET使用筆記又過了一年多
本次記錄了ASP.NET MVC與css/js/sql所遇到的問題
希望能幫到發生同樣問題的人
若內容有誤,歡迎網友指正
===========[ ASP.NET MVC ]===========
※ASP.NET MVC是什麼?
ASP.NET MVC是一種建構在ASP.NET上的類別庫
可以把ASP.NET使用MVC(model-view-controller)的設計模式實作網頁
優點是可以把畫面跟商業邏輯拆開,將來維護上更容易
此外MVC走回頭路使用當初ASP那樣直接用程式控制網頁的方式
可以更容易使用javascript跟ajax
由於網頁所有內容都是自己產生的
不會像過去使用ASP.NET的控制項後就無法通過Html無障礙標準
也沒有過去ViewState的包袱,讓網頁顯示的速度更加快速
缺點是進入門檻較高,MVC架構較複雜初期理解不易
設計模式無法直接預覽畫面,因此對js/css的技術都要很熟才行
※所以MVC是一種趨勢嗎?
現在越來越多網站開始使用MVC開發,書店也開始有MVC 4的書籍
能支援MVC的工具程式也越來越多(例如kendo UI)
甚至Visual Studio 2012已經內建了MVC 4
如果再搭配上EntityFramework,整個開發時間會更加快速且問題較少
※我應該把ASP.NET專案改寫成MVC嗎?
不要(一秒)
因為ASP.NET沒辦法直接轉到MVC架構,所以等於要重寫,不建議費這些功夫
未來要作新網站的時候再考慮MVC就好了
※MVC要怎麼把別的頁面內嵌進來?
使用Html.RenderAction或Html.Action,語法是
@{ Html.RenderAction("Name"); } @Html.Action("Name")
如果這個動作只會被內嵌進來的話,最好加上[ChildActionOnly]避免被直連
※Html.RenderAction跟Html.Action的差別是?
前者是直接把內容放到Response,後者會回傳MvcHtmlString,你可以存成變數使用
效能上哪個比較好? 其實沒差多少不用鑽牛角尖
寫哪種比較好? 當然是短的那種比較好
※PartialView的內容可以使用ajax方式取回html嗎?
可以,不過要寫一個RenderPartialViewToString
protected string RenderPartialViewToString(string viewName, object model) { if (string.IsNullOrEmpty(viewName)) viewName = ControllerContext.RouteData.GetRequiredString("action"); ViewData.Model = model; using (StringWriter sw = new StringWriter()) { ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName); ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw); viewResult.View.Render(viewContext, sw); return sw.GetStringBuilder().ToString(); } }
使用方式
string renderView = this.RenderPartialViewToString("ViewName", model);
在client用ajax接到之後,直接用$("#element").html(response);即可
※如何讓Ajax.BeginForm動態被改成Html.BeginForm?
要這樣改的原因是Ajax.BeginForm如果要回傳檔案讓使用者下載的話可能會出錯
最簡單的做法就是把form的data-ajax屬性true改成false,這樣就不會有問題了
※MVC的helper為什麼只有@Html.Button沒有@Html.Submit?
因為submit除了產生html code外,沒有(也不需要)validation跟model binding等功能
所以微軟就不做了吧
真的需要可以自己手寫一個helper
不過我是覺得View上面的helper少一點,可讀性比較高
※MVC的helper有沒有@Html.CheckBoxList或@Html.RadioButtonList?
沒有,不過你可以自己用迴圈寫,或是在NuGet用別人寫好的方法
※Html.Action的route可不可以用string?
可以,用json反序列化
以下範例會連到"controller/action?Name=John"
@Html.Action("action", "controller", Newtonsoft.Json.JsonConvert.DeserializeObject("{\"Name\":\"John\"}");
※使用PagedList沒法用DisplayNameFor的解決法
PagedList是一個可以幫IEnumerable建立分頁的一個套件 (使用說明)
不過因為需要把model改成@model PagedList.PagedList<SomeModel>
所以DisplayNameFor會失效
如果需要使用的話,需要寫上FirstOrDefault()
@Html.DisplayNameFor(model => model.UserID)
改成
@Html.DisplayNameFor(model => model.FirstOrDefault().UserID)
※如何讓View根據是不是Ajax載入回傳PartialView或View
以下兩種判斷方式任選一種
cshtml判斷
@if (Request.IsAjaxRequest()) { Layout = null; }
controller判斷
if (HttpContext.Request.IsAjaxRequest()) return PartialView(model); else return View(model);
可以考慮把這段寫成一個function
記得回傳型態要用ActionResult
個人建議是後者的寫法比較好,因為View最好不要寫邏輯判斷式
讓View單純顯示Model給它的資料就好
※Controller的return type預設是ActionResult
如果我今天要回傳PartialView,Return Type要用ActionResult或PartialViewResult都可以
那PartialViewResult到底有什麼意義?
就僅是型別檢查,告訴別人這個action絕對會回傳PartialView
※用Toi18n()簡單建置多國語言
VS 2008開始有擴充方法(Extension Methods)的功能,簡單來說就是可以把傳統的
NewMethod("value")改寫成"value".NewMethod()的形式,讓程式可讀性提高且撰寫方便
而且任何型態都可以用,也不限定只能傳一個參數,相當不錯
Toi18n可以參考這個網頁的語法教學
※我用了Toi18n的語法,可是文字竟然沒有顯示在畫面上
Ex. @Html.Label("UserNameResKey".Toi18n())
因為它如果對應到的Resource有包含"."
它產生的html code是<label for="value">value</label>
但因為for不能加上.,所以整段都不會產生
比較好的作法還是用DisplayNameFor,或是直接寫成
<label>@("UserNameResKey".Toi18n())</label>
※使用@Html.CheckBox(),為什麼MVC會自動幫我加上一個hidden field?
因為如果沒有這個hidden field,不勾選時它不會回傳這個欄位,會讓這個參數變成null
如果它又不允許null,就會出錯 (參考)
View
Controller
public ActionResult Test(bool rememberMe){ // 沒hidden時,不勾選會出錯 }
※如何對時間型態指定格式?
有兩種方法
1. 設定DisplayFormat
[DisplayFormat(DataFormatString = "{0:yyyy/MM/dd HH:mm}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> StartTime { get; set; }
這樣會在@Html.DisplayFor(model => model.StartTime)時顯示指定的格式
如果該格式也想在文字方塊(TextBox)有相同格式,請多設定ApplyFormatInEditMode = true
然後@Html.EditorFor(model => model.StartTime)
2. 在View指定格式
不要使用EditorFor,改成使用TextBoxFor
@Html.TextBoxFor(model => model.StartTime, "{0:yyyy/MM/dd HH:mm}"
※有沒有辦法對EditorFor增加style或其他參數?
MVC 4沒辦法,到MVC 5.1時才開始能對EditorFor增加參數
@Html.EditorFor(model => model, new { htmlAttributes = new { @class = "form-control" } })
※提高某個上傳頁面的上限
ASP.NET預設封包長度限制是4MB,代表上傳功能最多只能上傳4MB
要增加一般人會用修改maxRequestLength的方式
如在<system.web>中加入以下設定
<httpRuntime maxRequestLength="10240" executionTimeout="300"/>
可是這樣會造成所有頁面都會提高上限
有沒有辦法只讓特定頁面提高呢?可以的,利用location去限制
<location path="Data/Upload">
<system.web>
<!-- 單位 kb (1024 = 1MB) -->
<httpRuntime maxRequestLength="102400" />
</system.web>
<system.webServer>
<security>
<requestFiltering>
<!-- 單位 byte (1024000 = 1MB) -->
<requestLimits maxAllowedContentLength="102400000" />
</requestFiltering>
</security>
</system.webServer>
</location>
修改path/maxRequestLength/maxAllowedContentLength即可
如以上範例就是修改成可上傳100MB
有些人可能會問requestLimits是啥,這是IIS 7.0開始增加的額外限制
只改maxRequestLength,上傳大檔時可能就會出現「要求篩選模組設定為拒絕超過要求內容長度的要求」的錯誤訊息
因此也要修改相對應的requestLimits
※短時間快速存取DateTime.Now,其值可能重複
如題,如果這個時間戳記用在DB的PK欄位或是檔名等不允許重複的項目,就會造成錯誤
建議自行創建個時間戳記物件,請參考
https://stackoverflow.com/questions/5608980/how-to-ensure-a-timestamp-is-always-unique
※用了Ajax.BeginForm,在Server端回傳Json卻變成取代整個網頁
必須安裝Microsoft.jQuery.Unobtrusive.Ajax套件才能運作(NuGet可下載)
這個套件過去有在範本中,新範本卻拿掉了,不知為何
===========[ CSS ]===========
※css的字型有除以是什麼意思?
Ex. font: 15px/24px 'Helvetica Neue',sans-serif;
其實就是line-height的意思,而且是css1就有的寫法
只是大部分的人都會獨立出來寫成
font: 15px 'Helvetica Neue',sans-serif;
line-height: 24px;
※chrome把div拖曳的時候會有奇怪的殘影,要如何去掉?
這是chrome的固有bug (參考),目前的解法是在css加上
-webkit-backface-visibility: hidden;
※使用display: table-header-group;要在列印的時候重覆標題列
IE跟Firefox都正常,Chrome卻無效,為什麼?
因為chrome到現在還不願意去實作這個功能!
解決法: 沒有!自己想辦法兜出這個功能吧
※如何在一個div內把裡面的元素水平垂直置中?
如果你想就直接用align: center跟vertical-align: middle,直接說垂直是行不通的
(1) 用absolute的方式置中
<div class="div">
<img class="img" alt="" src="xxxxx" />
</div>
<style>
.div {
width: 100px;
height: 100px;
position: relative;
}
.img {
max-width: 100px;
max-height: 100px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
</style>
(2) IE 9以後的瀏覽器支援了display: table-cell; 這種css屬性
table-cell會把元素當成儲存格一樣渲染,所以可以直接加上vertical-align: middle;
※用css指定元素有四種方式 (1)id (2)class name (3)tag name (4)style,如果某元素同時被這四種方式指定,請由優先權最高至最低排序
4>1>2>3
原理是最能代表該元素的會最優先套用
style寫在元素上,只可能影響該元素
id有可能重複(雖然對DOM來說不允許同名ID)
class name可以套用在多個元素上
tag name連設定class都不必,只要是同樣tag就會被影響,故優先權最低
另外這是在css只有一層的情形,如果是div > div這樣多層又會有不同結果
===========[ jQuery ]===========
※如何在html元素外包一個div?
比方說原本網頁內容是<label>Hello</label>
我想用js改成<div><label>Hello</label></div>要怎麼做呢?
我一開始還在想創造一個div後把原來的html剪下貼上
其實正確作法相當簡單,只要使用jquery.wrap就可以了
$("label").wrap("<div></div>");
※jquery validation可以針對動態產生的網頁增加驗證嗎?
$.validator.unobtrusive.parse('#element');
※兩個網頁元素中跑出一個space,無法緊鄰,要如何解決?
會有space是因為兩個元素中間有空白,最好的做法就是去掉空白
1. <div></div><div></div> 強迫元素相接
2. <div></div><!--
--><div></div>
3. <div></div
><div></div>
※js如果要指定用Model指定的物件,使用IdFor的方式會比較好
因為到時候如果Model的屬性需要重構(refactor)改名時
雖然View的內容還是不會跟著改,不過編輯的時候就會因為找不到屬性報錯
總比完全沒報的好
$("#UserName").val(); // 當屬性更名後,除非網頁出錯不然設計師不知道要改 $("#@Html.IdFor(m => m.UserName)").val(); // 編輯網頁時就會顯示錯誤了
※$(document).ready(function () { });可以直接簡寫成$(function() { });
※js可以刪掉asp.net建立的cookie嗎? 直接刪沒用耶
可以,但是要加上path
$.removeCookie("cookieName", { path: "/" });
※讓Ajax避免CSRF攻擊
CSRF也就是跨站請求偽造(Cross-site request forgery)
簡單來說就是登入後使用偽造封包傳送
比較簡單的預防方法是增加校驗token,驗證封包的確是在網站上傳送
ASP.NET MVC有內建的方法
在View宣告@Html.AntiForgeryToken()
在Controller加上[ValidateAntiForgeryToken]的標籤
這樣當他沒有驗證到token時就會丟出exception
以上方法是針對一般的表單
但Ajax Post沒有內含token,所以沒法用[ValidateAntiForgeryToken]
解法就是建立個假表單,並產生token
當Ajax要Post時就將token塞入
請將以下網頁存成Partial
<form id="__AjaxAntiForgeryForm" action="#" method="post">@Html.AntiForgeryToken()</form>
<script>
AddAntiForgeryToken = function (data) {
data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
return data;
};
</script>
在Ajax時加上AddAntiForgeryToken這個方法
$.ajax({
url: "@Url.Action("GetCity")",
data: AddAntiForgeryToken({ country: "台灣" }),
type: "POST",
});
※Ajax的參數不建議直接寫在url
因為若參數是中文可能會造成IE跟Chrome編碼錯誤(Firefox反而正確...)
比較正統的方式是把參數寫在data中
或是用encodeURI()將url編碼
// 不好的寫法 $.ajax({ url: "@Url.Action("GetCity")?country=" + "台灣", type: "POST", }); // 較好的寫法 $.ajax({ url: "@Url.Action("GetCity")", data: { country: "台灣" }, type: "POST", });
※js要如何使用String.Format的寫法?
可以自己加上方法,以下取自網路
另外如果有使用Kendo UI,裡面有個kendo.format也是相同用法
if (!String.Format) { String.Format = function (format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match ; }); }; }
用法就是var value = String.Format("Hello {0}", "World");
===========[ EntityFramework ]===========
※如何讓EntityFramework產生的資料表物件增加DisplayName等metadata?
如果想要直接去改class那是一定不可行的,因為每次更新都會被清掉
如果要自己創建一個類似名稱的class,每次把參數手動搬過去實在太過麻煩
因為寫回db時又要做同樣的事情
db.Account.Select(x => new MyAccount { Name = x.Name // 不建議這樣的作法 });
比較建議的做法是使用metadata創建同名class,就可以在參數上增加metadata了
還可以做驗證
[MetadataType(typeof(AccountMetadata))] public partial class Account { public class AccountMetadata { [Display(Name = "姓名")] [StringLength(30)] public string Name { get; set; } } }
View的model可以設定成Account,這樣controller得到的也會是Account物件
就可以直接將該物件新增到DB
Ex: db.Account.Add(model);
如果想在model增加不同於資料表物件的參數(例如帳號修改會有確認密碼等等)
可以直接寫在partial class的裡面,之後直接新增也不會有問題
[MetadataType(typeof(AccountMetadata))] public partial class Account { public class AccountMetadata { [Display(Name = "密碼")] [DataType(DataType.Password)] public string Password { get; set; } } [Display(Name = "確認密碼")] [Compare("Password")] [DataType(DataType.Password)] public string ConfirmPassword { get; set; } }
※EntityFramework有沒有辦法用預設方法讓Model在Server做驗證?
雖然Model可以用Data Annotation,但沒法適用所有驗證(例如某時間必須大於某時間)
因此我們可以對Model增加新的驗證方法
使用方法就是繼承IValidatableObject
[MetadataType(typeof(EventMetadata))] public partial class Event : IValidatableObject { public class EventMetadata { public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } } public IEnumerable Validate(ValidationContext validationContext) { if (StartTime > EndTime) { yield return new ValidationResult("結束時間不能早於開始時間", new string[] { "EndTime" }); } } }
※EntityFramework想用Database-First的方式,但是卻變成Code-First,要如何改回來?
1. 刪除所有動態產生的tt檔
2. edmx的程式碼產生策略改成"預設值"
3. 執行自訂工具
沒記錯的話VS2010預設是DB-First,但2012是Code-First
至於我為什麼要捨棄Code-First使用DB-First
是因為Code-First似乎沒法指定ConnectionString,也沒有ExecuteQuery
※在Linq使用if else的縮寫卻發現找出來的結果不正確?
假設我今天查詢有兩個條件,A條件不重要
B條件是:如果某變數為空值表示不篩選欄位,反之篩選欄位
就會寫成
where a && b ? true : c
實際上這句話EF會解讀成
where (a && b) ? true : c
而不是我所想的
where a && (b ? true : c)
所以...請適時的條件加上括號
其實這種寫法也不好,更好的寫法是利用IQueryable來增加篩選條件
var queryable = db.Accounts.AsQueryable();
if (!stinrg.IsNullOrEmpty(filterAccount)) {
queryable = queryable.Where(x => x.Account == filterAccount)
}
也可以用網路上有人寫好的WhereIf擴展方法,可讀性更高
※EntityFramework要怎麼在新增一筆資料後,取得由資料庫自動編號的欄位?
其實你呼叫SaveChanges()後,該欄位就會出來了
以下假設有個table叫作User,包含ID跟Name,ID是自動產生的欄位
var entity = new User { Name = "John" }; dbcontext.User.Add(entity); dbcontext.SaveChanges(); int id = entity.ID;
但這代表一定要先儲存後才能取回id,所以就沒辦法作交易(transaction)
如果你要用這個id建立其他資料而且整段都要交易的話
就要改用TransactionScope了
※EntityFramework怎麼做批次刪除?
EF 5沒辦法
EF 6可以使用db.Account.RemoveRange(removeEntities);
※EntityFramework取一筆資料有沒有更快的做法?
EF 6新增了Find方法,如果該筆資料有cache的情況會優先使用cache
而且多個PK也支援
return db.Account.SingleOrDefault(x => x.ID == id); // 普通方法,無cache return db.Account.Find(id); // 新方法,有cache
※只改某筆資料欄位儲存的時候,出現了DbEntityValidationException?
因為DbContext會在儲存的時候先進行一次Server端Data Annotation驗證
如果出錯就不會跑到DB端去,減少讀取DB的次數
但如果我想要取消驗證該怎麼辦呢?
可以先把ValidateOnSaveEnabled設為false,存完後再打開
try { base.Configuration.ValidateOnSaveEnabled = false; base.SaveChanges(); } catch (DbEntityValidationException dbEx) { throw dbEx; } finally { base.Configuration.ValidateOnSaveEnabled = true; }
※出現DbEntityValidationException,卻沒有寫驗證失敗的欄位,要怎麼看?
必須使用try catch (DbEntityValidationException)才能看到其錯誤的資訊
如果你不想要每次SaveChanges()的時候都要寫一遍try catch
可以包成擴充方法(以下部分內容取自網路)
public override int SaveChanges() { try { return base.SaveChanges(); } catch (DbEntityValidationException ex) { // Retrieve the error messages as a list of strings. var errorMessages = ex.EntityValidationErrors .SelectMany(x => x.ValidationErrors) .Select(x => x.ErrorMessage); // Join the list to a single string. var fullErrorMessage = string.Join("; ", errorMessages); // Combine the original exception message with the new one. var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage); // Throw a new DbEntityValidationException with the improved exception message. throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors); } }
※我想用字串來指定Linq的欄位,有沒有辦法?
可以用Dynamic Linq (用NuGet下載)
缺點是編譯時會失去強型別檢查
※Dynamic Linq要怎麼作Group?
使用前請先修改DynamicLibrary.cs
static readonly Type[] predefinedTypes = { // 前略 typeof(SqlFunctions) // 加上這行讓它可以解析SqlFunctions }
以下假設有個Account資料表,針對其Birthday屬性作Group
dbContext.Account .GroupBy("new (String.Concat(SqlFunctions.DateName(\"yyyy\", Birthday) , \"/\", SqlFunctions.StringConvert(SqlFunctions.DatePart(\"mm\", Birthday)).Trim()) as Birthday)", "it") .Select("new (Key.Birthday)").OrderBy("new (Birthday)");
※Dynamic Linq對於SqlFunctions.StringConvert不支援int?,要如何解決?
修改DynamicLibrary.cs
static int CompareConversions(Type s, Type t1, Type t2) // 前略 if (s == typeof(Int32?) && t1 == typeof(Decimal?)) return 1; // 加上這行 return 0; }
※Dynamic Linq只要比對Guid就會出錯,要如何解決?
(訊息為 "Operator '=' incompatible with operand types 'Guid' and 'Guid'")
一樣修改DynamicLibrary.cs
interface IEqualitySignatures : IRelationalSignatures { void F(bool x, bool y); void F(bool? x, bool? y); void F(Guid x, Guid y); // 加上這行 void F(Guid? x, Guid? y); // 加上這行 }
※EntityFramework使用自定義function的轉換方法
EntityFramework雖然有SqlFunctions的函式可以提供基本轉換
但對於把string轉成decimal這種基本功能卻難以達成
(明明在SQL其實只要加一個CAST(field as decimal)就解決了...)
如果在SqlFunctions沒有看到自己需要的方法,可以自己撰寫
將edmx使用xml開啟,找到<edmx:ConceptualModels>底下的<Schema Namespace="xxx"這段
在內部直接加上
<Function Name="CastDecimal" ReturnType="Edm.Decimal">
<Parameter Name="stringvalue" Type="Edm.String" />
<DefiningExpression>
CAST(stringvalue as decimal(13,3))
</DefiningExpression>
</Function>
隨意一處加上這個靜態類別跟方法
public static class MySqlFunctions { [EdmFunction("DBModel", "CastDecimal")] public static decimal CastDecimal(string stringvalue) { return Convert.ToDecimal(stringvalue); } }
最後在作轉換的時候就能直接用MySqlFunctions.CastDecimal(fieldName)
dbContext.Account.Select(x => new { ID = MySqlFunctions.CastDecimal(x.ID) });
如果要用在Dynamic Linq,請先修改DynamicLibrary.cs
static readonly Type[] predefinedTypes = { // 前略 typeof(MyProject.MySqlFunctions) // 加上這行 }
※有沒有辦法取得IQueryable轉成SQL的語法?
IQueryable queryable = GetQueryable(); string sql = ((ObjectQuery)queryable).ToTraceString();
※沒有定義型態的IQueryable有沒有辦法取出欄位?
可以使用IQueryable to DataTable的方法,之後以DataTable的方式處理
以下語法取自網路
public static DataTable ToDataTable(this IQueryable varlist) { DataTable dtReturn = new DataTable(); // column names PropertyInfo[] oProps = null; if (varlist == null) return dtReturn; foreach (var rec in varlist) { // Use reflection to get property names, to create table, Only first time, others will follow if (oProps == null) { oProps = ((Type)rec.GetType()).GetProperties(); foreach (PropertyInfo pi in oProps) { Type colType = pi.PropertyType; if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>))) { colType = colType.GetGenericArguments()[0]; } dtReturn.Columns.Add(new DataColumn(pi.Name, colType)); } } DataRow dr = dtReturn.NewRow(); foreach (PropertyInfo pi in oProps) { dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue (rec, null); } dtReturn.Rows.Add(dr); } dtReturn.AcceptChanges(); return dtReturn; }
※Entity Framework要怎麼對連線寫Log?
EF6開始增加了Log屬性,可以顯示所有Linq to SQL的字串跟執行時間
var db = new MyEntities(); db.Database.Log = (log) => System.Diagnostics.Debug.WriteLine(log);
※查詢時間範圍,千萬不可使用"23:59:59"這種查詢方式
常看到有人查詢會把時間後面加上23:59:59來查詢
例如查詢當日,有人會用
where date >= DateTime.Parse(today + " 0:0:0") && date <= DateTime.Parse(today + " 23:59:59")
實際上這是非常不好的寫法,因為時間並不是只到秒
如果資料時間為23:59:59.1就查不到了
當然這種情形很少見,但不是不會發生,最正確的寫法是
where date >= today && date < today.AddDays(1)
讓時間小於邊界即可
===========[ MsSQL ]===========
※如何動態建立資料庫的時候限制資料庫大小?
利用Alter database語法修改max_size
EXEC('CREATE DATABASE [' + @db_name + '];
ALTER DATABASE [' + @db_name + '] MODIFY FILE
( NAME = N''' + @db_name + ''', MAXSIZE = ' + @max_size + ');')
※DB某欄位換行是\n,要怎麼都換成\r\n?
先將欄位\r\n都取代成\n,再取代回\r\n
不然若只把\n取代成\r\n,本來就是\r\n的資料就會出錯
UPDATE [MyDB].[dbo].[MyTable]
SET [MyTable].[MyColumn] = REPLACE(REPLACE([MyTable].[MyColumn], nchar(13) + nchar(10), nchar(10)), nchar(10), nchar(13) + nchar(10))
※如何直接砍掉某個資料庫
如果你的答案是直接執行
DROP DATABASE [DBName]
這段SQL的話,那很有可能會回傳這段話
Cannot drop database "DBName" because it is currently in use.
因此建議作法是先把資料庫轉成單人模式,由於轉換後自己會先佔用住
這時db砍掉就不會有人阻止了
USE [master]
ALTER DATABASE [DBName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [DBName];
===========[ 疑難雜症 ]===========
※已經產生的SelectList有沒有辦法去除某個項目?
雖然SelectList其實是IEnumerable<SelectListItem>
但它產生後就不可變了...
只能用重新產生的方式
SelectList origin = GetOriginSelectList(); SelectList newList = new SelectList(origin.Where(x => x.Value != "1"));
※如何把一個Enumerable的物件轉成代表的數字?
enum Sex { Male = 1, Female = 2 } // 答案是直接轉型就好 Sex sex = Sex.Male; int value = (int)sex; // 那要怎麼把數字直接轉成Enum? // 也是直接轉型就好... int value = 1; Sex sex = (Sex)value;
※Web.config會存在記憶體還是會每次使用變數時才去讀取一次?
第一次以後都是使用cached,所以不用費心幫它優化了 (參考)
The web.config file is usually just read once and the info cached so I dont think it will have any performance issue.
※全空白的字串trim()完之後會變成empty還是null?
empty
※假設有個form,有個textbox,不填任何值就submit
1. 在Model對應的型態是string時,最後回傳時結果會是?
2. 在Model對應的型態是DateTime?時,最後回傳時結果會是?
3. 在Model對應的型態是DateTime時,最後回傳時結果會是?
1. empty
2. null
3. exception,null無法轉型成DateTime
推測的原因是瀏覽器在沒有輸入的情況下回傳都是empty
但是對於非string且nullable的type他就會轉null
※別用ASP.NET內建的Json序列化程式JavaScriptSerializer
因為那實在是太慢又有問題
改用Json.Net吧(如果是MVC4的範例專案一開始就會附了)
※value.HasValue跟value != null的差別?
bool? test = null; if (test.HasValue && test.Value) { } // type 1 if (test != null && test.Value) { } // type 2
答案是沒有差別,因為compile幫我們做掉了 (參考)
哪個比較好?用HasValue可讀性高一點點
The compiler replaces null comparisons with a call to HasValue, so there is no real difference. Just do whichever is more readable/makes more sense to you and your colleagues.
※DataTable的DataColumn,除了Name、Caption外,有其他欄位可以記錄自定義資料嗎?
ExtendedProperty
※DataReader讀取資料的三種寫法,哪種比較快?
1. reader["field"].ToString()
2. (string)reader["field"]
3. reader.GetString(0)
速度上第二種較第一種快,但僅是幾微秒的差距
第一種當型態轉成int或別得不用特地改程式,第二種需要(不改會出錯)
第三種的缺點是它沒辦法用欄位名稱取回資料
所以可能會因為SQL或DB欄位順序改變導致取回的結果錯誤
※使用Visual Studio開啟專案一陣子後,編譯會出現VS2010建置時,發生"無法將檔案 "obj\Debug\ProjectName.dll" 複製到 "bin\Debug\ProjectName.dll"。由於另一個處理序正在使用檔案 'bin\Debug\ProjectName.dll',所以無法存取該檔案。",該如何解決?
Visual Studio 2010的固有bug,開前面版本專案就會發現這個錯誤
雖然網路上是說VS2010 SP1已經修好了這個bug,但我裝過還是會發生...
最後是改用VS 2012來編輯
You use the Visual Studio 2010 IDE to open a project that is in an earlier version. For example, you open a Visual Studio 2008 project. After a debug session, you cannot rebuild or debug the project again, and you receive an error message that resembles the following:
Unable to copy file "obj\Debug\assembly_name" to "bin\Debug\assembly_name". The process cannot access the file ‘bin\Debug\assembly_name" because it is being used by another process.
※超連結<a>使用onclick執行動作,其他瀏覽器正常但是IE 9會發生未預期的結果?
因為IE 9的動作跟其他瀏覽器都不同,試著在onclick後面加上return false;來解決
Link Link
※可以讓客戶修改的彈性設定,要放在web.config好還是db好?
比較有可能變動的放DB
比較不可能變動的放web.config
※判斷字串不能為null或empty
不用寫麻煩的if (stringvalue != null && stringvalue != "")
.NET 2.0後可以直接用String.IsNullOrEmpty(stringvalue)
但如果還要限制比方說trim完後不可為empty
.NET 4.0新增了String.IsNullOrWhiteSpace(stringvalue)
建議用內建的作法,可讀性比較高
※底下code會出現"輸入字串格式不正確"的錯誤訊息,想想看為什麼?
String.Format(@"<script>
$(""#{0}"").click(function(){
$(this).toggle();
});
</script>", "SomeOne");
因為大括號{}會被.NET視為特殊符號,如果要印出{或},請使用{{或}}
※為什麼有些人有問題都不願意求助?
定型心態
「當我們在考慮做或不做某件事情時,定型心態者是以「表現導向」做為背後的動機,而成長心態者則是以「學習導向」為出發點思考。如果去做這件事情,很有可能遭受失敗或是讓他看起來很蠢,定型心態者經常會避而遠之;而對於成長心態者來說,他們不會因為害怕失敗就不去做,因為他們重視的不是勝敗結果,而是知道自己能夠由每次的嘗試中更加進步並且更加熟練。」
※使用@Url.Action("action", "controller")時,卻產生action?Length=4這種網址,要怎麼解決?
這是因為同名異式造成呼叫function出錯
看一下MSDN就知道,雖然Url.Action的確有第一格回傳ActionName,第二格回傳ControllerName的組合(第四行)
但Action(String, String)又同時符合Action(String, Object)的條件(因String也是一個Object)
所以實際上編譯器會使用Url.Action(actionName, route)的方法
原本當作是Controller的參數會以Route方法讀取
但因為無法解析,所以變成了Length=X的輸出結果(X為ControllerName的長度)
這個問題也同時發生在Controller的return View(string);
如果今天Model的型態是string,那我丟入一個string時
他應該當成model還是viewName?
所以這個問題有沒有解決方法呢? 答案是有的
1. 給予所有的參數
例如Url.Action,若無Route,可以傳入null給他,變成這樣
@Url.Action("action", "controller", null)
他就不會認錯了
但這種方法實在太複雜,且不能保證一定有傳入所有參數的方法
2. 指定參數名稱
參數前面是可以指定名稱的,只要改寫成
@Url.Action("action", controllerName: "controller")
他就一定會使用Url.Action(actionName, coltrollerName)的方法了
我是建議用第二種啦
※我下載了Log4net,但好像沒有作用?
必須先讀取設定檔,有兩種方法
1. 在Global.asax.cs中Application_Start()最後加上
log4net.Config.XmlConfigurator.Configure();
2. 在AssemblyInfo.cs最後加上
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "config", Watch = true)]
建議是用第一種,第二種很多人不會注意
※SMTP寄信的設定值,不用寫在appSettings
大部份網站應該都會有寄信給使用者的功能
.NET本身就有SmtpClient這個類別可以寄信
比較差的工程師可能會直接把SMTP的位置跟Port寫死在程式中
好一點的會自己在appSettings加上相關設定
但其實只要直接宣告new SmtpClient(),他就會去抓組態檔的設定
不需要自己寫額外的code喔
在<configuration>內加上以下設定
<system.net>
<mailSettings>
<smtp deliveryMethod="Network" from=""顯示名稱" <電子信箱>">
<network host="郵件伺服器" port="25" defaultCredentials="false" userName="" password="" />
</smtp>
</mailSettings>
</system.net>
將from/host/port改成自己的設定即可
其中因為我的郵件伺服器不需要認證,所以defaultCredentials="false"
如果要帳密認證,請自行填上username/password
接著直接用var smtp = new SmtpClient();就可以使用了
※C#如何拿到(1)當前日期,不包含時分秒 (2)當前時間,不包含日期
(1) DateTime.Today / DateTime.Now.Date
(2) DateTime.Now.TimeOfDay
留言列表