2011年7月24日 星期日

如何修復造成 Windows XP 無法啟動的損毀登錄

請先參考微軟的解法:
如何修復造成 Windows XP 無法啟動的損毀登錄

當您嘗試啟動或重新啟動 Windows XP 電腦時,可能會收到下列其中一個錯誤訊息:
Windows XP 無法啟動,因為下列檔案遺失或損毀:\WINDOWS\SYSTEM32\CONFIG\SYSTEM
Windows XP 無法啟動,因為下列檔案遺失或損毀:\WINDOWS\SYSTEM32\CONFIG\SOFTWARE
停止:c0000218 {登錄檔案失敗} 登錄無法載入 Hive 檔案:\SystemRoot\System32\Config\SOFTWARE 或它的記錄檔或替代資料。
系統錯誤:Lsass.exe
當試圖更新密碼時,這個傳回狀態表示所提供的目前密碼數值不正確。

雖然可能以現在 Windows 7 的設計已經遇不太到這種狀況,
不過我公司的老爺車電腦還是遇到了,然而微軟的作法懶得教人用工具片開機,
所以落落長的一大串 DOS 指令,讓人很不舒服XD

以下簡要敘述核心作法:

以 WINDOWS\SYSTEM32\CONFIG\SYSTEM 損毀為例
整個做法就是取出舊的檔加配合系統還原來做處理.

微軟網站上所用的batch
***************************************************************
md tmp
copy c:\windows\system32\config\system c:\windows\tmp\system.bak
copy c:\windows\system32\config\software c:\windows\tmp\software.bak
copy c:\windows\system32\config\sam c:\windows\tmp\sam.bak
copy c:\windows\system32\config\security c:\windows\tmp\security.bak
copy c:\windows\system32\config\default c:\windows\tmp\default.bak

delete c:\windows\system32\config\system
delete c:\windows\system32\config\software
delete c:\windows\system32\config\sam
delete c:\windows\system32\config\security
delete c:\windows\system32\config\default

copy c:\windows\repair\system c:\windows\system32\config\system
copy c:\windows\repair\software c:\windows\system32\config\software
copy c:\windows\repair\sam c:\windows\system32\config\sam
copy c:\windows\repair\security c:\windows\system32\config\security
copy c:\windows\repair\default c:\windows\system32\config\default

***************************************************************

記得在c:底下操作.

主要就是要取出 system software, sam, security, default 這五個檔案。
這五個檔案也很好辨識。
你到 c:\windows\system32\config 底下找,沒有副檔名的那五個就是了。

以下為重點:
整個微軟的解法因為不想用工具片,所以一整個麻煩,需要多次重開機。
建議直接使用 Win PE 這類的工具片,或 XPE 這類的 Live 光碟

1: 先將 c:\windows\system32\config\裡舊的 system, software, sam, security, default 備份
2: 尋找 c 槽底下 System Volume Information 裡面的各個備份資料夾裡的 Snapshot 中的該5檔
3: 將舊的備份蓋掉 c:\windows\system32\config\ 裡的五個檔。(記得修改成相對映的檔名)

用 Win PE 這類的工具片來做會十分簡單,記得要開啟可以看到系統資料夾的選項。
System Volume Information 預設是隱藏的。

理論上只要有系統還原備份就可以順利處理掉這問題。

萬一沒有系統還原的時候怎麼辦?
以下為推論, 有部份我沒有實際做過

1: 先將 c:\windows\system32\config\裡舊的 system, software, sam, security, default 備份
2: 使用 c:\windows\repair 裡的五個檔取代 c:\windows\system32\config\ 裡的舊檔
3: 利用 Win PE 或其它工具片,除了 system 之外的四個檔再蓋回去

理論上它已經變成一個新的設定了,有可能其它四個檔會有不合的情形,
最少software這個檔是可以蓋的,可以省去重裝軟體的困擾。

2011年7月22日 星期五

Using jqGrid with ASP.NET

In this article I will explain how to use jqGrid with ASP.NET. jqGrid is one of the most popular jquery grid and it is one of the best grid component. With the help of jqGrid wecan represent and manipulate tabular data for representing and manipulating tabular data . The grid is Ajax enabled JavaScript control and data is fetched to the grid via Ajax calls i.e without PostBack. You can integrate jqGrid with any server side technology like ASP, PHP, Java Servlets etc. It was developed by Tony Tomov. Below I will explain how to integrate jqGrid with ASP.NET.
DB Part:

Let's start with DB part first. We are going to create a Users table with following columns UserID, UserName, FirstName, LastName, MiddleName and EmailID. Then 500 random rows will be inserted so that we can have enough data for the grid. Below is the script for table:

Create Table:


CREATE TABLE [Users]
(
[UserID] INT IDENTITY ,
[UserName] NVARCHAR(50),
[FirstName] NVARCHAR(50),
[LastName] NVARCHAR(50),
[MiddleName] NVARCHAR(50),
[EmailID] NVARCHAR(50)
)
GO

INSERT INTO Users
( UserName ,
FirstName ,
LastName ,
MiddleName ,
EmailID
)
SELECT dbo.GenerateRandomName(10),
dbo.GenerateRandomName(10),
dbo.GenerateRandomName(10),
dbo.GenerateRandomName(10),
dbo.GenerateRandomName(10)+'@'+ dbo.GenerateRandomName(3)+'.com'
GO 500


To insert random rows above I have used GenerateRandomName function whose script is below:

Random Function

CREATE FUNCTION [GenerateRandomName] ( @LENGTH INT )
RETURNS NVARCHAR(255)
AS
BEGIN

--DECLARE VARIABLES
DECLARE @RandomNumber NVARCHAR(255)
DECLARE @I SMALLINT
DECLARE @RandNumber FLOAT
DECLARE @Position TINYINT
DECLARE @ExtractedCharacter VARCHAR(1)
DECLARE @ValidCharacters VARCHAR(255)
DECLARE @VCLength INT

--SET VARIABLES VALUE
SET @ValidCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
SET @VCLength = LEN(@ValidCharacters)
SET @ExtractedCharacter = ''
SET @RandNumber = 0
SET @Position = 0
SET @RandomNumber = ''


SET @I = 1

WHILE @I < ( @Length + 1 ) BEGIN SET @RandNumber = ( SELECT RandNumber FROM [RandNumberView] ) SET @Position = CONVERT(TINYINT, ( ( @VCLength - 1 ) * @RandNumber + 1 )) SELECT @ExtractedCharacter = SUBSTRING(@ValidCharacters, @Position, 1) SET @I = @I + 1 SET @RandomNumber = @RandomNumber + @ExtractedCharacter END RETURN @RandomNumber END GO CREATE VIEW [RandNumberView] AS SELECT RAND() AS [RandNumber]


In the above function I have used "RandNumberView" View. Because I need to use the random number if I had used the rand() simply in the function I would have received this error "Invalid use of side-effecting or time-dependent operator in 'rand' within a function".
Now let's move to stored procedure part. In order to get rows from the DB the server side code will call the DB through SelectjqGridUsers SP which we are going to see below. This SP will accept the following params PageIndex(The index of the page), SortColumnName(The column on which sorting is needed), SortOrderBY(The order i.e asc or desc), NumberOfRows(The number of rows to be needed as the output), TotalRecords(It is the Output param it will give the total records present for that search). Below is the script for it:

Select Stored Procedure

CREATE PROC [SelectjqGridUsers]
@PageIndex INT ,
@SortColumnName VARCHAR(50) ,
@SortOrderBy VARCHAR(4) ,
@NumberOfRows INT ,
@TotalRecords INT OUTPUT
AS
BEGIN

SET NOCOUNT ON

SELECT @TotalRecords = ( SELECT COUNT(1)
FROM [Users]
)

DECLARE @StartRow INT
SET @StartRow = ( @PageIndex * @NumberOfRows ) + 1 ;


WITH CTE
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY CASE
WHEN @SortColumnName = 'UserID'
AND @SortOrderBy = 'asc'
THEN UserID
END ASC, CASE
WHEN @SortColumnName = 'UserID'
AND @SortOrderBy = 'desc'
THEN UserID
END DESC, CASE
WHEN @SortColumnName = 'UserName'
AND @SortOrderBy = 'asc'
THEN UserName
END ASC, CASE
WHEN @SortColumnName = 'UserName'
AND @SortOrderBy = 'desc'
THEN UserName
END DESC, CASE
WHEN @SortColumnName = 'FirstName'
AND @SortOrderBy = 'asc'
THEN FirstName
END ASC, CASE
WHEN @SortColumnName = 'FirstName'
AND @SortOrderBy = 'desc'
THEN FirstName
END DESC , CASE
WHEN @SortColumnName = 'MiddleName'
AND @SortOrderBy = 'asc'
THEN MiddleName
END ASC, CASE
WHEN @SortColumnName = 'MiddleName'
AND @SortOrderBy = 'desc'
THEN MiddleName
END DESC , CASE
WHEN @SortColumnName = 'LastName'
AND @SortOrderBy = 'asc'
THEN LastName
END ASC, CASE
WHEN @SortColumnName = 'LastName'
AND @SortOrderBy = 'desc'
THEN LastName
END DESC, CASE
WHEN @SortColumnName = 'EmailID'
AND @SortOrderBy = 'asc'
THEN EmailID
END ASC, CASE
WHEN @SortColumnName = 'EmailID'
AND @SortOrderBy = 'desc'
THEN EmailID
END DESC ) AS RN ,
UserID ,
UserName ,
FirstName ,
MiddleName ,
LastName ,
EmailID
FROM [Users]
)
SELECT UserID ,
UserName ,
FirstName ,
LastName ,
MiddleName ,
EmailID
FROM CTE
WHERE RN BETWEEN @StartRow - @NumberOfRows
AND @StartRow - 1

SET NOCOUNT OFF


END


Front end part:

Let's come to front end part. Before moving further please go through these two links first :

http://www.trirand.com/blog/?page_id=6 (From where you can download the neccessary files for jqGrid)
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:how_to_install#development_installation (From where you can read how to install it).
Client side code (ASPX)
Let's start with ASPX code, the client side code. Here we will be having jqGrid and it's corresonding configuration settings. User will do the operations on jqGrid and behind the scenes server side code will be hit via Ajax request. In the server side HTTP handler will be called in order to serve the request. In response HTTP handler will give the necessary response and accordingly, the data on the grid will be displayed. Below is the code for it:

Sample.aspx:

<%@ Page Language="C#" %>

<!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">
<title></title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/themes/ui-darkness/jquery-ui.css"
type="text/css" media="all" />
<link href="css/ui.jqgrid.css" rel="stylesheet" type="text/css" />

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>

<script src="js/i18n/grid.locale-en.js" type="text/javascript"></script>

<script src="js/jquery.jqGrid.min.js" type="text/javascript"></script>

<script type="text/javascript">
$(function() {
$("#UsersGrid").jqGrid({
url: 'jqGridHandler.ashx',
datatype: 'json',
height: 250,
colNames: ['UserID', 'UserName', 'FirstName', 'MiddleName', 'LastName', 'EmailID'],
colModel: [
{ name: 'UserID', index: 'UserID', width: 100, sortable: true },
{ name: 'UserName', width: 100, sortable: true },
{ name: 'FirstName', width: 100, sortable: true },
{ name: 'MiddleName', width: 100, sortable: true },
{ name: 'LastName', width: 100, sortable: true },
{ name: 'EmailID', width: 150, sortable: true }
],
rowNum: 10,
rowList: [10, 20, 30],
pager: '#UsersGridPager',
sortname: 'UserID',
viewrecords: true,
sortorder: 'asc',
caption: 'JSON Example'
});

$("#UsersGrid").jqGrid('navGrid', '#UsersGridPager', { edit: false, add: false, del: false });
});

</script>

</head>
<body>
<form id="HtmlForm" runat="server">
<table id="UsersGrid" cellpadding="0" cellspacing="0">
<div id="UsersGridPager">
</div>
</table>
</form>
</body>
</html>


HTTP Handler:

Let's come to the HTTP handler code which will be called by client side (ASPX). Request will be made from client side to the server and this HTTP handler will be called. Based on the params passed from client the handler will hit the database and fetch the rows from DB. Below is the code for it:

jqGridHandler.ashx:


<%@ WebHandler Language="C#" Class="jqGridHandler" %>

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Script.Serialization;


public class jqGridHandler : IHttpHandler
{

public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;

string _search = request["_search"];
string numberOfRows = request["rows"];
string pageIndex= request["page"];
string sortColumnName= request["sidx"];
string sortOrderBy = request["sord"];


int totalRecords;
Collection users = GetUsers(numberOfRows, pageIndex, sortColumnName, sortOrderBy, out totalRecords);
string output = BuildJQGridResults(users, Convert.ToInt32(numberOfRows), Convert.ToInt32(pageIndex), Convert.ToInt32(totalRecords));
response.Write(output);
}

private string BuildJQGridResults(Collection users,int numberOfRows, int pageIndex,int totalRecords)
{

JQGridResults result = new JQGridResults();
List rows = new List();
foreach (User user in users)
{
JQGridRow row = new JQGridRow();
row.id = user.UserID;
row.cell = new string[6];
row.cell[0] = user.UserID.ToString();
row.cell[1] = user.UserName;
row.cell[2] = user.FirstName;
row.cell[3] = user.MiddleName;
row.cell[4] = user.LastName;
row.cell[5] = user.EmailID;
rows.Add(row);
}
result.rows = rows.ToArray();
result.page = pageIndex;
result.total = totalRecords / numberOfRows;
result.records = totalRecords;
return new JavaScriptSerializer().Serialize(result);
}

private Collection GetUsers(string numberOfRows,string pageIndex,string sortColumnName, string sortOrderBy,out int totalRecords)
{
Collection users = new Collection();
string connectionString =
"Data Source=YourServerName; Initial Catalog=YourDatabase; User ID=YourUserName; Password=YourPassword";
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandText = "SelectjqGridUsers";
command.CommandType = CommandType.StoredProcedure;

SqlParameter paramPageIndex = new SqlParameter("@PageIndex", SqlDbType.Int);
paramPageIndex.Value =Convert.ToInt32(pageIndex);
command.Parameters.Add(paramPageIndex);

SqlParameter paramColumnName = new SqlParameter("@SortColumnName", SqlDbType.VarChar, 50);
paramColumnName.Value = sortColumnName;
command.Parameters.Add(paramColumnName);

SqlParameter paramSortorderBy = new SqlParameter("@SortOrderBy", SqlDbType.VarChar, 4);
paramSortorderBy.Value = sortOrderBy;
command.Parameters.Add(paramSortorderBy);

SqlParameter paramNumberOfRows = new SqlParameter("@NumberOfRows", SqlDbType.Int);
paramNumberOfRows.Value =Convert.ToInt32(numberOfRows);
command.Parameters.Add(paramNumberOfRows);

SqlParameter paramTotalRecords= new SqlParameter("@TotalRecords", SqlDbType.Int);
totalRecords = 0;
paramTotalRecords.Value = totalRecords;
paramTotalRecords.Direction = ParameterDirection.Output;
command.Parameters.Add(paramTotalRecords);


connection.Open();
using (SqlDataReader dataReader = command.ExecuteReader())
{
User user;
while (dataReader.Read())
{
user = new User();
user.UserID = (int) dataReader["UserID"];
user.UserName = Convert.ToString(dataReader["UserName"]);
user.FirstName = Convert.ToString(dataReader["FirstName"]);
user.MiddleName = Convert.ToString(dataReader["MiddleName"]);
user.LastName = Convert.ToString(dataReader["LastName"]);
user.EmailID = Convert.ToString(dataReader["EmailID"]);
users.Add(user);
}
}
totalRecords = (int)paramTotalRecords.Value;
}

return users;
}

}
public bool IsReusable
{
// To enable pooling, return true here.
// This keeps the handler in memory.
get { return false; }
}
}

Above I have used 2 structs JQGridResults and JQGridRow and one business class User. Below is the code for them:


public struct JQGridResults
{
public int page;
public int total;
public int records;
public JQGridRow[] rows;

}
public struct JQGridRow
{
public int id;
public string[] cell;
}

[Serializable]
public class User
{
public int UserID
{ get; set; }

public string UserName
{ get; set; }

public string FirstName
{ get; set; }

public string MiddleName
{ get; set; }

public string LastName
{ get; set; }

public string EmailID
{ get; set; }
}


Below is the screenshot of the Firebug's Conole's tab. As you can see we made a request to the server by making a request to jqGridHandler.ashx . The querysting params value is sent accoriding to the settings we kept while declaring jqGrid settings at ASPX page :

Reference To: http://codeasp.net/articles/asp-net/229/using-jqgrid-with-asp-net

2011年7月21日 星期四

DataTable.Select 方法 (String, String)

語法:

public DataRow[] Select (
string filterExpression,
string sort
)


飯粒:

private void GetRowsByFilter()
{
DataTable table = DataSet1.Tables["Orders"];

// Presuming the DataTable has a column named Date.
string expression = "Date > '1/1/00'";

// Sort descending by column named CompanyName.
string sortOrder = "CompanyName DESC";
DataRow[] foundRows;

// Use the Select method to find all rows matching the filter.
foundRows = table.Select(expression, sortOrder);

// Print column 0 of each returned row.
for(int i = 0; i < foundRows.Length; i ++) { Console.WriteLine(foundRows[i][0]); } }

2011年7月15日 星期五

ListView排序功能(不須寫Code-Behind)


 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ListViewSort.aspx.cs" Inherits="ListViewSort" %>

 <html>
 <head runat="server">
   <title>ListViewSort</title>
 </head>
 <body>
   <form id="form1" runat="server">
   <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
        SelectCommand="SELECT [ProductID], [ProductName], [UnitPrice]
                       FROM [Products]
                       Order by UnitPrice ASC ">
   </asp:SqlDataSource>
   <div  style="width:500px;float:left;">
     <asp:ListView ID="ListView1" runat="server" DataSourceID="SqlDataSource1" >
       <ItemTemplate>
         <tr>
           <td>
             <asp:Label ID="ProductIDLabel" runat="server" Text='<%#Eval("ProductID") %>' />
           </td>
           <td>
             <asp:Label ID="ProductNameLabel" runat="server"  Text='<%#Eval("ProductName") %>' />
           </td>
           <td>
             <asp:Label ID="UnitPriceLabel" runat="server" Text='<%#Eval("UnitPrice") %>' />
           </td>
         </tr>
       </ItemTemplate>
       <LayoutTemplate>
         <table ID="itemPlaceholderContainer" runat="server" border="1"
           <tr runat="server" style="background-color:#DCDCDC;color: #000000;"> 
             <th>
               <asp:LinkButton Text="產品編號" CommandName="sort" CommandArgument="ProductID" runat="server" />
             </th>
             <th>
               <asp:LinkButton  Text="產品名稱" CommandName="sort" CommandArgument="ProductName" runat="server" />
             </th>
             <th>
               <asp:LinkButton  Text="單價" CommandName="sort" CommandArgument="UnitPrice" runat="server" />
             </th>
           </tr>
           <tr ID="itemPlaceholder" runat="server">
           </tr>
           <tr>
             <td colspan="3"  runat="server">
               <asp:DataPager ID="DataPager1" runat="server" PageSize="20">
                 <Fields>
                   <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True" />
                 </Fields>
               </asp:DataPager>
             </td>
           </tr>
         </table>
       </LayoutTemplate>

     </asp:ListView>
   </div>
 </form>
 </body>
 </html>

重點就是在<table>的標題列,把想要排序欄位的標題弄成Button,然後CommandName=”sort”,CommandArgument=”欄位名稱”
ListView就可以排序了

只是很奇妙的是,因為SQL語法Order by UnitPrice ASC,所以第一次按單價按鈕沒有反應,要按第二次才會排序。

第一次執行網頁(確實按照UnitPrice遞增排序)
第一次執行網頁(確實按照UnitPrice遞增排序)
按下產品編號後,依產品編號遞增排序
再按一次產品編號,依產品編號遞減排序
點下一頁後,排序仍然依產品編號遞減

2011年7月13日 星期三

ASP.NET加密教學 (MD5和SHA1加密的幾種方法)

MD5的全稱是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由Mit Laboratory for Computer Science和Rsa data security inc的Ronald l. rivest開發出來,經md2、md3和md4發展而來。它的作用是讓大容量信息在用數字簽名軟件簽署私人密匙前被“壓縮”成一種保密的格式(就是把一個任意長度的字節串變換成一定長的大整數)。不管是md2、md4還是md5,它們都需要獲得一個隨機長度的信息並產生一個128位的信息摘要。
加密哈希函數將任意長度的二進制字符串映射為固定長度的小型二進制字符串。加密哈希函數有這樣一個屬性:在計算上不大可能找到散列為相同的值的兩個不同的輸入;也就是說,兩組數據的哈希值僅在對應的數據也匹配時才會匹配。數據的少量更改會在哈希值中產生不可預知的大量更改。所以你很難從加密後的文字中找到蛛絲馬跡。
SHA1的全稱是Secure Hash Algorithm(安全哈希算法)
MD5算法的哈希值大小為128位。而SHA1算法的哈希值大小為160位。兩種算法都是不可逆。
雖說2004年8月17日的美國加州聖巴巴拉的國際密碼學會議(Crypto’2004)上,來自中國山東大學的王小雲教授做了破譯MD5、HAVAL-128、MD4和RIPEMD算法的報告,公布了MD系列算法的破解結果。宣告了固若金湯的世界通行密碼標準MD5的堡壘轟然倒塌,引發了密碼學界的軒然大波。但是我覺得對於我們做普通的軟件來說,這個加密安全程度已經足夠使用了。
我們平常用的最多的無非就是加密用戶密碼,把加密好的密碼存儲到數據庫中,進行密碼比較的時候,把用戶輸入的密碼再進行加密,然後與數據庫中的密文進行比較。至於asp.net類中是如何實現加密算法的,這個我們不需要關心,會用就行了。
下面就是Asp.net中幾種加密方法。加密算法有兩種,也就是上面提到的MD5和SHA1,這裏我舉的例子是以MD5為例,SHA1大致相同,只是使用的類不一樣。
MD5相關類:
System.Security.Cryptography.MD5
System.Security.Cryptography.MD5CryptoServiceProvider()
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(strSource, "MD5")
SHA1相關類:
System.Security.Cryptography.SHA1
System.Security.Cryptography.SHA1CryptoServiceProvider()
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(strSource, "SHA1")
方法如下:(用的vs 2010)
1/**//// <summary> 2 /// 方法一:通過使用 new 運算符創建對象 3 /// </summary> 4 /// <param name="strSource">需要加密的明文</param> 5 /// <returns>返回16位加密結果,該結果取32位加密結果的第9位到25位</returns> 6 public string Get_MD5_Method1(string strSource) 7 { 8  //new 9  System.Security.Cryptography.MD5 md5 =
new System.Security.Cryptography.MD5CryptoServiceProvider(); 10 11  //獲取密文字節數組 12  byte[] bytResult = md5.ComputeHash(System.Text.Encoding.Default.
GetBytes(strSource)); 13 14  //轉換成字符串,並取9到25位 15  string strResult = BitConverter.ToString(bytResult, 4, 8); 16  //轉換成字符串,32位 17  //string strResult = BitConverter.ToString(bytResult); 18 19  //BitConverter轉換出來的字符串會在每個字符中間產生一個分隔符,需要去除掉 20  strResult = strResult.Replace("-", ""); 21  return strResult; 22 } 23 24 /**//// <summary> 25 /// 方法二:通過調用特定加密算法的抽象類上的 Create 方法,創建實現特定加密算法的對象。 26 /// </summary> 27 /// <param name="strSource">需要加密的明文</param> 28 /// <returns>返回32位加密結果</returns> 29 public string Get_MD5_Method2(string strSource) 30 { 31  string strResult = ""; 32 33  //Create 34  System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.
MD5.Create(); 35 36  //註意編碼UTF8、UTF7、Unicode等的選擇  37  byte[] bytResult = md5.ComputeHash(System.Text.Encoding.UTF8.
GetBytes(strSource)); 38 39  //字節類型的數組轉換為字符串 40  for (int i = 0; i < bytResult.Length; i++) 41  { 42 //16進制轉換 43 strResult = strResult + bytResult[i].ToString("X"); 44  } 45  return strResult; 46 } 47 48 /**//// <summary> 49 /// 方法三:直接使用HashPasswordForStoringInConfigFile生成 50 /// </summary> 51 /// <param name="strSource">需要加密的明文</param> 52 /// <returns>返回32位加密結果</returns> 53 public string Get_MD5_Method3(string strSource) 54 { 55  return System.Web.Security.FormsAuthentication.
HashPasswordForStoringInConfigFile(strSource,
"MD5"); 56 }

2011年7月12日 星期二

Google+ for Android 手機的照片即時上傳功能

擁有 Android 手機,也在手機上安裝 Google+ App 軟體的朋友,可以留意一下這個 Google+ 社群服務結合 Picasa 網路相簿的新功能。

在 Android 手機上,Google+ App 的設定頁面 (Settings) 可以看到 「Instant Upload」 這個選項,預設是啟動的。


也就是安裝 Google+ 之後,手機只要有連接網路,就會自動將新增照片,在背景自動上傳到 Picasa 網路相簿,並放在「即時上傳」這個相簿資料夾中。



這項服務是否會有隱私外洩的疑慮呢?從 Picasa 的設定可以看到,「即時上傳」是只限帳號本人自己瀏覽的權限。但什麼時候會有類似無名照片外流的新聞事件發生?!這就沒人敢保證了。

使用搭配3G行動網路的智慧型手機,必須自己更加提防個人資料外洩,不該寫的、不該拍的,就不要一時衝動,否則資料一上了雲端,就可能永遠也無法抹除。只有自己小心,才能享受行動應用服務帶來的便利。

Google 這次看起來是準備和 Facebook 槓上了,Google+ 剛推出就受到網友瘋狂搶著啟用,而 Android 以每天50萬台啟用的速度成長。

擁有智慧型手機的 Google+ 用戶,肯定會帶來另一個網路流量的爆量成長,也就是 Google 自家的網路相簿服務「Picasa Web」。因為對多數人來說,在路上看到一個驚奇的...事物,最方便快速的分享方式,就是拿起手機拍張照、直接上傳到社群網站發佈。這比自己說了140字或1400字更容易形容現場狀況,雖然拍照不像錄影可以完整記錄,但是目前在手機上剪輯影片並不容易,而且上傳影片耗時更耗電。

所以,這個新的網路服務組合起來,未來將可能佔用人們非常多的生活時間。

Google+ (社群服務) + Android (行動裝置) + Picasa Web (網路相簿)

可是,現階段最大的問題是,Picasa 雖然是很棒的相簿服務,功能簡單好操作;但最致命的一項缺點就是,免費版本僅有 1GB 容量,這根本不夠每天都在瘋狂拍照、立刻上傳的社交沉癮族。

還好 Google 目前的對策是,照片會自動轉檔成 2048 x 2048 大小的解析度,上傳到 Picasa 相簿後不會佔用原有的 1GB 容量。對一般手機的照相畫質來說,這種解析度其實已經夠用。

照片即時上傳的好處不少,不僅自動在雲端提供備份,要分享到其他網站、部落格,也可以省下手動上傳的麻煩。如果你的手機記憶卡容量不夠,也可以在照片上傳完成後,就刪除手機中儲存的那一份。


2011年7月6日 星期三

C# 密碼加密




密碼加密在寫登入程式的時候常常會用到。
不過不常寫的話又容易忘,所以在這邊來做一個紀錄。
如果只是要簡單的加密的話,如下:

string Password = "abcd";  //假設密碼是abcd

//使用FormsAuthentication.HashPasswordForStoringInConfigFile方法,
//第一個參數是要加密的字串,第二個參數是加密的演算法。

Password = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(Password, System.Web.Configuration.FormsAuthPasswordFormat.SHA1.ToString());

加密完之後,字串就會變成這樣:
81FE8BFE87576C3ECB22426F8E57847382917ACF
下面一個是稍微複雜一點的加密方式:


string Password = "abcd";
           
//密碼編譯亂數產生器
System.Security.Cryptography.RNGCryptoServiceProvider rng
          =new System.Security.Cryptography.RNGCryptoServiceProvider();


byte[] buffer = new byte[15];


//將產生的密碼亂數填入byte[]陣列
 rng.GetBytes(buffer); //

 //將陣列轉成字串
string shadow= Convert.ToBase64String(buffer);

//原輸入密碼abcd加上salt字串,再進行加密動作
Password = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(Password + shadow, "sha1");


加密完之後,可以看到跟上面簡單加密後的密碼不一樣了。


相較於使用System.Web.Security進行加密,若撰寫類別者,
System.Security.Cryptography亦提供相關功能:


string dataCrypted = "";
           
//實體化 myHash
System.Security.Cryptography.SHA1 myHash =
          System.Security.Cryptography.SHA1.Create();


byte[] dataBytes = Encoding.UTF8.GetBytes(dataUnencrypt);
           
//將產生的 hash 填入byte[]陣列
myHash.ComputeHash(dataBytes);

 //將myHash轉成字串
dataCrypted = BitConverter.ToString(myHash.Hash).Replace("-", "");


2011年7月5日 星期二

接收 Store Procedure 的傳回值


要將資料傳回一般有 3 種方式:
  1. 使用 SELECT 以表格方式傳回。
  2. 設定 Output Parameter 以參數方式傳回。
  3. 使用 RETURN 傳回 1 個整數型別的資料。
以下列出第 3 種傳回方式,在 SQL 及 ADO.NET 中接收的方法。
使用 RETURN 傳回單一數值
Store Procedure:
1
CREATE PROCEDURE mysp_InsData (
2
@LastName varchar(30),
3
@FirstName varchar(10)
4
)
5
AS
6
BEGIN
7
    INSERT INTO Customer (LastName, FirstName) VALUES (@LastName, @FirstName);
8
    RETURN SCOPE_IDENTITY();
9
END
在新增完資料後,使用 RETURN 返回新增資料的識別值。

在另一支預儲程序中接收此預儲程序傳回的值:
1
DECLARE @intRow int;
2
EXEC @intRow = mysp_InsData 'Walter''Liao';
3
SELECT @intRow;

C#
01
SqlConnection conn = new SqlConnection(strConn);
02
SqlCommand cmd = new SqlCommand(string.Empty, conn);
03
conn.Open();
04
05
cmd.Parameters.Clear();
06
cmd.CommandType = CommandType.StoredProcedure;
07
cmd.CommandText = "mysp_InsData";
08
cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 30).Value = "Walter";
09
cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = "Liao";
10
11
SqlParameter retID = cmd.Parameters.Add("@ReturnValue", SqlDbType.Int);
12
retID.Direction = ParameterDirection.ReturnValue;
13
14
try
15
{
16
    cmd.ExecuteNonQuery();
17
}
18
catch (Exception ex)
19
{
20
    //當新增資料時若發生錯誤,可撰寫程式將錯誤訊息記錄下來
21
    //InsErrorLog("mysp_InsData", ex.Message);
22
}
23
24
Console.WriteLine("Return Value:" + retID.Value);
25
26
conn.Close();
27
conn.Dispose();
第 11 行:建立要接收 RETURN 的參數,參數名稱 @ReturnValue 可自定。
第 12 行:將參數設定為 Return Value。(假使參數為 OUTPUT則.Direction可設定為.Output)
第 24 行:用 .value 將傳回資料取出。