分享
 
 
 

Building a Robust Web Based Email Client (WebMail) Using the IP*Works! ADO.NET Data Provider(原文)

王朝c#·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Building a Robust Web Based Email Client (WebMail) Using the IP*Works! ADO.NET Data Provider

By Lance Robinson - Technical Evangelist, /n software.

In the fall of 2004, /n software introduced a first in the world of Internet development: Internet ADO.Net Providers. Some of the most commonly used objects from the popular IP*Works! toolkit were included a new product called IP*Works! ADO.Net Provider, which allows you to work with these protocols in a way that database developers are more familiar. To get all of the mail from your Inbox, you can SELECT * from INBOX. To read the latest RSS feed you can SELECT * from feed. To send an email, just insert a new row into the OUTBOX table.

In this article, I will talk about the features and use of the Provider, and along the way I'll create an IMAP and POP capable Webmail interface with a minimal amount of code. You can also download the full sample project here.

Overview Of The Provider

In the beginning, the protocols available are IMAP, POP, SMTP, NNTP, and RSS. Others will be added, like WebDAV (aka HTTPMail), LDAP, and more. IP*Works! ADO.Net Data Provider makes integration of Internet capabilities into applications quick and easy - without the need to become familiar with the inner-workings of the protocols themselves.

You are familiar with the DbConnection, DbDataAdapter, and DbCommand objects. Now let me introduce the IPWorksConnection, IPWorksDataAdapter, and IPWorksCommand objects. They work in the same familiar way, except with something a little bit different happening on the inside - updating from a server instead of a database. Here is a brief description of the different objects in the Provider. Later in this article I'll get into more specifics and show how to use each one.

IPWorksConnection

The IPWorksConnection object manages a connection to some server, whether it be an IMAP, POP, HTTP, SMTP, or NNTP server. The IPWorksConnection can be opened and closed explicitly, or the connection can be managed automatically (opened only when necessary) by the IPWorksDataAdapter.

IPWorksDataAdapter

The IPWorksDataAdapter is just like the DataAdapter you're used to. It will allow you to execute commands to populate a DataSet or DataTable. If a connection is not open, one will be created automatically in order to perform the necessary operation.

IPWorksCommand

The IPWorksCommand object represents a SQL command: SELECT, INSERT, DELETE, or UPDATE.

IPWorksCommandBuilder

The IPWorksCommandBuilder object will automatically generate INSERT, DELETE, and UPDATE commands for an IPWorksDataAdapter, given a defined SELECT command.

Connection

To get started, first I'll setup an IPWorksConnection, so I need to determine the connection string. To form the connection string, simply specify all of the properties of the connection as semi-colon separated values. One connection property is required in all instances of IPWorksConnection: protocol. The protocol connection property specifies the Internet protocol to use for this connection. Depending on the protocol, other connection properties will apply. For example, if I use the IMAP protocol, I'll need to specify mailserver, user, and password properties in order to connect. If I use the RSS protocol, I'll need a URL at least. Here are a few examples:

ipWorksConnection ipwConnection1 = new ipWorksConnection("protocol=imap;

mailserver=myserver; user=myusername; password=mypassword");

ipWorksConnection ipwConnection2 = new ipWorksConnection("protocol=rss;

url=http://slashdot.org/");

ipWorksConnection ipwConnection3 = new ipWorksConnection("protocol=nntp;

newsserver=msnews.microsoft.com");

ipWorksConnection ipwConnection4 = new ipWorksConnection("protocol=smtp;

mailserver=myserver");

ipWorksConnection ipwConnection5 = new ipWorksConnection("protocol=pop;

mailserver=myserver; user=myusername; password=mypassword");

For a full list of connection string properties, please consult the documentation for the IP*Works! ADO.Net Data Provider.

My goal is to create a webmail application - so my connection string will need to take values from a web form where the user can specify their username, password, etc. My connectionstring will look like so:

ipWorksConnection1 = new ipWorksConnection(String.Format("protocol={0};

mailserver={1}; user={2}; password={3};",

rblProtocol.SelectedItem.Value, txtServer.Text,

txtUser.Text, txtPass.Text));

Columns

For the next step, I'll create a data adapter, and configure its commands:

ipWorksDataAdapter ipworksDataAdapter1 = new ipWorksDataAdapter();

Each command will be associated with a connection that should be used when performing that command. For the webmail application, I need to be able to select using an IMAP connection, and a POP connection. Since my connection string allows the user to select whether to use IMAP or POP, I just need to make sure that my SELECT command will be valid for either. Each protocol has its own list of valid columns and tables.

For example, the POP protocol supports the following columns:

messageid

messagefrom

messagesubject

messagetext

messagedate

messagecc

messageheaders

messagereplyto

messagesize

messageto IMAP, being a much more featured protocol, supports many more columns. In addition to all of those provided by POP above, IMAP also provides the following columns:

messageflags

messagedeliverytime

messagesender

messagebcc

messageinreplyto

messagenetid

messagecontenttype

messagecontentencoding In order to make the same SELECT statement work for either protocol, I'll limit myself to only those columns supported by both protocols. Optionally, I could use different SELECT statements depending on the protocol, or I could use a SELECT * to get all of the columns.

ipWorksDataAdapter1.SelectCommand = new ipWorksCommand("SELECT messageid,

messagefrom, messagesubject, messagedate, messagesize FROM INBOX",

ipWorksConnection1);

Tables

The above SELECT command gets a few columns from the INBOX table. But what other tables are available? The available tables depend on the protocol. For POP, INBOX is the only table there. Similarly RSS has only one table (the feed itself). But for other protocols like IMAP and NNTP, there are multiple tables.

For the IMAP protocol, the table is simply the name of the IMAP mailbox (folder) you are interested in. So INBOX will normally work for both POP and IMAP, but again IMAP has additional abilities over POP, so if your IMAP INBOX had a sub folder called "ToDo", you would also have an "INBOX.ToDo" table.

A special table, the "Schema Table", can be used to get a table of table names. This would be useful with the IMAP protocol to get a list of all of the mailbox folders, or in NNTP to get a list of all of the groups available on a particular news server. To use the schema table, you would use the following SELECT statement:

"SELECT * FROM INFORMATION_SCHEMA.TABLES"

Filling a Data Table

For the purposes of this article, I will stick to using the INBOX table for both POP and IMAP. At this point, we're almost done with the basics. We have a connection, an adapter with a select command. All thats left is to fill a table with the results.

ipWorksConnection1 = new ipWorksConnection(String.Format("protocol={0};

mailserver={1}; user={2}; password={3};",

rblProtocol.SelectedItem.Value, txtServer.Text,

txtUser.Text, txtPass.Text));

ipWorksDataAdapter ipworksDataAdapter1 = new ipWorksDataAdapter();

ipWorksDataAdapter1.SelectCommand = new ipWorksCommand("SELECT messageid,

messagefrom, messagesubject, messagedate, messagesize FROM INBOX",

ipWorksConnection1);

System.Data.DataTable dataTable1 = new System.Data.DataTable();

ipWorksDataAdapter1.Fill(dataTable1);

Webmail - Login

In this webmail application - I don't have to think much about the network communications (IMAP, POP, SMTP), since I'll be using the IP*Works! ADO.Net Provider. I do have to think about session management, and data presentation. I need to provide a login mechanism, so I'll add a forms authentication section to the web.config:

<authentication mode="Forms">

<forms name="Login" loginUrl="login.aspx" />

</authentication>

Then I'll implement the login form (login.aspx). The login form will contain textBoxes for the user to enter the necessary user, password, and server information. It will also contain a radioButtonList to select either POP or IMAP, and of course a "login" button. When the login button is clicked, an ipWorksConnection object will be created using the user input.

When I use the ipWorksDataAdapter, it could automatically open a connection when it is required, rather than me keeping the connection open. However, since the user will be interacting over the lifetime of the session with postbacks, I'll maintain the connection by adding the ipWorksConnection instance to the session as soon as the user logs in, and manually opening it, to keep it open until the session ends or until the user logs out.

Finally, after all of this I'll RedirectFromLoginpage back to the URL where we came from (ie, default.aspx).

private void bLogin_Click(object sender, System.EventArgs e)

{

ipWorksConnection1 = new IPWorksConnection(String.Format("protocol={0};

mailserver={1}; user={2}; password={3};",

rblProtocol.SelectedItem.Value, txtServer.Text,

txtUser.Text, txtPass.Text));

Session.Clear();

try

{

ipWorksConnection1.Open();

Session.Add("IPWorksConnection", ipWorksConnection1);

FormsAuthentication.RedirectFromLoginPage(txtUser.Text, false);

}

catch (Exception ex)

{

lError.Text = ex.Message;

}

}

Browsing Emails

In default.aspx, I will use a datagrid to display the emails in the INBOX. In the Page_Load of this main page, I'll check to see if there is a dataView object in the session. If it is not there, I know that this is the first time this session has been logged into, and I will perform some steps to setup this session:

Create an ipWorksConnection instance and set it equal to the one in the session (which was created in login.aspx).

Create an ipWorksDataAdapter and SELECT command to select the message columns I want.

Fill a DataTable with the ipWorksDataAdapter.

Set a dataView object equal to the default view of the newly filled DataTable, and add the new dataView to the session. If the dataView already exists in the session, I know not to perform these steps, and instead just databind the datagrid.

private void Page_Load(object sender, System.EventArgs e)

{

DataView dv = (DataView)Session["MessageView"];

if (dv == null)

{

DataTable dt = new DataTable();

IPWorksConnection dataConnection =

(IPWorksConnection)Session["IPWorksConnection"];

IPWorksDataAdapter dataAdapter = new IPWorksDataAdapter();

dataAdapter.SelectCommand = new IPWorksCommand("SELECT messageid,

messagefrom, messagesubject, (DateTime)messagedate,

(int)messagesize FROM INBOX", dataConnection);

dataAdapter.Fill(dt);

dv = dt.DefaultView;

Session.Add("MessageView", dv);

}

dgMessages.DataSource = dv;

dgMessages.DataBind();

}

Presentation

At this point, the user has logged in and has a bound datagrid containing information about emails. Notice that the SELECT statement used only gets the messageid, messagefrom, messagesubject, messagedate, and messagesize. I did not select the messagetext. This is best because the contents of the actual message body could be huge (if say there were large attachments, or just many emails). I will instead only select the messagetext after a user has clicked on a particular message.

To create a way for a user to click on a message, I'll make some of the columns of the datagrid HyperLink Columns, formatted so that the hyperlink created includes the messageID of the message they've clicked on. For example, the Subject column text value will be bound to the "messagesubject" column, but its URL Field will be "messageid". The URL Format String of the column will be "read.aspx?uid={0}". This gives us the ability to make the text of this column into a link to read.aspx where the uid querystring variable value will come from the messageid column of the selected row. I could of course do the same with the From, Date, and/or Size columns if so desired.

Reading Emails

read.aspx will contain a form to display the contents of the email, as well as the important message headers like From, To, Subject, etc.

Inside the Page_Load, I'll simply SELECT the columns from before, in addition to the messagetext column. This time I'll use the WHERE clause to select only those columns from the row where the messageid is the one passed in the querystring, like so:

private void Page_Load(object sender, System.EventArgs e)

{

IPWorksConnection dataConnection =

(IPWorksConnection)Session["IPWorksConnection"];

IPWorksDataAdapter dataAdapter = new IPWorksDataAdapter();

dataAdapter.SelectCommand = new IPWorksCommand("SELECT messageid,

messagefrom, (String)messageto, messagesubject,

(DateTime)messagedate, (int)messagesize, messagetext FROM INBOX

WHERE messageid = " + Request.QueryString["uid"], dataConnection);

dataAdapter.Fill(dt);

this.DataBind();

}

In design time, I have bound the Text properties of the textBoxes on the form to their respective columns in the DataTable. In the databindings of the textBox named txtMessage, which I have placed on the form to contain the contents of the message body, I have set the custom binding expression of the Text property to dt.Rows[0]["messagetext"]. I'll also set the databindings of the other labels on this form (lSubject, lTo, lFrom, etc). This way, as soon as I call DataBind in the Page_Load, all of the control values will be populated automatically from the DataTable.

For the databinding of the lSize label, I'll bind it to a function called FormatSize (passing in the messagesize column value) instead. This way I can format the size text in Mb, Kb, or just bytes.

public static string FormatSize(object o)

{

int i = Convert.ToInt32(o);

string[] suffix = {"b","kb", "mb", "gb"};

int j = 0;

while (i > 1024 && j < 4)

{

i = i / 1024;

j++;

}

return (i + " " + suffix[j]);

}

Compose Mail

When sending an email, and thinking about that with respect to a DataTable - it follows naturally that to send a new mail, you should insert a new row.

One way to do this is to just create a new ipWorksCommand object, open the connection, and call the ipWorksCommand objects ExecuteReader method. To use the INSERT command, it is necessary to set the Parameters array of the command object to the values that match their respective column names from the INSERT command itself, like in the example below:

private void bSend_Click(object sender, System.EventArgs e)

{

IPWorksConnection dataConnection = new IPWorksConnection(

String.Format("protocol=smtp; mailserver={0};",

getConnParam("mailserver")));

try

{

IPWorksCommand ipWorksCommand1 = new IPWorksCommand("INSERT INTO outbox

(sendto, subject, messagetext, messagefrom)", dataConnection);

((IDataParameter)ipWorksCommand1.Parameters[0]).Value = txtTo.Text;

((IDataParameter)ipWorksCommand1.Parameters[1]).Value = txtSubj.Text;

((IDataParameter)ipWorksCommand1.Parameters[2]).Value = txtMsg.Text;

((IDataParameter)ipWorksCommand1.Parameters[3]).Value = txtFrom.Text;

dataConnection.Open();

ipWorksCommand1.ExecuteReader();

}

catch (Exception ex)

{

lError.Text = ex.Message;

}

finally

{

dataConnection.Close();

}

}

For more details on the Provider itself, please download the IP*Works! ADO.Net Provider, which provides demo code (both winforms and webforms) and complete documentation for all of the Provider capabilities and protocols.

We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at kb@nsoftware.com.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有