------*%*%##$@$##%*%*----*%*%##$@$##%*%*----*%*%##$@$##%*%*----*%*%##$@$##%*%*------
Thuốc để giải ưu phiền là công việc, thú vui chỉ là liệu thuốc tạm thời..
---------------------------------------------------------------------------------------------------------------
Thứ Năm, 31 tháng 1, 2008
Truyện Vui 1
A New AJAX Approach - Client-side Controls Invoking Web Services
Since the time we shipped our first production suite of native ASP.NET AJAX controls back in November of 2006, we've been experimenting with new ways of doing efficient incremental page updates. We felt that we had something promising on our hands with full fledged client-side controls. The ability to create high-level UI elements (menus, treeviews, grids, etc.) on the client seemed like a solid foundation to build on. Our research produced a new high-performance AJAX technique which is currently gaining quite a bit of momentum among our customers. I will explain how this technique differs from standard AJAX techniques, with comments on ease of use, performance, elegance and the available client-side features within each technique.
I highly recommend trying the live examples associated to individual AJAX techniques below. Significant performance improvements are quite visible when the same functionality is implemented using different AJAX approaches. The final example is so fast that it truly feels like a local desktop application. Overview of Common AJAX Techniques Technique 1 - Server-centric AJAX Containers (ASP.NET AJAX UpdatePanel)
The server-centric AJAX container technique is employed by the ASP.NET AJAX UpdatePanel control as well as several AJAX solutions sold by the leading 3rd party control vendors. UpdatePanels are driven entirely by ASP.NET postbacks. AJAX applications are created by wrapping postback-based ASP.NET portions of the page and specifying which triggers (server-side events) will cause certain page areas to re-render.
Ease of use: The most obvious advantage of this approach is that it is extremely easy to implement. It is really not much harder than building a vanilla postback-based ASP.NET application and then wrapping certain areas of the page with UpdatePanels. This approach is ideal for quickly adding AJAX features to existing ASP.NET applications.
Performance: The biggest downside of this approach is performance. UpdatePanels always post the entire page - including full viewstate - to the server. Even though the required AJAX update to the page is often minimal, its server-side page processing essentially takes the same resources as when doing a full postback. The response sends raw HTML back to the browser, adding kilobytes to the required network traffic to process the AJAX request.
Elegance: The server-centric AJAX container technique is fairly elegant from the implementation point of view. Page areas are cleanly wrapped by UpdatePanel instances and AJAX updates are accomplished by mapping server-side events to triggers. All AJAX magic is performed by the UpdatePanel control itself.
Features: All features exposed to the developer using the UpdatePanel control are entirely on the server side. The control was not designed to be driven by client-side logic. The server-centric approach lacks the finer level of control on the client, which is definitely needed to build sophisticated AJAX apps with hyper-responsive user interfaces.
AJAX Explorer Example:
Technique 1 - Server-centric AJAX Containers (ASP.NET AJAX UpdatePanel)
Technique 2 - Client-centric AJAX Containers (ComponentArt CallBack)
ComponentArt CallBack is similar to the UpdatePanel control in its high-level concept of acting as a generic AJAX container for ASP.NET content. Both controls allow rendering custom ASP.NET content (including server controls, user controls as well as literal content) through AJAX callbacks - without reloading the entire page.
However, ComponentArt CallBack is driven entirely by its client-side API. Developers specify exactly when a callback will be triggered and exactly which parameters will be sent to the server (CallBack doesn't post the page by default). This triggers a server-side event, where the developer has full control over what will be rendered back to the client.
Ease of use: ComponentArt CallBack is not as easy to use as the UpdatePanel control. It requires JavaScript code to initiate the callback request through the control's client-side API as well as implementing a server-side event handler to render content back to the browser. In most cases this amounts to just a few lines of code on the client and the same amount on the server.
Performance: Requests made through the CallBack control are extremely lightweight in terms of network traffic. However, each request has to go through the full page life cycle and the response typically generates HTML and sends it back to the browser.
Elegance: The CallBack control hooks into the page life cycle and exposes the native ASP.NET object for rendering (HtmlTextWriter) to the developer. While the developer needs to write custom code both on the server and the client to perform an AJAX request, the level of control that is gained makes it worthwhile in most cases.
Features: The client-centric AJAX approach exposes more capabilities to rich web applications with highly-responsive user interfaces because all AJAX request decision-making logic resides within the client-side event-driven code.
AJAX Explorer Example:
Technique 2 - Client-centric AJAX Containers (ComponentArt CallBack)
Technique 3 - Manual JavaScript Coding Against Server-side Logic (Ajax.NET, ASP.NET 3.5 Script Services)
The previous two techniques revolve around the ASP.NET page model and are essentially delivered as ASP.NET server controls. In contrast with these techniques is a pure JavaScript approach originally introduced by Michael Schwarz with his Ajax.NET library. The core idea is to provide a way to mark methods of any server-side class with the "[AjaxMethod]" attribute and then be able to invoke that method from client-side code.
A similar technique is available with ASP.NET AJAX/3.5, which makes it incredibly easy to expose a web service and invoke it directly from client-side code. Significant performance improvements of this approach over the previous two are probably the main reason for its incredible popularity within the development community.
Ease of use: Invoking server-side logic on the client is easy with Ajax.NET / ASP.NET 3.5. However, this solution assumes quite a bit of manual JavaScript coding in order to generate and update user interface elements of the page. This is why it doesn't get high marks in the "ease of use" category.
Performance: There are two important performance breakthroughs of this approach: 1) Since methods of any class can be invoked through client-side code, the server-side request processing doesn't need to go through the ASP.NET page life cycle. The client-side request hits exactly the method it needs and it receives exactly the response it needs. There is no waste of server resources. 2) The response doesn't contain HTML markup. Rather, it contains only the data requested by the client. This can reduce the network traffic required to process the AJAX request by an order of magnitude. The received data is used on the client side to generate or update user interface elements.
Elegance: All functionality included with Ajax.NET or ASP.NET 3.5 Script Services is well architected. However, the overall solution is missing a piece of the AJAX puzzle and this is the reason why this approach loses points in the "elegance" category. The fact that developers are stuck with generating the user interface layer leaves the application with quite a bit of JavaScript code to maintain.
Features: The Ajax.NET library as well as ASP.NET 3.5 Script Services are loaded with client-side features. They contain the ability to easily invoke server-side logic as well as serialize .NET objects to their JSON representations. They don't, however, have the ability to manipulate high level UI elements (menus, treeviews, grids, etc.).
AJAX 2.0 - Client-side Controls Invoking Web Services
The new AJAX approach builds on best performance practises presented in the previous technique: efficiently executing server-side logic by invoking ASP.NET 3.5 web services and only sending data over the network. However, instead of requiring manual JavaScript coding to create and manipulate user interface elements, this functionality is now built into ComponentArt Web.UI client controls.
Ease of use: High-level client controls expose API methods to invoke web services. The structure and content of those controls is automatically populated with the results returned by the web service and the update is immediately visible on the screen. Even though some client-side coding is required to create and maintain user interface elements, it is reduced from many hundreds of lines to just a handful of high-level API calls. Not as easy as using the UpdatePanel control, but pretty close.
Performance: As already stated, this approach builds on best performance practises presented in the previous technique. However, the overall performance of an application built with this new approach actually exceeds the previous one. Additional performance improvements come from extensive client-side UI generation optimizations that we've built into the ComponentArt Web.UI suite.
Elegance: A high-level description of this technique is simple and powerful: "Objects on the client (client-side controls) communicate directly with objects on the server (web services)". The server-side logic of the application is delivered as a collection of web services - without any preconceived user interface decisions. This produces a real separation of tiers and greater code reuse options. Those web services could potentially be reused by multiple types of applications: mobile, smart client, Silverlight or other ASP.NET apps.
Features: Not only is AJAX request decision-making logic in the same domain as the rest of the app, but it is transparent to it. Updating a portion of the user interface through a fast AJAX request is no different than invoking any other client-side API method.
Thứ Tư, 30 tháng 1, 2008
Chúc Tết Bà Con
2. Đong cho đầy Hạnh phúc. Gói cho tròn Lộc tài. Giữ cho mãi An Khang. Thắt cho chặt Phú quý. Cùng chúc nhau Như ý, Hứng cho tròn An Khang, Chúc năm mới Bình An. Cả nhà đều Sung túc
Cung chúc tân niên, Sức khỏe vô biên, thành công liên miên, hạnh phúc triền miên, túi luôn đầy tiền, sung sướng như tiên.
3. Chúc mọi người hay ăn chóng béo, tiền nhiều như kẹo, tình chặt như keo, dẻo dai như mèo, mịn màng trắng trẻo, sức khỏe như voi
4. Sang năm mới chúc mọi người có một bầu trời sức khoẻ, một biển cả tình thương, một đại dương tình cảm, một điệp khúc tình yêu, một người yêu chung thủy, một tình bạn mênh mông, một gia đình thịnh vượng. Chúc các bà, các ông, các cô, các chú, các chị, các anh sang năm mới vạn sự như ý, tỷ sự như mơ, làm việc như thơ, đời vui như nhạc, coi tiền như rác, coi bạc như rơm, chung thủy với cơm và sắc son với phở.
5. Năm nay là năm tý.Chúc các em bồ nhí. Vạn sự được như ý. Mỗi năm đẹp một tí. Mắt tròn xoe hai mí. Tóc thơm không có chí. Mỗi tháng sụt một ký. Ăn nói phải có lý. Đừng ăn xài phung phí. Đừng làm chuyện để ý. Chúc tới đây anh bí. Cho anh hun một tí. Em vui cười hí hí. Mình mừng xuân mậu tý
6. Năm mới năm me Được nhiều hạnh phúc Ngàn lần chúc phúc Cho được bình an Tài lộc bạc vàng Nhiều vô số kể Ai mà ở rể Mẹ vợ sẽ cưng Ai đang lừng khừng Đầu năm sẽ cưới Có niềm vui mới Vào cuối năm nay Sinh đứa con trai Tuổi nhằm Đinh Hợi Cười nhe cả lợi Nằm đợi mà ăn Không có nhăn nhăn Như...ba má nó Nhà nào gặp khó Sẽ lại qua mau Tìm được sang giàu Làm ăn chân chính Tiêu xài nhín nhín Để vợ nó vui như Tết... Happy new year!
7.Tôi cầu xin Trời: Hãy mang niềm vui và sức khỏe đến cho các bạn của con mãi mãi. Trời nói: chỉ có thể 4 ngày! Tôi nói: được, Ngày Xuân, Ngày Hạ, Ngày Thu, Ngày Đông. Trời lại nói: vậy 3 ngày thui. Tôi cũng nói: Được, ngày hôm qua, hôm nay và ngày mai. Trời nói: Không được, vậy 2ngày. Tôi nói: Được, ngày sáng và ngày tối. Trời nói: Không được, chỉ một ngày duy nhất. Tôi lại nói: cũng được. Trời ngạc nhiên hỏi: Ngày nào? Tôi nói: ngày mà tất cả bạn bè tôi còn sống! Trời khóc ... và nói: Sau này tất cả bạn của ngươi ngày ngày đều khỏe mạnh và vui vẻ. Happy New Year!
8."CHÚC MỪNG NĂM MỚI. 12 tháng phú quý, 365 ngày phát tài, 8760 giờ sung túc, 525600 phút thành công 31536000 giây VẠN SỰ NHƯ Ý. (Wishing you 1 year of happiness, 12 months of fun, 52 weeks of gladness, 365 days of success, 8760 hours of good health and 525600 minutes of good luck !)
9.Chúc ông bà một tô như ý, chúc cô chú một chén an khang, chúc anh chị một dĩa, một dĩa tài lộc ... hehehe"
1. Năm hết Tết đến Đón Chuột tiễn lợn Chúc ông chúc bà Chúc mẹ chúc cha Chúc cô chúc cậu Chúc chú chúc dì Chúc anh chúc chị Chúc luôn các em Chúc cả các cháu Dồi dào sức khoẻ Có nhiều niềm vui Tiền xu nặng túi Tiền giấy đầy bao Đi ăn được khao Về nhà người rước Tiền vô như nước Tình vào đầy tim Chăn ấm nệm êm Sung sướng ban đêm Hạnh phúc ban ngày Luôn luôn gặp may Suốt năm con Chuột Cần gì là có thứ đó
2. Đong cho đầy Hạnh phúc. Gói cho tròn Lộc tài. Giữ cho mãi An Khang. Thắt cho chặt Phú quý. Cùng chúc nhau Như ý, Hứng cho tròn An Khang, Chúc năm mới Bình An. Cả nhà đều Sung túc
Cung chúc tân niên, Sức khỏe vô biên, thành công liên miên, hạnh phúc triền miên, túi luôn đầy tiền, sung sướng như tiên.
3. Chúc mọi người hay ăn chóng béo, tiền nhiều như kẹo, tình chặt như keo, dẻo dai như mèo, mịn màng trắng trẻo, sức khỏe như voi
4. Sang năm mới chúc mọi người có một bầu trời sức khoẻ, một biển cả tình thương, một đại dương tình cảm, một điệp khúc tình yêu, một người yêu chung thủy, một tình bạn mênh mông, một gia đình thịnh vượng. Chúc các bà, các ông, các cô, các chú, các chị, các anh sang năm mới vạn sự như ý, tỷ sự như mơ, làm việc như thơ, đời vui như nhạc, coi tiền như rác, coi bạc như rơm, chung thủy với cơm và sắc son với phở.
5. Năm nay là năm tý.Chúc các em bồ nhí. Vạn sự được như ý. Mỗi năm đẹp một tí. Mắt tròn xoe hai mí. Tóc thơm không có chí. Mỗi tháng sụt một ký. Ăn nói phải có lý. Đừng ăn xài phung phí. Đừng làm chuyện để ý. Chúc tới đây anh bí. Cho anh hun một tí. Em vui cười hí hí. Mình mừng xuân mậu tý
6. Năm mới năm me Được nhiều hạnh phúc Ngàn lần chúc phúc Cho được bình an Tài lộc bạc vàng Nhiều vô số kể Ai mà ở rể Mẹ vợ sẽ cưng Ai đang lừng khừng Đầu năm sẽ cưới Có niềm vui mới Vào cuối năm nay Sinh đứa con trai Tuổi nhằm Đinh Hợi Cười nhe cả lợi Nằm đợi mà ăn Không có nhăn nhăn Như...ba má nó Nhà nào gặp khó Sẽ lại qua mau Tìm được sang giàu Làm ăn chân chính Tiêu xài nhín nhín Để vợ nó vui như Tết... Happy new year!
7.Tôi cầu xin Trời: Hãy mang niềm vui và sức khỏe đến cho các bạn của con mãi mãi. Trời nói: chỉ có thể 4 ngày! Tôi nói: được, Ngày Xuân, Ngày Hạ, Ngày Thu, Ngày Đông. Trời lại nói: vậy 3 ngày thui. Tôi cũng nói: Được, ngày hôm qua, hôm nay và ngày mai. Trời nói: Không được, vậy 2ngày. Tôi nói: Được, ngày sáng và ngày tối. Trời nói: Không được, chỉ một ngày duy nhất. Tôi lại nói: cũng được. Trời ngạc nhiên hỏi: Ngày nào? Tôi nói: ngày mà tất cả bạn bè tôi còn sống! Trời khóc ... và nói: Sau này tất cả bạn của ngươi ngày ngày đều khỏe mạnh và vui vẻ. Happy New Year!
8."CHÚC MỪNG NĂM MỚI. 12 tháng phú quý, 365 ngày phát tài, 8760 giờ sung túc, 525600 phút thành công 31536000 giây VẠN SỰ NHƯ Ý. (Wishing you 1 year of happiness, 12 months of fun, 52 weeks of gladness, 365 days of success, 8760 hours of good health and 525600 minutes of good luck !)
9.Chúc ông bà một tô như ý, chúc cô chú một chén an khang, chúc anh chị một dĩa, một dĩa tài lộc ... hehehe"
Thứ Hai, 28 tháng 1, 2008
Utilities XML
using System.IO;
using System.Data;
using System.Xml;
using System.Xml.XPath;
using System.Text;
using System.Xml.Xsl;
using System.Collections;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.Localization;
namespace Lib.Utils
{///
/// Summary description for XMLUtil.
///
public class XMLUtil
{
public XMLUtil()
{
//
// TODO: Add constructor logic here
//
}
public static string TransformFile(string xmlFile, string xslFile)
{
return TransformFile(xmlFile, xslFile, null);
}
public static string TransformFile(string xmlFile, string xslFile, Hashtable paramList)
{
StringWriter sWriter = null;
MemoryStream ms = null;
XmlReader input = null;
XslCompiledTransform xslCompiledTransform = null;
try
{
XPathDocument xpathdocument = new XPathDocument(xmlFile);
XmlDocument stylesheet = new XmlDocument();
stylesheet.Load(xslFile);
//Create the XslCompiledTransform and Load it with the xsltDocument
xslCompiledTransform = new XslCompiledTransform();
XsltSettings settings = new XsltSettings();
settings.EnableScript = true;
xslCompiledTransform.Load(stylesheet, settings, new XmlUrlResolver());
StringBuilder sb = new StringBuilder();
//Create StringWriter for transformation output
sWriter = new StringWriter(sb);
//Create the XsltArgumentList.
XsltArgumentList xslArg = null;
if (paramList != null && paramList.Count > 0)
{
xslArg = new XsltArgumentList();
foreach (string param in paramList)
{
xslArg.AddParam(param, "", paramList[param]);
}
}
xslCompiledTransform.Transform(xpathdocument, xslArg, sWriter);
return sb.ToString();
}
finally
{
if (sWriter != null)
{
sWriter.Close();
}
if (ms != null)
{
ms.Close();
}
if (input != null)
{
input.Close();
input = null;
}
xslCompiledTransform = null;
}
}
public static bool IsValidXML(string xml_data) //DM 12.29.02
{
XmlDocument XmlDoc;
try
{
XmlDoc = new XmlDocument();
XmlDoc.LoadXml(xml_data);
return true;
}
catch
{
return false;
}
} //IsValidXML
///
/// Get a list of specified field name's values of input string
///
///
///
///
public static object[] GetFieldValues (string p_szXmlSrc, string p_szSrcFieldName)
{
if (p_szXmlSrc == null p_szXmlSrc.Length == 0)
return null;
object[] objRet = null;
DataSet ds = new DataSet();
StringReader src = new StringReader(p_szXmlSrc);
ds.ReadXml(src);
int n;
try {n = ds.Tables[0].Rows.Count;}
catch {n = 0;}
if (n > 0)
{
objRet = new object[n];
for (int i = 0 ; i < arrsrcfieldname =" new">
/// Get a list of specified field names' values of input string
///
///
///
///
public static object[] GetFieldValues (string p_szXmlSrc, object [] p_arrSrcFieldNames)
{
if (p_szXmlSrc == null p_szXmlSrc.Length == 0
p_arrSrcFieldNames.Length == 0)
return null;
object[] objRet = null;
DataSet ds = new DataSet();
StringReader src = new StringReader(p_szXmlSrc);
ds.ReadXml(src);
if (ds.Tables.Count == 0 ds.Tables[0].Rows.Count == 0)
return null;
int n = ds.Tables[0].Rows.Count;
int nFK = p_arrSrcFieldNames.Length;
if (n > 0)
{
objRet = new object[n];
for (int i = 0 ; i < strvalues =" new" j =" 0">
/// Get a list quoted double of specified field name's values of input string
///
///
///
///
public static string QuotedObject (object[] p_obj)
{
if (p_obj == null p_obj.Length == 0)
return null;
string strQuoted = "", strValue;
for (int i = 0 ; i < strvalue =" p_obj[i].ToString();" strvalue =" p_obj[p_obj.Length-1].ToString();">
/// Get a list quoted single of specified field name's values of input string
///
///
///
///
public static string SingleQuotedObject (object[] p_obj)
{
if (p_obj == null p_obj.Length == 0)
return null;
string strQuoted = "", strValue;
for (int i = 0 ; i < strvalue =" p_obj[i].ToString();" strvalue =" p_obj[p_obj.Length-1].ToString();">
/// Merge two xml string into one with one filed is defined primary field
///
///
///
///
///
/// The return xml string has the same schema with the first input xml string
///
public static string Merge(string p_szFirstXml, string p_szSecondXml, string p_szPKFieldName)
{
object[] primaryField = new object[1];
primaryField[0] = p_szPKFieldName;
return Merge (p_szFirstXml, p_szSecondXml, primaryField);
}
///
/// Merge two xml string into one with one filed is defined primary field
///
///
///
///
///
/// The return xml string has the same schema with the first input xml string
///
public static string Merge(string p_szFirstXml, string p_szSecondXml, object[] p_arrPKFieldNames)
{
DataSet ds1 = new DataSet();
StringReader src = new StringReader(p_szFirstXml);
ds1.ReadXml(src, XmlReadMode.Auto);
DataSet ds2 = new DataSet();
src = new StringReader(p_szSecondXml);
ds2.ReadXml(src, XmlReadMode.Auto);
ds2.DataSetName = ds1.DataSetName;
ds2.Tables[0].TableName = ds1.Tables[0].TableName;
DataColumn[] pk = new DataColumn[p_arrPKFieldNames.Length];
for (int i = 0 ; i < primarykey =" pk;" p_szfirstxml =" RemoveDuplicatedLoans(p_szFirstXml);" ds1 =" new" src =" new" pk =" new" ii =" 0" primarykey =" pk;">" + exp.Message + ". Please contact your System Administrator.");
}
ds1.Merge(ds2, false, MissingSchemaAction.Add);
ds1.AcceptChanges();
return ds1.GetXml();
}
///
/// Merge two xml string into one with one filed is defined primary field
///
///
///
///
///
public static string MergeXML(string PrimaryXML, string AuxiliaryXML, string PrimaryFieldName)
{
object[] primaryField = new object[1];
primaryField[0] = PrimaryFieldName;
return MergeXML (PrimaryXML, AuxiliaryXML, primaryField);
}
///
/// Merge two xml string into one with many fileds are defined primary fields
///
///
///
///
///
public static string DistinctColumns(string srcXML, object[] prikeys_colsname)
{
StringReader src = new StringReader(srcXML);
DataSet ds = new DataSet();
ds.ReadXml(src);
DataTable stbl = ds.Tables[0].Copy();
DataTable dtbl = ds.Tables[0].Copy();
System.Collections.Hashtable hshtbl = new System.Collections.Hashtable();
try
{
string objvalues = "";
int i=0;
foreach(DataRow objRow in stbl.Rows)
{
for(int j=0;j
foreach(DataColumn objCCol in MergedDs.Tables[1].Columns)
MergedDs.Tables[0].Rows[j][objCCol.ColumnName]= objChildRow[0][objCCol.ColumnName].ToString();
j++;
}
// Clear all data of the LoanServices and ListOfUsers table
MergedDs.Tables[1].Clear();
// write data to Schema and XML file.
MergedDs.DataSetName = oldDataSetName;
MergedDs.Tables[0].TableName = oldTableName;
Merged_XML = MergedDs.GetXml();
MergedDs.Dispose();
return Merged_XML;
}
catch(Exception e)
{
string strerr = e.Message;
return "";
}
}
///
/// Remove duplicated loans in the input string
///
///
///
public static string RemoveDuplicatedLoans(string p_szXml)
{
//This below block will be customise later to supports for cases in which have many primary keys
object [] p_arrPKFieldNames = new Object[1];
p_arrPKFieldNames[0] = "loan_no";
//end block
//Check duplicated primary key
object[] arrPK = GetFieldValues(p_szXml, p_arrPKFieldNames);
if (arrPK == null)
return p_szXml;
//Change the name of node into "Loan"
StringReader src = new StringReader(p_szXml);
DataSet ds = new DataSet();
ds.ReadXml(src, System.Data.XmlReadMode.Auto);
string strOldTbName = ds.Tables[0].TableName;
ds.Tables[0].TableName = "Loan";
p_szXml = ds.GetXml();
//end
int i = 0, j = 0;
while ( i < j =" i+1;" bldup =" true;" k =" 0" dstmp =" new" p_szxml =" (new" src =" new" ds =" new" tablename =" strOldTbName;" p_szxml =" ds.GetXml();">
/// Remove the duplicated node with the specified loan no in the xml
///
///
///
///
private string RemoveDuplicatedLoanById(string p_szXml, string p_szLoanNo)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(p_szXml);
XmlElement root = xmlDoc.DocumentElement;
XmlNodeList nodeList = root.SelectNodes("descendant::Loan[loan_no='" + p_szLoanNo + "']");
if (nodeList == null)
return p_szXml;
for (int i = 1 ; i < nodeloan =" nodeList[i];" xdoc =" new" nodes =" XDoc.SelectNodes(path);" n =" Nodes.Count;" m =" tag_names.GetLength(0);" i =" 0;" j =" 0;" node =" Nodes.Item(i).SelectSingleNode(tag_names[j]);" innertext =" Node.InnerText.Replace(" szresult =" TagValue;" szresult =" szResult.Replace(" szresult =" szResult.Replace(" szresult =" szResult.Replace(">", ">");
szResult = szResult.Replace("\'", "'");
szResult = szResult.Replace("\"", """);
return szResult;
}
public static string BuildTag(string TagName, string TagValue)
{
if (TagValue != "")
{
return "<" + TagName + ">" + TagValue + "" + ? TagName>}
else
{
return "";
}
} //BuildTag
public static string BuildChekedTag(string TagName, string TagValue)
{
if (TagValue != "")
{
TagValue = ReplaceSpecialChars(TagValue);
return "<" + TagName + ">" + TagValue + "" + ? TagName>}
else
{
return "";
}
} //BuildTag
public static string GetNode(string xml_data, string node_name) //DM 01.02.03
{
return "<" + node_name + ">" + GetNodeValue(xml_data, node_name) + "" + ? node_name>} //GetNode
public static string GetNodeValue(string xml_data, string node_name) //DM 10/25/02
{
int i, j;
string data = "";
i = xml_data.IndexOf("<" + node_name + ">");
if (i >= 0)
{
i = i + node_name.Length + 2;
j = xml_data.LastIndexOf("" + ? node_name>data = xml_data.Substring(i, j-i);
}
return data;
} //GetNodeValue
}
}
Ajax Method
{
[Ajax.AjaxMethod(Ajax.HttpSessionStateRequirement.ReadWrite)]
public void CurrentFolder(string value)
{
HttpContext.Current.Session["CurrentFolder"] = value;
}
public bool IsExistsImageFile(string folderPath)
{
bool fileOK = false;
String[] allowedExtensions = { ".gif", ".png", ".jpeg", ".jpg" };
if (folderPath != Null.NullString)
{
String fileExtension = System.IO.Path.GetExtension(folderPath).ToLower();
for (int i = 0; i < allowedExtensions.Length; i++)
{
if (fileExtension == allowedExtensions[i])
{
fileOK = true;
}
}
}
return fileOK;
}
}
Load Tree View không dùng đệ qui
{
DataSet ds = new DataSet();
categoryController = new CategoryController();
ds = categoryController.GetDataExecStoreProc("cadGetCategoryLevel @PARENTID =0"); //stored procedure
categoryTreeView.Nodes.Clear();
int currLevel = 1;
int maxLevel = Int32.Parse(ds.Tables[0].Rows[ds.Tables[0].Rows.Count - 1]["level"].ToString());
Hashtable listNode = new Hashtable();
Hashtable tmplistNode = new Hashtable();
DataRow[] levelsub;
while (currLevel <= maxLevel)
{
listNode = (Hashtable)tmplistNode.Clone();
tmplistNode.Clear();
levelsub = ds.Tables[0].Select("level = " + currLevel.ToString());
foreach (DataRow dbRow in levelsub)
{
string parentid = dbRow["ParentID"].ToString();
int catid = Convert.ToInt32(dbRow["CategoryID"].ToString());
TreeNode newNode = CreateNode(dbRow["CategoryName"].ToString(), dbRow["CategoryID"].ToString(), false);
if (currLevel == 1)
{
categoryTreeView.Nodes.Add(newNode);
}
else
((TreeNode)listNode[parentid]).ChildNodes.Add(newNode);
tmplistNode.Add(newNode.Value.ToString(), newNode);
}
currLevel++;
}
}
Thứ Sáu, 18 tháng 1, 2008
Thơ tin học
Em lại dùng Matlab để build,
Bức thư tình sẽ chẳng thể view,
Duyên tình ta, một buổi chiều, break!
Anh níu tay em, mong mình refresh,
Em lạnh lùng, chặn mọi đường link,
Anh âu sầu, tim ôm chuỗi String,
Chứa tên em, value hoài không đổi.
Đêm từng đêm, anh gửi lời request,
Ngày qua ngày, anh mong nhận response,
Nhưng tim em, IP giờ đã khác,
Em ẩn mình sau một host nào chăng?
Em hỡi em, nơi server có biết?
Ở client, anh khắc khoải nhớ thương...
Thứ Tư, 16 tháng 1, 2008
Phân tích một cuộc tấn công (Phần 1)
Nmap
IPEye
Tcpdump
Metasploit Framework
Netcat
SolarWinds TFTP Server
Tftp client
FU Rootkit
Bước thiết lập Có rất nhiều hành động quét trên Internet ngày nay, không đề cập đến hành động của worm và các dạng malware khác như virus. Tất cả chúng sẽ chỉ như tạp nhiễu vô hại với các mạng máy tính được bảo vệ tốt. Những gì chúng ta nên xem xét là một người đang chủ tâm nhắm đến một mạng máy tính. Bài này sẽ thừa nhận rằng kẻ tấn công đã tấn công vào nạn nhân của hắn và đã thực hiện các nghiên cứu trước như tìm ra địa chỉ IP và các địa chỉ mạng của nạn nhân. Kẻ tấn công này có thể cũng đã cố gắng khai thác thông tin như các địa chỉ email có liên quan đến mạng đó. Kiểu thông tin này là rất quan trọng trong trường hợp kẻ tấn công đã tìm nhưng không có cách nào vào mạng sau khi đã thực hiện các hành động quét, liệt kê và giả mạo nó. Các địa chỉ email mà hắnđã thu lượm được sẽ rất hữu dụng trong việc thiết lập lên một tấn công trình khách bằng cách thử và mời người dùng vào một website mã độc thông qua một liên kết trong email. Những kiểu tấn công đó sẽ được giới thiệu trong các bài sau. Cách thức thực hiện Chúng ta nên quan sát các hành động của một hacker khi hắn thực hiện công việc quét, và liệt kê mạng nạn nhân. Công cụ đầu tiên mà hacker sử dụng là Nmap. Mặc dù Nmap có khá ít ký hiệu IDS nhưng nó vẫn là một công cụ khá hữu dụng và được sử dụng nhiều.
Chúng ta có thể xem thông qua cú pháp được sử dụng bởi hacker trong màn hình nhỏ hiển thị bên trên, hacker đã chọn cổng 21 và 80 vì hắn có một số khai thác có thể sử dụng thông qua Metasploit Framework. Không chỉ điều đó mà còn cả hai dịch vụ hệ thống và giao thức mà hắn hiểu khá tốt. Được hiển thị khá rõ là rằng hắn đang sử dụng quét SYN, đây là kiểu quét cổng được sử dụng thông dụng nhất. Đó cũng là do thực tế là khi một dịch vụ sử dụng TCP đang nghe trên một cổng nhận được gói SYN thì nó sẽ gửi trở lại một gói SYN/ACK (phúc đáp). Gói SYN/ACK chỉ thị rằng một dịch vụ quả thực đang nghe và đang chờ đợi kết nối. Tuy nhiên vấn đề tương tự lại không giống với UDP, nó lại dựa trên các dịch vụ như DNS (DNS cũng sử dụng TCP nhưng nó hầu như sử dụng UDP đối với phần lớn các phiên giao dịch của nó). Cú pháp được liệt kê dưới đây là đầu ra mà Nmap thu lượm được từ các gói nó đã gửi, nhưng chính xác hơn là từ các gói nó nhận với tư cách là kết quả của quét SYN mà nó đã thực hiện. Chúng ta có thể thấy rằng bề ngoài có vẻ có cả các dịch vụ FTP và HTTP được cung cấp. Chúng ta không thực sự quan tâm đến địa chỉ MAC vì vậy sẽ bỏ qua điều đó. Các công cụ như Nmap không thường xuyên có lỗi nên nó thường rất tốt cho việc thẩm định thông tin của bạn ở mức gói dữ liệu để bảo đảm cho sự chính xác. Không chỉ vậy mà nó cũng cho phép quan sát được cả các gói trở lại, từ mạng nạn nhân để có thể thu thập được các thông tin kiến trúc, dịch vụ và host từ đó. Hãy tra cứu các gói dữ liệu Có một số chương trình được cung cấp ngày nay sẽ khai phá được các gói và tìm ra những thông tin cần thiết như kiểu hệ điều hành, thông tin về kiến trúc, ví dụ như x86 hay SPARC và nhiều vấn đề khác nữa. Đó chưa phải là đủ nhưng nó cũng quan trọng khi chúng ta đang tìm hiểu về việc cho phép một chương trình thực hiện công việc cho chúng ta. Với lưu ý đó, chúng ta hãy xem xét đến dấu vết gói Nmap và tìm ra một số thông tin nào đó về mạng nạn nhân.
10:52:59.062500 IP (tos 0x0, ttl 43, id 8853, offset 0, flags [none], proto: ICMP (1), length: 28) 192.168.111.17 > 192.168.111.23: ICMP echo request seq 38214, length 80x0000: 4500 001c 2295 0000 2b01 0dd3 c0a8 6f11 E..."...+.....o.0x0010: c0a8 6f17 0800 315a 315f 9546 ..o...1Z1_.F10:52:59.078125 IP (tos 0x0, ttl 128, id 396, offset 0, flags [none], proto: ICMP (1), length: 28) 192.168.111.23 > 192.168.111.17: ICMP echo reply seq 38214, length 80x0000: 4500 001c 018c 0000 8001 d9db c0a8 6f17 E.............o.0x0010: c0a8 6f11 0000 395a 315f 9546 0000 0000 ..o...9Z1_.F....0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
Thể hiện trong hai gói dữ liệu ở trên là loạt mở từ Nmap. Những gì nó thực hiện là gửi một yêu cầu ICMP echo đến mạng nạn nhân. Bạn sẽ thấy rằng nó không được trang bị tại một cổng nào đó, bởi vì ICMP không sử dụng các cổng, nhưng lại được quản lý bởi bộ thông báo lỗi ICMP xây dựng bên trong ngăn xếp giao thức TCP/IP. Gói ICMP này cũng được dán nhãn bằng một số duy nhất, trong trường hợp này là 38214 để giúp ngăn xếp TCP/IP có thể kiểm tra được lưu lượng trả về, và liên kết nó với gói ICMP trước đó đã gửi. Gói tin ngay trên là đáp trả từ một mạng nạn nhân, trong biểu mẫu của một đáp trả (reply) ICMP echo. Cũng tính đến cả số chuỗi 38214. Chính vì vậy hacker biết được rằng có một máy tính hoặc một mạng đằng sau địa chỉ IP đó. Chuỗi gói ICMP đang mở này là lý do tại sao Nmap có một ký hiệu IDS cho nó. Tùy chọn khám phá ICMP host có thể bị vô hiệu hóa trong Nmap nếu muốn. Loại thông tin gì có thể được thu lượm thông qua kết quả của gói trả lời ICMP echo từ mạng nạn nhân? Trong thực tế ở đây không có nhiều thông tin giúp chúng ta nắm được về mạng. Mặc dù vậy vẫn có thể sử dụng những đòn sơ bộ tại những chỗ liên quan đến hệ điều hành. Thời gian để cư trú một trường và giá trị bên cạnh nó được đánh dấu tô đậm trong gói trên. Giá trị 128 cho thấy một sự thật rằng máy tính này có thể là một máy tính chạy hệ điều hành Windows. Trong khi đó giá trị ttl lại không trả lời một cách chính xác như những gì về có liên quan đến hệ điều hành, nó sẽ được căn cứ cho các gói kế tiếp mà chúng ta sẽ xem xét. Kết luận Trong phần một này, chúng ta đã xem xét về một quá trình quét đối với một mạng trong một tấn công cho hai cổng cụ thể bằng Nmap. Đến đây, kẻ tấn công này đã biết chắc chắn rằng có một máy tính hoặc một mạng máy tính cư trú tại địa chỉ IP đó. Trong phần 2 của loạt bài này, chúng tôi sẽ tiếp tục giới thiệu đến các bạn phần kết của nghiên cứu về dấu vết của gói này, và tìm ra những mẩu thông tin còn lại.
Phân tích một tấn công (Phần 2)
10:52:59.078125 IP (tos 0x0, ttl 49, id 9808, offset 0, flags [none], proto: TCP (6), length: 40) 192.168.111.17.37668 > 192.168.111.23.80: ., cksum 0xfd46 (correct), ack 85042526 win 20480x0000: 4500 0028 2650 0000 3106 0407 c0a8 6f11 E..(&P..1.....o.0x0010: c0a8 6f17 9324 0050 67d1 a55e 0511 a55e ..o..$.Pg..^...^0x0020: 5010 0800 fd46 0000 P....F..
10:52:59.078125 IP (tos 0x0, ttl 128, id 397, offset 0, flags [none], proto: TCP(6), length: 40) 192.168.111.23.80 > 192.168.111.17.37668: R, cksum 0x6813 (correct), 85042526:85042526(0)win 00x0000: 4500 0028 018d 0000 8006 d9c9 c0a8 6f17 E..(..........o.0x0010: c0a8 6f11 0050 9324 0511 a55e 0511 a55e ..o..P.$...^...^0x0020: 5004 0000 6813 0000 0000 0000 0000 P...h.........
Hai gói ở trên xuất hiện sau các gói ICMP mà chúng ta đã quan sát trong phần 1. Nmap đã gửi một gói ACK đến IP mạng nạn nhân là 192.168.111.23 trên cổng 80. Dưới dạng thông tin giả mạo chúng ta không có được toàn bộ vấn đề ở đây. Chỉ thấy được rằng gói ACK đã nhận từ kẻ tấn công một gói RST phản hồi, vì ACK này không được mong đợi. Bản chất là nó không thuộc về một kết nối đã được thiết lập trước đó. Chúng ta vẫn có một ttl 128 tương ứng với ttl đã quan sát từ trước.
10:52:59.296875 IP (tos 0x0, ttl 58, id 45125, offset 0, flags [none], proto: TCP (6), length: 40) 192.168.111.17.37644 > 192.168.111.23.21: S, cksum 0x37ce (correct), 2010644897:2010644897(0) win 30720x0000: 4500 0028 b045 0000 3a06 7111 c0a8 6f11 E..(.E..:.q...o.0x0010: c0a8 6f17 930c 0015 77d8 01a1 0000 0000 ..o.....w.......0x0020: 5002 0c00 37ce 0000 P...7...
10:52:59.296875 IP (tos 0x0, ttl 128, id 398, offset 0, flags [DF], proto: TCP (6), length: 44) 192.168.111.23.21 > 192.168.111.17.37644: S, cksum 0x4f58 (correct), 1685290308:1685290308(0) ack 2010644898 win 64240
10:52:59.296875 IP (tos 0x0, ttl 128, id 110, offset 0, flags [none], proto: TCP(6), length: 40) 192.168.111.17.37644 > 192.168.111.23.21: R, cksum 0xca50 (correct), 2010644898:2010644898(0) win 00x0000: 4500 0028 006e 0000 8006 dae8 c0a8 6f11 E..(.n........o.0x0010: c0a8 6f17 930c 0015 77d8 01a2 77d8 01a2 ..o.....w...w...0x0020: 5004 0000 ca50 0000 P....P..
Theo sau quá trình trao đổi gói ACK và RST, chúng ta có thể thấy gói SYN thật đã được gửi từ hacker đến mạng nạn nhân, minh chứng trong gói với chữ S in đậm. Vấn đề này cho ta có thể suy luận ra rằng gói SYN/ACK phản hồi về từ mạng nạn nhân trên cổng 21 của nó. Quá trình trao đổi này sau đó được kết thúc bởi gói RST được gửi trở về từ máy tính của hacker đến mạng nạn nhân. Ba gói này lúc này giữ rất nhiều thông tin phong phú về sự giả mạo. Chúng ta cũng có ttl 128 từ máy tính nạn nhân, nhưng cũng có win64240. Tuy giá trị này không có trong danh sách, nó quả thực là một size mà tôi đã thấy nhiều lần trước đây từ Win32 (các phiên bản 32 bit của Microsoft Windows như Win NT, 2K, XP và 2K3). Tính năng hạn chế khác của máy tính Windows là rằng khả năng đoán trước số các IP ID. Trong trường hợp này, chúng ta chỉ có một giá trị IP ID. Chúng ta cần ít nhất giá trị nữa trước khi có thể tự tin nói rằng máy tính này là một máy tính sử dụng Windows của Microsoft. Lưu ý rằng, hãy quan sát các gói còn lại từ quá trình quét của Nmap.
10:52:59.312500 IP (tos 0x0, ttl 59, id 54025, offset 0, flags [none], proto: TCP (6), length: 40) 192.168.111.17.37644 > 192.168.111.23.80: S, cksum 0x3393 (correct), 2010644897:2010644897(0) win 40960x0000: 4500 0028 d309 0000 3b06 4d4d c0a8 6f11 E..(....;.MM..o.0x0010: c0a8 6f17 930c 0050 77d8 01a1 0000 0000 ..o....Pw.......0x0020: 5002 1000 3393 0000 P...3...
10:52:59.312500 IP (tos 0x0, ttl 128, id 399, offset 0, flags [DF], proto: TCP (6), length: 44) 192.168.111.23.80 > 192.168.111.17.37644: S, cksum 0x7913 (correct), 1685345101:1685345101(0) ack 2010644898 win 64240
10:52:59.312500 IP (tos 0x0, ttl 128, id 111, offset 0, flags [none], proto: TCP(6), length: 40) 192.168.111.17.37644 > 192.168.111.23.80: R, cksum 0xca15 (correct), 2010644898:2010644898(0) win 00x0000: 4500 0028 006f 0000 8006 dae7 c0a8 6f11 E..(.o........o.0x0010: c0a8 6f17 930c 0050 77d8 01a2 77d8 01a2 ..o....Pw...w...0x0020: 5004 0000 ca15 0000 P.......
Mẩu thông tin đầu tiên mà hacker quan sát là để xem xem số IP ID có tăng đến 399 không. IP DI này quả thực là 399 như chúng ta có thể quan sát ở phần giữa gói. Với thông tin này, hacker khá tự tin rằng máy tính nạn nhân hắn đang tấn công là Windows NT, 2K , XP, hoặc 2K3. Cũng quan sát trong chuỗi gói này là cổng 80 trên mạng nạn nhân dường như có một dịch vụ, minh chứng bởi gói SYN/ACK, gói SYN/ACK được xác định bằng việc thẩm định trường flag trong TCP header, trong trường hợp này giá trị hex gạch chân là 12 hoặc 18 với hệ thập phân. Giá trị này có thể phát hiện được bằng giá trị SYN flag 2 được bổ sung vào giá trị ACK flag 16.
Liệt kêKhi hacker biết được cả hai cổng 21 và 80 đều mở cho doanh nghiệp, anh ta sẽ chuyển sang trạng thái liệt kê. Những gì anh này cần biết lúc này là kiểu webserver đang lắng nghe cho các kết nối là gì. Sẽ vô nghĩa đối với hacker này nếu sử dụng một lỗ hổng Apache trên một IIS web server. Với lưu ý đó kẻ tấn công sẽ mở cmd.exe session và tìm ra chủng loại mạng.
C:\>nc.exe 192.168.111.23 80GET slslsllsHTTP/1.1 400 Bad RequestServer: Microsoft-IIS/5.0Date: Mon, 06 Aug 2007 15:11:48 GMTContent-Type: text/htmlContent-Length: 87
The parameter is incorrect. C:\>
Chúng ta có thể quan sát chủng loại mạng đã được đánh dấu ở trên hoặc cú pháp nc.exe mà hacker đánh vào địa chỉ IP của nạn nhân cũng như cổng 80. Khi vào được, hacker sẽ đánh thêm vào HTTP của phương thức GET và theo sau là một số câu sai ngữ pháp. Hành động này có thể làm cho webserver của mạng nạn nhân gửi ngược trở về thông tin hệ thống của nó khi nó không hiểu yêu cầu là gì. Chính vì vậy mà chúng tự nhiên liệt kê những thông tin cần thiết cho hacker. Hacker lúc này có thể biết được rằng hắn đang ở trong Microsoft IIS 5.0. Tin tuyệt vời hơn nữa vì hacker có một số khai thác lỗ hổng đối với phiên bản này. Kết luận Với việc thực hiện quét mạng của nạn nhân bằng cách sử dụng Nmap, hacker có thể nhận được một loạt các gói dư liệu quan trọng sau đó. Bên trong các gói dữ liệu này, như chúng ta đã nhìn thấy, chứa đầy đủ thông tin để hacker có thể lợi dụng vào các lỗ hổng trong kiến trúc, hệ điều hành và chủng loại mạng cũng như kiểu máy chủ. Tóm lại, với cách này, hacker có thể nắm được các thông tin chính về host, kiến trúc và dịch vụ được cung cấp. Với các thông tin này trong tay, hacker có thể tiến hành một tấn công vào webserver của mạng nạn nhân. Trong phần sau chúng tôi sẽ giới thiệu thêm về những tấn công nào hacker có thể dùng để tấn công vào người dùng trong trường hợp này.
Thứ Ba, 15 tháng 1, 2008
Writing XML
// Write Example:
private void XmlNewData()
{
FileStream fsNew = File.Create("data.xml");
XmlTextWriter XmlWriter = new XmlTextWriter(fsNew, null);
XmlWriter.Formatting = Formatting.Indented;
WriteXmlFormat(writer);
XmlWriter.Flush();
XmlWriter.Close();
}
WriteXmlFormat(writer); will call the method where the xml file is formatted, this method looks like:
// Method for designing the XML tree called by Update and Write example:
private void WriteXmlFormat(XmlWriter writer)
{
// Here you could put code to get the data from the database and drop it in the dsData dataset.
writer.WriteStartElement("data");
// Looping al rows in de dataset and specified table
foreach (DataRow drItem in dsData.Tables["table1"].Rows)
{
writer.WriteStartElement("row");
writer.WriteAttributeString("column1", drItem["column1"]);
writer.WriteEndElement();
}
writer.WriteEndElement();
}In the following example you read the XML file into a dataset and then fill the specified dropdownlist: // Read Example:
private void ReadDataIntoListBox()
{
DataSet dsData = new DataSet();
dsData.ReadXml("data.xml");
foreach(DataRow dr in dsData.Tables["rows"].Rows)
{
ddlSome.Items.Add(dr["colomname"]);
}
}
And if you want to update:
// Update example:
private void XmlUpdateData()
{
File.Delete("data.xml");
FileStream fsNew = File.Create("data.xml");
XmlTextWriter XmlWriter = new XmlTextWriter(fsNew, null);
XmlWriter.Formatting = Formatting.Indented;
WriteQuote(writer);
XmlWriter.Flush();
XmlWriter.Close();
}
Thứ Hai, 14 tháng 1, 2008
Cách diệt Virus ..hiii
Thứ Tư, 9 tháng 1, 2008
Chuyển mailbox trong Exchange 2007 thông qua Exchange Management Console
Hình 1: Mailbox được hiển thị trong Exchange Management Console
4. Để chuyển một mailbox, cách thực hiện rất đơn giản, bạn chỉ cần đánh dấu vào mailbox cần chuyển, kích chuột phải vào nó và chọn Move Mailbox... Lưu ý rằng bạn có thể chọn nhiều mailbox cùng một lúc. Chọn tùy chọn Move Mailbox… sẽ làm xuất hiện tiện ích Move Mailbox, đây là màn hình đầu tiên của tiện ích này bạn sẽ thấy trong hình 2.
Hình 2: Màn hình giới thiệu của tiện ích Move Mailbox
5. Trên màn hình giới thiệu này, chọn máy chủ Exchange 2007 mục tiêu, nhóm lưu trữ và cơ sở dữ liệu mà bạn sẽ đặt các mailbox vào đó. Khi thực hiện xong các thiết lập này, kích vào nút Next. 6. Tiếp theo, màn hình Move Options sẽ được hiển thị, như trong hình 3. Màn hình này sẽ cho phép bạn kiểm soát những gì xảy ra nếu bất thình lình quá trình chuyển mailbox gặp phải thông lỗi. Ở đây bạn có thể chọn để bỏ qua mailbox và vì vậy không chuyển nó, hoặc bỏ qua một số thông báo lỗi. Bạn có thể khai báo bao nhiều thông báo lỗi trong quá trình chuyển mailbox mà bạn sẽ bỏ qua. Trong Exchange 2003, số lượng lớn nhất của mục này là 100, nhưng bên trong tiện ích move mailbox hiện nay bạn có thể nhập đến 2^31-1, or 2,147,483,647. Nếu bạn hỏi tôi, 100 là quá đủ vì nếu thấy được nhiều mailbox bị lỗi thì bạn có thể có một vấn đề nào đó khi thực hiện. Khi đã hoàn toàn nhất trí với lựa chọn của mình, hãy kích Next.
Hình 3: Màn hình chọn của Move Mailbox
7. Tiếp theo là màn hình Move Schedule, như được thể hiện trong hình 4. Màn hình này cho phép bạn có thể chuyển mailbox ngay tức thì, hoặc sau một thời gian đã lên lịch trình. Màn hình này không có giá trị trong suốt quá trình chuyển. Nếu bạn chọn tùy chọn At the following time, thì ngày và thời gian được thiết lập bằng thời điểm hiện tại, vì vậy bạn sẽ phải chọn thời gian khi muốn quá trình chuyển bắt đầu. Bạn cũng cần lưu ý rằng tùy chọn Cancel tasks that are still running after (hours) sẽ cho phép chỉ định quá trình sẽ chạy bao lâu trước khi bị hủy bỏ. Việc này đặc biệt hữu dụng khi chuyển một số lượng lớn các mailbox trong đêm. Ví dụ, hình 4 thể hiện rằng việc chuyển mailbox sẽ được hủy bỏ sau 8 giờ đồng hồ, điều đó có nghĩa rằng nếu chúng được bắt đầu lúc 21h thì quá trình này sẽ được dừng vào lúc 5h sáng, cách này bảo đảm được rằng bất cứ người dùng nào có thể đến sớm làm việc đều không bị ảnh hưởng bởi quá trình chuyển mail. Nếu một mailbox đang được trong quá trình này chưa xong thì nó sẽ được chuyển quay trở về máy chủ nguồn còn tất cả các mailbox đã chuyển xong trước đó được giữ trên máy chủ mục tiêu. Tiếp đó, khi đã hoàn toàn hài lòng với các lựa chọn của mình, hãy kích Next.
Hình 4: Màn hình lập lịch trình cho quá trình chuyển mailbox
8. Màn hình áp chót sẽ được hiển thị là màn hình tóm tắt cho hoạt động chuyển mail của bạn sẽ được thực hiện như thế nào, để bạn có thể xem lại toàn bộ các chi tiết về công việc này. Khi đã hài lòng với quyết định của mình, kích nút Move để thực hiện quá trình. Nếu bạn quyết định chuyển các mailbox theo một thời gian đã được lên lịch trình thì màn hình tóm tắt sẽ hiện một quá trình đếm ngược như hình 5. Bạn có thể hủy bỏ quá trình chuyển này bất cứ khi nào bằng việc kích nút Cancel.
Hình 5: Bảng thời gian đếm ngược đã được lên lịch trình
9. Nếu chọn chuyển nhiều mailbox tại cùng một thời điểm thì bạn sẽ thấy màn hình tương tự như được hiển thị trong hình 6. Ở đây như bạn thấy, có 4 mailbox đang được chuyển tại cùng một thời điểm, mailbox thứ năm, mailbox của User9 thể hiện ở phần cuối với trạng thái Pending. Bên trong Exchange Management Console, bạn không thể chuyển hơn 4 mailbox cùng một thời điểm, mặc dù vậy bạn lại có thể thay đổi số luồng chuỗi công việc này khi sử dụng Exchange Management Shell (chúng tôi sẽ giới thiệu đến trong phần sau của loạt bài này).
Hình 6: Chuyển đổi nhiều Mailbox một lúc
10. Nếu tất cả mọi việc đều diễn ra tốt đẹp thì màn hình cuối cùng sẽ được hiển thị như hình 7.
Hình 7: Màn hình cuối cùng
Exchange Management Console không thể được sử dụng để chuyển mailbox trong các forest khác nhau. Để thực hiện điều đó, bạn cần phải sử dụng Exchange Management Shell. Exchange thực hiện khá nhiều kiểm tra để bảo đảm cho việc chuyển mailbox của bạn diễn ra thành công. Ví dụ, nếu bạn cố gắng chuyển mailbox sang một cơ sở dữ liệu Exchange 2007 có kích thước mailbox nhỏ hơn kích thước của mailbox hiện thời thì bạn sẽ thấy thông báo lỗi xuất hiện như trong hình 8. Hay một ví dụ về việc kiểm tra khác, bạn có thể thấy trong hình 9 khi tôi đã thực hiện để tạo một mailbox bản sao trong suốt quá trình kiểm thử, kết quả là mailbox bản sao này đã bị xóa trước khi thử chuyển đổi mailbox.
Hình 8: Kiểm tra kích thước mailbox
Hình 9: Thông báo lỗi của mailbox bảo sao
Bản ghi sự kiện Bạn thấy những gì trong bộ xem sự kiện khi quá trình chuyển mailbox được thực hiện? Trong bài test của tôi, đều có các sự kiện tương tự nhau được ghi dù việc ghi chuẩn đoán được thiết lập ở chế độ thấp hay cao đi chăng nữa. Trong toàn bộ mục bản ghi sự kiện bên dưới, bạn sẽ thấy được rằng có 3 nguồn của Exchange Migration và một chủng loại của Move Mailbox. Sự kiện đầu tiên được ghi là sự kiện 1006, như trong hình 10. Ở đây bạn có thể thấy rằng quá trình là đang được thực hiện. Các cơ sở dữ liệu nguồn và đích được tiết lộ cũng như cả thuộc tính Exchange DN của mailbox đang được chuyển.
Hình 10: Sự kiện 1006
Khi mailbox đã được chuyển xong, sự kiện 1007 được ghi lại như những gì bạn có thể thấy trong hình 11.
Hình 11: Sự kiện 1007
Cuối cùng, sự kiện 9354 được ghi lại, đây là sự kiện khai báo cho bạn biết rằng mailbox gốc của bạn đã bị xóa từ cơ sở dữ liệu nguồn, xem hiển thị trong hình 12.
Hình 12: Sự kiện 9354
Một mục ghi sự kiện khác cũng đáng phải đưa ra là mục được giới thiệu đầu tiên trong Exchange 2003. Nó thường được quan tâm như một cách thao tác tốt nhất để bảo đảm rằng người dùng sẽ truy xuất ra khỏi mailbox của họ khi bạn chuyển nó. Nếu người dùng cố gắng truy cập vào mailbox của họ trong khi nó đang trong quá trình chuyển thì sự kiện 9660 sẽ được ghi lại với nguồn MSExchangeIS và hạng mục Logons. Một ví dụ cho sự kiện này được thể hiện trong hình 13.
Hình 13: Sự kiện 9606
Kết luận Việc chuyển mailbox trong Exchange 2007 được thực hiện khá dễ dàng khi bạn sử dụng Move Mailbox wizard từ bên trong Exchange Management Console. Trong phần hai của loạt bài này, chúng tôi sẽ tiếp tục giới thiệu về quá trình chuyển đổi này nhưng sử dụng Exchange Management Shell.