微軟又推出了Microsoft Urlscan Filter v3.0,可用來防止 SQL Injection attack
當然,已經不支援 Windows 2000 了。請 Windows 2000 的維護人員自行撰寫程式。
之前我是使用 HttpModule 來加強 asp.net 對SQL Injection 的攻擊。
如今,使用微軟的方法,也可以使用在 asp了。
微軟又推出了Microsoft Urlscan Filter v3.0,可用來防止 SQL Injection attack
當然,已經不支援 Windows 2000 了。請 Windows 2000 的維護人員自行撰寫程式。
之前我是使用 HttpModule 來加強 asp.net 對SQL Injection 的攻擊。
如今,使用微軟的方法,也可以使用在 asp了。
關於 Refactoring(重構),我一直並不了解其意義。
後來,讀了這本書後才發現,原來我也大致地遵循著相同的原則不斷的改善我的程式碼。
我將書中的第一二章節,做成了投影片,並且也改寫成 c# 3.0的版本。看來 c# 3.0 真的比 Java 來的好,程式碼又簡潔了不少。
投影片可於這裡下載
微軟與中華電信最近推出了 live pages 。很好用。
搜尋公司的名稱,可以找到哦!可是電話有些怪怪的,不是我熟悉的 87121298。
問了一下,原來是晶片卡部門在使用。
與 google maps 比較一下,見maps ,地圖的服務,無論是放大縮小的流暢度,或者是地圖的解析度,看來目前還是 Google 做的比較好。
而國內做的最久的 urmap ,可以說被雙面夾攻,輸入「金財通」是找不到東西的。看來龍頭地位不保。
看來網路地圖的應用,潛力十足,創意無限。是未來的web 服務的主流之一。
一直以來,我們都希望開發網站時,能以模組的型式來開發。部署時,只要部署所需要的模組即可。
列如說,asp.net 應用程式Root 能容納多個模組,分別是公告、訂單、發票三個模組。
開發時,四個專案分別開發(包含asp.net應用程式Root及三個模組)
部署時,可以只部署所需要的模組,如 root + 公告,其餘的不要。
其實,方法已經有了。可見 Creating sub-projects in IIS with Web Application Projects 。
這樣的方式好處是簡單,而且可以分開部署。
可是,如果要談到資料交換(root 與 模組,模組與模組) 的資料交換,就又顯得複雜了。
只能靠 Session 或 database 來交換資料,並不是很好的做法。
目前我知道最好的做法,是 Web Client Software Factory, WCSF。
它不但可以模組與模組之間交換,甚至可以有依賴關係,例如公告模組依賴於權限模組。
並且又加上了 page flow (可取代之前的 User Interface Process (UIP) Application Block),還設計了權限、ObjectContainerDataSource、realtime search
連 source code 都給你了,真是物超所值。
http://labs.developerfusion.co.uk/convert/csharp-to-vb.aspx ,看該來不錯。
一個簡單的例子,
using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using System.Web.Configuration; using BankPro.EI2.BusinessComponents; namespace EI2.Utility { public class CommonUtil { ///經過轉換後,可以轉成 VB.NET 無慮。/// 虛擬目錄名稱 /// public static string EInvoiceVDName { get { return WebConfigurationManager.AppSettings["VDName"]; } } ////// 登入者所屬公司的 CompanyOid /// public static int LoginUserCompanyOid { get { return UserBC.GetUserCompanyOidByAccount( HttpContext.Current.User.Identity.Name).Value; } } } }
Imports System Imports System.Data Imports System.Configuration Imports System.Linq Imports System.Web Imports System.Web.Security Imports System.Web.UI Imports System.Web.UI.HtmlControls Imports System.Web.UI.WebControls Imports System.Web.UI.WebControls.WebParts Imports System.Xml.Linq Imports System.Web.Configuration Imports BankPro.EI2.BusinessComponents Namespace EI2.Utility Public Class CommonUtil '''但是,碰到新的 c# 3.0 (linq 的語法就會失敗了) 例如''' 虛擬目錄名稱 ''' Public Shared ReadOnly Property EInvoiceVDName() As String Get Return WebConfigurationManager.AppSettings("VDName") End Get End Property '''''' 登入者所屬公司的 CompanyOid ''' Public Shared ReadOnly Property LoginUserCompanyOid() As Integer Get Return UserBC.GetUserCompanyOidByAccount(HttpContext.Current.User.Identity.Name).Value End Get End Property End Class End Namespace
protected void gvInvoices_DataBound(object sender, EventArgs e) { foreach (GridViewRow row in gvInvoices.Rows) { for (int i = 0; i < gvInvoices.Columns.Count; i++) { DataControlField item = gvInvoices.Columns[i]; BoundField boundField = item as BoundField; if ((boundField != null) && string.IsNullOrEmpty(boundField.DataField)) { string headerText = item.HeaderText; int oid = Convert.ToInt32(gvInvoices.DataKeys[row.RowIndex].Value); var tmpType = tmpTypes.SingleOrDefault(t => t.OID == oid && t.GroupName == headerText); if ((tmpType != null) && (!string.IsNullOrEmpty(tmpType.ObjectValue))) { row.Cells[i].Text = tmpType.ObjectValue; } } } } }會產生 Conversion was attempted, however the following errors were reported: -- line 1 col 11: invalid TypeDecl
Oracle 的 rownum 是一個 pseudocolumn,意思是不存在的 column,是經由計算得來的.
先建立範例資料 .
create table emp(id int, sid char(10) not null, name char(10) not null); insert into emp(id, sid, name) values (1, 'Charles', 'F111222333'); insert into emp(id, sid, name) values (2, 'Jerry', 'A121121121'); insert into emp(id, sid, name) values (3, 'Abel', 'H114567898');執行下面的語法,可得到所有資料,且得到 rownum 代表的「列號」
select id, sid, name, rownum from emp;結果如下,很正常。
select id, sid, name, rownum from emp order by name;
結果如下,RowNum 是先經過編號後,才再 order by name 的。
所以,如果要先 order by name 才編號,就必須下這樣的sql script
select t.*, rownum from ( select id, sid, name from emp order by name ) t
結果如下
相同的問題,如果在 SQL Server 2005 上,就設計地好多了,因為語法上很清楚地說明了「編號是針對order by name」來編號。
select *, ROW_NUMBER() over (order by name) from emp;結果如下圖。看來 sql server 的設計是較貼近 developer 的.
select * from ( select *, ROW_NUMBER() over(order by invoicenumber) as rn from B2CInvoice ) a where a.rn between 21 and 30SQL Server 2000的語法就不說了,是很差的,而且並沒有通用的版本。
SELECT * FROM ( SELECT A.*, rownum r FROM ( SELECT * FROM B2CINVOICE ORDER BY invoiceNumber ) A WHERE rownum <= 30 ) B WHERE r >= 21;注意到,下面的是沒有資料回傳的,也就是錯誤的查詢結果。雖然看起來比較直覺而且易懂
SELECT A.*, rownum r FROM ( SELECT * FROM B2CINVOICE ORDER BY invoiceNumber ) A WHERE rownum >= 21 and rownum <=30
create database test; go use test; go create table Emp(id int not null, IsRetired bit not null);所以,有一個員工編號1號,尚未退休時,就會用下面的sql script 來 insert
insert into dbo.Emp(id, IsRetired) values (1, 0);接下來,使用 LINQ to Sql 並寫如下的程式,找出所有未退休的員工資料
TestDataContext ctx = new TestDataContext(); var q = from e in ctx.Emps where e.IsRetired == false select e;
Oracle資料庫是相當大的層級,而與SQL Server 的層級不太相同。
例如,SQL Server 的層級是 Instance-Database-Schema-Securable
像是 server.myDB.mySchema.myTable
系統層級的權限,會設定在 instance 層級上,而資料庫層級的權限,則會在 database 層級上。因此,會有sysadmin (instance level role, 即server role) 及 db_owner (database level role) 會如此的類似。見之前的文章 db_owner 與 database owner
而Oracle 的設計是不太一樣的。Oracle 的資料庫相當的「高級」,幾乎等同於 SQL Server 的 Instance,因此system level 的 privileges 直接設在 database level。
雖然 Oracle 也可以安裝多個 instance 在同一個 server,但幾乎沒人這麼做,因為一個 instance 就會把伺服器的資源吃完了。
Oracle 資料庫內建的 role 有 connect, resource等,其實已經是相當大的權限了。例如 conect 就有 create table 的權限。
不知道 SQL Server database levle 的 role : db_datareader,在Oracle 上要如何設定呢?
從 Google 搜尋後,得到了如下的 answer
grant select any table to myUser但是,這仍然只是近似的方法,並非等同的sql server 的 db_datareader 的權限。
使用 configuration 時,常常為了如何配置檔案而傷腦筋。
如果全部使用 appSettings,則設定將會很雜亂而難以維護。
如果使用自訂的 ConfigurationElement, 又會產生程式碼需要維護的問題。
在.net 2.0 有個很好用的 SingleTagSectionHandler 可以使用。
配置檔如下。
<?xml version="1.0"?> <configuration> <configSections> <section name="MySection" type="System.Configuration.SingleTagSectionHandler"/> </configSections> <MySection key1="A" key2="B" key3="C"/> </configuration>
讀設定時,可以用下面的方法讀出資料
Hashtable ht = ConfigurationManager.GetSection("MySection") as Hashtable; string key1 = ht["key1"].ToString(); string key2 = ht["key2"].ToString(); string key3 = ht["key3"].ToString();code download
使用 SQL Server 2008 備份時,有內建的壓縮功能哦!
這樣一來,使用的磁碟或磁帶空間就變小了,restore 時也會加快。
雖然比較偒CPU,但在緊急回復時,時間比較重要吧。
測試的結果,原本需要 1.48GB 的空間,壓縮後只需要 277MB
What Is Refactoring?
Refactoring is the process of changing a software system in such a way that it does not alter the
external behavior of the code yet improves its internal structure. It is a disciplined way to clean up
code that minimizes the chances of introducing bugs. In essence when you refactor you are
improving the design of the code after it has been written.
from Refactoring: Improving the Design of Existing Code
提醒一下。由於微軟的 mainstream support 策略,使用Visual Studio.NET 2003 的主流支援到 2008/10/14,見這裡。
也就是說,除非你自己出錢請微軟修改,否則 Visual Studio.NET 2003 不會再新增功能了。
建議開發新專案時,請使用 Visual Studio 2008,至少主流支援可到 2013 年。
Visual Studio 2005 也可以到 2011年
原本使用 CTP, RCO 時,Sql Server Management Studio 2008 的 intellisense 非常的好用。但我發現,正式版的 SSMS 不能連到2000, 2005 上了!! 這是真的。
When IntelliSense Is Unavailable. 上有一這麼一段 Intellisense is only available when the Database Engine Query Editor is connected to an instance of the SQL Server 2008 Database Engine.
MS 也真的好樣的!
因為,安裝 SQL Server 2008的client tool 時失敗了。原因是我的開發電腦上安裝的 Visual Studio 2008 尚未升級成 sp1。不讓我安裝。
當時就知道沒差幾天 Visual Studio 2008 就會出 sp1,否則會影響多少 developer 啊。
一直都在實作 asp.net,很少寫 window form 的程式。
現在才發現,這兩個是如此的不同。
在 Asp.Net 的 GridView,簡單的程式如下是可以運作的
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="GridViewDataBid_AspNet._Default" %>code behind
protected void Page_Load(object sender, EventArgs e) { string[] ary = { "A", "B", "C" }; GridView1.DataSource = ary; GridView1.DataBind(); }
執行結果如下圖
寫起來實在容易。而在 Windows Form這麼做的話,得到的結果是一片空白
private void Form1_Load(object sender, EventArgs e) { string[] ary = { "A", "B", "C" }; dataGridView1.DataSource = from s in ary select new { Name = s }; }記得在Form 上的 DataGridView ,要新增一個 Name 的 column
這一段不成功的原因是,DataGridView.DataSource 必須是 IList 介面,包括一維陣列。 IListSource 介面,例如 DataTable 和 DataSet 類別。 IBindingList 介面,例如 BindingList 類別。 IBindingListView 介面,例如 BindingSource 類別。 ( see here )
上一段的程式,只會造成 IEnumable<T>。因此,GridView.DataSource 可以吃,而DataGridView.DataSource 不行。 改一下程式,就可以看到結果了private void Form1_Load(object sender, EventArgs e) { string[] ary = { "A", "B", "C" }; dataGridView1.DataSource = (from s in ary select new { Name = s }).ToList(); }code sample download
同事問到,如何將 "中華民國97年2月29日" 的字串轉成 DateTime, 與將 DateTime 輸出成 "中華民國97年2月29日"
沒遇過這個問題。
打開 MSDN, 找到了 TaiwanCalendar
開始寫程式囉
DateTime dt = new DateTime(2008, 2, 29); TaiwanCalendar c = new TaiwanCalendar(); CultureInfo ci = new CultureInfo("zh-TW", true); ci.DateTimeFormat.Calendar = c; Thread.CurrentThread.CurrentCulture = ci; Console.WriteLine(dt.ToLongDateString()); DateTime dt2; dt2 = DateTime.Parse("97-02-29", ci); Console.WriteLine(dt2.ToLongDateString()); dt2 = DateTime.Parse("97/02/29", ci); Console.WriteLine(dt2.ToLongDateString()); dt2 = DateTime.Parse("97-2-29", ci); Console.WriteLine(dt2.ToLongDateString()); dt2 = DateTime.ParseExact("97|02|29", "yy|MM|dd", ci); Console.WriteLine(dt2.ToLongDateString()); dt2 = DateTime.ParseExact("中華民國97年2月29日", "中華民國yy年M月dd日", ci); Console.WriteLine(dt2.ToLongDateString()); dt2 = DateTime.ParseExact("中華民國97年2月29日", "中華民國yy年M月dd日", ci); Console.WriteLine(dt2.ToLongDateString()); dt2 = DateTime.Parse("97/02/29 下午 3:46:01"); Console.WriteLine(dt2.ToString());
輸出的結果如下
97年2月29日
97年2月29日
97年2月29日
97年2月29日
97年2月29日
97年2月29日
sample code download here
--Create User set timing off; spool log\createMyDbReader.log; create user MyDbReader identified by MyPassword default tablespace users temporary tablespace temp quota unlimited on users quota unlimited on INDX quota unlimited on objects quota unlimited on temp ; grant create session to MyDbReader; grant unlimited tablespace to MyDbReader; grant query rewrite to MyDbReader; spool off; exit; --使用 MyDbReader 登入後更改 password 為 MyNewPassword connect MyDbReader/MyPassword@MyServer ; alter user MyDbReader identified by MyNewPassword --刪除使用者 drop user MyDbReader;
之前使用 Asp.Net 時,一直使用 UpdatePanel。這個實在是好用。
但是,我卻誤解了,誤以為使用 Ajax 一定會降低頻寬。
我寫了一個範例 , 一個使用傳統的 UpdatePanel,一個使用 PageMethod。
可以使用 fiddler 之類的工具,查到ajax 所使用的 request 及 response 內容。
大小差別如附圖。
使用 UpatePanel 的版本,Request (244 bytes)及 Response(648 bytes) 的內容竟然包山包海,根本無法將傳輸的資料量降低。
竟然還有 __VIEWSTATE!?
原來,asp.net ajax team 當初設計 UpdatePanel 的目的,在於簡化開發的過程。因此對於傳回的 request 內容 ,幾乎等同於未 ajax 的版本。相同地, Response 也是幾乎等同於未 ajax 的版本。只不過不必自己塞到不同的 html control 內了。
相反地,使用 PageMethod 是一個相當經清的方法。
[WebMethod] [ScriptMethod] public static string GetCurrentTime() { return DateTime.Now.ToString(); }
function Button2_onclick() { PageMethods.GetCurrentTime(ShowTime); } function ShowTime(value) { $get("Label2").innerHTML = value; }這樣的好處是,傳輸的資料可直接控制。Requet 0 bytes,Response 27 bytes。