——Hello,获取未读邮件数!
但凡学习一种新的编程语言,书中的第一个范例都是经典的“Hello,World”。初次尝试使用WebDAV,也得找一个基本的例子试试,以对其有一个感性的认识,我的例子是用来获取未读邮件数目的,所以就有了如上的小标题。
首先在SDK中搜索WebDAV,找到一些范例,看了看,有一个Getting a List of Folders (WebDAV) ,和所要实现的功能有点贴近。不管三七二十一。运行一下代码吧:
1using System;
2using System.Net;
3using System.IO;
4using System.Text;
5using System.Xml;
6
7namespace 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,形式分别如下: 2using System.Net;
3using System.IO;
4using System.Text;
5using System.Xml;
6
7namespace 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
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" 。 + "<D:sql>SELECT \"DAV:displayname\",\"urn:schemas:httpmail:unreadcount\" FROM \"" + strRootURI + "\""
+ "WHERE \"DAV:ishidden\" = false AND \"DAV:isfolder\" = false"
+ "</D:sql></D:searchrequest>";
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文件的反馈,最终得到完整的查询未读邮件代码如下: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();
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;
}
{
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被组织为文件夹体系的形式。