顯示具有 C# 標籤的文章。 顯示所有文章
顯示具有 C# 標籤的文章。 顯示所有文章

2009年4月19日 星期日

在Visual Studio 2005 簡易使用 Web Service

在Visual Studio 2005 簡易使用 Web Service

1. 產生Web Service 專案

1.1 使用C# 建立Web Service 專案

1.2 修改Namespace 和WebService的Service名稱

1.3 按F5執行時會開起執行的網頁,而網頁這時候的結果:

1.4 Method說明
修改WebMethod 加上Description

結果:多了My First WebService Say Hello描述

2. 使用Client呼叫Web Service

建立一個Windows Application專案
2.1 加入Web 參考

輸入URL:

結果:


2.2 Call Web Server - Hello Word







執行結果:

2.2 呼叫的Web Service 位址改變
如Web Service的位址是會變動的(從測試機台到正式機台),可以改變Url屬性的值


3. 使用Session

3.1 Server Code 加入Session的邏輯

3.2 Client 加入存Session的邏輯
Client端要 new 一個CookieContainer才會把Session的值存下來


4. 權限管理

4.1 Web Server 在Class一產生出來就判斷,使用Header

4.2 在Client端新增一個Proxy繼承RiceService,用來產生帳號和密碼的Header

原先用Web Servic的地方改為使用Proxy


5.Web Service 搬到IIS Service

5.1 Vista 的步驟




設定完看是X的樣式可以重新啟動他


在重新啟動後試著連上去剛被我們啟動的Web Service



發生了Access Deny的Exception :這是因為我們在程式裡面的寫法是要利用帶Heardr ,Header裡面要有帳號和密碼的資訊。
而我們直接使用Web測試,所以才會有這樣的狀況。



5.2 XP 設定的方式







Other:
1.Client 在使用Web Service的服務時會有TimeOut的情形發生,可以設定用web 參考得到的Web Service Class中的timeout屬性,來決定要等待的時間。(試過設成-1就不會有client 等待過久變成timeout的Exception)

2.Code






2009年3月23日 星期一

Crystal Report

Crystal Report為用來製作報表的工具


運作模型分為兩種:pull model 和 push model。

pull model:報表的資料來源是在設計報表時就指定好的,亦即在執行時期產生報表時,會向預先指定的資料來源(通常是資料庫)將所需的資料「拉」回來。


Push model :是在執行時由程式將資料給報表,

pull model 是將大部分的工作都在設計報表時完成,而 push model 還必須撰寫程式將資料丟給報表,push mode可以將報表資料透過程式全部都準備好之後,再利用報表工具呈現出來 ,如動態欄位、極複雜的 SQL...。

在非開發環境要使用Crystal Report需要有Crystal Report Runtime的環境,在Visual Studio 2005的開發環境可以運行,是因為Visual Studio 把運行的Runtime整合到開發環境。

取得Runtime開發環境的方式
Step 1. 取得Crystal Report Runtime合併模組 (
http://resources.businessobjects.com/support/additional_downloads/runtime.asp )
Step 2. 新增專案的安裝及部署項目(Step 1解壓後的文件中有word檔教學),加入Step 1.的合併模組
Step 3. 在要運行Crystal Report的環境安裝 Step 2.產生的安裝檔


由Crystal Report 吃XML資料的方式
XML → DataSet →Crystal Report
說明:
http://www.codeproject.com/KB/cs/xmlcrreport.aspx
Example


MSDN資料:
合併模組專案
[合併模組] 專案讓您建立可重複使用的安裝元件。就如同動態連結程式庫能讓您在應用程式間分享程式碼一樣,合併模組能讓您在 Windows 安裝程式間分享安裝程式碼。
合併模組 (.msm 檔) 是一個包含安裝元件所需的所有檔案、資源、登錄項目及安裝邏輯的單獨套裝。合併模組無法單獨安裝,必須在 Windows Installer (.msi) 檔案內容中使用。
合併模組能讓您擷取一特定元件的所有相依性,以確保安裝正確版本。一旦您散發了合併模組就無法再做修改,而應為元件的每個後續版本建立新的合併模組。
為了避免版本問題,多重應用程式所共用的元件或檔案都應該使用合併模組。


Ref:
http://msdn.microsoft.com/zh-tw/library/0h4bhcz3(VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/ms225593(VS.80).aspx
http://www.dotblogs.com.tw/huanlin/archive/2008/04/23/3315.aspx
http://www.codeguru.com/csharp/.net/net_general/toolsand3rdparty/article.php/c13253/


2009年3月22日 星期日

C# and Flash

在C Sharp 播放Flash有三個步驟

1. Add Shockwave Flash Object to Tool Box
2. Register Flash ActiveX Control
3. Use Shockwave Flash Object

1.Add Shockwave Flash Object to Tool Box


2.Register Flash ActiveX
找到Flash9f.ocx的路徑(名稱會依安裝的版本不同而有改變)
一般是放在C:\WINDOWS\system32\Macromed\Flash\
在命令列輸入regsvr32 C:\WINDOWS\system32\Macromed\Flash\Flash9f.ocx

3.Use Shockwave Flash Object
使用Toolbox裡的Shockwave Flash Object

更改Movie 屬性指到Flash 檔所在的位址

另外當使用Visual Studio做過Register Flash ActiveX的步驟後,托拉Shockwave Flash Object到Form時,如果有下面的錯誤發生:

那需要使用Windows Form ActiveX控制項匯入工具(AxImp.exe)來手動產生dll
1. AxShockwaveFlashObjects.dll
2. ShockwaveFlashObjects.dll
再加入Visual Studio 專案中的參考裡面,再去手動Coding

AxImp.exe 需要安裝過.Net Framework SDK
“C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin” 底下會有AxImp.exe
AxImp.exe 的使用方式
Command-Line: cd C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin
Command-Line: aximp C:\WINDOWS\system32\Macromed\Flash\Flash9f(10a).ocx

程式的配置方式
namespace PA_Project
{
partial class PAParty
{
...
...
private void InitializeComponent()
{
...
...
this.axShockwaveFlash1 = new AxShockwaveFlashObjects.AxShockwaveFlash();
...
...
//
// axShockwaveFlash1
//
this.axShockwaveFlash1.Enabled = true;
this.axShockwaveFlash1.Location = new System.Drawing.Point(-1, 3);
this.axShockwaveFlash1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.axShockwaveFlash1.Name = "axShockwaveFlash1";
this.axShockwaveFlash1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axShockwaveFlash1.OcxState")));
this.axShockwaveFlash1.Size = new System.Drawing.Size(700, 500);
this.axShockwaveFlash1.TabIndex = 3;
...
...
}
...
...
public AxShockwaveFlashObjects.AxShockwaveFlash axShockwaveFlash1;
...
...
}
}



Reference: http://msdn.microsoft.com/zh-tw/library/8ccdh774.aspx

2009年2月18日 星期三

C# Remoting


Remoting可建立的Channel有(1)TCP Channel. (2)Http Channel. (3)IPC Channel

.Net 1.1 : TCP Channel、Http Channel.
.Net 2.0 : 之後多了IPC Channel 使用Windows程式間通信系統(IPC:Inter process Communication)

Remoting 的使用流程
1.建立Remoting 物件
2.在Server建立使用Remoting物件的Channel
3.在Client使用Remoting


//------------------ Example --------------------//
1.建立Remoting物件









1.1 建立Interface1.2.實作Remoting物件
using System;
using System.Collections;
namespace G5.RemotingEvent.ICommon
{
public delegate void PAEventHandler(Hashtable fax);
public interface IG5Business
{
void SendPA(Hashtable fax);
}
}

using System;
using System.Collections;
using G5.RemotingEvent.ICommon;

namespace G5.RemotingEvent.RemoteObj
{
public class G5Business:MarshalByRefObject,IG5Business
{
// 建立Event
public static event PAEventHandler PASendedEvent;
#region
public void SendPA(Hashtable fax)
{
if (PASendedEvent != null)
{
PASendedEvent(fax);
}
}
#endregion
public override object InitializeLifetimeService()
{
return null;
}
}
}

2.在Server建立使用Remoting物件的Channel





2.1 using
//using System.Runtime.Remoting.Channels.Http;
//using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels.Ipc;

2.2 建立Channel
// IPC Channel
IpcChannel channel = new IpcChannel("G5Channel");
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(typeof (G5Business), "G5Loader", WellKnownObjectMode.Singleton);

//TCP Channel
//TcpServerChannel channel = new TcpServerChannel(3210);
//ChannelServices.RegisterChannel(channel, false);
//RemotingConfiguration.RegisterWellKnownServiceType(typeof(G5Business), "G5Loader", WellKnownObjectMode.Singleton);

// Http Channel
// HttpChannel channel = new HttpChannel(8080);
// ChannelServices.RegisterChannel(channel);
// RemotingConfiguration.RegisterWellKnownServiceType(typeof(G5Business),"G5Business.soap",WellKnownObjectMode.Singleton);

G5Business.PASendedEvent += new PAEventHandler(OnPASended);



3.在Client使用Remoting




1.using

//using System.Runtime.Remoting.Channels.Http;
//using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Ipc;

2.使用Channel
private IG5Business faxBus = null;

// IPC Channel
string stringIpc = "ipc://G5Channel/G5Loader";
faxBus = (IG5Business)Activator.GetObject(typeof(IG5Business), stringIpc);

//TCP Channel
//string stringTcp = "tcp://localhost:3210/TestLoader";
//faxBus = (IG5Business)Activator.GetObject(typeof(IG5Business), stringTcp);
//Http Channel
//HttpChannel channel = new HttpChannel(0);
//ChannelServices.RegisterChannel(channel);
//faxBus = (IG5Business)Activator.GetObject(typeof(IG5Business),
// http://localhost:8080/G5Business.soap);



參考資料:
http://www.cnblogs.com/idior/archive/2007/01/04/611265.html (原理)
http://www.codeguru.com/csharp/csharp/cs_syntax/remoting/article.php/c9251



2009年2月16日 星期一

C# 設定和取得機碼(Registry Key)的值

設定機碼(Registry Key)

string keyPathString = "SOFTWARE\\AB Tool";
Microsoft.Win32.RegistryKey start = Microsoft.Win32.Registry.LocalMachine;
Microsoft.Win32.RegistryKey programName = start.CreateSubKey(keyPathString);
programName.SetValue("Application Path", System.Windows.Forms.Application.StartupPath);
programName.Close();

執行的結果

------------------------------------------------------------------------------------------------------------------------------------

取得機碼(Registry Key) 的值

string pathString = null;
string keyPathString = "SOFTWARE\\AB Tool";
Microsoft.Win32.RegistryKey start = Microsoft.Win32.Registry.LocalMachine;
Microsoft.Win32.RegistryKey programName = start.OpenSubKey(keyPathString);
if (programName != null)
{
pathString = (string)programName.GetValue("Application Path");
}

------------------------------------------------------------------------------------------------------------------------------------

MSMQ


MSMQ
::Microsoft Message Queue(訊息駐列)


啟動MSMQ
::


C#使用方式
傳訊
1.建立要傳送資料
System.Messaging.Message hashtable_Msg = new System.Messaging.Message(strHashtable, new System.Messaging.BinaryMessageFormatter());
2.指定MSMQ Channel 或建立MSMQ Channel
msgQ = new System.Messaging.MessageQueue(@".\Private$\MDSQueue");
msgQ = System.Messaging.MessageQueue.Create(@".\Private$\MDSQueue");

3.傳送到Message Queue
msgQ.Send(hashtable_Msg);

收訊
1.指定MSMQ Channel 或建立MSMQ Channel
msgQ = new System.Messaging.MessageQueue(@".\Private$\MDSQueue");
msgQ = System.Messaging.MessageQueue.Create(@".\Private$\MDSQueue");

2.設定這個Message Queue資訊格式
msgQ.Formatter = new System.Messaging.BinaryMessageFormatter();
3.接收Message
strHashtable = ((System.Collections.Hashtable)msgQ.Receive().Body);

//-------------- 範例 ---------------//
傳訊
Hashtable strHashtable = new Hashtable();
double key = 0;
string valueString = "Dispose";
strHashtable.Add(key, valueString);
// 傳送Hashtable 格式資料時,需要使用BinaryMessageFormatter方式傳送
System.Messaging.Message hashtable_Msg = new System.Messaging.Message
(strHashtable, new System.Messaging.BinaryMessageFormatter());


System.Messaging.MessageQueue msgQ;
// 確認是否有用來傳送的Channel存在,在這 Channel 名稱由使用者定為MDSQueue
if (System.Messaging.MessageQueue.Exists(@".\Private$\MDSQueue"))
{
msgQ = new System.Messaging.MessageQueue(@".\Private$\MDSQueue");
}
else
{
msgQ = System.Messaging.MessageQueue.Create(@".\Private$\MDSQueue");
}

// 使用Message Queue 的 Object 來傳送訊息
try
{
msgQ.Send(hashtable_Msg);
// 中斷在接收訊息的Message Queue Thread
ThreadAll[0].Interrupt();
}
catch
{
}

收訊
public void ListenMDSQueue()
{
// Create MessageQueue Object。
System.Messaging.MessageQueue msgQ;
// 確認是否有用來傳送的Channel存在,在這 Channel 名稱由使用者定為MDSQueue

if (System.Messaging.MessageQueue.Exists(@".\Private$\MDSQueue"))
{
msgQ = new System.Messaging.MessageQueue(@".\Private$\MDSQueue");
}
else
{
msgQ = System.Messaging.MessageQueue.Create(@".\Private$\MDSQueue");
}


// Always listen MDS Queue until interrupt。
while (true)
{
try
{
// 使用Thread時interrup機制在MessageQueue Receive時無法中斷
// 需要MessageQueue收到訊息釋放Thread的控制,interrup才能有作用
// 可以使用 Sleep機制在進入Receive時,先確定是否有Interrup發生.

System.Threading.Thread.Sleep(80);


System.String ContextString = "";
System.Collections.Hashtable strHashtable = new System.Collections.Hashtable();
System.Object o = new System.Object();
System.Type[] arrTypes = new System.Type[2];
arrTypes[0] = strHashtable.GetType();
arrTypes[1] = o.GetType();
// Message 如果沒有定義格式.預設是使用XmlMessageFormatter
// 這個格式無法存放Hashtable型態的訊息,所以改用BinaryMessageFormatter
// msgQ.Formatter = new System.Messaging.XmlMessageFormatter(arrTypes);
msgQ.Formatter = new System.Messaging.BinaryMessageFormatter();

// 收到的訊息轉為Hashtable格式
strHashtable = ((System.Collections.Hashtable)msgQ.Receive().Body);

// Get Type
ContextString = (string)strHashtable[(double)0];

// 如果收到的訊息為"Dispose” 代表傳訊的人要結束接收訊息的動作.那在下一次迴圈Sleep時
// 會執行傳訊的人所下的ThreadAll[0].Interrupt() 指令

if (ContextString == null || !ContextString.Equals("Dispose"))
{
this.setValueTable(strHashtable);
}
}
catch (System.Threading.ThreadInterruptedException e)
{
System.Console.WriteLine("Exception e:"+e.Message);
msgQ.Dispose();
break;
}
}
}


private System.Threading.Thread[] ThreadAll = new System.Threading.Thread[2];
private void StartListenMQThreads()
{
ThreadAll[0] = new System.Threading.Thread(new System.Threading.ThreadStart(ListenMDSQueue));
ThreadAll[0].Start();
}

// 這個例子有二個Thread , Main Thread 和 Linten Message Queue Thread
// 當Message Queeu Thread想改變Main Thread的資料時,要使用delegate的方式來達到目的

private delegate void InvokeUpdateState_forHashtable(System.Collections.Hashtable strHashtable);
private void setValueTable(System.Collections.Hashtable strHashtable)
{
if (this.InvokeRequired)
{
this.Invoke(new InvokeUpdateState_forHashtable(this.setValueTable), new object[] { strHashtable });
}
else
{
this.strHashtable_value = strHashtable;
}
}

C# Gargabe 觀念整理



CLR(Common Language Runtime)

:CLR自動配置與管理的記憶體,稱為Managed資源
:不受CLR管理的便被稱為Unmanaged資源

使用強制釋放資源
System.GC.Collect();

通知 .Net framework不要對這個object進行資源回收
System.GC.SuppressFinalize(this)

// ---以下引用 慮山佚城所寫的文章-- 留做個人以後查資料的記錄 --- //

在執行.NET的程式時,對於不同型別,CLR(Common Language Runtime)會在不同的地方分配資源空間。對於實值型別(Value Type),當宣告一個變數時,CLR會在Stack(堆疊)中配置一塊空間,設定該變數的值時,其值也直接存放於該空間中,如下圖:


而對於參考型別(Reference Type),CLR則在Stack中配置一塊存放記憶體位址的空間,在初始化該型別的實體時(ex: new),則在Heap(堆積)上配置該型別所需的空間,再將該空間的位址傳回給存放在Stack中的那塊空間,如下圖:

這些由CLR自動置與管理的記憶體,被稱為Managed資源;反之,不受CLR管理的便被稱為Unmanaged資源(ex: Stream、與資料庫的連結、COM物件……等)。
而對於資源的釋放,CLR則主要以GC來回收已用不到的記憶體空間,這些空間便被稱為garbage。(上述的記憶體配置及GC的運作可參考
MSDN: CLR的自動記憶體管理)
那麼garbage如何產生或被判定呢?
基本的原則是當該變數「不再有效」時,便會被視為garbage,具體的情況則包括超出該變數的有效範圍(ex:離開了對應的大括號的區域變數)、 將變數指定為null、重新指向其他物件(而原先指向的物件已無法被取得)、重新初始化…等,這時原先變數佔有的空間都會被CLR視為garbage而等待回收。
若變數為數值型別,則當其超出有效範圍時,CLR會直接回收它在Stack上所佔用的空間;若變數為參考型別,則CLR會先回收它在Stack上佔用的空間,而將Heap上的空間視為garbage,等待GC回收。若參考型別的變數在其有效範圍內重新初始化,則原先所指向的物件亦會被視為garbage。
然而,被視為garbage的變數,並不是馬上就被GC回收,而是根據GC內的演算法,依變數被判定的generation而有不同。在Managed Heap上的物件會被CLR分為三個generation:0、1、2,數字越大表示存活時間越長。這樣的設計乃是建構在「只壓縮部份的Heap會比一次壓縮整個Heap來得有效率」的事實上,因此將物件分成不同的層級,在回收時針對不同層級做回收,是.NET Framework考量效率後所採用的方法。
CLR會將新建立的物件擺在第0個generation,當GC進行gen 0的回收時,會將仍為有效的gen 0物件提昇至gen 1。而若gen 0的空間回收後仍不足以建立新物件,則GC會繼續檢查gen 1的物件,存留下來的gen 1物件會被提昇至gen 2(最高只到gen 2,故若gen 2被檢查後仍存活,只會停留在gen 2)。進行gen 1的回收時,也會進行gen 0回收;同理進行gen 2回收時,也會進行gen 1、gen 0的回收。在這樣的設計下,程式中常會應用到的區域物件與暫時物件因都屬於gen 0,故可確保被回收的頻率最高,對一般不會用到大量暫時物件的程式而言,不需擔心資源的浪費。
至目前為止,我們了解了Managed資源的回收機制,但還有至少二個問題殘留著:
「若是程式員希望在某個時間點確保Managed資源被回收,應該怎麼做?」
「若是類別中含有Unmanaged資源,又該如何釋放?」
對於這二個問題的回答,在這裡便開始要提到程式員如何撰寫明確釋放資源的函式了。在C++中,程式員撰寫類別的Destructor來達成類別資源的釋放,而在C#中,同樣有類似效果的函式有Finalize()與Dispose() ,而這二個函式也常令許多C#的初學者混淆,以下便解釋二者的差別:
前面提到Managed資源會自動被GC回收,但若類別中含有Unmanaged資源,則程式員除了撰寫該Unmanaged資源本身的釋放函式(如Destructor)之外,又該在何處確保這些釋放函式會被呼叫呢?答案就是C#類別的Finalize()函式中。然而,因Finalize()本身的存取層級是protected,所以在實作上,對於類別T,程式員是撰寫名為 「~T()」的函式(如同C++中的解構函式語法),該函式經過編譯後,編譯器便會產生類別T的Finalize()方法,並將函式的內容包在try 區塊中。
public class T
{
Unmgd un;
~T()
{
un.Release(); //假設Unmgd的釋放資源函式為Release();亦可呼叫~Unmgd()
}
}
然而,Finalize()的呼叫是不明確的,因為它只被GC給呼叫,亦即程式員只能預期GC在進行某個T的實體的回收時,會呼叫T.Finalize(),卻無法在程式員自己想要的特定位置呼叫Finalize()。另一方面,Finalize()也並非在GC對該物件進行第一次回收時便被呼叫,事實上,GC的第一次回收,僅是將該物件的參考移至FReachable Queue中,標示為不再使用,等到GC下一次的回收時,Finalize()才真正地被呼叫。從這些事實來看,程式員沒有辦法預期Finalize()究竟會在程式中的何處被呼叫,只能被動地等待GC去呼叫它。因此,為了讓程式員能明確執行Unmanaged資源釋放的工作,C#提供了另一個函式Dispose()。
Dispose()與Finalize()最大的不同,在於Dispose()是明確地在「程式員呼叫」與「using語句區塊結束時」二種情況下被呼叫的。也就是說,當程式員想確保某個類別T中的Unamaged資源會在某個特定位置被釋放掉時,他便可以實作IDisposable介面中的Dispose()函式;而為了提供程式員在操作常用的暫時物件上不會忘記呼叫Dispose(),C#中提供了using陳述式,確保在小括弧中的變數,在離開using區塊時,其Dispose()會被明確地呼叫。
using(T t = new T())
{
.........
} //<-此時T.Dispose()會被呼叫
當一個物件的Dispose()被呼叫後,亦即標示了這個物件為無效,則在第一次的GC回收行程中便會被回收到。值得一提的是,即使某個物件的Dispose()已經被呼叫過了,該物件的Finalize()仍然有可能再被GC給呼叫到,這是為了避免當Dispose()失敗時可能產生的資源浪費。然而,若Dispose()成功地執行了,則應該避免再讓GC去呼叫Finalize(),否則會造成程式效率的低落。因此在撰寫Dispose()函式時,必須記得在裡面加上一行GC.SuppressFinalize(this); 這可以告訴GC不需再去呼叫這個物件的Finalize()。

//------------------------------------------------------------------------------------------//

資料來源:
史帝芬心得筆記
http://home.so-net.net.tw/idealist/CS/Basic/Garbage.html
廬山佚城 http://sedc.pixnet.net/blog/post/14184015
Joel Lee http://dialog.bcse.info/archives/memory-leak-in-c-sharp