2013年12月22日 星期日

KendoUI & ASP.NET MVC系列文章 - 在Visual Studio安裝及更換主題

前言

此篇主要介紹在Visual Studio如何用Nuget安裝KendUI Freamwork及如何更換主題

下載與安裝

在專案上點右鍵,選擇管理Nuget套件

image

選擇線上分類,輸入kendoui,點選安裝

image

安裝完後,在MVC的專案,content(.css)和Scripts(.js)資料夾會多出Kendo資料夾,底下會有版號的資料夾名稱

image

載入方式

如果是純html,可以在<head></head>標籤內載入以下檔案

image

接著我們在html新增一個input標籤,實做KendoUI的日期選擇器

image

並加入以下JavaScript

image

這樣就完成基本的日期選擇器了

image

更換主題

KendoUI有另一個很吸引我的另一點是他有非常多的主題可以更換,且每個主題配色都蠻舒服的

image (圖片截取自官網)

而我們要切換主題,其實只要載入不同的css即可

image

如此就變成bootstrap主題了!

image

自訂主題

如果提供的主題與系統配色不合,對自己配色有信心,KendoUI也有提供很方便的Theme Builders,可以客製化你的主題檔

image

調整完後可以點選Get CSS,將所有程式碼貼回你的.css檔(建議是另外新增一個.css)

image

讓Visual Studio看懂KendoUI intellisense

如果不是用Nuget,而是用手動加入.css或.js的方式,可能Visual Studio不會有Intellisense(智慧提示功能)

image

解決方式是打開Scripts底下的_references.js檔案,將KendoUI Scripts路徑參考進去

image

後續

此篇主要簡單介紹開發前的準備,接下來幾篇文章,主要針對最常用的Grid來介紹!

2013年12月13日 星期五

[ASP.NET MVC]MVC 5.1 Prerelease – EnumDropDownList 小筆記

前言

前幾天看到MVC 5.1 Release 的消息,利用假日玩了一下新增的Html - EnumDropDownList。
在以往要自己擴充這個MvcHtmlString,目前新的版本已經內建進去,以下用MVC預設範本記錄些Sample Code

安裝

至套件管理主控台輸入 Install-Package Microsoft.AspNet.Mvc -Version 5.1.0-rc1 –Pre 來安裝
image
至Models資料夾加入MyEnum class
image
定義一個DeptEnum
image
打開Modles->AccountViewModels –> RegisterViewModel,新增一個DeptEnum的成員
image
至Account註冊頁面,打開Register.cshtml,加入Html.EnumDropDownListFor()
image
如此就可以看到下拉式選單!
image
Sumbit後也可以看到自動的Model binding了,看來以後開發MVC會越來越方便了 ^_^
image

延伸閱讀

Release Candidates for ASP.NET MVC 5.1, Web API 2.1 and Web Page 3.1.
如何讓舊版MVC實做EnumDropDownList
Enum (C# 參考)

[C#]取得類別(Class)所有的成員(Members),以產生XML為例

前言

工作上寫到很多的XML Element,但看到有些人再寫複雜XML文件時,程式碼還冗長的,譬如以下的XML文件:

image

有些人可能不會想太多,很直覺的寫以下程式:

image

XmlDocument doc = new XmlDocument();
XmlElement company = doc.CreateElement("Company");
doc.AppendChild(company);

XmlElement id = doc.CreateElement("id");
id.InnerText = _Staff.id.ToString();
company.AppendChild(id);

XmlElement StaffName = doc.CreateElement("StaffName");
StaffName.InnerText = _Staff.StaffName.ToString();
company.AppendChild(StaffName);

XmlElement Birthday = doc.CreateElement("Birthday");
Birthday.InnerText = _Staff.Birthday.ToShortDateString();
company.AppendChild(Birthday);

XmlElement weight = doc.CreateElement("Dept");
weight.InnerText = _Staff.weight.ToString();
company.AppendChild(weight);

但根據DRY原則(Don’t repeat youself),如果發現一直在ctrl+v程式碼,一定要跟李組長一樣眉頭一皺,發現專案並不單純…


實做


因目前資料來源習慣都使用Entity Framework (強型別)來操作物件,取代ADO.NET的DataReader or DataTable (弱型別)


而C#能用PropertyInfo來抓取object的所有成員


故我將產生冗長的XmlElement抽出來處理:


private void CreateModelXmlElement(ref XmlDocument doc,ref XmlElement root)
{
Type type = model.GetType();
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
if (propertyInfo.CanRead)
{
XmlElement _element = doc.CreateElement(propertyInfo.Name);
if (propertyInfo.PropertyType == typeof(DateTime))
{
//針對DateTime去做日期格式處理
DateTime value = Convert.ToDateTime(propertyInfo.GetValue(model, null));
_element.InnerText = value.ToShortDateString();
}
else
{
var value = propertyInfo.GetValue(model, null);
_element.InnerText = value.ToString();
}
root.AppendChild(_element);
}
}
}

這樣子就將麻煩的Create XmlElement縮短成以下片段:

XmlDocument doc = new XmlDocument();
XmlElement company = doc.CreateElement("Company");
doc.AppendChild(company);

CreateModelXmlElement(ref doc, ref company);

延伸閱讀


http://msdn.microsoft.com/zh-tw/library/system.reflection.propertyinfo(v=vs.110).aspx


http://stackoverflow.com/questions/3723934/using-propertyinfo-to-find-out-the-property-type


http://stackoverflow.com/questions/957783/loop-through-an-objects-properties-in-c-sharp

2013年12月7日 星期六

[ASP.NET]相同的IIS,讓多個網站共用Session資訊

前言

先談談為什麼會有此需求吧,擔任甲方的IT部門最大的挑戰就是要維護舊的系統,要瞭解很多的business logic,而因為舊系統技術過舊架構也不太好,造成維護困難,故提出了重構的建議,但現實往往不可能那麼美好,因為還是要面對新的需求,處理使用者的操作問題,又因人力不足沒辦法專注的在重構這件事,所以只能列出計畫,有計劃性的慢慢重構,而短期目標就是舊的系統不要在增肥,而新的需求遵循新的架構走。

本公司舊系統是WebForm 2.0的Website,我試著導入MVC,故最初的想法是將舊網站先升級到FrameWork 4.0,再將新的MVC Application加入進去,但升級上遇到了困難,因舊的WebSite有買第三方Grid套件,故他是綁死在.NET 2.0的,嘗試升級後整個就悲劇了,故開始朝向兩個Website去處理,而遇到的課題就是一些Session資料如何共用:

1.將使用者的資訊存入Cookie - 可行,但有安全性的疑慮

2.利用SQL Server的Session機制實現

本篇將介紹第二點的實現方式

Step 1 建置並發佈兩個網站

image

而在這網站新增一個WebForm,程式也簡單到不行,秀出當前的Session及新增Session功能

image

Step 2 建置存放Session專用的資料庫

進入C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319 將此路徑複製

image

進入命令提示字元,鍵入以下指令

aspnet_regsql.exe -S 資料庫主機IP -U sa -P 密碼 -ssadd -sstype c -d 資料庫名稱

請依情況去改變上方參數

image

利用SSMS,就可看到資料庫已經建置完成

image

Step 3 修改WebSite的Web.config

在Web.config system.web區塊加入以下程式,程式區塊都不用動

<sessionState mode="SQLServer" sqlConnectionString="data source=KYLE;initial catalog=SessionPool;user id=sa;password=kyle" allowCustomSqlDatabase="true"  timeout="120"/>

Step 4 修改SQL Session Table

進入DB,會看到有以下兩個表: 

ASPStateTempApplications 用來儲存應用程式的ID和名稱

ASPStateTempSessions 用來儲存Session的值

image

先兩分別Run看看在兩個網站寫入一個Session資料會變什麼情況

image

會發現會有兩筆AppName,而ASPStateTempSessions 則會有Session紀錄

接著最重要的,其實就是在SQL stored procedure做些手腳,讓不同的Apps,指向同一個AppName

打開預存程序dbo.TempGetAppID

image

修改@appName

image

這樣就大功告成了,我們重啟IIS和SQL,把Session清掉再來各新增一筆看看:

image

後記

建議,要重構還是整個重新規劃會比較好,畢竟Session移到SQL上,DB因為connection次數變多而負擔加重,多少會有些效能問題,但不能忍受古人的技術債又因為一些因素影響的人,就可以參考這種方式 T___T

--

Reference

http://www.cnblogs.com/haoxue/archive/2010/10/11/asp_net_session_share.html

http://www.debugease.com/aspdotnet/1712975.html

[MS SQL]如何抓取某筆資料的上下筆(Cross Join)

朋友問到,如何將下圖的資料,抓取指定的上下筆,以新聞輪播的功能來舉例:

image

用程式來講蠻單純的,只要取得目前的ID,就可以用select top 1 + where條件就可以完成,

但這樣有可能要connection兩次,所以就寫了一個Script + CROSS JOIN 來解決 :P

Script

declare @TABLE TABLE (ID int,Title nvarchar(50))
declare @tagetID int

--新增資料
INSERT INTO @TABLE VALUES(1,N'新聞標題1')
INSERT INTO @TABLE VALUES(2,N'新聞標題2')
INSERT INTO @TABLE VALUES(3,N'新聞標題3')
INSERT INTO @TABLE VALUES(4,N'新聞標題4')
INSERT INTO @TABLE VALUES(5,N'新聞標題5')

select * from @TABLE

set @tagetID = 3 --抓取ID為3的上下筆

SELECT P.PrevID,P.Name as 'Prev News', N.NextID,N.Name as 'Next News' FROM
(
SELECT MAX(A.id) PrevID,
(select Title FROM @TABLE where id = MAX(A.id)) Name
from @TABLE A
where A.id < @tagetID
) P
CROSS JOIN
(
SELECT MIN(A.id) NextID,
(select Title FROM @TABLE where id = MAX(A.id)) Name
from @TABLE A
where A.id > @tagetID
) N


CROSS JOIN


Cross Join 是一個實現笛卡兒乘積 (Cartesian Product)的語法,已兩個table來講,如tableA資料5筆,table資料4筆,select出來就會是20筆,用文字說明有點複雜,以下寫個Sample :

declare @employee TABLE (empID int,Name nvarchar(50)) --員工表
declare @Dept TABLE (DeptID int,Name nvarchar(50)) --部門表

--新增資料
INSERT INTO @employee VALUES(1,N'周杰倫')
INSERT INTO @employee VALUES(2,N'蕭敬騰')
INSERT INTO @employee VALUES(3,N'方大同')

INSERT INTO @Dept VALUES(1,N'財務部')
INSERT INTO @Dept VALUES(2,N'行銷部')
INSERT INTO @Dept VALUES(3,N'研發部')


select * from @employee cross join @Dept -- 3 * 3 9筆資料

--結果等同於
select * from @employee,@Dept

image


使用如果不慎注意會是效能殺手,譬如1000*1000筆資料吃的效能可是很可怕的,而回到上例,其實上一頁跟下一頁都只是會有一筆資料而已,故只是很簡單的應用讓他查詢出來會是一筆記錄


--


Reference


http://technet.microsoft.com/zh-tw/library/ms190690(v=sql.105).aspx


http://blog.csdn.net/xiaolinyouni/article/details/6943337

[MS SQL]寫給新手的Cursor小筆記

前言

雖然網路範例非常多,但之前在回答新手問題時,丟了一些範例連結給他,他還是看不太懂,後來就自己寫了一個範例加註釋,終於讓他瞭解並應用,所以我想試著用自己的解釋方式紀錄下來,提供給一些還不熟悉的初心者。

Cursor(資料指標)

常常我們都會在程式撰寫迴圈,在SQL裡面就是使用Cusor,Cursor會先從資料庫裡面讀出資料,暫存於tempDB資料庫內,再從tempDB逐筆讀出處理,就因為有寫入tempDB的動作,所以使用上也要注意,譬如我看過明明就能用update語法直接處理掉的程式,還使用Cusor逐筆跑出去update,這種影響效能就會非常巨大。

一個簡單的Cursor範例


--定義Cursor並打開
DECLARE MyCursor Cursor FOR --宣告,名稱為MyCursor

-- 此區段就可以撰寫你的資料集,如找出名稱為John的資料
select id from tableA where name like '%John%'

Open MyCursor


print @@CURSOR_rows --查看總筆數


--定義ID變數
declare @id varchar(25) --用來存放ID的變數

--開始迴圈跑Cursor Start
Fetch NEXT FROM MyCursor INTO @id
While (@@FETCH_STATUS <> -1)
BEGIN

--此區塊就可以處理商業邏輯,譬如利用tableA的ID將資料塞入tableB
insert into tableB
select top 1 * from tableA where id=@id

Fetch NEXT FROM MyCursor INTO @id
END

--開始迴圈跑Cursor End

--關閉&釋放cursor
CLOSE MyCursor
DEALLOCATE MyCursor


--


Reference


http://sharedderrick.blogspot.tw/2013/02/cursors-rowsets.html

2013年12月4日 星期三

[EF]找出EntityValidationErrors的明細錯誤訊息

在開發MVC使用EntityValidationErrors時,如果遇到如下圖錯誤:

QQ截圖20131204154904

利用瀏覽器的開發者工具也無法找到錯誤 e.g Chome F12 -> Network :

image

只看到Model驗證失敗,卻找不到很明確的錯誤訊息。

這時我們就可以用EntityValidationErrors來catch錯誤訊息:

try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException e)
{
string ErrorMsg = e.Message;
}
catch(Exception e)
{

}


可以發現是某個欄位為空值,導致新增失敗


image