Release Mode程式, 利用Ildasm除錯

如果.NET程式遇到圖一這種情況, 可以利用事件檢視器和Ildasm工具找出問題的原因.

首先, 打開 控制台>…>事件檢視器, 路徑會因為作業系統而改變, Win7是控制台>系統及安全性>檢視事件記錄檔

找出錯誤記錄, 圖二, 記錄描述解讀如下

P1 出錯的程式名稱, P4 出錯的組件, P7 組件裡出錯的方法, P9 錯誤名稱

根據圖二, 出錯的是system.windows.forms, 錯誤為argumentnullexception

接下來就要找出是那一個方法出錯, 先打開Ildasm反組譯工具, 可能找看看下列位置

% WindowsRoot%\Microsoft.NET\Framework\version\

%Program Files%\Microsoft SDKs\Windows\version\bin

我是在%Program Files%\Microsoft SDKs\Windows\v7.0A\bin 找到的

執行Ildasm, File>Open, 把P4的組件打開, 打開後點選View>MetaInfo>Show!

會打開一個文字檔, 裡面是該組件的meta資料, 利用Find功能找出有問題的方法

搜尋 0600+P7, 根據圖二, 這裡要搜尋的是06001521, 找到一個名稱Method #467 (06001521) NotifyEnter的方法

也就是說, 程式裡導致錯誤的原因跟system.windows.forms NotifyEnter方法相關

P.S. Report to Microsoft一點用都沒有, 還是靠自己吧

Use Memcached in .NET application with Linq

First of all, get the memcached, I user win32 version. http://jehiah.cz/projects/memcached-win32/ version 1.2.1
Secondly, get a client for memcached, I use this one http://memcachedproviders.codeplex.com/ version 1.2
Get the document for the client too, I start without it and I think you should read it in advance.
I will share some of my experience too.

The official documentation is a bit poor, I am going to give an introduction on the main points.

1. Memcached is a universal distributed cache.

i.e. it can run multiple instances and appears to the programmer as one cache server which is programming language independent. A really large hashtable.

2. It stores no object, you’ll have to serialze every object that you want to cache.

3. It won’t throw any exception no matter what happens.

I will focus on how to use the memcached server, not how to setup since you should be run it without a problem.

Setup the client in your application. Unarchive and add reference to all three .dll in your project.

Then configure your web.config or app.config like this, inside <configSections> tag, add the following:

<section name="cacheProvider" type="MemcachedProviders.Cache.CacheProviderSection, MemcachedProviders"
 allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
 <sectionGroup name="enyim.com">
 <section name="memcached"
 type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
 </sectionGroup>
 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>

This tells the application that there will be a section with tag <cacheprovider> and <log4net>. Also will have a section with tag <enyim.com> who has a child tag <memcached> inside. You can just copy and paste the above, it should work.

Then add the detail settings in <configuration> tag.

<cacheProvider defaultProvider="MemcachedCacheProvider">
 <providers>
 <add name="MemcachedCacheProvider" type="MemcachedProviders.Cache.MemcachedCacheProvider, MemcachedProviders"
 keySuffix="_MySuffix_" defaultExpireTime="2000"/>
 </providers>
 </cacheProvider>

 <enyim.com>
 <memcached>
 <servers>
 <add address="192.168.1.2" port="11211" />
 </servers>
 <socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
 </memcached>
 </enyim.com>

 <log4net>
 <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
 <layout type="log4net.Layout.PatternLayout">
 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}]- %message%newline" />
 </layout>
 </appender>
 <root>
 <priority value="WARN"/>
 <appender-ref ref="ConsoleAppender">
 <filter type="log4net.Filter.LevelRangeFilter">
 <levelMin value="WARN"/>
 <levelMax value="FATAL"/>
 </filter>
 </appender-ref>
 </root>
 </log4net>

You can change the default expire time. Server address is the host which you run memcached and 11211 is the default port.

Caching string and serialized object should be something you already know. For simple class, just add [Serializable] to the class.

Let’s see how it works with LINQ.

To serialize LINQ object, open .dbml design view, select serialize mode to unidirectional.

Then you will need to use DataContractSerializer to actually serialize your object. For more information.

There are a few serializer, XML, binary, JSON, etc. I am using DataContractJsonSerializer since it should be faster than XML. The following code snippet serialize and cache the object array to memcached.

//create a serialize provider with specify object type
DataContractJsonSerializer serializeProvider = new DataContractJsonSerializer(typeof(myClass[]));
//a memory stream as buffer since the provider do not directly generate string
 using (MemoryStream ms = new MemoryStream())
 {
 serializeProvider.WriteObject(ms, myClassArrayObject);
 byte[] l_buffer = new byte[ms.Length];
 ms.Position = 0;
//If the string is out of integer range, skip it, you can do whatever you need to handle this
 if (ms.Length < int.MaxValue)
 {
 ms.Read(l_buffer, 0, (int)ms.Length);
 string l_serialized = Encoding.Unicode.GetString(l_buffer);
//remove existing cache with the same key
 DistCache.Remove("keyString");
 DistCache.Add("keyString", l_serialized);
 }
 else
 {
 throw new Exception("object data large.");
 }
 }

Then you can check whether you succussfully cache it with telnet.

Telnet to your server and type the command ‘stats’, it will then shows the status of your memcached.

curr_items is the number of items inside memcached.

There is some common practices in choosing the hash key but that is another topic.

I am using Application:Method:Parameters:Salt and then hash it with SHA256, convert it to base64.

This should be enough for testing purpose, you can come up with your own hash decision.

Then we will get the cache and deserialize it to our object.

string l_serialized = (string)DistCache.Get("keyString");
 DataContractJsonSerializer serializeProvider = new DataContractJsonSerializer(typeof(myClass[]));
 using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(l_serialized)))
 {
 myClass[] members = (myClass[])serializeProvider.ReadObject(ms);
 }

You can do this with your object, object array, object collection, etc.

But remember you are in a different data context if you get you data from cache.

This will need some workaround to update or delete data with Linq.

I will cover this part later in another article.

中文版

C# Extension Method By Simple Example!

For Example, You want to add new methods to System.Web.UI.WebControls.CheckBoxList
Step One. Declare a static class with *any* name.
Step Two. Declare a static method just like any normal method. This method can have return value and arguments.
Remember, we need to have the first argument define like this *this ClassName object*. In our case :
public static void MethodName(this CheckBoxList checkBoxList)
{
...
}

Okay now, Let’s see an example. Let’s say we want to have all selected checkbox values.
We can do like this.
public static class CheckBoxListExtension
{
public static string[] GetSelectedValues(this CheckBoxList checkBoxList)
{
List l_selected = new List(5);
foreach (ListItem item in checkBoxList.Items)
{
if (item.Selected)
{
l_selected.Add(item.Value);
}
}return l_selected.ToArray();
}
}

Then, when you use it, .NET may tells you that it can’t find that method.
The auto add using won’t work in this situation.
That make sense since the extension methods is not in that extended class.
Just add using YourNameSpace manually and we are good.

Try MS Chart Control with Normal Distribution Sample

There is a very good introduction blog post here.

This new control is amazing. Ajax real time update, So many types of chart, 3D, common statistic feature, etc.
And it is good looking.

這裡有一篇寫得很好的介紹文章

這個新的工具真的很酷. Ajax即時更新, 非常多種類的圖表, 3D圖表, 一些常用的統計功能等. 而且風格蠻好看的.

This is the application which I use to test integrating some skills.
1. Multithreaded Application to show progress of lengthy calculation.
2. Generating Normal distribution outcome sample with box-muller formula.
3. Draw a chart with the chart control.
4. Create a Setup project to wrap the application into a installer.

這應該是我用來測試整合自己的技巧的.
1. 多執行緒,讓介面顯示長時間計算的進度
2. 用box-muller公式產生符合常態分佈的亂數
3. 畫一個圖
4. 用一個安裝專案包起來,產生安裝檔

Here is what it looks like. 截圖
10000 outcome
1000000 outcome

Here is the link to download the application.
程式安裝檔的下載連結

I will talk about different kind of data source and some basic setting of the chart control next time.
下一次會花點時間介紹一下不同的資料來源和基本設定.

Minimize your .NET Application to System Tray

Just come across this requirement today.

1. Drag a NotifyIcon from your toolbox.

2. The ‘Text’ value is what it shows when you move hover your icon.

3. Link your ‘Icon’ property to an .ico

4. Add this event handler to your form.

private void Form1_Resize(object sender, System.EventArgs e)
{
   if (FormWindowState.Minimized == WindowState)
      Hide();
}

5. Add this event handler to your NotifyIcon

private void notifyIcon1_DoubleClick(object sender,
                                     System.EventArgs e)
{
    Show();
    WindowState = FormWindowState.Normal;
}

For adding right click context menu to your system tray icon, see here.