90%使用WebDAV开发的Exchange邮件管理(二)
——Hello,获取未读邮件数!
但凡学习一种新的编程语言,书中的第一个范例都是经典的“Hello,World”。初次尝试使用WebDAV,也得找一个基本的例子试试,以对其有一个感性的认识,我的例子是用来获取未读邮件数目的,所以就有了如上的小标题。
首先在SDK中搜索WebDAV,找到一些范例,看了看,有一个Getting a List of Folders (WebDAV) ,和所要实现的功能有点贴近。不管三七二十一。运行一下代码吧:
1
using
System;
2
using
System.Net;
3
using
System.IO;
4
using
System.Text;
5
using
System.Xml;
6
7
namespace
ExchangeSDK.Snippets.CSharp
8

{
9
class GettingListOfFoldersWebDAV
10
{
11
[STAThread]
12
static void Main(string[] args)
13
{
14
// Variables.
15
System.Net.HttpWebRequest Request;
16
System.Net.WebResponse Response;
17
System.Net.CredentialCache MyCredentialCache;
18
string strRootURI = "http://server/TestStore/TestStoreFolder/";
19
string strUserName = "UserName";
20
string strPassword = "!Password";
21
string strDomain = "Domain";
22
string strQuery ="";
23
byte[] bytes = null;
24
System.IO.Stream RequestStream = null;
25
System.IO.Stream ResponseStream = null;
26
System.Xml.XmlTextReader XmlReader = null;
27
28
try
29
{
30
// Build the SQL query.
31
strQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >";
32
strQuery += "<D:sql>SELECT \"DAV:href\" FROM scope('hierarchical traversal of \"";
33
strQuery += strRootURI + "\"')</D:sql></D:searchrequest>";
34
35
// Create a new CredentialCache object and fill it with the network
36
// credentials required to access the server.
37
MyCredentialCache = new System.Net.CredentialCache();
38
MyCredentialCache.Add( new System.Uri(strRootURI),
39
"NTLM",
40
new System.Net.NetworkCredential(strUserName, strPassword, strDomain)
41
);
42
43
// Create the HttpWebRequest object.
44
Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strRootURI);
45
46
// Add the network credentials to the request.
47
Request.Credentials = MyCredentialCache;
48
49
// Specify the method.
50
Request.Method = "SEARCH";
51
52
// Encode the body using UTF-8.
53
bytes = Encoding.UTF8.GetBytes((string)strQuery);
54
55
// Set the content header length. This must be
56
// done before writing data to the request stream.
57
Request.ContentLength = bytes.Length;
58
59
// Get a reference to the request stream.
60
RequestStream = Request.GetRequestStream();
61
62
// Write the SQL query to the request stream.
63
RequestStream.Write(bytes, 0, bytes.Length);
64
65
// Close the Stream object to release the connection
66
// for further use.
67
RequestStream.Close();
68
69
// Set the content type header.
70
Request.ContentType = "text/xml";
71
72
// Send the SEARCH method request and get the
73
// response from the server.
74
Response = (HttpWebResponse)Request.GetResponse();
75
76
// Get the XML response stream.
77
ResponseStream = Response.GetResponseStream();
78
79
// Create the XmlTextReader object from the XML
80
// response stream.
81
XmlReader = new XmlTextReader(ResponseStream);
82
83
// Read through the XML response, node by node.
84
while(XmlReader.Read())
85
{
86
// Look for the opening DAV:href node. The DAV: namespace is
87
//typically assigned the a: prefix in the XML response body.
88
if(XmlReader.Name == "a:href")
89
{
90
// Advance the reader to the text node.
91
XmlReader.Read();
92
93
// Display the value of the DAV:href text node.
94
Console.WriteLine("Value: " + XmlReader.Value);
95
Console.WriteLine("");
96
97
//Advance the reader to the closing DAV:href node.
98
XmlReader.Read();
99
}
100
}
101
102
// Clean up.
103
XmlReader.Close();
104
ResponseStream.Close();
105
Response.Close();
106
107
}
108
catch(Exception ex)
109
{
110
// Catch any exceptions. Any error codes from the SEARCH
111
// method request on the server will be caught here, also.
112
Console.WriteLine(ex.Message);
113
}
114
}
115
}
116
}
117
118
31~33行构造了Web Storage System SQL查询的XML,去头去尾,对我们比较关键就是SELECT "DAV:href" FROM scope('hierarchical traversal of "+strRootURI+')。SQL查询相信大家都会的了。“DAV:href”是DAV属性,表示条目的URL。其他的还包括:DAV:displayname(条目通用名称)、DAV:isfolder(表示这个条目是否文件夹),DAV:则是Web Storage System(WSS)的名称空间了,当然还有如下的名称空间:“http://schemas.microsoft.com/exchange/”,“urn-schemas:calendar:”,“Urn:schemas:httpmail:”等等。各项具体属性可以在Exchange SDK中根据索引查找。scope是用于指定查询的位置和深度。而strRootURI则是要查询条目的路径。在Exchange中的每个条目都可以通过URL访问,其所有编程任务也是以URL为基础的。URL分为文件URL和HTTP URL,形式分别如下:
file://./backofficestorage/<domain-name>/<public -folder-tree-name>/<path>
http://<server-name>/<virtual-directory>/<virtual-path>
因此,我们可以拼接查询未读邮件数的查询语句
strQuery
=
"
<?xml version=\
"
1.0
\
"
?><D:searchrequest xmlns:D = \
"
DAV:\
"
>
"
+
"
<D:sql>SELECT \
"
DAV:displayname\
"
,\
"
urn:schemas:httpmail:unreadcount\
"
FROM \
""
+ strRootURI +
"
\
""
+
"
WHERE \
"
DAV:ishidden\
"
= false AND \
"
DAV:isfolder\
"
= false
"
+
"
</D:sql></D:searchrequest>
"
;
其中strRootURI="http://servername/exchagne/useralias" 。
37~41行创建了用于访问资源的NTLM的凭据。60行以后则是通过将服务器返回XML解析,通过查找XML节点中的属性得到查询结果。在这里,我实在搞不清楚XML节点属性名称有哪些,且在不同的方法下,形如a:displayname的前缀到底是指DAV:还是其他的名称空间,就干脆把后半段的方法改写了,直接将XML输出到文件中,方便查看。(顺便也学习了一下System.IO)
//
Get the XML response stream.
ResponseStream
=
Response.GetResponseStream();


System.IO.StreamReader reader
=
new
StreamReader(ResponseStream);
string
xml
=
reader.ReadToEnd();
FileInfo textfile
=
new
FileInfo(
@"
C:\1.xml
"
);
StreamWriter outStream
=
textfile.CreateText();
outStream.Write(xml);
outStream.Close();
最后,根据各种不同查询的尝试,及得到的XML文件的反馈,最终得到完整的查询未读邮件代码如下:
private
int
GetUnReadMailCount()

{
string url=ConfigurationSettings.AppSettings["ExchangeServer"];
System.Net.HttpWebRequest Request;
System.Net.WebResponse Response;
System.Net.CredentialCache MyCredentialCache;
string strRootURI = url+"/"+User.Identity.Name;
string strUserName = User.Identity.Name;
string strPassword = DAL.Data.UserModel.SelectByUserId(User.Identity.Name).Password.Trim();
string strDomain = ConfigurationSettings.AppSettings["ExchangeDomain"];
string strQuery ="";
byte[] bytes = null;
System.IO.Stream RequestStream = null;
System.IO.Stream ResponseStream = null;
XmlDocument ResponseXmlDoc = null;
XmlNodeList HrefNodes= null;
XmlNodeList SizeNodes= null;
int count=0;
try

{
// Build the SQL query.
strQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >"
+ "<D:sql>SELECT \"DAV:displayname\",\"urn:schemas:httpmail:unreadcount\" FROM \"" + strRootURI + "\""
// +"where \"DAV:contentclass\"=\"urn:schemas:httpmail:read \""
// + "WHERE \"DAV:ishidden\" = false AND \"DAV:isfolder\" = false"
+ "</D:sql></D:searchrequest>";

// Create a new CredentialCache object and fill it with the network
// credentials required to access the server.
MyCredentialCache = new System.Net.CredentialCache();
MyCredentialCache.Add( new System.Uri(strRootURI),
"NTLM",
new System.Net.NetworkCredential(strUserName, strPassword, strDomain)
);

// Create the HttpWebRequest object.
Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strRootURI);

// Add the network credentials to the request.
Request.Credentials = MyCredentialCache;

// Specify the method.
Request.Method = "SEARCH";

// Encode the body using UTF-8.
bytes = Encoding.UTF8.GetBytes((string)strQuery);

// Set the content header length. This must be
// done before writing data to the request stream.
Request.ContentLength = bytes.Length;

// Get a reference to the request stream.
RequestStream = Request.GetRequestStream();

// Write the SQL query to the request stream.
RequestStream.Write(bytes, 0, bytes.Length);

// Close the Stream object to release the connection
// for further use.
RequestStream.Close();

// Set the content type header.
Request.ContentType = "text/xml";

// Send the SEARCH method request and get the
// response from the server.
Response = (HttpWebResponse)Request.GetResponse();
// Get the XML response stream.
ResponseStream = Response.GetResponseStream();
// Create the XmlDocument object from the XML response stream.
ResponseXmlDoc = new XmlDocument();
ResponseXmlDoc.Load(ResponseStream);
HrefNodes = ResponseXmlDoc.GetElementsByTagName("a:displayname");
SizeNodes = ResponseXmlDoc.GetElementsByTagName("d:unreadcount");
for(int i=0;i<HrefNodes.Count;i++)

{
if(HrefNodes[i].InnerText=="收件箱")
count=int.Parse(SizeNodes[i].InnerText);
}
ResponseStream.Close();
Response.Close();
}
catch(Exception)

{
// Catch any exceptions. Any error codes from the SEARCH
// method request on the server will be caught here, also.
return -1;
}
return count;
}
名词解释:
Web Storage System:是一项数据库技术,随着Windows2000操作系统引入的,可用于存储、共享和管理很多类型的数据。WSS被组织为文件夹体系的形式。