Chủ Nhật, 20 tháng 7, 2014

Thủ thuật trong ASP.NET

Nguồn: hmweb
Trong bài viết này tôi sẽ tìm lại và tổng hợp các thủ thuật khi lập trình với asp.net.
 Có thể nó sẽ giảm bớt công sức khi bạn lập trình.

1. Kiểm tra FileUpload chỉ có thể là file ảnh

Để tải lên hình ảnh đến máy chủ từ một ứng dụng web Asp.Net, Bạn sử dụng FileUpload. 
Nhưng bạn chỉ muốn giới hạn chỉ cho upload file ảnh thôi => Sử dụng RegularExpressionValidator như minh họa dưới đây.
Code:
<asp:FileUpload ID="FileUpload1" runat="server" /> 
<asp:RegularExpressionValidator 
 ID="RegularExpressionValidator1" 
 runat="server" 
 ControlToValidate="FileUpload1" 
 ErrorMessage="Không phải file ảnh" 
 ValidationExpression= 
"^([0-9a-zA-Z_-~ :\])+(.jpg|.JPG|.jpeg|.JPEG|.bmp|.BMP|.gif|.GIF|.png|.PNG)$"> 
</asp:RegularExpressionValidator>

2. Tạo nhiều QueryString từ Hyperlink NavigateUrl trong GridView

Trong Gridview khi bạn muốn một trường nào đó là liên kết và bạn muốn truyền các QueryString hoặc Parameter để ở trang chuyển tiếp
 bạn có thể Request được các Parameter này.

- Nếu là trường được convert thành TemplateField bạn dùng như minh họa sau:
Code:
<asp:HyperLink ID="HyperLink1" runat="server" Text="View Data" 
NavigateUrl='<%# String.Format("TestPage.aspx?param1={0}&param2={1}&param3={2}", 
Eval("Field1"), Eval("Field2"), Eval("Field2")) %>'></asp:HyperLink>
- Nếu là HyperLinkField
Code:
<asp:HyperLinkField 
DataNavigateUrlFields="Field1,Field2,Field3" 
DataNavigateUrlFormatString="TestPage.aspx?param1={0}&param2={1}&param3={2}" 
Text="View Data" />
Hãy thay các Field1, Field2, ... Thành các tên trường dữ liệu của bạn

3. Giới hạn chỉ nhập số trong Textbox

Để giới hạn khi người dùng chỉ có thể nhập ký tự số (số chứng minh thư chẳng hạn) 
trong textbox bạn có thể dùng FilteredTextBoxExtender của AjaxControl toolkit như sau:
Code:
<asp:TextBox ID="txtCMT" Width="50px" runat="server" />
<cc1:FilteredTextBoxExtender ID="ftbeCMT" runat="server" 
    Enabled="True" FilterType="Numbers" TargetControlID="txtCMT" />
Nếu không dùng ajax bạn cần viết hàm javascript như sau:
Code:
function onlyNumbers(evt) {
    var e = event || evt; 
    var charCode = e.which || e.keyCode;
    if (charCode > 31 && (charCode < 48 || charCode > 57))
     return false;
    return true;
}
Trong Textbox bạn sửa lại thành:
Code:
<asp:TextBox ID="txtCMT" runat="server" onkeypress="return onlyNumbers();" />
4. Tính số ngày, tháng, năm giữa hai mốc thời gian

Tham khảo ví dụ sau:
Code:
DateTime date1 = Convert.ToDateTime("2008/01/01");
DateTime date2 = Convert.ToDateTime("2010/12/31");
TimeSpan timespan = date2.Subtract(date1);
int intDays = timespan.Days;
double intMonths = Math.Floor(intDays / 30.0);
double intYears = Math.Floor(intDays / 365.0);
Response.Write("Số ngày : " + intDays.ToString());
Response.Write("Số tháng : " + intMonths.ToString());
Response.Write("Số năm : " + intYears.ToString());
5. Thêm điều kiểm xác nhận xóa/sửa trong gridview

Trong gridview nếu bạn muốn có thêm cột cho phép người dùng chọn bản ghi để xóa,
 Bạn có thể thêm cột và convert thành TemplateField và khi người dùng click chọn xóa bạn có yêu cầu xác nhận thao tác xóa này. Bạn xem minh họa sau:
Code:
<asp:TemplateField HeaderText="Xóa">
    <ItemTemplate>
        <asp:LinkButton ID="lbtDelete" runat="server" 
            OnClientClick="return confirm('Bạn có chắc chắn xóa không?')" 
            onclick="lbtDelete_Click"><img 
            src="Images/Xoa.jpg" border="0" /></asp:LinkButton>
    </ItemTemplate>
</asp:TemplateField>
Hoặc bạn cũng có thể code bằng C# trong hàm RowDataBound của gridview như sau:
Code:
if (e.Row.RowType == DataControlRowType.DataRow)
{
    if (e.Row.Cells[1].HasControls())
    {
        LinkButton lbtDelete= ((LinkButton)e.Row.Cells[1].Controls[0]);
        lbtDelete.Attributes.Add("onclick", "return confirm('Bạn có chắc chắn xóa không?');");
    }
} 
//Chú ý là Cell bắt đầu từ 0. 
//if (e.Row.Cells[1].HasControls()) Sẽ kiểm tra Cells[1] có tồn tại hay không
6. Sử dụng nhiều Web.Config trong ứng dụng Asp.Net

Nếu bạn muốn sử dụng nhiều file web.config trong ứng dụng của bạn 
(Minh họa rất rõ nếu bạn đã cài Forum yetanotherforum Bạn sẽ thấy các thông số được lưu ở file db.config, app.config, ...). 
Ví dụ bạn muốn lưu riêng các thông số kết nối Database, các thông số về cấu hình ứng dụng, ... ra một file web.config. Bạn tham khảo ví dụ sau:

- Tạo file condb.config nội dung như sau:
Code:
<appSettings> 
<add key="TestConnect" value="data source=.SQL2005;initial catalog=MyDatabase;User ID=sa; Password=***"/> 
</appSettings>
- Trong file web.config tại thẻ appSettings bạn trỏ đến file condb.config như sau:
Code:
<appSettings> 
 <appSettings file="condb.config"> 
</appSettings>
Giờ bạn muốn lấy các thông số kết nối này bạn in thử giá trị của nó như sau:
Code:
Response.Write(ConfigurationManager.AppSettings.Get("TestConnect"));
Tương tự như vậy bạn có thể tạo các file *.config khác để lưu các thông số cấu hình ứng dụng khác

7. Bắt sự kiện phím Enter.

Giả sử bạn có Form tìm kiếm và bạn muốn khi nhập dữ liệu ở Textbox và
 nhấn phím Enter thì sự kiện onclick lên nút Button được thực hiện bạn viết hàm javascript như sau:
Code:
<script language="javascript">
 function doClick(buttonName, e) {
     var key;
     if (window.event)
         key = window.event.keyCode;     //IE
     else
         key = e.which;     //firefox
     if (key == 13) {
         var btn = document.getElementById(buttonName);
         if (btn != null) {
             btn.click();
             event.keyCode = 0
         }
     }
 }
</script>
Trong code C# bạn muốn khi bạn nhấn Enter tác dụng với control nào bạn dùng như ví dụ sau:
Code:
 txtTuKhoa.Attributes.Add("onKeyPress", "doClick('" + btnTim.ClientID + "',event)");
8. Viết hàm ShowMessage đưa ra thông điệp bạn muốn

Tham khảo hàm sau:
Code:
void ShowMessage(string mTextMsg, string mControlFocus)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder("");
    sb.Append("<script language="JavaScript">");
    if (mTextMsg != "") sb.Append("  alert('" + mTextMsg + "');");
    if (mControlFocus != "") sb.Append("document.forms[0].item('" + mControlFocus + "').focus();");
    sb.Append("</script>");
    if (!IsStartupScriptRegistered("setFocus")) RegisterStartupScript("setFocus", sb.ToString());
}
Sử dụng hàm này: Giả sử bạn có một Button bạn viết như sau:
Code:
protected void Button1_Click(object sender, EventArgs e)
{
    ShowMessage("Thông điệp của bạn!", "Button1");
    return;
}
9. Thêm cột tự tăng trong Grid.

Trong Gridview nếu bạn muốn có thêm cột số thứ tự bạn Add thêm TemplateField như sau vào Grid nhé
Code:
<asp:TemplateField HeaderText="STT">     
     <ItemTemplate>     
         <%# Container.DataItemIndex + 1 %>     
      </ItemTemplate>     
 </asp:TemplateField>
10. Chuyển hướng sang trang khác sau khi click OK từ MessageBox

Giả sử bạn muốn alert một thông điệp nào đó và sau khi người dùng nhấn OK thì trang hiện hành được điều hướng sang trang khác.
 Bạn tham khảo code sau:
Code:
string strScript = "<script>"; 
strScript += "alert('Thông điệp của bạn');"; 
strScript += "window.location='NextPage.aspx';"; 
strScript += "</script>"; 
Page.RegisterClientScriptBlock("strScript", strScript);
Một cách khác bạn có thể dùng:
Code:
ScriptManager.RegisterStartupScript(
    this, this.GetType(), "alert", 
    "alert('Thông điệp của bạn');location.href='NextPage.aspx';", true);
11. Tổng hợp nhiều file js trong một file duy nhấtThông thường trang web của bạn sẽ sử dụng nhiều file javascript ví dụ như:
Code:
<script src="Tooltip/System_Tooltip.js" type="text/javascript"></script>
<script src="js/jquery-1.4.2.js" type="text/javascript"></script>
<script src="movies/swfobject.js" type="text/javascript"></script> 
<script src="js/jquery-ui.min.js" type="text/javascript"></script>
Thay vì trong code ta gọi quá nhiều file JS ta sẽ tạo 1 file duy nhất totalScript.js chẳng hạn nội dung file này sẽ là:
Code:
document.write('<script type="text/javascript" src="Tooltip/System_Tooltip.js"></script>');
document.write('<script type="text/javascript" src="js/jquery-1.4.2.js"></script>');
document.write('<script type="text/javascript" src="movies/swfobject.js"></script>');
document.write('<script type="text/javascript" src="js/jquery-ui.min.js"></script>');
Như vậy trong code bạn sẽ không phải khai báo quá nhiều javascript nữa mà chỉ cần 1 là đủ
Code:
<script src="totalScript.js" type="text/javascript"></script>
12. Khai báo các namespaces trong web.config
Thông thường khi ta tạo một trang mới với code behind thì chúng ta vẫn dùng các khai báo như:
Code:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
Giả sử ta dùng DataTable mà lại quên khai báo using System.Data; thì khi chạy sẽ báo lỗi. Vậy ta tránh trường hợp đó bằng cách khai báo các namespaces trong web.config:
Code:
<namespaces>
 <clear/>
 <add namespace="System"/>
 <add namespace="System.Collections"/>
 <add namespace="System.Collections.Specialized"/>
 <add namespace="System.Configuration"/>
 <add namespace="System.Text"/>
 <add namespace="System.Text.RegularExpressions"/>
 <add namespace="System.Web"/>
 <add namespace="System.Web.Caching"/>
 <add namespace="System.Web.SessionState"/>
 <add namespace="System.Web.Security"/>
 <add namespace="System.Web.Profile"/>
 <add namespace="System.Web.UI"/>
 <add namespace="System.Web.UI.WebControls"/>
 <add namespace="System.Web.UI.WebControls.WebParts"/>
 <add namespace="System.Web.UI.HtmlControls"/>
</namespaces>
13. Nhấn phím TAB 2 lần liên tiếp để hiện nhanh câu lệnh
Ví dụ bạn dùng câu lệnh IF:
Trong chế độ dòng lệnh, bạn gõ if sau đó NHẤN PHÍM TAB 2 LẦN thì câu lệnh IF sẽ xuất hiện như sau:
Code:
        if (true)
        {

        }
Lúc này, con trỏ chuột sẽ ở vị trí của chữ true, bạn chỉ cần gõ điều kiện của câu lệnh IF.
Tác dụng:
- Làm theo cách trên bạn sẽ rút ngắn được thời gian gõ câu lệnh
- Không rơi vào tình trạng thiếu dấu đóng hoặc mở câu lệnh {}
Áp dụng với các câu lệnh khác:
- FOR: bạn gõ chữ FOR rồi NHẤN PHÍM TAB 2 LẦN bạn sẽ có kết quả như sau:
Code:
for (int i = 0; i < length; i++)
{

}
- Áp dụng tương tự với các câu lệnh khác như: switch, foreach, while, do while, … bạn sẽ cảm thấy rất thoải mái khi gõ các câu lệnh trong Visual Studio.
14. Đưa các thông tin tĩnh vào file xml
Khi làm website có những phần thông tin tĩnh rất ít khi thay đổi như ảnh banner, copy right, địa chỉ liên hệ, … nếu các thông tin này bạn đưa luôn vào code aspx thì khi có sự thay đổi bạn lại phải sửa lại code, Nếu đưa vào Database thì ta sẽ sử dụng connect tới Database server nhiều. Vậy có cách khác là các thông tin này bạn đưa vào file xml và trong code bạn viết để hiển thị chúng. Khi có thay đổi ta cập nhật lại file xml là xong. Như bài hướng dẫn sau: Asp.net Đưa các thông tin tĩnh vào file xml (Vì minh họa sẽ hơi dài nên tôi viết thành bài hướng dẫn riêng)
15. Ngăn chặn duplicate insert khi refresh trang
Vấn đề thường hay gặp khi thêm dữ liệu là bị duplicate insert khi trang web refresh. Nó xảy ra khi 1 trang refresh sau khi câu lệnh insert được thực thi.
Giải pháp đơn giản nhất để giải quyết vấn đề này là redirect sau khi người dùng insert. Bạn tham khảo code demo sau khi insert sẽ redirect đến chính nó
Code:
private void InsertData()
{
    string strQuery = "INSERT INTO TB_TacGia (MaTacGia, TenTacGia) values(@MaTacGia, @TenTacGia)";
    SqlCommand cmd = new SqlCommand(strQuery);
    cmd.Parameters.AddWithValue("@MaTacGia", "AnhKhoa");
    cmd.Parameters.AddWithValue("@TenTacGia", "Bùi Anh Khoa");
    InsertUpdateData(cmd);
    Response.Redirect(Request.Url.AbsoluteUri);
}
16. Giới hạn độ dài của Textbox trong khoảng [a,b]
Giả sử bạn muốn giới hạn độ dài Textbox mật khẩu trong khoảng [a,b] bạn có thể dùng CustomValidator như minh họa sau:
Code:
<asp:TextBox runat="server" ID="txtTest"></asp:TextBox>
<asp:CustomValidator ID="CustomValidator1" runat="server" 
        ErrorMessage="Độ dài phải trong khoảng [6,20]" 
        ControlToValidate="txtTest" OnServerValidate="CustomValidator1_ServerValidate">
  </asp:CustomValidator>
Viết sự kiện CustomValidator1_ServerValidate
Code:
protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
    if (args.Value.Length = 20)
        args.IsValid = false;
    else
    {
        if (args.Value.Length < 6)
            args.IsValid= false;
        else
            args.IsValid = true;
    }
}
17. Nhúng trạng thái Online/Offline của yahoo
Trên web của bạn muốn hiển thị trạng thái Online/Offline của yahoo tại nơi muốn báo cho người dùng biết yahoo hỗ trợ trực tuyến. Bạn dùng đoạn mã như sau:
Code:
<a href="ymsgr:sendIM?yahooid"> 
<img src="http://opi.yahoo.com/online?u=yahooid&m=g&t=2" border="0" width="125" height="25" />
</a>
Khi yahoo có id là yahooid Online thì hình ảnh Online của yahoo được hiển thị, tương tự là trạng thái Offline. Bạn thay yahooid bằng id của bạn nhé
Khi yahoo có id là yahooid Online thì hình ảnh Online của yahoo được hiển thị, tương tự là trạng thái Offline. Bạn thay yahooid bằng id của bạn nhé
18. Ngăn không cho người khác copy hay nhấn phải chuột trên trang web.
Khi cần không cho người khác bôi đen hoặc nhấn phải chuột trên trang web hay ứng dụng của bạn bạn hãy sửa lại thẻ <Body> như sau:
<body oncontextmenu=”return false;” onpaste=”return false;” onselectstart=”return false;”>
Bạn còn có thể ứng dụng trong trường hợp bạn viết form đăng ký thành viên thường có trường Email và có yêu cầu người dùng xác nhận Email chính xác với Email đã nhập. Trường Xác nhận Email bạn cần ngăn không cho người dùng chọn ô Email và copy (Như thế chưa đúng nguyên tắc). Bạn sửa lại thuộc tính trong TextBox như minh họa sau
Code:
<asp:TextBox ID="TextBox1" runat="server"  
oncontextmenu="return false;" 
onkeypress="return onPaste(event)" 
onpaste="return false;" ></asp:TextBox>
19. Tạo Ico cho địa chỉ website.
Các trang web khi bạn truy cập hay có icon là biểu tượng của trang web đó. bạn sẽ thấy trên thanh address trước chữ http sẽ có biểu tượng của website. Để thực hiện bạn thêm mã html như sau vào trong thẻ head:
Code:
<link href="http://hmweb.com.vn/hmico.ico" rel="shortcut icon" type="image/x-icon" />
20. hiệu ứng chuyển trang bằng thẻ meta.
Khi người dùng đang xem trang web của bạn, họ chuyển qua trang web khác, bạn có thể dùng thẻ Meta như sau để tạo hiệu ứng chuyển trang như một lời chào thân thiện
Code:
<meta http-equiv="Site-Exit" content="revealTrans(Duration=3.0,Transition=23)"/>
Hoặc khi họ mở liên kết trên cùng trang của bạn, bạn cũng có thể tạo hiệu ứng chuyển trang đơn giản bằng cách dùng thẻ meta như sau:
Code:
<META http-equiv="Page-Exit" content="progid:DXImageTransform.Microsoft.GradientWipe
(duration=.5)">
21. Hiển thị chính xác nội dung văn bản TextArea
Khi bạn nhập nội dung văn bản trong TextArea thường mất các ký tự khoảng trắng hoặc ký tự xuống dòng. Nếu bạn muốn giữ đúng định dạng đã nhập trong TextArea bạn thực hiện thay thế các ký tự đó như ví dụ
Code:
Label1.Text = TextBox1.Text.Replace("n", "<br />").Replace(" ", "&nbsp;");
22. Sử dụng ViewState đúng chỗ
Khi lập trình web với asp.net sử dụng các control, khi bạn view source sẽ thấy như minh họa
Code:
<input type="hidden" name="__EVENTVALIDATION" 
id="__EVENTVALIDATION" value="/wEWAgKK7LjKBwKM54rGBgzCWqbCIzq33uVXHF19FzfdGPsJ" />
Nếu bạn sử dụng càng nhiều control thì value càng lớn. điều này sẽ làm ảnh hưởng đến tốc độ, băng thông cũng như các cỗ máy tìm kiếm (Các máy tìm kiếm tìm kiếm tốt nhất cho khoảng 20KB source đầu tiên trên trang của bạn, quá số này thường sẽ bị bỏ qua – Tham khảo ASP.NET SEO around VIEWSTATE). Vì vậy nếu là lập trình website bạn nên bỏ ViewState bằng cách
Trong web.config
Code:
<pages enableViewStateMac='false'/>
Hoặc trong từng trang:
Code:
<%@ Master Language="C#" EnableViewState ="false"
Hoặc với từng control bạn cũng có thể bỏ ViewState
Code:
<asp:Button ID="BT1" EnableViewState="false" runat="server" />
Nhưng bạn chú ý 1 điều là khi bạn bỏ ViewState thì các sự kiện postback sẽ không có đúng hiệu lực của nó, chính vì vậy bạn cân nhắc ở trang nào nên dùng ViewState, trang nào không nên dùng ViewState.
23. Cách dùng khác của mệnh đề if … else
Thông thường hoặc theo thói quen bạn hay dùng mệnh đề if … else như sau:
Code:
private string abc(int gio)
{
    string str = "";
    if (gio < 12)
    {
        str = "Chào buổi sáng";
    }
    else
    {
        str = "Chào buổi chiều";
    }
    return str;
}
Với dạng if … else đơn giản bạn có thể dùng theo cấu trúc khác như sau (dễ và gọn hơn nhiều)
Code:
private string abc(int gio)
{
    string str = "";
    str = (gio < 12) ? "Chào buổi sáng" : "Chào buổi chiều";
    return str;
}
24. Xóa hết các thẻ html của nội dung
Khi trình bày dữ liệu nhất là khi bạn copy dữ liệu từ trang khác, thường là sẽ có các style sheet của trang bạn copy về. Khi trình bày dữ liệu nhất là sử dụng Tooltip bạn sẽ bị lỗi không hiển thị được (Đây cũng là vấn đề nhiều bạn hỏi khi thực hiện theo bài Hướng dần thực hiện tooltip). Để xóa hết html của một chuỗi bạn dùng hàm sau:
Code:
private string RemoveHTMLTag(string HTML)
{
    // Xóa các thẻ html
    System.Text.RegularExpressions.Regex objRegEx = new System.Text.RegularExpressions.Regex("<[^>]*>");

    return objRegEx.Replace(HTML, "");
}
25. Dùng hàm Split với tham số là một chuỗi
Bình thường bạn sử dụng hàm Split để chuyển chuỗi thành mảng với 1 ký tự xuất hiện trong chuỗi, với hàm Split tham số truyền vào là char nên bạn chỉ chuyên được 1 lý tự. Nếu bạn dùng hàm Split với tham số là 1 chuỗi bạn dùng như ví dụ sau:
Code:
string strHTML = "<p>Bài 1</p><p>Bài 2</p><p>Bài 3</p><p>Bài 4</p>";
string[] strSplit = Regex.Split(strHTML, "</p>");
Ở ví dụ này ta dung Regex.Split của lớp System.Text.RegularExpressions – tôi tạo ra mảng strSplit để lấy các phần tử là các thẻ <p> và nội dung của nó. Điều này khi bạn không sử dụng Regex.Split sẽ không thực hiện được#pendtag#
26. Lấy nội dung của một thẻ html
Giả sử bạn có một chuỗi gồm nhiều đoạn được đặt trong các thẻ html (thẻ <p> chẳng hạn), bạn muốn lấy nội dung của một thẻ <p> trong chuỗi đó. bạn dùng hàm như cí dụ sau:
Code:
static string GetParagraphOfHTMLTag(string strHTML)
{
    Match m = Regex.Match(strHTML, @"<p> s*(.+?)s*</p>");
    if (m.Success)
    {
        return m.Groups[1].Value;
    }
    else
    {
        return "";
    }
}
Trong hàm trên bạn thay chỉ số 1 bằng chỉ số thứ tự thẻ html bạn muốn lấy
Code:
string strHTML = "<p>Bài 1</p><p>Bài 2</p><p>Bài 3</p><p>Bài 4</p>";
string s1 = GetParagraphOfHTMLTag(strHTML);
Khi đó s1 của bạn sẽ là Bài 1
27. Khắc phục lỗi font khi viewsource khi dùng FCKEditor
Nếu bạn không để ý config cho FCKEditor thì khi lưu lại dữ liệu trong CSDL sẽ lưu tiếng Việt dưới dạng Encode, trong text sẽ có các ký tự như sau:
Code:
< ="Microsoft FrontPage 5.0" name=GENERATOR> < =FrontPage.Editor. name=ProgId> Kh&ocirc;ng cần chạy đ&ocirc;n chạy đ&aacute;o khắp
các trung t&acirc;m để mong t&igrave;m được một c&ocirc;ng
việc l&agrave;m th&ecirc;m tăng thu nhập, chẳng cần phải gật
đầu với những c&ocirc;ng việc nằm ngo&agrave;i v&ugrave;ng
Mặc dù đoạn text này vẫn được trình duyệt hiển thị đúng nhưng trong html code bị như thế, nhìn không thích một chút nào cả hơn nữa có thể gây ra dư thừa dữ liệu hoặc tìm kiếm tiếng Việt không chính xác. Để khắc phục hiện tượng này bạn thêm vào file config dòng sau (vào file fckconfig.js):
Code:
FCKConfig.ProcessHTMLEntities = false ;
Xem thêm Cấu hình và sử dụng bộ soạn thảo FCKEditor
28. Sử dụng ImageGallery của FreeTextbox để quản lý và chèn ảnh vào bài viết
Khi sử dụng FreeTextbox . Nếu không config thì bạn không có trình quản lý Image với chức năng upload và chèn ảnh vào nội dung bài viết. Với FreeTextBox cũng đã hỗ trợ bạn đủ công cụ để quản lý và chọn ảnh vào bài viết. Khi download thư viện này về tại [Bạn phải đăng kí mới nhìn thấy link này. ] trong thư mục giải nén có file ftb.imagegallery.aspx và thư mục aspnet_client. Bạn hãy copy file và thư mục này vào thư mục web của bạn. Sau đó trong code bạn dùng như sau:
Code:
<FTB:FreeTextBox ID="ftbContent" runat="server" Height="120px"
 ImageGalleryUrl="../ftb.imagegallery.aspx?rif=/imagespath/&cif=~/uploads/image/" 
 Width="100%" ToolbarLayout=" ParagraphMenu,FontFacesMenu,FontSizesMenu,FontForeColorsMenu|Bold,Italic,Underline,
Strikethrough;Superscript,Subscript,RemoveFormat|JustifyLeft,JustifyRight,JustifyCenter,JustifyFull;BulletedList,NumberedList,Indent,Outdent;CreateLink,Unlink,InsertImage,InsertRule|Cut,Copy,Paste;Undo,Redo,Print, InsertImageFromGallery,Preview,SelectAll,WordClean,NetSpell">
</FTB:FreeTextBox>
Với code ví dụ trên tất cả ảnh sẽ được quản lý và lưu vào thư mục uploads/image/ trong web của bạn. Khi viết bài bạn có thể tạo các thư mục con và hiển thị các hình ảnh dạng ImageGallery rất dễ quản lý và tiện không kém FCKEditor
Xem thêm Hướng dẫn sử dụng và cấu hình FreeTextbox
29. Viết comment cho các hàm
Khi sử dụng VS để viết code bạn thấy VS hỗ trợ viết code và list ra các hàm, phương thức tương ứng và khi bạn chọn một phương thức nào đó sẽ có comment về các tham số, kiểu dữ liệu, giá trị trả về, …
Khi bạn viết hàm bạn cũng có thể tạo comment như vậy bằng cách bạn đưa con nháy lên phía trên của hàm đang viết và gõ 3 dấu /// khi đó VS sẽ tự tạo các commnet và bạn ghi các comment của bạn vào và khi dùng nó cũng sẽ hiển thị comment như trên.
Ví dụ:
Code:
/// <summary>
/// Xóa một file được chọn
/// </summary>
/// <param name="fileName">file cần xóa</param>
public void DeleteFile(string fileName)
{
    try
    {
        FileInfo fi;
        if (System.IO.File.Exists(fileName) == true)
        {
            fi = new FileInfo(fileName);
            fi.Delete();
        }
    }
    catch (Exception ex) { ex.Message.ToString(); }
}
30. Đọc nôi dung của một trang web
Bạn cần đọc nội dung của một trang nào đó để bóc tách dữ liệu bạn dùng hàm sau để đọc nội dung.
Code:
/// <summary>
/// Đọc nội dung trang bất kỳ
/// </summary>
/// <param name="Address">Địa chỉ trang</param>
/// <returns>string</returns>
public string GetWebContent(string Address)
{
    string txOutput = "";
    try
    {
        if (Address != "")
        {
            System.Net.WebClient MyClient = new System.Net.WebClient();
            System.IO.Stream MyStream = MyClient.OpenRead(Address);
            System.IO.StreamReader MyStreamReader = new System.IO.StreamReader(MyStream);
            string NewLine;
            while ((NewLine = MyStreamReader.ReadLine()) != null)
            {
                txOutput += NewLine + "rn";
            }
        }
    }
    catch { }
    return txOutput;
}
Kết quả hàm này trả về là chuỗi html như khi bạn chọn viewsource của trang bạn muốn đọc
31. Refresh lại trang gốc khi kết thúc thao tác ở trang popupKhi bạn cần thực hiện hành động như thao tác dữ liệu hay cần làm một tác vụ nào đó và cần mở cửa số dạng popup và sau khi thực hiện xong công việc ở cửa số popup này bạn muốn refresh lại trang gốc. Ví dụ rõ nhất là ở diễn đàn aspvn.net (Khi bạn trả lời hoặc đặt câu hỏi aspvn.net sẽ mở cửa sổ popup để bạn nhập nội dung và lưu lại thì trang gốc được refresh lại) bạn thực hiện như sau:Ở trang popup bạn cần có đoạn javascript như sau:
Code:
<script language="JavaScript">
    function refreshParent() {
      window.opener.location.href = window.opener.location.href;
      if (window.opener.progressWindow)
         {
        window.opener.progressWindow.close()
      }
      window.close();
    }
    </script>
Trong code C# khi thực hiện lưu dữ liệu xong bạn dùng như dòng lệnh sau:
ScriptManager.RegisterStartupScript(this, this.GetType(), “refresh”, “refreshParent();”, true);
Nếu dùng code html trong trang popup bạn dùng như ví dụ:
Code:
 <asp:Button ID="btnClose" runat="server" OnClientClick="refreshParent();" Text="Đóng" />
32. Chèn thông tin chỉ số Alexa vào trang web
Khi lướt web bạn thấy có một số trang hiển thị chỉ số Alexa Traffic Rank như hmweb cũng đang dùng ở cuối trang. Làm điều này rất đơn giản bạn chỉ cần chèn đoạn code sau vào nơi bạn muốn hiển thị là xong:
Code:
<a href="http://www.alexa.com/siteinfo/hmweb.com.vn">
<script type='text/javascript' language='javascript' src='http://xslt.alexa.com/site_stats/js/t/a?url=hmweb.com.vn'></script>
</a>
33. Sử dụng MaskedEditExtender của ajax để thực hiện ghi đè dữ liệu.
Bạn có textbox ví dụ để nhập ngày tháng, bạn muốn khi nhập số thì dữ liệu được nhập kiểu overwrite bạn dùng MaskedEditExtender của ajax như sau:
Code:
<asp:TextBox ID="TextBox1" runat="server" Width="80px" />
<cc1:MaskedEditExtender ID="meeTuNgay" MaskType="Date" 
Mask="99/99/9999" runat="server" TargetControlID="txtTuNgay" />
Copy đoạn code này vào trang aspx của bạn và kiểm chứng (Chú ý bạn cần đảm bảo đã khai báo sử dụng ajax AjaxControlToolkit)
34. Cấu hình tiếng việt cho Ajax CalendarExtender
Bạn sử dụng Ajax CalendarExtender với dữ liệu ngày tháng và muốn cấu hình tiếng việt cho nó bạn làm như ví dụ sau: (DEMO)
Code:
<%@ Page Language="C#"  Culture="vi-VN" uiCulture="vi"%>
<%@ Register Assembly="AjaxControlToolkit" 
    Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
</head>
<body>
    <form id="form1" runat="server">
    <cc1:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" 
    EnableScriptGlobalization="True" />
    <div>
        Nhập ngày tháng:
        <asp:TextBox ID="txtNgayThang" runat="server" CausesValidation="True"></asp:TextBox>
        <cc1:CalendarExtender ID="txtNgayThang_CalendarExtender" runat="server" 
            Enabled="True" TargetControlID="txtNgayThang" Format="dd/MM/yyyy">
        </cc1:CalendarExtender>
    </div>
    </form>
</body>
</html>
35. SetFocus Textbox theo điều kiện
Bạn có Form login và khi người dùng truy cập bạn muốn đặt focus luôn đến txtUserName (Tên đăng nhập), Nếu txtUserName đã có (Thường do trình duyệt có chế độ nhớ UserName) thì chuyển focus đến txtPassword. Điều này bạn thấy rõ nhất nếu bạn sử dụng mail của MDaemon bạn làm như sau
Code:
protected void Page_Load(object sender, EventArgs e)
{
    if (txtUserName.Text + "" != "")
    {
        this.SetFocus(txtPassword);
    }
    else { this.SetFocus(txtUserName); }
}
36. Cho phep upload hay export khi dùng updatepanel
Khi sử dụng updatePanel của ajax nếu bạn lồng asp:FileUpload hay button cho phéo export ra excel chẳng hạn trong một asp:UpdatePanel thì sẽ không upload hay export được, Nguyên nhân thì chưa rõ nhưng cũng có cách khắc phục bằng cách thêm asp:PostBackTrigger bên trong thẻ UpdatePanel như sau:
Code:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        Chọn dữ liệu: <asp:FileUpload ID="filMyFile" runat="server"  CssClass="textbox" 
Width="300px" />
        <asp:Button ID="btnImport" runat="server" 
            OnClick="btnImport_Click" 
            OnClientClick="javascript:showWait();"
            Text="Import" />
     </ContentTemplate>
     <Triggers>
            <asp:PostBackTrigger ControlID="btnImport" />
    </Triggers>
</asp:UpdatePanel>
37. Sử dụng asp:UpdateProgress của ajax kết hợp với updatepanel
Trong mục 36 có cái OnClientClick=”javascript:showWait();” tức là khi người dùng chọn dữ liệu upload và click upload ta sẽ thông báo đang xử lý dữ liệu, để làm vậy ta cần dùng một UpdateProgress cùng với một updatepanel như sau:
Code:
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1"
    DynamicLayout="true">
    <ProgressTemplate>
        Đang xử lý dữ liệu ...
    </ProgressTemplate>
</asp:UpdateProgress>
Và hàm showWait:
Code:
 <script language="javascript" type="text/javascript">
    function showWait()
    {
        if ($get('filMyFile').value.length > 0)
        {
            $get('UpdateProgress1').style.display = 'block';
        }
    }
</script>
Bạn có thể tìm một ảnh gif động và style sheet để làm nổi cái UpdateProgress thông báo cho sinh động
38. Thiết lập Title page theo bài viết
Khi người dùng đọc một bài viết thì Title page sẽ chính là tiêu để của bài viết đó, thiết lập này sẽ có tác dụng cho các máy tìm kiếm tốt hơn. Để thiết lập khi bạn đã truy vấn được ID của bài viết bạn dùng Page.Title như minh họa sau:
Code:
Page.Title = dtb.Rows[0]["Title"] + "";
Trong đó dtb là Datatable khi truy vấn dữ liệu với IdBaiViet và Fill vào dtb
39. Định dạng số phân cách hàng nghìn
Bạn có một số 123456789 chẳng hạn giờ muốn định dạng hiển thị phân cách hàng nghìn để hiển thị thành 123,456,789 bạn làm như ví dụ sau:
Code:
int so = 123456789;
txtSo.Text = so.ToString("#,###");
Tương tự cách dùng ToString bạn cũng có thể định dạng ngày tháng hiển thị dạng dd/MM/yyyy như sau:
Code:
txtSo.Text = DateTime.Now.ToString("dd/MM/yyyy");
40. Hiển thị thời gian chạy kiểu đồng hồ điện tử
Bạn muốn có label hiển thị như đồng hồ điện từ trên trang của bạn bạn dùng như sau:
Code:
<script language="JavaScript">
    function updateTime()
    {
        var label = document.getElementById('ctl00_currentTime');
        if (label) {
            var time = (new Date()).localeFormat("T");
            label.innerHTML = time + '&nbsp;&nbsp;&nbsp;';
        }
    }
    updateTime();
    window.setInterval(updateTime, 1000);
</script> 
......
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <span id="currentTime" runat="server"></span>
    </ContentTemplate>
</asp:UpdatePanel>
Bạn chú ý trong hàm javascript trên ta có dùng ctl00_currentTime là ID của thẻ span – ctl00_ là chỉ số tự sinh khi bạn đặt trong updatepanel, Nếu bạn thực hiện không chạy bạn view source tìm và lấy đúng id của thẻ span (Vì có thể bạn dùng lồng trong nhiều control thì id này sẽ khác).

C# – Tối ưu hóa chương trình C# – P1

C# – Tối ưu hóa chương trình C# – P1

CSharp_iconĐây là một số kinh nghiệm về tối ưu hóa mã nguồn C# sau một khoảng thời gian làm việc với nó. Bạn có thể áp dụng một số thủ thuật này trong các ngôn ngữ khác như VB.Net, Java…


Để đo thời gian thực thi của các đoạn mã ví dụ bên dưới, bạn có thể dùng DateTime.Now.Ticks lưu thời điểm bắt đầu và kết thúc. Tuy nhiên .Net cung cấp cho bạn sẵn đối tượng Stopwatch (đồng hồ bấm giờ) nằm trong không gian tên System.Diagnostics để dùng cho những công việc dạng này.
Trong mỗi phần tôi sẽ so sánh hai phương pháp (đoạn mã), phương pháp thứ hai sẽ là phương pháp tối ưu hơn cho bạn lựa chọn. Mặc dù các giải pháp thay thế có thể tốt hơn nhưng không hẳn đã là tối ưu, việc tối ưu một đoạn mã đòi hỏi sự hiểu biết và phân tích khá sâu vào nền tảng .Net, hơn nữa còn phụ vào thuật toán bạn sử dụng trong từng trường hợp.

1.      So sánh chuỗi:

Ở đây tôi dùng hai phương pháp so sánh chuỗi thường sử dụng (có phân biệt hoa thường). Điểm khác biệt giữa hai phương thức này là phương thức thứ 1 là tĩnh (static) nên ta có thể gọi trực tiếp từ lớp String.
-      (1) int String.Compare(string strA, string strB, bool ignoreCase)
-      (2) bool string.Equals(string value, StringComparison comparisonType)
string s1=”aaa”;
string s2=”AAA”;
Đoạn mã 1:
for (int i = 0; i < 100000; i++)
{
bool b = String.Compare(s1, s2,true)==0;
}
Đoạn mã 2:
for (int i = 0; i < 100000; i++)
{
bool b = s1.Equals(s2,StringComparison.OrdinalIgnoreCase);
}
Đoạn mã thứ nhất chạy chậm hơn đoạn thứ hai hơn 3 lần. Tuy nhiên nếu bạn sử dụng tham số StringComparison.CurrentCultureIgnoreCase cho phương thức Equals thì tốc độ giữa hai đoạn mã là xấp xỉ. Một số người dùng cách chuyển cả hai chuỗi về dạng chữ hoa hoặc chữ thường rồi so sánh sẽ tốn thời gian lâu nhất (hơn 2 lần so với cách một).

2.      Xây dựng chuỗi – String và StringBuilder:

Đây có lẽ là điều bạn thường gặp và cũng đã nắm bắt được sự khác biệt rõ ràng giữa chúng. Với số lần lặp tương đối lớn bạn sẽ có một khoảng thời gian chờ tương đối lâu khi làm việc với lớp String, vì thế tôi sẽ giảm số lần lặp xuống trong ví dụ này.
Đoạn mã 1:
string str=””;for (int i = 0; i < 10000; i++)
{
str += “a”;
}
Đoạn mã 2:
StringBuilder str=new StringBuilder();
for (int i = 0; i < 10000; i++)
{
str.Append(“a”);
}
Kết quả cho ta thấy đoạn mã một chạy chậm hơn khoảng từ 200 đến 300 lần đoạn mã hai. Nguyên nhân là toán tử + của lớp string sẽ tạo ra một đối tượng string mới trong mỗi lần lặp, trong khi phương thức Append của StringBuilder sẽ nối trực tiếp vào chuỗi hiện tại.
Tuy nhiên cũng cần chú ý điều này có thể ngược lại nếu như bạn cần chuyển chuỗi StringBuilder thành String trong mỗi lần lặp. Tốc độ thực thi của đoạn mã thứ hai sẽ lâu hơn so với đoạn mã một. Hãy kiểm chứng bằng cách chạy thử đoạn mã hai sau khi sửa lại như sau:
Đoạn mã 2 (đã sửa):
StringBuilder str = new StringBuilder();
string strRet;
for (int i = 0; i < 10000; i++)
{
str.Append(“a”);
strRet = str.ToString();
}

3.      Nối chuỗi – Phương thức Insert() và toán tử +:

Bạn thường sử dụng hai cách để nối hai chuỗi lại với nhau là dùng toán tử + và phương thức Insert() của đối tượng string. Cách đầu tiên được sử dụng nhiều hơn vì cách viết tiện lợi và dễ hiểu hơn, tuy nhiên bạn chỉ có thể nối vào đầu hoặc cuối chuỗi. Hãy thử so sánh xem phương pháp nào cho tốc độ thực thi nhanh hơn, giả sử bạn cần nối một chuỗi con vào đầu một chuỗi.
Đoạn mã 1:
string str=””;
for (int i = 0; i < 10000; i++)
{
str = “string”;
str= str.Insert(0, “my “);
}
Đoạn mã 2:
string str=””;
for (int i = 0; i < 10000; i++)
{
str = “string”;
str = “my ” + str;
}
Nếu chạy thử vài lần, bạn sẽ nhận thấy rằng đoạn mã thứ hai chạy nhanh gấp đôi đoạn mã một. Tuy nhiên nếu như không khởi tạo lại giá trị của biến str trong mỗi lần lặp, tốc độ của hai đoạn mã này là xấp xỉ nhau.

4.      Cắt chuỗi – Substring() và Remove():

Hai phương thức trên của lớp string có chức năng khá giống nhau là cắt bỏ một phần chuỗi nguồn. Cả hai phương thức đều có 2 kiểu nạp chồng, và đều yêu cầu truyền vào vị trí bắt đầu của chuỗi. Tùy vào trường hợp, Substring() thích hợp cho việc cắt bỏ chuỗi phía trước, còn Remove() lại thường dùng để cắt bỏ phía sau chuỗi. Trong ví dụ này tôi sẽ dùng hai phương thức này để cắt bỏ 1 kí tự phía trước chuỗi:
Đoạn mã 1:
string str;
for (int i = 0; i < 10000; i++)
{
str = “string”;
str = str.Remove(0, 1);
}
Đoạn mã 2:
string str;
for (int i = 0; i < 10000; i++)
{
str = “string”;
str = str.Substring(1);
}
Sự khác biệt giữa đoạn mã hai so với đoạn mã một là tốc độ nhanh hơn khoảng 2 lần. Tuy nhiên sự khác biệt này sẽ trở nên khó phân biệt nếu như bạn dùng chúng để cắt ở vị trí khác, như là cuối chuỗi chẳng hạn.

5.      Chuyển đối tượng về dạng chuỗi – Format() và ToString();

Format là một phương thức khá hiệu quả trong một số trường hợp bạn cần thêm các tham số và một chuỗi, sử dụng tương tự như cách bạn in một chuỗi ra màn hình console bằng phương thức WriteLine().
Đoạn mã 1:
string str = “”;
int obj = 1;
for (int i = 0; i < 100000; i++)
{
str = String.Format(“{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}”, obj);
}
Đoạn mã 2:
string str = “”;
int obj = 1;
for (int i = 0; i < 100000; i++)
{
string s = obj.ToString();
str = s + s + s + s + s + s + s + s + s + s;
}
Ở đây tôi tạo ra một đối tượng string với giá trị là mười số 1 trong mỗi lần lặp. Cả hai phương pháp này đều chạy khá lâu với số lần lặp là 100000. Tuy nhiên đoạn mã thứ nhất sẽ tốn thời gian gấp gần 5 lần so với đoạn mã thứ hai, mặc dù đoạn mã thứ hai còn sử dụng toán tử cộng chuỗi.

6.      Sự khác biệt giữa các phương thức nạp chồng (overloaded):

Bạn có thể không để ý rằng giữa các phương thức nạp chồng, thực hiện cùng một công việc lại có sự khác biệt về khoảng thời gian mà chúng thực thi. Điều này thường thấy trong các phương thức với tham số là một hoặc nhiều kiểu đối tượng được tạo ra từ những thành phần đơn giản hơn.
Chẳng hạn như phương thức khởi tạo của đối tượng Rectangle, ta sẽ thử xét hai phương thức:
-      (1) Rectangle (Point location, Size size)
-      (2) Rectangle (int x, int y, int width, int height)
Sự khác biệt về thời gian thực thi giữa 2 phương thức phụ thuộc vào đoạn mã chúng ta viết.
Nếu bạn so sánh giữa 2 đoạn mã sau:
Đoạn mã 1:
for (int i = 0; i < 100000; i++)
{
Rectangle rec = new Rectangle(new Point(i,i), new Size(i,i));
}
Đoạn mã 2:
for (int i = 0; i < 100000; i++)
{
Rectangle rec = new Rectangle(i,i,i,i);
}
Bạn có thể nhận thấy là đoạn mã thứ nhất chạy lâu hơn đoạn thứ hai khoảng 7 lần. Lý do xảy ra điều này bạn có thể đoán được là phương thức thứ nhất phải tạo ra 2 đối tượng trong mỗi lần lặp.

7.      Hạn chế sử dụng khối try catch:

Việc xử lý các ngoại lệ trong C# thường chiếm một khoảng thời gian tương đối lâu. Một số ngoại lệ có thể dự đoán trước được ,và thay vì sử dụng khổi try catch để bao đoạn mã không an toàn này lại, bạn hãy tự xử lý thông qua các dòng lệnh kiểm tra trước khi để đoạn mã tiếp tục thực hiện. Đây là một ví dụ:
int a = 0, b = 10;
Đoạn mã 1:
for (int i = 0; i < 1000; i++)
{
try
{
int c = b / a;
}
catch { }
}
Đoạn mã 2:
for (int i = 0; i < 1000; i++)
{
if (a == 0)
continue;
int c = b / a;
}
Dòng lệnh int c = b / a dĩ nhiên luôn ném ra ngoại lệ Divide by Zero (chia cho 0) nếu được thực thi. Tuy nhiên ngoại lệ này bạn có thể đoán trước và kiểm tra mẫu số phải khác 0 trước khi tiếp tục hay không. Sự cẩn trọng như trong đoạn mã 2 giúp bạn tiết kiệm được thời gian khoảng 30,000 (30 nghìn) lần so với đoạn mã 1.

8.      Hạn chế việc gọi phương thức:

Việc gọi phương thức nhiều lần có thể làm giảm tốc độ thực thi của chương trình so với việc viết trực tiếp thân hàm vào nơi cần thiết. Vì thế đối với những phương thức có nội dung đơn giản và không được gọi ở nhiều nơi khác nhau, bạn nên loại bỏ bớt đi những phương thức này. Điều này thường ít xảy ra nhưng có thể giúp bạn cẩn thận hơn trong việc quyết định có nên tạo ra một phương thức mới hay không.
Giả sử bạn có 1 phương thức Method() đơn giản như sau:
private void Method()
{
int a = 1, b = 2;
int c = a + b;
}
Bạn có hai cách để thực thi hai phương thức trên như sau:
Đoạn mã 1:
for (int i = 0; i < 1000000; i++)
{
Method();
}
Đoạn mã 2:
for (int i = 0; i < 1000000; i++)
{
int a = 1, b = 2;
int c = a + b;
}
Đoạn mã thứ hai chạy nhanh đoạn thứ nhất 3 lần. Các lệnh nhảy mặc dù rất tốn rất ít chi phí nhưng với số lượng nhiều có thể làm chậm tốc độ thực thi của chương trình khá rõ ràng.

9.      Sử dụng cấu trúc thay cho lớp:

Đối với những kiểu dữ liệu đơn giản và không cần tham chiếu, bạn nên sử dụng cấu trúc (structure) thay cho lớp (class), điều này sẽ giúp giảm bớt chi phí tài nguyên tiêu hao cho chương trình của bạn. Tuy nhiên bạn cũng cần cân nhắc dựa vào yêu cầu của dự án trước khi quyết định dùng struct hay class cho phù hợp.
Giả sử bạn có một lớp và một cấu trúc có cùng thành viên và thuộc tính đơn giản như sau:
class MyClass
{
private int value;
public int Value
{
get { return this.value; }
set { this.value = value; }
}
}
struct MyStruct
{
private int value;
public int Value
{
get { return this.value; }
set { this.value = value; }
}
}
Hai đoạn mã cũng thực hiện cùng một nhiệm vụ:
Đoạn mã 1:
for (int i = 0; i < 1000000; i++)
{
MyClass myClass = new MyClass();
myClass.Value = 1;
}
Đoạn mã 2:
for (int i = 0; i < 1000000; i++)
{
MyStruct myStruct= new MyStruct();
myStruct.Value = 1;
}
Khi chạy thử bạn có thể nhận thấy đoạn mã thứ hai chạy nhanh hơn khoảng trên 4 lần so với đoạn mã thứ nhất. Lý do chính khá đơn giản là cấu trúc đơn giản và có ít tính năng hơn lớp, vì thế như đã nói trước, bạn chỉ nên sử dụng đối với những kiểu dữ liệu đơn giản, thành viên của nó thường là những kiểu dữ liệu đã được xây dựng sẵn.

10.  Sử dụng tập hợp (collection) có định kiểu:

Mục đích của việc này là giúp hạn chế tối đa việc ép kiểu khi bạn thao tác với các tập hợp này. Thường thì chúng ta chỉ chứa một loại đối tượng trong một tập hợp, vì thế thay vì dùng lớp ArrayList để lưu trữ, bạn hãy thử dùng List<T>. Các tập hợp có định kiểu được cung cấp trong namespace System.Collections.Generic.

11.  Mảng (array) và tập hợp  (collection) – tốc độ hay sự linh hoạt:

Bạn có thể đã biết rằng việc sử dụng mảng sẽ giúp truy xuất nhanh hơn tuy hơn lại không linh hoạt bằng tập hợp. Về mặt lý thuyết, tập hợp giống như một danh sách liên kết (linked list) với khả năng cấp phát động để cung cấp các thao tác thêm, xóa theo vị trí mà mảng không hỗ trợ. Trong một số trường hợp, nếu không cần đến các chức năng này của tập hợp, bạn nên sử dụng mảng để tối ưu cho chương trình của mình.
Đoạn mã 1:
List<int> list = new List<int>();
for (int i = 0; i < 1000000; i++)
{
list.Add(1);
}
Đoạn mã 2:
int[] arr = new int[1000000];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = 1;
}
Tốc độ thực thi của đoạn mã thứ hai có thể nhanh hơn 4-6 lần đoạn mã một. Tuy nhiên nếu bạn sử dụng ArrayList trong đoạn mã một, sự khác biệt này có tăng lên đến 15 lần. Một lần nữa bạn thấy sự cải thiện đáng kể khi sử dụng tập hợp có định kiểu.
Trên đây chỉ là một vài kinh nghiệm cơ bản, bạn có thể tự tìm hiểu và khám phá thêm trong quá trình thực hành.
17/9/2209

Thứ Sáu, 13 tháng 12, 2013

Kết nối CSDL MySql trong C#

Đây là 1 VD minh họa đơn giản việc kết nối MySQL trong C#. Để kết nối với các hệ CSDL khác bằng ADO.NET ( Microsoft SQL Server , Oracle, Microsoft acess) thì có khá nhiều giáo trình đề cập đến rồi nên mình sẽ không nói thêm nữa. Hi vọng bài viết này sẽ giúp ích cho các bạn.
Để kết nối với CSDL các bạn sử dụng file connector của MySQL tải tại đây
Tạo một CSDL bằng MySQL, các bạn có thể cài đặt trọn bộ webserver(trong đó có sẵn MySQL) , ở đây mình sẽ dùng gói xampp-win32 (Server:Localhost, Database:temp , user:root/pass=””).
Tạo project mới, sau đó vào Project/Add reference…. Và Add file MySQL.Data.DLL vừa mới tải về vào project.
Sử dụng lớp MySql.Data.MySqlClient:
using MySql.Data.MySqlClient;
Khai Báo một Connection String:
string MyConString = “SERVER=localhost;” +
“DATABASE=temp;” +
“UID=root;” +
“PASSWORD= ; ” ;

Dạng đầy đủ của Connection String:
Connection String : “Server=hostname;” + “Database=database;” “Port=3306;”+ “User ID=username;” + “Password=password;” + “Pooling=false”

Server :Hostname hoặc IP của MySQL server.
Database: tên của CSDL. (Vd này mình dặt là ‘temp’)
Port: TCP/IP Port để kết nối (mặc dịnh là 3306).
User ID: user (Vd:root).
Password: pass.
Pooling: YES hoặc TRUE để sử dụng kết nối lấy từ pool , NO hoặc FALSE kết nối không lấy từ pool(mặc dịnh là TRUE (YES)).
Connection – pooling là gì?
Trích dẫn:
Quote
Connection-pooling làm giảm đáng kể tổng phí liên hợp với việc tạo và hủy kết nối cơ sở dữliệu. Connection-pooling cũng cải thiện tính quy mô của các giải pháp bằng cách giảm số lượng kết nối đồng thời mà một cơ sở dữ liệu phải duy trì—đa số thường “ngồi không” suốt một phần đáng kể thuộc thời gian sống của chúng. Với connection-pooling, thay vì tạo và mở một đối tượng kết nối mới mỗi khi cần, bạn có thể lấy kết nối đã mở từ pool. Khi bạn đã hoàn tất việc sử dụng kết nối, thay vì đóng nó, bạn trả nó về cho pool và cho phép đoạn mã khác sử dụng nó.
Theo mặc định, SQL Server và Oracle Data Provider cung cấp chức năng connection-pooling. Một pool sẽ hiện diện đối với mỗi chuỗi kết nối do bạn chỉ định khi mở một kết nối mới. Mỗi khi bạn mở một kết nối mới với chuỗi kết nối đã được sử dụng qua, nó sẽ được lấy từ pool hiện có. Chỉ khi bạn chỉ định một chuỗi kết nối khác thì data-provider mới tạo một pool mới.
Bạn có thể điều khiển các đặc tính của pool bằng cách sử dụng các thiết lập trong chuỗi kết
nối .
Tạo kết nối:
Vd:
Quote
MySqlConnection con = new SqlConnection(MyConString);
MySqlCommand com = con.CreateCommand();
MySqlDataReader reader;
Nhập lệnh SQL:
Quote
com.CommandText = “select * from login”;
Mở kết nối:
vd:
Quote
con.Open();
Thực hiện lệnh:
vd:
Quote
reader = com.ExecuteReader();
Lấy kết quả trả về (ở đây mình sẽ sử dụng listbox) :
Quote
while (reader.Read())
{
string thisrow = “”;
for (int i = 0; i < reader.FieldCount; i++)
thisrow += reader.GetValue(i).ToString() + “,”;
listBox1.Items.Add(thisrow);
}
Code tham khảo:
Quote
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string MyConString = “SERVER=localhost;” +
“DATABASE=temp;” +
“UID=root;” +
“PASSWORD= ; ” ;
MySqlConnection con = new MySqlConnection(MyConString);
MySqlCommand com = con.CreateCommand();
MySqlDataReader reader;
com.CommandText = “select * from login”;
con.Open();
reader = com.ExecuteReader();
while (reader.Read())
{
string thisrow = “”;
for (int i = 0; i < reader.FieldCount; i++)
thisrow += reader.GetValue(i).ToString() + “,”;
listBox1.Items.Add(thisrow);
}
con.Close();
}
}
}

Thứ Sáu, 29 tháng 11, 2013

Dictionary Class

Represents a collection of keys and values.
Namespace:  System.Collections.Generic
Assembly:  mscorlib (in mscorlib.dll)
   Syntax

[SerializableAttribute]
[ComVisibleAttribute(false)]
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, 
 ICollection<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, 
 IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, 
 IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, ISerializable, 
 IDeserializationCallback


Thứ Hai, 7 tháng 10, 2013

Creating a Windows Phone 7 Application Consuming Data Using a WCF Service

Introduction: 

The objective of this article is to create a WCF service that retrieves data from the database using LINQ to SQL classes and a Windows Phone 7 application that consumes that service to display the data. 
The article contains three main parts:

  1. Creating the database
  2. Creating the WCF Service
  3. Creating the Windows Phone 7 application that consumes the WCF service
The above mentioned scenario has been illustrated with an example. In the example I have created a table that contains some details about an employee (Employee ID, Employee Name and Phone No). When the user of our Windows Phone 7 application enters an employee id, he will be able to retrieve the details of that employee from the database through the WCF service.
1. Creating the Database:
The following steps have been followed to create the database

Image6.gif

    Now some data are added to the table.
    Image7.gif

    Now we have created our database.


    2. Creating the WCF Service

    We have followed the steps given below to create the WCF Service.
    Open the Visual Studio 2010 & create a new WCF Service Application. (In our case, the name of the WCF service is MyService)
    Image8.gif
     
    Right Click on the project name and then add a new item.

    Image9.gif
     
    Now add a LINQ to SQL class to the project.

    Image10.gif
     
    Now go to server explorer and add a new data connection. (Right click on Data Connection and select Add Connection)

    Image11.gif
     
    Give the server name, select the database and click test connection. Then click OK.

    Image12.gif
     
    Now from server explorer select your database and table and drag the table to the middle pane.

    Image13.gif
     
    Now open the IService1.cs and delete all the default codes. Write down the following code there. I have explained the code later.
     
    Now open the Service1.svc.cs and delete all the default codes. Write down the following code there. I have explained the code later.
     
    Right click on service1.svc and select the "view in browser" option.

    Image16.gif
     
    Our service is running now (In Cassini server).

    Image17.gif
     
    Copy the URL of the service.
    3. Creating the Windows Phone 7 application that consumes the WCF service
    1. Open the Microsoft Visual Studio 2010 Express for Windows Phone and create a Windows Phone Application. (In our case the name of the Windows Phone 7 application is MyClientWin7)
    Image18.gif

    In MainPage.xaml drag and drop a TextBox and a Button as shown below.

    1. Image19.gif

    2. The XAML code for MainPage.xaml is given below

    3. <phoneNavigation:PhoneApplicationPage 
    4.     x:Class="MyClientWin7.MainPage"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:phoneNavigation="clr- namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Navigation"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"    FontFamily="{StaticResource PhoneFontFamilyNormal}"    FontSize="{StaticResource PhoneFontSizeNormal}"    Foreground="{StaticResource PhoneForegroundBrush}">
    5.     <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneBackgroundBrush}">        <Grid.RowDefinitions>            <RowDefinition Height="Auto"/>            <RowDefinition Height="*"/>        </Grid.RowDefinitions>
    6.         <!--TitleGrid is the name of the application and page title-->        <Grid x:Name="TitleGrid" Grid.Row="0">            <TextBlock Text="MY APPLICATION" x:Name="textBlockPageTitle" Style="{StaticResource PhoneTextPageTitle1Style}"/>            <TextBlock Text="page title" x:Name="textBlockListTitle" Style="{StaticResourcePhoneTextPageTitle2Style}"/>        </Grid>
    7. Right click on the project name (MyClientWin7) and add a new item. Then select a Windows Phone Portrait Page and add it to the project.

    8. Image20.gif
    9.  
    10. In Page1.xaml, drag and drop a list box.

    11. Image21.gif

    12. The XAML code for Page1.xaml is given below

    13. <navigation:PhoneApplicationPage 
    14.     x:Class="MyClientWin7.Page1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:navigation="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Navigation"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    SupportedOrientations="Portrait"    mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="480">
    15. </navigation:PhoneApplicationPage>
    16. Now right click on the References and add a Service Reference.

    17. Image22.gif
    18.  
    19. In the Address paste the URL of the WCF service which is running and click Go. Then click OK.

    20. Image23.gif
    21.  
    22. Now open the MainPAge.xaml.cs (Double click on the button "Find") and write down the follwing code.
    23.  
    24. Open Page1.xaml.cs and write down the code.
    25.  
    26.             listBox1.ItemsSource = e.Result;
    27.         }    }
    28. Replace the code for the ListBox in the Page1.xaml in the following way.
    29.  
    30. Rebuild the solution and start debugging. The following screen will appear in the emulator.

    31. Image26.gif
    32.  
    33. Enter some Employee ID in the textbox and click the Find button. (Here I have entered U22975 in the text box )The following screen will appear then showing the details of the employee whose ID was entered in the textbox.

    34. Image27.gif



    35. using System;




    1. using System.Collections.Generic;
    2. using System.Linq;
    3. using System.Runtime.Serialization;
    4. using System.ServiceModel;
    5. using System.ServiceModel.Web;
    6. using System.Text;
    7. using System.Collections.Generic;

    8. namespace MyService
    9. {
    10.     [ServiceContract]
    11.     public interface IService1
    12.     {
    13.         [OperationContract]
    14.         List<MyEmployee> FindEmployee(string uid);
    15.      
    16.     }
    17. }

    18. Image14.gif

    19. Explanation of the code :

    20. The interface Iservice1 is the service contract of our WCF service. We have declared only one function (FindEmployee) as our operation contract. This function takes a string as an argument (which is the employee ID entered by the user) and return a List of MyEmployee which is our data model class.
    21. using System;
    22. using System.Collections.Generic;
    23. using System.Linq;
    24. using System.Runtime.Serialization;
    25. using System.ServiceModel;
    26. using System.ServiceModel.Web;
    27. using System.Text;
    28. namespace MyService
    29. {
    30.     public class Service1 : IService1
    31.     {
    32.         public List<MyEmployee> FindEmployee(string uid)
    33.         {
    34.             DataClasses1DataContext context = new DataClasses1DataContext();
    35.             var res = from r in context.MyEmployees where r.EmpID == uid select r;
    36.             return res.ToList();
    37.         }
    38.     }
    39. }

    40. Image15.gif

    41. Explanation of the code :
    42. The class Service1 is our service that implements the service contract IService1. In this class we have defined the operation contract FindEmployee. In this method, we have created a data context object. Then we have written a simple LINQ to SQL query that fetches the details of a particular employee whose employee id was passed as an argument of the operation contract. The method returns a list of objects of MyEmployee class. (We could have returned only one object of MyEmployee class also as we are fetching data using the primary key)
    43.         <!--ContentGrid is empty. Place new content here-->        <Grid x:Name="ContentGrid" Grid.Row="1">            <TextBox Height="32" HorizontalAlignment="Left" Margin="40,87,0,0"Name="textBox1" Text="" VerticalAlignment="Top" Width="401" />            <Button Height="70" HorizontalAlignment="Left" Margin="152,304,0,0"Name="button1" VerticalAlignment="Top" Width="160" Content="Find" Click="button1_Click" />        </Grid>    </Grid>
    44.  </phoneNavigation:PhoneApplicationPage>
    45.     <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneBackgroundBrush}">        <Grid.RowDefinitions>            <RowDefinition Height="170"/>            <RowDefinition Height="*"/>        </Grid.RowDefinitions>
    46.         <!--This is the name of the application and page title-->        <Grid Grid.Row="0" x:Name="TitleGrid">            <TextBlock x:Name="ApplicationName" Text="MY APPLICATION" Style="{StaticResource PhoneTextPageTitle1Style}"/>            <TextBlock x:Name="ListName" Text="page title" Style="{StaticResourcePhoneTextPageTitle2Style}"/>        </Grid>
    47.         <!--This section is empty. Place new content here Grid.Row="1"-->        <Grid Grid.Row="1" x:Name="ContentGrid">            <ListBox Height="444" HorizontalAlignment="Left" Margin="20,81,0,0" Name="listBox1"VerticalAlignment="Top" Width="434" />        </Grid>    </Grid>
    48. using System;
    49. using System.Collections.Generic;
    50. using System.Linq;
    51. using System.Net;
    52. using System.Windows;
    53. using System.Windows.Controls;
    54. using System.Windows.Documents;
    55. using System.Windows.Input;
    56. using System.Windows.Media;
    57. using System.Windows.Media.Animation;
    58. using System.Windows.Shapes;
    59. using Microsoft.Phone.Controls;

    60. namespace MyClientWin7
    61. {
    62.     public partial class MainPage : PhoneApplicationPage
    63.     {
    64.         public MainPage()
    65.         {
    66.             InitializeComponent();

    67.             SupportedOrientations = SupportedPageOrientation.Portrait |SupportedPageOrientation.Landscape;
    68.         }

    69.         private void button1_Click(object sender, RoutedEventArgs e)
    70.         {
    71.             string s = textBox1.Text;
    72.             this.Content = new Page1(s);

    73.         }
    74.     }
    75. }

    76. Image24.gif

    77. Explanation of the code:

    78. In the button click event (button1_Click), we have stored the textbox entry in a string and move to a new page (Page1) . In the Page1 constructor, we have passed the textbox entry.
    79. (Here we will find an error in new Page1(s) as the constructor defined in Page1.xaml.cs has no arguments. But we will change the constructor in the next step. Then the error will be removed.)
    80. using System;
    81. using System.Collections.Generic;
    82. using System.Linq;
    83. using System.Net;
    84. using System.Windows;
    85. using System.Windows.Controls;
    86. using System.Windows.Documents;
    87. using System.Windows.Input;
    88. using System.Windows.Media;
    89. using System.Windows.Media.Animation;
    90. using System.Windows.Shapes;
    91. using Microsoft.Phone.Controls;
    92. using MyClientWin7.ServiceReference1;

    93. namespace MyClientWin7
    94. {
    95.     public partial class Page1 : PhoneApplicationPage
    96.     {
    97.         public Page1(string s)
    98.         {
    99.             InitializeComponent();
    100.             Service1Client proxy = new Service1Client();
    101.             proxy.FindEmployeeCompleted += newEventHandler<FindEmployeeCompletedEventArgs>(proxy_FindEmployeeCompleted);
    102.             proxy.FindEmployeeAsync(s);

    103.         }
    104.      void proxy_FindEmployeeCompleted(object sender, FindEmployeeCompletedEventArgse)
    105.         {
    106. }

    107. Image25.gif

    108. Explanation of the code:

    109. In the Page1 constructor, we have created a proxy object of the service. Now all WCF service calls from Silverlight are made through asynchronous communications. The FindEmployee contract is implemented in the generated proxy with an asynchronous method FindEmployeeAsync and an event proxy_FindEmployeeCompleted that is raised when the operation has completed.
    110. The proxy_ FindEmployeeCompleted event sets the ItemSource property of the list box with the return value of the operation contract.
    111. <ListBox Height="444" HorizontalAlignment="Left" Margin="20,81,0,0" Name="listBox1"VerticalAlignment="Top" Width="434" >
    112.                 <ListBox.ItemTemplate>
    113.                     <DataTemplate>
    114.                         <StackPanel Orientation="Horizontal">
    115.                             <TextBlock Text="{Binding EmpID}"/>
    116.                             <TextBlock Text="{Binding EmpFirstName}"/>
    117.                             <TextBlock Text="{Binding EmpLastName}"/>
    118.                             <TextBlock Text=" " />
    119.                             <TextBlock Text="{Binding PhoneNo}"/>
    120.                         </StackPanel>
    121.                     </DataTemplate>
    122.                 </ListBox.ItemTemplate>
    123.             </ListBox>
    124. Explanation of the code:

    125. In this code we have overriden the ListBox control's ItemTemplate and supplied a custom DataTemplate. This DataTemplate uses one StackPanel to stack some textblocks together horizontally. These textblocks are used to bind to the data from the table in a readable manner. 
    (Sưu tầm)