2012年3月21日 星期三
2012年3月16日 星期五
ASP.NET網站管理工具的Table新增至自己的資料庫
在ASP.NET 2.0裡提供了好用又強大的會員管理控制項,而且只要在Visual Studio中點擊「ASP.NET組態」就可以馬上使用「ASP.NET網站管理工具」,但預設會在「~/App_Data」之下產生一個「ASPNETDB.MDF」的資料庫檔案,內建了11個系統預設資料表。
如果今天我們想把這些資料表整合到我們自己的資料庫中,那要怎麼做?其實一點都不難,方法有二(其實都是同一個方法,一個使用GUI,一個使用指令):
一、使用GUI(使用檔案總管)
1. 先切換目錄到
C:\Windows\Microsoft.NET\Framework\v2.0.50727;
二、點擊ASPNET_REGSQL.EXE;
三、依畫面輸入「主機名稱、帳號、密碼、資料庫名稱」;
主機名稱可以是本機也可以是遠端,只要你的帳號有足夠的權限,都可以新增資料表,按下確定後,系統就會自動將11個表格新增至你所指定的SQL Server的資料庫中。
二、使用指令(cmd.exe)
如果今天我們想把這些資料表整合到我們自己的資料庫中,那要怎麼做?其實一點都不難,方法有二(其實都是同一個方法,一個使用GUI,一個使用指令):
一、使用GUI(使用檔案總管)
1. 先切換目錄到
C:\Windows\Microsoft.NET\Framework\v2.0.50727;
二、點擊ASPNET_REGSQL.EXE;
三、依畫面輸入「主機名稱、帳號、密碼、資料庫名稱」;
主機名稱可以是本機也可以是遠端,只要你的帳號有足夠的權限,都可以新增資料表,按下確定後,系統就會自動將11個表格新增至你所指定的SQL Server的資料庫中。
二、使用指令(cmd.exe)
1. 先切換目錄到
cd C:\Windows\Microsoft.NET\Framework\v2.0.50727;
2. ASPNET_REGSQL.EXE指令
aspnet_regsql.exe -S papa -U kkbruce -P 1029384756 -d KKDataCenter -A all
按下Enter,一樣,系統會自動新增資料表到指定的資料庫中。
3. 訊息
開始加入下列功能:
Membership
Profile
RoleManager
Personalization
SqlWebEventProvider
.....
已經完成。
-S:SQL Server資料庫主機名稱。
-U:帳號。
-P:密碼。
-d:資料庫名稱。
-A:加入哪些Provider支援,all指全部要支援。
採用ASP.NET內建的會員管理系統,讓各網頁在page_load時能夠驗證會員的角色,並將無此權限的會員導至error.aspx
Protected Sub Page_Load(ByVal sender As Object, ByVal e AsSystem.EventArgs) Handles Me.Load
Dim name As String = My.User.Name
Dim db As New SqlDataSource("Data Source=.\SQLEXPRESS;AttachDbfilename=|DataDirectory|\ASPNETDB.MDF; Integrated Security=True; User Instance=True", "")
db.SelectCommand = "select rolename from aspnet_Roles where RoleId = (select RoleId from aspnet_UsersInRoles where userid = (select userid from aspnet_Users where UserName ='" & name & "' ) )"
Dim dv As New Data.DataView
dv = db.Select(New DataSourceSelectArguments)
If dv.Table.Rows(0).Item(0).ToString = "admin" Then
Label1.Text = “會員:” & name & “登入中”
Else
Response.Redirect("error.aspx")
End If
End Sub
當然上述的作法,可以將網頁置於同一資料夾後,再透過ASP.NET組態設定角色的權限即可達到驗證(坊間關於ASP.NET的書非常多,請自行參考),不過有時不同的角色,使用的網頁卻是一樣時,這樣處理又太麻煩,所以我的目的是要在同一資料夾下,利用rolename做為網頁的title,Ex:製作進銷存系統時,若公司有分公司的倉庫,如台北分公司、台中分公司、高雄分公司,則可將rolename設定為台北、台中、高雄等,不過因為ASP.NET組態可以讓會員同時擁有多個角色,所以須特別注意不可讓會員同時擁有兩個分倉以上的角色。
Protected Sub Page_Load(ByVal sender As Object, ByVal e AsSystem.EventArgs) Handles Me.Load
Dim name As String = My.User.Name
Dim db As New SqlDataSource("Data Source=.\SQLEXPRESS;AttachDbfilename=|DataDirectory|\ASPNETDB.MDF; Integrated Security=True; User Instance=True", "")
db.SelectCommand = "select rolename from aspnet_Roles where RoleId = (select RoleId from aspnet_UsersInRoles where userid = (select userid from aspnet_Users where UserName ='" & name & "' ) )"
Dim dv As New Data.DataView
dv = db.Select(New DataSourceSelectArguments)
If dv.Table.Rows(0).Item(0).ToString = "guest" Then
Response.Redirect("error.aspx")
Else
Label_title.Text = dv.Table.Rows(0).Item(0).ToString & “倉庫存管理系統”
End If
End Sub
多级会员管理系统
设计方法如下:
1. 建立部门、用户组;
2. 建立权限划分,添加,删除,复制,粘贴,编辑,导出,备份等等,权限进行编号,例如添加(1),删除(2);
3. 建立用户,分配部门;
4. 细化用户组,将用户绑定用户组;
4.1 建立各个版块名称和绑定版块权限ID(进入版块时进行判断)
5. 细化权限划分部分内容,允许有绑定用户组和用户两种方法,绑定用户组的同时可以将用户组下所有用户进行绑定;
5.1 权限划分部门加入各个版块名称,后面依次对应着所有的权限划分
6. 拼装权限代码,存入数据表
登陆时取出权限代码,存入缓存。注销时清除缓存内容。
1. 建立部门、用户组;
2. 建立权限划分,添加,删除,复制,粘贴,编辑,导出,备份等等,权限进行编号,例如添加(1),删除(2);
3. 建立用户,分配部门;
4. 细化用户组,将用户绑定用户组;
4.1 建立各个版块名称和绑定版块权限ID(进入版块时进行判断)
5. 细化权限划分部分内容,允许有绑定用户组和用户两种方法,绑定用户组的同时可以将用户组下所有用户进行绑定;
5.1 权限划分部门加入各个版块名称,后面依次对应着所有的权限划分
6. 拼装权限代码,存入数据表
登陆时取出权限代码,存入缓存。注销时清除缓存内容。
ASP.NET 定時任務與IIS應用程序回收
研究動機¶
最常見是「電子報」的定時寄送,在ASP.NET應用裏,我們通常會建立一個Windows Service來負責定時的電子報寄送服務,但每次佈署網站時得需要管理員權限來佈署這服務。其實,ASP.NET應用程式可以透過Global.aspx中的定義來執行定時計劃性任務,實作方式很簡單(加入一個Timer即可),但它會遇到iis的應用程序定時回收機制(預設是每29個小時),即會停止運作。解決的方式可詳看這篇文章: asp.net計劃任務-解決應用池回收問題。整個技術的重點在於掌握Timer失去功效的時機,為此我作了一番測試與驗證,才敢正式使用。Timer執行時機¶
原文沒把timer物件的宣告等級調為全域,隨時有可能被回收:原本要用EventLog寫入事件記錄,但ASP.NET在安全等級不允許,因此我使用一個I/O Log來記錄timer觸發的時機點。
IIS回收時機¶
IIS管理員中,你可以隨時停止一個虛擬子網站的運行:然而,它只是阻止Web Client連線,並不會影響該Web程式的內應用程序,只有透過Browse該網站,才會啟動Application_Start()函式。每個ASP.NET應用程式都會對映到其「應用程式池」,它預設29小時會回收所衍生的程序(取消定時回收並不是一個好的主意):
這個回收程序執行時,就會觸發Application_End()函式,並停止所有運作,等到有人再Browse該網站任一頁,才會再啟動Application_Start()函式。 因此我們若要維持timer不中斷,就必須在End函式中,再去觸發browse網站任一頁。
當你要手動執行回收時,在「應用程式集區」按右鍵:
本文結論¶
這篇文章探討IIS觸發Web應用程式的Application_Start()與End()時機,唯有充份了解,才能掌握Timer計劃性任務的確切執行。asp電子報製作與程序
電子報大概包括三個部份:(一).訂閱系統(填寫窗體、修改資料、退訂、查詢密碼);(二).電子報的製作與傳 送;(三).討論迴響。 伺服環境:IIS4.0/5.0或PWS,使用CDOMail或其它Mail組件(如:JMail、ASPEMail、ASPMail等..) |
2012年3月15日 星期四
訂單編號方式探討
一、編號方式(年月編定法):
訂單編號的方式,沒有特定的哪一種是比較好的,其實依照不同的需求會有不同的方式
小喵介紹的是依照訂單產生的年月來做編號的方式
訂單編號的方式,沒有特定的哪一種是比較好的,其實依照不同的需求會有不同的方式
小喵介紹的是依照訂單產生的年月來做編號的方式
首先,要先確認您的編號位數有幾位
如果以民國年來編排,那麼例如今天是94年9月13日
那麼依照【民國年月】9409
但是為了顧及超過民國100年以後會多一碼的問題...
所以建議使用09409的方式.....
如果以民國年來編排,那麼例如今天是94年9月13日
那麼依照【民國年月】9409
但是為了顧及超過民國100年以後會多一碼的問題...
所以建議使用09409的方式.....
接著要來預想一下....單月的最大訂單數可能為多少
必須想出一個不會太多(太多了浪費位數)...也不會太少(太少了到時候編碼放不下)
必須想出一個不會太多(太多了浪費位數)...也不會太少(太少了到時候編碼放不下)
假設單月的最高定單位數為99999筆(5位數字)
(將近10萬筆...如果超過的話...大賺錢的情況下...再改程式也是一邊笑一邊改)
那麼本月的第一筆訂單的方式就會是0940900001
(將近10萬筆...如果超過的話...大賺錢的情況下...再改程式也是一邊笑一邊改)
那麼本月的第一筆訂單的方式就會是0940900001
如果是西元年
把094改為2005即可
那麼本月的第一筆訂單的方式就會是20050900001
這樣的編碼方式應該還可以用7千多年(千年老店^_^)
把094改為2005即可
那麼本月的第一筆訂單的方式就會是20050900001
這樣的編碼方式應該還可以用7千多年(千年老店^_^)
二、編號產生時機: 接著要來討論一下...編號要何時來產生呢
小喵要介紹的是兩種方式.....
1.資料維護時產生訂單編號:
2.預先產生訂單編號:
小喵要介紹的是兩種方式.....
1.資料維護時產生訂單編號:
2.預先產生訂單編號:
這兩種方式各有各的需求
維護時產生:
不需要使用金流,因此不必預先產生訂單編號,在維護資料庫的時候,在即時產生訂單編號即可
過程如下:
使用者按下新增→訂單內容輸入表單→使用者按下【維護新增】→產生訂單編號→INSERT到訂單相關資料
維護時產生:
不需要使用金流,因此不必預先產生訂單編號,在維護資料庫的時候,在即時產生訂單編號即可
過程如下:
使用者按下新增→訂單內容輸入表單→使用者按下【維護新增】→產生訂單編號→INSERT到訂單相關資料
預先產生訂單編號:
由於線上刷卡的金流機制是記錄著訂單編號、訂單總額
如果使用1.的方式,那麼假設消費者完成了完整的訂購流程、也完成了刷卡流程...那樣沒有問題
問題是如果訂單內容產生了、消費者到了刷卡的畫面時,就直接把網頁關閉(消費者只是測試、並沒有真正購買)
此時訂單內容已經維護到訂單的相關資料了...卻因為沒有刷卡的紀錄...造成了無效的訂單資料
通常這樣的消費者測試行為無法避免,而且因測試產生的訂單也是沒有用的資料居多
(測試嘛...姓名大多是小明小華之類的假名)
這些無效資料還得另外一個機制來剔除
因此,如果能夠預先產生訂單編號→直到刷卡成功→再將訂單內容維護到訂單檔案
這樣就能夠杜絕無效訂單內容的產生
他的過程大約如下
使用者按下新增→訂單內容輸入表單(購物車)→使用者按下【結帳】→預先產生訂單編號→進入刷卡流程→刷卡成功維護訂單檔
由於線上刷卡的金流機制是記錄著訂單編號、訂單總額
如果使用1.的方式,那麼假設消費者完成了完整的訂購流程、也完成了刷卡流程...那樣沒有問題
問題是如果訂單內容產生了、消費者到了刷卡的畫面時,就直接把網頁關閉(消費者只是測試、並沒有真正購買)
此時訂單內容已經維護到訂單的相關資料了...卻因為沒有刷卡的紀錄...造成了無效的訂單資料
通常這樣的消費者測試行為無法避免,而且因測試產生的訂單也是沒有用的資料居多
(測試嘛...姓名大多是小明小華之類的假名)
這些無效資料還得另外一個機制來剔除
因此,如果能夠預先產生訂單編號→直到刷卡成功→再將訂單內容維護到訂單檔案
這樣就能夠杜絕無效訂單內容的產生
他的過程大約如下
使用者按下新增→訂單內容輸入表單(購物車)→使用者按下【結帳】→預先產生訂單編號→進入刷卡流程→刷卡成功維護訂單檔
三、訂單碰撞:
網路系統為多人同時使用系統。而訂單編號是訂單資料的主索引,必須不能夠重複,因此如何避免訂單編號發生碰撞
是我們程式設計者要注意到的問題
因此,在產生訂單編號的過程中,如何讓產生訂單編號的過程儘量縮短、並且適度的Lock資料是必須的
接著就來說明一下如何產生訂單編號的方式
四、維護時產生編號方法:
過程
使用者按下新增→訂單內容輸入表單→使用者按下【維護新增】→產生訂單編號→INSERT到訂單相關資料
在這樣的模型中,【產生訂單編號】可以拆解為以下的細部動作
【取得當月訂單最大值】
→【無資料==>新增當月第1筆訂單編號】
→【有資料==>最大值後5碼轉數字+1】
假設訂單資料表名稱為OrderHead
訂單編號欄位名稱為OrderNo(文字,11位)
那麼方式是
四、維護時產生編號方法:
過程
使用者按下新增→訂單內容輸入表單→使用者按下【維護新增】→產生訂單編號→INSERT到訂單相關資料
在這樣的模型中,【產生訂單編號】可以拆解為以下的細部動作
【取得當月訂單最大值】
→【無資料==>新增當月第1筆訂單編號】
→【有資料==>最大值後5碼轉數字+1】
假設訂單資料表名稱為OrderHead
訂單編號欄位名稱為OrderNo(文字,11位)
那麼方式是
01 | SqlTxt= "SELECT Max(OrderNo) as MOdrNo FROM OrderHead WHERE (Left([OrderNo],6)='200509') " |
02 | rs.Open SqlTxt |
03 | 'Max一定會有一筆資料,但是如果沒有最大值,會是Null |
04 | NewOrderNo=Year(Now) & Right( CStr (Month(Now)+100),2) |
05 | tmpOdrNo=0 |
06 | If IsNull(rs.Fields( "MOdrNo" ).value) Then |
07 | '當月沒有訂單編號 |
08 | NewOrderNo = NewOrderNo & "00001" |
09 | Else |
10 | '當月有訂單編號 |
11 | tmpOdrNo= CLng (rs.Fields( "MOdrNo" ).value)+1 |
12 | NewOrderNo=NewOrderNo & Right( CStr (tmpOdrNo+10^5),5) |
13 | End If |
14 | rs.close |
15 | '維護OrderHead |
16 | sqlInsert= "Insert Into OrderHead ......" |
17 | Conn.Execute sqlInsert |
18 | '維護OrderDetail(迴圈多筆) |
19 | For y = 1 to Request.Form( "Model" ).Count |
20 | sqlInsert= "Insert Into OrderDetail ......" |
21 | Conn.Execute sqlInsert |
22 | Next |
這樣就能夠新增料前產生訂單編號
五、預先產生編號方法:
預先產生訂單編號,會比上一個方式更複雜一些
因為產生的訂單編號並不是即時維護入OrderHead中
所以必須有另外一個資料表用來管理目前的訂單編號
資料表:
CurrOrderNo:訂單編號管理檔
欄位:OrderNo(文字,11)
OrderHead:訂單檔
欄位:OrderNo(文字,11)
流程如下:
1.取得訂單編號管理檔目前年月的訂單編號
2a.無資料→新編編號→維護回CurrOrderNo
2b.有資料→編號尾數+1→編出新編號→維護回CurrOrderNo
1.取得訂單編號管理檔目前年月的訂單編號
2a.無資料→新編編號→維護回CurrOrderNo
2b.有資料→編號尾數+1→編出新編號→維護回CurrOrderNo
01 | '1.取得訂單編號管理檔(CurrOrderNo)目前年月的訂單編號 |
02 | SqlTxt= "SELECT Max(OrderNo) as MOdrNo FROM CurrOrderNo WHERE (Left([OrderNo],6)='200509') " |
03 | rs.Open SqlTxt |
04 | 'Max一定會有一筆資料,但是如果沒有最大值,會是Null |
05 | NewOrderNo=Year(Now) & Right( CStr (Month(Now)+100),2) |
06 | tmpOdrNo=0 |
07 | If IsNull(rs.Fields( "MOdrNo" ).value) Then |
08 | '2a.無資料→新編編號→維護回CurrOrderNo |
09 | NewOrderNo = NewOrderNo & "00001" |
10 | sqlUpdate= "Update CurrOrderNo Set OrderNo = '" & NewOrderNo & "' " |
11 | Conn.Execute sqlUpdate |
12 | Else |
13 | '2b.有資料→編號尾數+1→編出新編號→維護回CurrOrderNo |
14 | tmpOdrNo= CLng (rs.Fields( "MOdrNo" ).value)+1 |
15 | NewOrderNo=NewOorderNo & Right( CStr (tmpOdrNo+10^5),5) |
16 | sqlUpdate= "Update CurrOrderNo Set OrderNo = '" & NewOrderNo & "' " |
17 | Conn.Execute sqlUpdate |
18 | End If |
19 | rs.close |
20 | '維護OrderHead |
21 | sqlInsert= "Insert Into OrderHead ......" |
22 | Conn.Execute sqlInsert |
23 | '維護OrderDetail(迴圈多筆) |
24 | For y = 1 to Request.Form( "Model" ).Count |
25 | sqlInsert= "Insert Into OrderDetail ......" |
26 | Conn.Execute sqlInsert |
27 | Next |
訂閱:
文章 (Atom)