Outlook里发出去的mail都可以设Follow Up flag和Due time,这个功能蛮实用……如何编程实现?
有人在Newsgroup里贴了段CDOEx的code:
http://groups.google.com/groups?q=outlook+follow+up&hl=zh-CN&lr=&c2coff=1&selm=eApolE7pEHA.2864%40TK2MSFTNGP12.phx.gbl&rnum=5%20&hl=zh-CN&lr=&c2coff=1&selm=eApolE7pEHA.2864%40TK2MSFTNGP12.phx.gbl&rnum=5
CDOEx只有装了Exchange Server的机器上才有……
其实只要给System.Web.Mail.MailMessage设置相应的Header就可以了:
message.Headers.Add("X-Message-Flag", "Follow up");
message.Headers.Add("Reply-By", "Tue, 26 Oct 2004 01:00:00 +0900");
思归的“动态控件的状态问题”很有意思:
http://blog.joycode.com/saucer/archive/2004/10/20/35927.aspx
希望写下这样的logic对大家做troubleshooting有所帮助。我们可以这样分析这个问题:
第一步,简化一下Page。建一个新的ASP.Net Web Application,用下面的code:
private void Page_Load(object sender, System.EventArgs e)
{
DropDownList ddlDynamic = new DropDownList();
ddlDynamic.ID = "ddlDynamic";
HtmlForm form1 = (HtmlForm)this.FindControl("Form1");
if (!IsPostBack)
{
ddlDynamic.Items.Add("Before");
}
form1.Controls.Add(ddlDynamic);
if (!IsPostBack)
{
ddlDynamic.Items.Add("After");
}
}
在Page上扔个Button,以便可以PostBack。运行后Postback的结果,“Before” item没被保留,“After”被保留了。问题被isolate:问题不在于DropDownList或者ListCollection对于view state的处理出问题,而是特定一个ListItem view state的处理有异。
现在有目标了,接下来看ListItem source code:
internal object SaveViewState()
{
if (this.misc.Get(2) && this.misc.Get(3))
{
return new Pair(this.Text, this.Value);
}
if (this.misc.Get(2))
{
return this.Text;
}
if (this.misc.Get(3))
{
return new Pair(null, this.Value);
}
return null;
}
可以看到只有misc.Get(2)或misc.Get(3)符合一定条件才存view state,鉴于misc是private member,继续在ListItem的code里找什么会影响misc.Get(2) or misc.Get(3)的值,结果如下:
internal bool Dirty
{
set
{
this.misc.Set(2, value);
this.misc.Set(3, value);
}
}
找到了唯一的可能,在Reflector里看Set方法的Callee Graph,找到System.Web.UI.WebControls.ListItemCollection.Add(ListItem):Void方法。接续看source code:
public void Add(ListItem item)
{
this.listItems.Add(item);
if (this.marked)
{
item.Dirty = true;
}
}
这里有一个private bool marked flag。继续在ListItemCollection里找:
internal void TrackViewState()
{
this.marked = true;
for (int num1 = 0; num1 < this.Count; num1++)
{
this[num1].TrackViewState();
}
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
好了,看来这个方法就是关键了……由于是Interface的方法,我们可以尝试一下在Page2里调用它:
((IStateManager)(ddlDynamic.Items)).TrackViewState();
if (!IsPostBack)
{
for (int i=1; i <=3; i++)
ddlDynamic.Items.Add(new ListItem(i.ToString(), i.ToString()));
}
form1.Controls.Add(ddlDynamic);
确实是起作用了……鉴于如此,我们可以猜测ControlCollection.Add一定调用了System.Web.UI.WebControls.ListItemCollection.TrackViewState()这个方法。要证明这点容易多了……
用WinDbg,在System.Web.UI.WebControls.ListItemCollection.TrackViewState()方法上设个断点。Call Stack如下:
019cf8b0 06538fd0 [DEFAULT] [hasThis] Void System.Web.UI.WebControls.ListItemCollection.TrackViewState()
019cf8b4 06538fbe [DEFAULT] [hasThis] Void System.Web.UI.WebControls.ListControl.TrackViewState()
019cf8bc 06538e53 [DEFAULT] [hasThis] Void System.Web.UI.Control.InitRecursive(Class System.Web.UI.Control)
019cf8d8 0653758a [DEFAULT] [hasThis] Void System.Web.UI.Control.AddedControl(Class System.Web.UI.Control,I4)
019cf8f4 06537462 [DEFAULT] [hasThis] Void System.Web.UI.ControlCollection.Add(Class System.Web.UI.Control)
019cf904 063c06fc [DEFAULT] [hasThis] Void WebApplication37.WebForm3.Page_Load(Object,Class System.EventArgs)
at [+0x13c] [+0x8c] c:\inetpub\wwwroot\webapplication37\webform3.aspx.cs:36
019cf944 065391a4 [DEFAULT] [hasThis] Void System.Web.UI.Control.OnLoad(Class System.EventArgs)
…
好了……一切都明了……
在ASP.Net Web Service中,一个很常见的做法就是给WebServiceAttribute和WebMethodAttribute的Description属性作修饰,例如注明方法接受的参数含义,返回值之类。如此一来,当Web Service的用户通过IE访问ASMX页面时,可以对Web Service的用途得到一个很直观的了解。
在“著名”的.Net Framework 1.1 Service Pack 1出来之前,我们对WebMethodAttribute的Description使用HTML Tag对于Helper Page是有作用的。如下面的Description将产生如图的效果:
[WebMethod(Description=@"<font color=red>Test Description</font>")]
public string HelloWorld()
{
return "Hello World";
}
不幸的是,这样一个有用的feature在Service Pack 1中被“无意”的破坏了。
HTML Tag被HtmlEncode了……
很多用户对这样的design change很不满……对于这个问题,我们暂时可以通过自定义Web Service Helper Page的方法解决:
1. 把下面这个文件复制到Web Service自己的目录(e.g. C:\Inetpub\wwwroot\WebService1\)
C:\windows\microsoft.net\framework\v1.1.4322\CONFIG\DefaultWsdlHelpGenerator.aspx
2. 修改Web.Config,加入下面的element:
<configuration>
<system.web>
<webServices>
<wsdlHelpGenerator href="DefaultWsdlHelpGenerator.aspx"/>
</webServices>
</system.web>
</configuration>
<wsdlHelpGenerator> Element
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/gngrfwsdlhelpgenerator.asp
3. 打开步骤1中复制的DefaultWsdlHelpGenerator.aspx:
搜索:
<%#DataBinder.Eval(Container.DataItem, "Value.Documentation")%>
替换为:
<%#Server.HtmlDecode(DataBinder.Eval(Container.DataItem, "Value.Documentation").ToString())%>
搜索:
<%#ServiceDocumentation%>
替换为:
<%#Server.HtmlDecode(ServiceDocumentation)%>
这样一来,我们又可以在Description中使用HTML tag了……
办公室里冷冷清清的,整个team只有5个人驻守着……似乎US和EMEA的customer都理解我们在过国庆,没什么Case进来……
离开座位去break room(注:不是厕所)给杯子加水时看到我们的CPR和TL正在那里聊着,在探讨有什么好办法自动批量地关case,CPR建议直接修改SQL Server数据库,而TL觉得录Macro比较好……一会又说到了在Sql连接上设断点和NetMon,看来Asia这边也没什么活干……
窗外就是繁华喧闹的徐家汇……昨天晚上下班时,楼下还有露天晚会,精美的小食,音响里放着backstreet boy的歌,走不出五步便会见到一个让人眼睛一亮的MM……(也或许我的品位比较低)
好像完全是两个世界,楼里的人们都是埋头苦干的工作狂,典型的特征便是脚上旧款的凉鞋,头发凌乱,没刮胡子,穿着公司发的t shirt几天不换……楼外的则是俊男靓女们,衣着前卫光鲜,装备着最新的MD、手机……似乎我们这群楼里的土包子,和这个小资之地有些不格格不入……
活干完了,看了一会Jeff的PRGAPPS4,六点到了便准备下班了,真是难得,迟疑了几分钟,有点不好意思走的感觉……看了一下MSN,楼上的姐姐似乎活还没做完,可怜的姐姐,四年的国庆就没休过一天假,我和她道了别,一路离开时经过CPR和TL们的cubicle,他们居然都已经不见踪影了……
五分钟后,徐家汇美罗城前的时尚人群中,一个胡子拉碴的青年匆匆穿过……