Pages

Advertisement

Showing posts with label Ajax. Show all posts
Showing posts with label Ajax. Show all posts

Monday, February 11, 2008

Hiding whole web page & displaying image instead of it during Ajax processing ..

When a WebGrid triggers an AJAX request, there is a delay until the request completes and is displayed on the client. In some cases, the programmer will want to hide or otherwise disable input on the WebGrid until this processing finishes. This article shows how to display an image or other "Loading" message while these requests process.

Additional Information

You can use the WebGrid’s BeforeXmlHttpRequest and AfterXmlHttpResponse client-side events to hide the grid and display a loading message.
Note that these events are only raised when an AJAX request is created by the WebGrid itself, not when processing custom AJAX requests.
This approach only works in NetAdvantage 2006 Volume 1 and later. In previous versions, the WebGrid is non-responsive during the BeforeXmlHttpRequest event.

Step-By-Step Example

The following functions hide the WebGrid and display an image when an AJAX request from the WebGrid starts, and hides the image and displays the WebGrid when the AJAX response finishes processing. In this example, both "grd" and "loadinggif" are the IDs of DIV elements which respectively contain the WebGrid and the loading image.
In JavaScript:

function grid_BeforeXmlHttpRequest(gridName,type)
{
    document.getElementById("grd").style.visibility = 'hidden';
    document.getElementById("loadinggif").style.visibility = 'visible';
}
function UltraWebGrid1_AfterXmlHttpResponseProcessed(gridName)
{
    document.getElementById("grd").style.visibility = 'visible';
    document.getElementById("loadinggif").style.visibility = 'hidden';
}

When both these DIV elements are positioned identically, it appears as though the image replaces the grid for the period it takes to process the AJAX request and response .

Sample Downloads

kb_displayloadingimageduringxmlrequests_cs.zip

Demonstrates replacing a WebGrid with a loading image while processing an AJAX request

Fade in Animation in Asp.net

Animation Using Ajax Toolkit

While the AJAX Control Toolkit is focused primarily on providing great AJAX controls and extenders, it also includes a powerful animation framework which you can use to add awesome visual effects on your pages. This walkthrough describes the basics of using this framework to create declarative animations.

The animations are implemented in JavaScript as an ASP.NET AJAX class hierarchy and can be invoked via JavaScript by calling the Animation's play function. This is very useful when writing to the animation classes from code, but writing complex animations ends up being time consuming and error prone. To make it very easy to use the animation framework without writing any JavaScript, the Toolkit provides the ability to declare animations via XML markup.

Extenders with animation support, like the AnimationExtender, expose various events, like OnClick, that can be associated with a generic XML animation declaration. Within this declaration, you specify which types of animation effects you would like to occur. For example, to make a Panel with ID = "MyPanel" disappear from the page when clicked, you could add an AnimationExtender like this:

<ajaxToolkit:AnimationExtender id="MyExtender"
runat="server" TargetControlID="MyPanel">
<Animations>
<OnClick>
<FadeOut Duration=".5" Fps="20" />
</OnClick>
</Animations>
</ajaxToolkit:AnimationExtender>



Let's take a closer look at exactly what's going on in the XML above. The AnimationExtender is used to indicate that we want to make our animation target the control with ID = "MyPanel". The Animations section is where all generic animations are declared. OnClick indicates that when the target is clicked we will play the animation nested inside it. Finally, FadeOut defines the specific animation that will be played and sets the values of its Duration and Fps properties.



That's what this simple code does animation does ...



U can try implementing Ajax toolkit in ur Asp.net Application for much more pretty animation ...

Monday, November 12, 2007

Creating Rounded Corners With Ajax In C#

Learn how to create rounded corners with Ajax

read more | digg story

Thursday, August 30, 2007

Redirecting Configuration with a Custom Provider

A common issue with Web applications is that applications are managed in various environments. Aside from development environments, you may have test servers, staging servers, live production servers, and potentially warm backup servers. If you store selected Web configuration sections in a central location (such as a central file share or a central configuration database), you have a more manageable solution and, depending on how you implement this, a more secure solution as well.

With ASP.NET 2.0, you can write a custom protected configuration provider that determines information about the current server and the currently running application. A custom provider can reach out to a central repository of configuration information and return the appropriate configuration information. When you have a group of individuals who manage the configuration data for live production servers, it is probably much easier to have such a group manage updates to a single database as opposed to synchronizing configuration files across multiple machines.

Implementing a custom protected configuration provider requires you to derive from the System.Configuration.ProtectedConfigurationProvider class. As you can see, the class signature is very basic:

    public abstract class ProtectedConfigurationProvider : ProviderBase
{
public abstract XmlNode Encrypt(XmlNode node);
public abstract XmlNode Decrypt(XmlNode encryptedNode);
}

For a sample provider that demonstrates redirecting configuration to a database, you implement only the Decrypt method because this is the method used at runtime to return configuration data to the caller. If you store more complex data inside your protected configuration format, implementing the Encrypt method will make life easier when storing configuration sections in a custom data store.

First look at what a "protected" configuration section in a web.config file will look like using the custom provider:

<membership configProtectionProvider="CustomDatabaseProvider">

<EncryptedData>
<sectionInfo name="membership" />
</EncryptedData>
</membership>

The <membership /> section references a protected configuration provider. Instead of the actual definition of the <membership /> section though, the <EncryptedData /> element is common to all protected configuration sections. However, what is enclosed within this element is determined by each protected configuration provider. In this case, to keep the sample provider very simple, the protected data consists of only a single element: a <sectionInfo /> element.

Unlike protected configuration providers that blindly encrypt and decrypt data, this sample provider needs to know the actual configuration section that is being requested. The custom provider needs to know what section is really being requested because its purpose is to store configuration data in a database for any arbitrary configuration section. The name attribute within the <sectionInfo /> element gives the custom provider the necessary information. Although this is just a basic example of what you can place with <EncryptedData />, you can encapsulate any kind of complex data your configuration provider may need within the XML.

The custom provider will store configuration sections in a database, keying off of a combination of the application's virtual path and the configuration section. The database schema that follows shows the table structure for storing this:

create table ConfigurationData (
ApplicationName nvarchar(256) NOT NULL,
SectionName nvarchar(150) NOT NULL,
SectionData ntext
)
go
alter table ConfigurationData
add constraint PKConfigurationData
PRIMARY KEY (ApplicationName,SectionName)
Go

Retrieving this information will similarly be very basic with just a single stored procedure pulling back the SectionData column that contains the raw text of the requested configuration section:

create procedure RetrieveConfigurationSection
@pApplicationName nvarchar(256),
@pSectionName nvarchar(256)
as
select SectionData
from ConfigurationData
where ApplicationName = @pApplicationName
and SectionName = @pSectionName
go

Because the custom protected configuration provider needs to connect to a database, a connection string must be included within the definition of the provider.

<configProtectedData>
<providers>
<add name="CustomDatabaseProvider"
type="CustomProviders.DatabaseProtectedConfigProvider,
CustomProviders"
connectionStringName="ConfigurationDatabase"
/>
</providers>
</configProtectedData>

The sample provider configuration looks similar to the configurations for the RSA and DPAPI protected configuration providers that ship in the 2.0 Framework. In this case, however, the custom provider requires a connectionStringName element so that it knows which database and database server to connect to. The value of this attribute is simply a reference to a named connection string in the <connectionStrings /> section, as shown here:

<connectionStrings>
<add name="ConfigurationDatabase"
connectionString="server=.;Integrated _
Security=true;database=CustomProtectedConfiguration"/>
</connectionStrings>

When creating your own custom providers, you have the freedom to place any provider-specific information you deem necessary in the provider's <add /> element.

Now that you have seen the data structure and configuration related information, take a look at the code for the custom provider. Because a protected configuration provider ultimately derives from System.Configuration.Provider.ProviderBase, the custom provider can override portions of ProviderBase as well as ProtectedConfigurationProvider. The custom provider overrides ProviderBase.Initialize so that the provider can retrieve the connection string from configuration:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Configuration.Provider;
using System.Web;
using System.Web.Hosting;
using System.Web.Configuration;
using System.Xml;
namespace CustomProviders
{
public class
DatabaseProtectedConfigProvider : ProtectedConfigurationProvider
{
private string connectionString;
public DatabaseProtectedConfigProvider() { }
public override void Initialize(string name,
System.Collections.Specialized.NameValueCollection config)
{
string connectionStringName = config["connectionStringName"];
if (String.IsNullOrEmpty(connectionStringName))
throw new ProviderException("You must specify " +
"connectionStringName in the provider configuration");
connectionString =
WebConfigurationManager.ConnectionStrings[connectionStringName] _
.ConnectionString;
if (String.IsNullOrEmpty(connectionString))
throw new ProviderException("The connection string " +
"could not be found in <connectionString />.");
config.Remove("connectionStringName");
base.Initialize(name, config);
}
//Remainder of provider implementation
}
}

The processing inside of the Initialize method performs a few sanity checks to ensure that the connectionStringName attribute was specified in the provider's <add /> element, and that furthermore the name actually points at a valid connection string. After the connection string is obtained from the ConnectionStrings collection, it is cached internally in a private variable.

Of course, the interesting part of the provider is its implementation of the Decrypt method:

public override XmlNode Decrypt(XmlNode encryptedNode)
{
//Application name
string applicationName = HostingEnvironment.ApplicationVirtualPath;
XmlNode xn =
encryptedNode.SelectSingleNode("/EncryptedData/sectionInfo");
//Determine the configuration section to retrieve from the database
string sectionName = xn.Attributes["name"].Value;
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd =
new SqlCommand("RetrieveConfigurationSection", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter p1 =
new SqlParameter("@pApplicationName", applicationName);
SqlParameter p2 = new SqlParameter("@pSectionName", sectionName);
cmd.Parameters.AddRange(new SqlParameter[] { p1, p2 });
conn.Open();
string rawConfigText = (string)cmd.ExecuteScalar();
conn.Close();
//Convert the string information from the database into an XmlNode
XmlDocument xd = new XmlDocument();
xd.LoadXml(rawConfigText);
return xd.DocumentElement;
}
}

The Decrypt method's purpose is take information about the current application and information available from the <sectionInfo /> element and use it to retrieve the correct configuration data from the database.

The provider determines the correct application name by using the System.Web.Hosting.HostingEnvironment class to determine the current application's virtual path. The name of the configuration section to retrieve is determined by parsing the <EncryptedData /> section to get to the name attribute of the custom <sectionInfo /> element. With these pieces of data the provider connects to the database using the connection string supplied by the provider's configuration section.

The configuration data stored in the database is just the raw XML fragment for a given configuration section. For this example, which stores a <membership /> section in the database, the database table just contains the text of the section's definition taken from machine.config stored in an ntext field in SQL Server (i.e. just copy the <membership /> section from machine.config and insert it into the sample database table's SectionData column). Because protected configuration providers work in terms of XmlNode instances, and not raw strings, the provider converts the raw text in the database back into an XmlDocument, which can then be subsequently returned as an XmlNode instance. Because the data in the database is well-formed XML, the provider can just return the DocumentElement for the XmlDocument.

What is really powerful about custom protected configuration providers is that the Framework's configuration system is oblivious to how the configuration information is obtained. For example the following configuration code works unchanged even though the <membership /> section is now being retrieved from a database.

MembershipSection ms =
(MembershipSection)ConfigurationManager.GetSection(
"system.web/membership");

This is exactly what you would want from protected configuration. Nothing in the application code changes despite the fact that now the configuration section is stored remotely in a database as opposed to locally on the file system.

One caveat to keep in mind with custom protected configuration providers is that after the data is physically stored outside of a configuration file, ASP.NET is no longer able to automatically trigger an app-domain restart whenever the configuration data changes. With the built-in RSA and DPAPI configuration providers, this isn't an issue because the encrypted text is still stored in web.config and machine.config files. ASP.NET listens for change notifications and triggers an app-domain restart in the event the encrypted sections in any of these files change.

However, ASP.NET does not have a facility to trigger changes based on protected configuration data stored in other locations. For this reason, if you do write a custom provider along the lines of the sample provider, you need to incorporate operational procedures that force app-domains to recycle whenever you update configuration data stored in locations other than the standard file-based configuration files.

ASP.NET Tip: Persistent Logins Under ASP.NET 2.0

For some sites, allowing users to "save their passwords" is not a major security concern, and it speeds up the user's ability to interact with the site. Assuming your site security can allow for persistent logins, this feature also is easy to provide. Under ASP.NET 1.x, the built-in FormsAuthentication enabled this very easily: it simply specified a True argument when the user ID was saved using FormsAuthentication.RedirectFromLoginPage.

However, ASP.NET 2.0 has changed how the forms authentication tickets work. Simply using the same method with a True argument won't actually persist the cookie. If you want to have a significantly longer timeout for your forms authentication ticket, the code in this tip performs the same steps as the built-in FormsAuthentication methods but gives you more control over the specifics of how it works.

For starters, you'll need to add a block to your Web.config to enable FormsAuthentication:

<authentication mode="Forms">
<forms name="MyApplication" loginUrl="/login.aspx" />
</authentication>

If you want to switch into SSL mode for the login, you can specify the full URL, including the "https://" prefix in the loginUrl parameter. Also add an authorization section to lock down your entire site or virtual directory:

<authorization>
<deny users="?"/>
</authorization>

The code in your login form, after you've done your own validation to see if the user can log into your application, looks like this:

FormsAuthenticationTicket t =
new FormsAuthenticationTicket(1, userID,
DateTime.Now, DateTime.Now.AddMonths(3),
chkSave.Checked, userID.ToString(),
FormsAuthentication.FormsCookiePath);

string encTicket = FormsAuthentication.Encrypt(t);

HttpCookie c = new HttpCookie(FormsAuthentication.FormsCookieName,
encTicket);

if (chkSave.Checked)
c.Expires = DateTime.Now.AddMonths(3);

Response.Cookies.Add(c);

In this example, the userID variable is the value that will be available if you look at User.Identity.Name after the user has logged in. On my page, chkSave is a check box that lets the user indicate whether or not to save the password. That true/false value is passed into the FormsAuthenticationTicket constructor to mark the ticket as persistent or not. After you get the ticket back, encrypt it and then put it into the designated cookie.

If the user has chosen to save the cookie, the cookie needs to be assigned an expiration date. In this case, I'm using three months as the expiration timeframe.

ASP.NET Tip: Testing Web Sites with HttpWebRequest

As a third type of verification, I check certain Web sites to make sure that the server is up, running, and not generating any Web errors. In some cases, Microsoft's Web server produces a Web page even if it has an error. If you don't check the content of that page, it might look as though the server is actually up and running. As a result, I also have a type of check that simulates a browser visiting the page and reading the content. I use the HttpWebRequest and HttpWebResponse classes, as well as some other network I/O code. The following code loops through some good addresses and one bad address to read the TITLE tag from each page:

ArrayList addrs = new ArrayList();
addrs.Add("http://iis02.northcomp.com");
addrs.Add("http://iis03.northcomp.com");
addrs.Add("http://ncs01.northcomp.com");
addrs.Add("http://blahblahblah.northcomp.com");

foreach (string s in addrs)
{
try
{

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(s);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream st = resp.GetResponseStream();
StreamReader sr = new StreamReader(st);
string buffer = sr.ReadToEnd();
int startPos, endPos;
startPos = buffer.IndexOf("&lt;title>",
StringComparison.CurrentCultureIgnoreCase) + 7;
endPos = buffer.IndexOf("&lt;/title>",
StringComparison.CurrentCultureIgnoreCase);

string title = buffer.Substring(startPos, endPos - startPos);
Console.WriteLine("Response code from {0}: {1}", s,
resp.StatusCode);
Console.WriteLine("Page title: {0}", title);
sr.Close();
st.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error connecting to {0}.", s);
Console.WriteLine("Exception:");
Console.WriteLine(ex.ToString());
}

}
Console.WriteLine("Web site check completed.");

 


The basic construction of the code is similar to my other tips covering Ping and the TcpClient class; however, reading data is somewhat different. I first create an HttpWebRequest by using the WebRequest Create method. I immediately get the HttpWebResponse from the request and start reading the data. I do this by using a regular StreamReader class, and the results are dumped into a string. I then look at the string for the TITLE tag and the end of that tag, and then pull the results into a separate string. The assumption here is that if I see the appropriate TITLE tag, the page is functioning properly. In addition, the StatusCode will display as OK for the first three addresses. The fourth generates an error and is trapped appropriately.

You can modify this code to look for any string in the page. For instance, you might want to verify that the last line or HTML tag on the Web page is present, which would imply that the page completed without any errors.

Consuming Membership and Profile Services via ASP.NET AJAX

ASP.NET 2.0 introduced various application services—such as Membership, Roles, and Profiles—that eliminate a lot of coding that was required to provide the same functionality. However, these services are part of ASP.NET's server-side framework, which could pose a challenge when you use ASP.NET AJAX to consume the services from client-side JavaScript code. Fortunately, ASP.NET AJAX provides an out-of-the-box solution to this problem. This article explains how to use this solution in C# with Visual Studio.

Sample Scenario

uppose you are developing a new web site and want to implement forms authentication. The web site will have a user registration page, a login page, and one or more pages that you must secure. The user registration and login pages use ASP.NET AJAX for an enhanced user experience. Also, the site must capture details such as birth date and address at the time of registration. This information is to be stored in the Profile of the user.

To develop a web site that fulfills all the above requirements, begin by creating a new ASP.NET AJAX-enabled web site with C# (see Figure 1).

Figure 1. Creating a New ASP.NET AJAX-enabled Web Site

Configuring the Web Site

Before you begin coding, configure the web site for forms authentication as well as Membership and Profile services. Open a web.config file in your Visual Studio IDE and add the following markup inside the connectionStrings section:

<connectionStrings>
<add name="connstr"
connectionString="data source=.\sqlexpress;
initial catalog=northwind;
integrated security=true"

providerName="System.Data.SqlClient"/>
</connectionStrings>

You specified a database connection string named connstr that points to a Northwind database. Make sure to change the connection string to match your development environment. I assume that your database is configured for application services using the aspnet_regsql.exe tool. You will use this connection string while configuring membership and profile providers.

Now, add the following markup inside the system.web section:


<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx"></forms>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
<membership defaultProvider="p1">
<providers>
<add name="p1"
connectionStringName="connstr"
type="System.Web.Security.SqlMembershipProvider"
requiresQuestionAndAnswer="false"/>
</providers>
</membership>
<profile defaultProvider="p2">
<providers>
<add name="p2"
connectionStringName="connstr"
type="System.Web.Profile.SqlProfileProvider"/>
</providers>
<properties>
<add name="FullName"/>
<add name="DOB" type="System.DateTime"/>
<group name="Address">
<add name="Street"/>
<add name="Country"/>
<add name="PostalCode"/>
</group>
</properties>
</profile>

Review the above markup carefully, and you'll notice the following:


  • The authentication section sets the authentication mode to Forms. The forms tag sets the URL of the login page by using the loginUrl attribute.
  • The authorization section disables anonymous users by setting the users attribute of the deny tag to "?".
  • The membership section configures a membership provider named p1. (You can change this any name you choose.)
  • The connectionStringName attribute specifies the database that will be used for storing membership information.
  • The type attribute indicates the class that will act as the membership provider. You use the built-in SQL Membership provider called SqlMembershipProvider.
  • The requiresQuestionAndAnswer attribute indicates that you do not intend to accept a secret question and answer from the end user at the time of registration.
  • The profile section configures a profile provider named p2 and various profile properties. The significance of the connectionStringname and type attributes is same as for the membership section. Note, however, that this time the type is a SqlProfileProvider class. The properties section defines profile properties and groups.
  • You defined two simple properties called FullName and DOB and a property group called Address. The Address group further contains three properties: street, country, and postalcode. The DOB property is of type DateTime; therefore, its type attribute is set to System.DateTime.

Now that you have configured your web site for using forms authentication and membership services, it's time to expose Membership and Profile services to the client-side AJAX code. The web.config file will have a pre-defined section called webServices. By default, all its content is commented. You need to un-comment and modify it so that it looks as shown below:


<webServices>
<authenticationService enabled="true"
requireSSL="false"/>
<profileService enabled="true"
readAccessProperties="FullName,DOB,Address.Street,Address.Country,
Address.PostalCode"

writeAccessProperties="FullName,DOB,Address.Street,Address.Country,
Address.PostalCode"
/>
</webServices>

The authenticationService tag is used to expose forms authentication and membership services to AJAX code. The enabled attribute governs whether AJAX code can avail membership services. The requireSSL attribute indicates whether the authentication is happening over SSL. Similarly, the Profile service is exposed to AJAX code by using the profileService tag. The readAccessProperties and writeAccessProperties attributes of the profileService tag specify the profile properties that are readable and writable, respectively. Notice how the grouped properties are specified using the dot (.) notion. If you do not include a specific profile property in these attributes, it will not be accessible to the client code.

Applying forms authentication ensures that all the forms of the web site except the login page are secured. However, you want your registration page to be unsecured because new users will need to access it. Do this by adding a location section in the web.config file as shown below:


<location path="register.aspx">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>

The path attribute of the location tag specifies a virtual path of a file or folder that is to be configured. It then allows access to all the users using the authorization section and allow tag.

This completes the web site configuration. Now, you will move on to develop the required web forms.

User Registration

First of all, you will create the user registration page. Add a new web form named Registration.aspx. Drag and drop a ScriptManager control from the toolbox (see Figure 2).

 




Figure 2. Drag and Drop a ScriptManager Control

Also, drag and drop an UpdatePanel and UpdateProgress control on the web form. The UpdatePanel control represents a part of the total web form that can be refreshed without causing a post back of the entire form. The UpdateProgress control is used to display a progress message while the UpdatePanel is being refreshed.

Drag and drop a Label control inside the UpdateProgress control and set its Text property to "Please wait...". Also, set its AssociatedUpdatePanelID property to the ID of the UpdatePanel control. The AssociatedUpdatePanelID property links the UpdateProgress with an UpdatePanel.

Add a table into the UpdatePanel and design it as shown in Figure 3.


Figure 3. Design for Table in the UpdatePanel

The first column of the table contains Label controls that act as prompts for the textboxes. The second column of the table contains TextBox controls. Each TextBox control is validated by using a RequiredFieldValidator control. The TextMode property of the password and confirm password textboxes is set to Password. Similarly, the TextMode property of the street address textbox is set to MultiLine.

There is a Button called "Check Availability" that the end user can use to check the availability of a user ID. The "Check Availability" button will make an AJAX call to the web form to decide whether the specified user ID is available for registration. Set the OnClientClick property of the "Check Availability" button to "return CheckAvailability();" (CheckAvailability() is a client-side JavaScript function that you will write later). This function will call a web method to decide whether the user ID is available for registration. Finally, the Register button will create the user in the system with the help of the Membership features. The Label at the bottom is used for displaying success or error messages.

Now, go in the code behind of the Register.aspx and add a static web method called CheckAvailability. The following is the complete code of the method:


[WebMethod]
public static bool CheckAvailability(string uid)
{
MembershipUser user = Membership.GetUser(uid);
if (user == null)
{
return true;
}
else
{
return false;
}
}

You might be wondering why you added a web method inside a web form. Remember that you have a "Check Availability" button that is supposed to check whether the specified user ID is available for registration. You will be making an AJAX call to do that. ASP.NET AJAX allows you to call web methods defined in web forms via an object called PageMethods. Therefore, you marked the CheckAvailability() method with a [WebMethod] attribute. Note that you must refer to the System.Web.dll and import the System.Web.Services namespace to use the [WebMethod] attribute.

The CheckAvailability() method accepts a user ID and returns true if that ID is available for registration. Inside, it calls the GetUser() method of the Membership object. The GetUser() method returns an instance of the MembershipUser class that represents the specified user. If it returns null, it indicates that the specified user doesn't exist and accordingly true or false is returned to the caller.

When the user clicks the Register button, you need to add user details in the membership and profile tables. Use the Membership and Profile objects to do this BECAUSE ASP.NET AJAX doesn't allow you to create users from client-side code. The following code shows the Click event handler of the Register button:

protected void Button1_Click(object sender, EventArgs e)
{
try
{
MembershipUser user = Membership.CreateUser
(TextBox2.Text, TextBox3.Text, TextBox5.Text);
ProfileCommon pc = Profile.GetProfile(user.UserName);
pc.FullName = TextBox1.Text;
pc.DOB = DateTime.Parse(TextBox6.Text);
pc.Address.Street = TextBox7.Text;
pc.Address.Country = TextBox8.Text;
pc.Address.PostalCode = TextBox9.Text;
pc.Save();
lblMsg.Text = "User created successfully!";
}
catch (Exception ex)
{
lblMsg.Text = ex.Message;
}
}

You call the CreateUser() method of the Membership object to create the user and pass user ID, password, and email. The CreateUser() method returns an instance of MembershipUser representing the newly created user. At this point, the user is not authenticated, so you cannot set the user's profile directly via the Profile object. Instead, you call the GetProfile() method of the Profile object. The GetProfile() method returns an instance of the ProfileCommon class. Through this instance, you set various profile properties. Once all the profile properties are saved, the Save() method of the ProfileCommon class is called to save profile information to the underlying database. A success message is then displayed in a Label control. Any exceptions during the registration process are captured BY using try-catch blocks and an error message is displayed in a Label control.

Now, code the client-side CheckAvailability() function. Switch to the HTML source view of the Register.aspx and add a script block in the HEAD section of the page. Then, add the following functions in the script block:

function CheckAvailability()
{
var uid=document.getElementById('TextBox2').value;
if(uid=="")
{
alert('Please enter user ID!');
return false;
}
PageMethods.CheckAvailability(uid,OnComplete);
return false;
}

function OnComplete(result)
{
var lblMsg=document.getElementById('lblMsg');
if(result)
{
lblMsg.innerText="The ID is available!";
}
else
{
lblMsg.innerText="The ID is unavailable!";
}
}

The CheckAvailability() function retrieves the user ID textbox using the getElementById() method of the HTML DOM, which accepts the ID of an element and returns a reference to it. The code checks whether the user ID is empty and, if so, displays an error message. It then calls the CheckAvailability() web method via the PageMethods object and passes the specified user ID to it. The PageMethods object is a built-in object provided by ASP.NET AJAX that allows you to call web methods defined in web forms. The second parameter of the CheckAvailability() call is nothing but the name of another JavaScript function (OnComplete in this example) that gets called after the web method call completes. You may find this mechanism a bit odd, but remember that ASP.NET AJAX communication is always asynchronous. The OnComplete() function receives the return value of the web method as a result parameter. It then simply displays a success or error message in a Label control. Note that the CheckAvailability() JavaScript function returns false so that there won't be any post back.

This completes your registration page. To test it, run the Register.aspx in the browser and try creating new users. Also, check how the "Check Availability" button works. Figure 4 shows a sample run of the web form.


(
Full Size Image)

Figure 4. Sample Run of the Web Form

Developing a Login Page

Now that users can register themselves with the web site, you need to provide a facility that enables them to log in and access various pages. To do so, add a new web form called Login.aspx to the web site. Remember that you have set the loginUrl attribute of the forms tag to Login.aspx. Drag and drop a ScriptManager control on it and design the login page as shown in Figure 5 by assembling various controls.


Figure 5. The Login Page Design

As you can see, the login page consists of textboxes for entering a user ID and password. The "Remember Me" checkbox allows you to preserve your logged-in status even after closing the browser window. The TextMode property of the password textbox is set to Password. Further, the OnClientClick property of the Login button is set to "return BeginAuthenticateUser();". BeginAuthenticateUser() is a JavaScript function that uses the ASP.NET AJAX authentication service to authenticate the user. The following is the BeginAuthenticateUser() function:

function BeginAuthenticateUser()
{
var uid;
var pwd;
var isPersistent;
uid=document.getElementById('TextBox1').value;
pwd=document.getElementById('TextBox2').value;
isPersistent=document.getElementById('CheckBox1').checked;
Sys.Services.AuthenticationService.login
(uid,pwd,isPersistent,null,null,
EndAuthenticateUser,OnError,uid);
return false;
}

The BeginAuthenticateUser() JavaScript function retrieves the user IDs and passwords entered in their respective textboxes. It also retrieves the status of the "Remember Me" checkbox. ASP.NET AJAX provides a built-n class called AuthenticationService that resides in the Sys.Services namespace. Remember that the Sys.Services namespace is defined by the client-side framework of ASP.NET AJAX. The AuthenticationService class offers two methods: login() and logout(). The code above used the login() method, which takes in all eight parameters. Their significance is listed below:

Parameter
Significance

1
A user ID

2
A password

3
A boolean value indicating whether an authentication cookie will be persistent

4
The web page where the user should be redirect after a successful login

5
Reserved for future use

6
A callback function that will be called after a successful login (EndAuthenticateUser in this example)

7
A callback function that will be called in case a login attempt fails (OnError in this example)

8
A custom value that is passed to the callback functions

If the user is successfully authenticated, the EndAuthenticateUser function will be called. The following is the EndAuthenticateUser function:

function EndAuthenticateUser(result,userContext,methodName)
{
if(result)
{
window.location='default.aspx';
}
else
{
alert("Unable to login! Please check user id and password!!");
}
}

The EndAuthenticateUser() function takes three parameters: the result of the login operation, the user context that you passed earlier in the eighth parameter of the login() method, and the method name. Inside, it checks whether the result is true (in other words, the user is successfully authenticated) and, if so, it sets the location property of the windows object to default.aspx. This way, the user is redirected to the default page after a successful login attempt. If there is any error, an error message is displayed using the alert() function.

The OnError() function is called whenever an error occurs when calling the authentication service. This function is shown below:

function OnError(result,userContext,methodName)
{
alert(result.get_message());
}

The function simply displays an error message to the user. The result parameter received is actually an object and has a method called get_message() that returns a descriptive error message.

This completes the login page.

---

Implementing Logout Functionality

Add another web form called Default.aspx. This web form will allow users to logout and manage their profiles. Firstly, you will implement logout functionality. Drag and drop a ScriptManager control on the Default.aspx and design the web form as shown in Figure 6.

 




Figure 6. The Web Form Design

The web form consists of a couple of Label controls to display a welcome message to the user. The Logout button allows the user to delete the authentication cookie, thus logging him out. The OnClientClick property of the Login button is set to "return BeginLogOut();" (BeginLogout() is a JavaScript function that you will write later). The "Show My Profile" button toggles the profile panel. The OnClientClick property of the "Show My Profile" button is set to "return BeginProfileLoad();" (you will create the BeginProfileLoad() function later). The profile panel consists of a Panel control containing textboxes to display and show profile property values. It also contains the "Save Profile" button for saving changes made to the profile values. The OnClientClick property of the "Save Profile" button is set to "return BeginSaveProfile();" (the BeginSaveProfile() function will be coded later).

In the Page_Load event of the web form, you set the welcome label to the ID of the user. The following code shows how:

protected void Page_Load(object sender, EventArgs e)
{
Label4.Text = Membership.GetUser().UserName;
}

The code simply retrieves the user name of the current user and assigns it to the label. Note that the GetUser() method of the Membership object returns an object of type MembershipUser. The UserName property of the MembershipUser class is then called. You need to display the user name from the server-side code because ASP.NET AJAX doesn't provide any way to retrieve it via client-side code.

Now, switch to the HTML source view of Default.aspx and write the BeginLogOut() and EndLogOut() JavaScript functions as shown below:

function BeginLogOut()
{
Sys.Services.AuthenticationService.logout
(null,EndLogout,OnError,null);
return false;
}

function EndLogout(result)
{
//nothing here
}

The BeginLogOut() function again uses the AuthenticationService class. This time, it calls the logout() method of AuthenticationService. The logout() method takes the following four parameters:


As before, the BeginLogOut() function returns false so that there is no post back. The EndLogOut() function doesn't perform any action in this example.

Reading Profile Properties

Initially, the profile panel should be hidden from the end user. This is done in the pageLoad() JavaScript function. Note that the pageLoad() function is called by the ASP.NET AJAX framework when the page loads in the browser. You can think of it as a client-side counterpart of server-side Page_Load event. The pageLoad() function is shown below:

function pageLoad()
{
var panel3=document.getElementById('Panel3');
panel3.style.visibility="hidden";
}

The pageLoad() function simply sets the visibility property of the style object to hidden, thus hiding the profile panel.

When you click on the "Show My Profile" button, the profile panel needs to be displayed with the profile property values filled in. The BeginProfileLoad() function does this job:

function BeginProfileLoad()
{
if(event.srcElement.value=="Show my profile")
{
var panel3=document.getElementById('Panel3');
panel3.style.visibility="visible";
event.srcElement.value="Hide my profile";
Sys.Services.ProfileService.load
(null,EndProfileLoad,OnProfileFailed, null);
}
else
{
var panel3=document.getElementById('Panel3');
panel3.style.visibility="hidden";
event.srcElement.value="Show my profile";
}
return false;
}

The BeginProfileLoad() function toggles visibility of the profile panel. If the profile panel is to be displayed, then you must populate various textboxes with profile values. The ASP.NET AJAX framework provides a class called ProfileService that allows you to work with profile properties. The load() method of the ProfileService class loads profile property values. The load() method takes four parameters, which do the following:

Parameter
Significance

1
An array of property names that are to be loaded. If you have too many profile properties, then it makes sense to load the ones that you really want to use. This will improve the performance of your page.

2
A callback function that will be called when the load operation is completed

3
A callback function that will be called if the load operation fails

4
Custom context information, if any

Once the profile is loaded the EndProfileLoad() function is called. This is the EndProfileLoad():

function EndProfileLoad(numProperties, userContext, methodName)
{
document.getElementById('TextBox3').value =
Sys.Services.ProfileService.properties.FullName;
document.getElementById('TextBox4').value =
Sys.Services.ProfileService.properties.DOB;
document.getElementById('TextBox5').value =
Sys.Services.ProfileService.properties.Address.Street;
document.getElementById('TextBox6').value =
Sys.Services.ProfileService.properties.Address.Country;
document.getElementById('TextBox7').value =
Sys.Services.ProfileService.properties.Address.PostalCode;
}

The EndProfileLoad() function receives three parameters: number of properties that are loaded, context information that is supplied to the load() function, and method name. It then populates the textboxes with the profile property values. The ProfileService class exposes profile properties via the properties collection. Remember that only the properties specified in the readAccessProperties attribute of the profileService tag of web.config are exposed. The properties and groups are accessed with the familiar dot (.) notion.

Modifying Profile Properties

When profile property values are displayed in various textboxes, the user can change them and click on the "Save Profile" button. Clicking on the "Save Profile" button calls the BeginSaveProfile() function, which is shown here:

function BeginSaveProfile()
{
Sys.Services.ProfileService.properties.FullName=
document.getElementById('TextBox3').value;
Sys.Services.ProfileService.properties.DOB=
document.getElementById('TextBox4').value;
Sys.Services.ProfileService.properties.Address.Street=
document.getElementById('TextBox5').value;
Sys.Services.ProfileService.properties.Address.Country=
document.getElementById('TextBox6').value;
Sys.Services.ProfileService.properties.Address.PostalCode=
document.getElementById('TextBox7').value;
Sys.Services.ProfileService.save
(null,EndSaveProfile,OnProfileFailed,null);
return false;
}

The code again uses the ProfileService class and its properties collection to assign new values. Once all the profile properties are set, it calls the save() method of the ProfileService class. The save() method takes the same four parameters as the load() method (in other words, the array of properties to write, the callback function to be called after successful saving, the callback function to be called after unsuccessful save, and custom context information). The EndSaveProfile() function simply displays a message box to the user:

function EndSaveProfile(numProperties, userContext, methodName)
{
alert('Your profile is saved successfully!');
}

That's it! You just completed your AJAX-driven membership and profile pages. You now can log in to the web site and test the profile features. Figure 7 shows a sample run of the default.aspx.


Figure 7. A Sample Run of the Default.aspx

Consuming Membership and Profile Features from the Client Side

ASP.NET AJAX provides a handy way to consume membership and profile features. To consume these features, you need to enable them by using the authenticationService and profileService tags of web.config. Once enabled, you can use the AuthenticationService and ProfileService classes to consume them.

Server-Based AJAX for Enterprise Applications

AJAX has been breaking new ground almost every day. With over 150 AJAX frameworks, there are plenty of options to choose from and, one might say, there are too many. Most of the AJAX frameworks provide you with browser extension libraries that will help you utilize the browser and interact with the server in a more productive way. What they are trying to do in most cases is to provide larger building blocks to achieve your goals by abstracting the calls to the browser API and to the server.

The last is a significant improvement over the plain vanilla browser coding, but you are still writing your application in a very poor environment with very poor developer tools. Your end result is a JavaScript application vulnerable in terms of security, manageability, and your IP protection.

When you are writing enterprise applications that are actually business apps, the security, productivity, manageability, and IP issues of AJAX development are becoming a real turn off. Applying SSL to your application can only bring you so far because you are still exposing server services for the client to consume through plain old JavaScript and running business logic that can easily be hijacked by using a simple script debugger. Also, the different AJAX frameworks still, in most cases, force you to write your application mainly in client-side JavaScript code that has its limits and productivity issues. The most obvious issue regarding JavaScript UI programming is the lack of design time capabilities, but that is only the tip of the iceberg.

Server-based AJAX is a recent addition to the AJAX frameworks arena; it basically changes the way you think about AJAX applications. It introduces a concept of server-based computing for web applications where your code runs entirely on the server and reflects changes to the client. This concept is used widely in remote desktop or application streaming software, but has not been available until now for web developers.

The server-based AJAX concept provides great benefits for developers in terms of productivity, manageability, and usability. Currently, the only available framework implementing full server-based AJAX is Visual WebGui, which provides full WinForms, such as API and design time capabilities for developing web applications. Although it sounds very much like Google's GWT, it is not because it does not serialize the application code to JavaScript but rather uses it at runtime on the server and reflects the UI to the client. This means that you have what can be called an "empty client" that is managed entirely by the server. Client events are sent to the server that, in turn, return its update commands to the client, reflecting changes made to the UI on the server. This process can be optimized in various scenarios explicitly to reduce the amount of server callbacks and bandwidth consumption, making the end result as responsive as standard AJAX applications.

There are some downsides to the server-based AJAX concept, mainly in terms of scalability, because you are utilizing a server session to run your application, but when applied to enterprise applications, rather then Amazon-sized sites, you get a very nice ROI that you would not get in any other architecture. In terms of responsiveness and performance, one would think that this concept lacks, but the opposite is the case; the server uses fewer resources in terms of CPU and IO because it does not have to receive/return large blobs and, most importantly, does not need to construct and deconstruct the application classes on every request. Also, as said before, there are many optimizations that can be applied to reduce server callbacks and bandwidth consumption.

The server-based AJAX concepts may just be the solution for enterprise AJAX applications because it provides these applications with the best of both worlds. Having a responsive, rich AJAX UI that behaves pretty much like desktop UI, but still maintaining the productivity, IP protection, and security of running the application on server side provides a compelling offering for enterprises.

Saturday, July 14, 2007

Another example to send Email via Asp.Net

E-mail is one of the most common and reliable methods of communication for both personal and business purposes. It also plays an important role in each and every Web site. This role will be in the type of automated e-mails from the server after posting information from a form. You may have noticed these types of e-mails while registering on a site. As soon as you post the form, the server will send an e-mail asking you to confirm either your registration or with the information you entered. If you have to confirm the registration, the server will send you a long URL that you have to click to proceed further with the registration process. A classic example of this functionality is ASP.NET forums. As soon as you register, you will be e-mailed a random password. You will also get e-mails after your post has been accepted by a moderator or if somebody replies to your post. If you are wondering that this is a server magic—it is not. The whole process is made possible with the help of server-side programming languages such as ASP and ASP.NET.

Classic ASP provided a component named CDONTS that a developer should use intelligently to provide e-mail functionality on his or her applications. But this component lacked major functionalities. You can easily send an e-mail, but the process is very difficult for sending e-mails with attachments, HTML versions, and so forth. Almost all server-side languages provide some sort of solution for achieving these tasks. But, ASP.NET simplified the work of developers with the introduction of a special .NET namespace called System.Web.Mail. Moreover, it is very tedious to upload a file to a server with ASP. You have to depend upon third-party components. ASP.NET ships with a cute built-in uploading capability with which your users can easily upload their files. They can also send the file as an attachment along with their e-mails. In this article, you will learn how to send different types of e-mails with ASP.NET.

To send e-mails, you should require access to a server with .NET Framework and SMTP enabled on it. SMTP stands for Simple Mail Transfer Protocol and e-mails are sent using this protocol. If you don't have a paid server space, you can register for a free ASP.NET hosting account at a site such as http://europe.webmatrixhosting.net/.

The .NET Framework supplies a SMTP class that enables you to send a simple e-mail message. If you have to send an e-mail with added functionalities, you have to make use of the MailMessage class. With the help of this class, you can insert attachments, set priorities, and much more, very easily. You can also send HTML e-mail using this class.

Sending a Simple E-Mail Message

To send an e-mail with a simple text message, you have to use the Send() method of SMTP class. The syntax of the Send() method is shown in Listing 1.1 and an example is shown in Listing 1.2:

Listing 1.1

[Visual C# .NET]

SmtpMail.Send("FROM","TO","SUBJECT","MESSAGE BODY");

[Visual Basic .NET]

SmtpMail.Send("FROM","TO","SUBJECT","MESSAGE BODY")

Listing 1.2

[Visual C# .NET]

SmtpMail.Send("info@mydomain.com","hello@hello.com","Thank You",
"We look forward to working with you again in the
future");

[Visual Basic .NET]

SmtpMail.Send("info@mydomain.com","hello@hello.com","Thank You", _
"We look forward to working with you again in the _
future")

You can place the above code either on the form's Load() event or in a button control.

Sending E-Mail Messages Using WebForm Controls

The main problem with the code given in Listing 1.2 is that you have to change the parameter values each time for sending different mail messages. To solve this problem, you should build a User Interface using the required WebForm controls, as shown in Figure 1.


Figure 1: The User Interface

As you can see, the above User Interface is made up of two text boxes, one multiline text box, and a button. I have also applied ASP.NET validation controls to the above GUI to avoid errors. For more information regarding the usage of validation controls, refer to my previous articles Performing Validations with ASP.NET — Part 1 and Performing Validations with ASP.NET — Part 2.

Instead of supplying all parameters in the Send() method, you can define properties and their corresponding values separately by creating an instance of the MailMessage class. With the help of this class, you can easily add attachments, set priorities, BCC, CC values, and much more. Table 1, given at the end of this article, shows a list of properties of the MailMessage class. Add the code given in Listing 1.3 by double-clicking the button captioned Submit:

Listing 1.3

[Visual C# .NET]

MailMessage objEmail          = new MailMessage();
objEmail.To = txtTo.Text;
objEmail.From = txtFrom.Text;
objEmail.Cc = txtCc.Text;
objEmail.Subject = "Test Email";
objEmail.Body = txtName.Text + ", " +
txtComments.Text;
objEmail.Priority = MailPriority.High;
//SmtpMail.SmtpServer = "localhost";
try{
SmtpMail.Send(objEmail);
Response.Write("Your Email has been sent sucessfully -
Thank You");
}
catch (Exception exc){
Response.Write("Send failure: " + exc.ToString());
}

[Visual Basic .NET]

  Dim objEmail as New MailMessage()
objEmail.To = txtTo.Text
objEmail.From = txtFrom.Text
objEmail.Cc = txtCc.Text
objEmail.Subject = "Test Email"
objEmail.Body = txtName.Text & ", " &txtComments.Text
objEmail.Priority = MailPriority.High
'SmtpMail.SmtpServer = "localhost"
try
SmtpMail.Send(EMail)
Response.Write(Your E-mail has been sent sucessfully - _
Thank You)

catch exc as Exception
Response.Write("Send failure: " + exc.ToString())
End Try

Note: If you are using your local system (Server = localhost) instead of a real live server, you should properly enable relying on the Internet Information Server (IIS).

When you execute the above code, the server not only displays a confirmation message but also sends an e-mail to the address mentioned in the To and Cc text boxes with the information you entered in the respective fields. It is not necessary for you to enter a Cc address, but it is shown here as part of the explanation. Further, the e-mail will be sent with the highest priority.

Table 1: MailMessage class properties

Property
Description

Attachments
Used for sending e-mails with attachments

From
Sender's e-mail address

To
Recipient's e-mail address

Cc
Recipient's e-mail address (Carbon Copy)

Bcc
Recipient's e-mail address (Blind Carbon Copy)

Body
Text of the e-mail message

BodyFormat
Specifies the format of an e-mail message (Possible Values: Text, Html)

Priority
Specifies the priority of an e-mail message (Possible Values: High, Low, and Normal)

Subject
Denotes the subject of an e-mail message

Headers
Denotes a collection of acceptable headers (Example: Reply-To)

BodyEncoding
Specifies the method of encoding an e-mail message (Possible Values: Base64 and UUEncode)

Sending HTML E-Mail Messages

If you would like to send the above e-mail in HTML Format, simply add the code given below to the above listing:

[Visual C# .NET]

objEmail.BodyFormat = MailFormat.Html;

[Visual Basic .NET]

objEmail.BodyFormat = MailFormat.Html

You can download the complete source code by clicking here.

Fast and Simple Mobile Access to Pocket Outlook Data

For a new developer tool function to be useful, it must be easy to implement, provide a significant benefit to the task at hand, and perform well. As a Windows Mobile developer, I believe the addition of managed classes for accessing and interacting with the data contained within Pocket Outlook (contacts, tasks, and appointments) meets all these criteria.

 

Developers who build .NET Compact Framework applications for Pocket PCs and Smartphones must all-too-often provide access to Pocket Outlook data. Previously, this meant using P/Invoke to either call native DLLs' functionalities or access internal data stores directly, or acquiring third-party managed code libraries. The result was increased development time and/or increased cost. With the new managed classes, C# and VB .NET Compact Framework developers can quickly gain access to this often-vital information and modify it (if necessary) without additional products.

The ABCs of Pocket Outlook Access

To utilize the new managed classes for Pocket Outlook, you need the following:

The new managed classes are not available for Windows Mobile 2003 Second Edition or earlier devices. You can, however, use Visual Studio 2005 to develop either .NET Compact Framework 1.0 or 2.0 projects that take advantage of the new managed classes.

You need to perform only a few basic steps to access Pocket Outlook data from a Smart Device project in Visual Studio 2005:

  1. Add references to required assemblies.
  2. Create an instance variable for a Pocket Outlook session.
  3. Access the needed collection of information (appointments, tasks, contacts).
  4. Work with the collection.
  5. Dispose the Pocket Outlook session object.

By performing these steps, you can gain access to any information you need.

Adding References to Your Project

To gain access to the new managed classes for Pocket Outlook, you need to add references to two .NET Compact Framework assemblies to your project. You'll find Microsoft.WindowsMobile.dll and Microsoft.WindowsMobile.PocketOutlook.dll in the Add References dialog, as shown in Figure 1.

Figure 1: Necessary References for Pocket Outlook Access

From a coding perspective, you access classes only in the Microsoft.WindowsMobile.PocketOutlook namespace. The other assembly is required, however, because the PocketOutlook assembly has dependencies on the first assembly for interfaces.

The PocketOutlook namespace contains a vast array of classes. Figure 2 shows just some of the available classes you'll see in the Visual Studio Object Browser.

Figure 2: PocketOutlook Namespace Viewed in the Object Browser

Going forward, this article points out some of the more relevant classes to get you started.

Creating an OutlookSession Instance

For developers who have worked with the object model for Microsoft Outlook on the desktop, the Pocket Outlook object model should seem quite familiar. The object hierarchy and tasks associated with programming against this object model are very similar. One example of this is the initial programming step for accessing Pocket Outlook data: creating an instance of an Outlook session.

In the sample project, I created a single form containing a ListView control (named lvAppt) that I programmatically populate with Appointment information. Figure 3 shows this screen in design mode.

Figure 3: Appointments Screen in Design Mode

As you can see, I set up the ListView control into three columns for relevant appointment information. I use a ListViewItem object and its associated SubItems collection to populate this information.

To hold an instance of the PocketOutlook session, I created an instance variable in my form class named AppSession:

private OutlookSession AppSession;

For this demonstration, I added code to the form's constructor (immediately following the call to the InitializeComponent method that creates the instance of the PocketOutlook session):

public Form1()
{
InitializeComponent();

//Create an instance of the Pocket Outlook session
AppSession = new OutlookSession();

Accessing the Appointments Collection

The PocketOutlook object hierarchy provides simple access to collections of information. The collections are exposed through properties representing the folders containing associated items. They are accessed directly from the OutlookSession object. The most commonly used of these objects are the following:


Each of these categories also has associated collection objects in the forms of AppointmentCollection, TaskCollection, and ContactCollection. In my sample project, I need to access appointments. So, I created an instance variable to hold an Appointment collection (named AppAppts). To access the Appointments collection, I use the following code:

//Capture the AppointmentCollection into a variable
AppAppts = AppSession.Appointments.Items;

Once you have the collection, you can access individual items using the Appointment object. In my project, I used this object in conjunction with a foreach loop to walk through the collection:

//We now iterate through the entire collection with a foreach,
//using an appointment object...
foreach (Appointment appt in AppAppts)
{
//Create a ListViewItem object
lviAppt = new ListViewItem ();

//Add the appointment date to the ListViewItem, and the time
//and subject to ListViewItem SubItems
lviAppt.Text = appt.Start.ToShortDateString();

lviAppt.SubItems.Add(appt.Start.ToShortTimeString());
lviAppt.SubItems.Add(appt.Subject);

//Add the ListViewItem to the ListView
lvAppts.Items.Add(lviAppt);
}

Note: The Task object for tasks and the Contact object for contacts can be used for this same purpose. Each of these objects provides programmatic access to all of the properties that are stored locally in the Pocket Outlook data stores. Figure 4 shows some of the properties associated with a Task object in the Object Browser.



Figure 4: Task Object Properties Displayed in the Object Browser

 


Disposing the Pocket Outlook Session Object

When you have completed use of the Pocket Outlook data, you should dispose the session object to free up resources. To do this, simply call the Dispose method of the session instance:

//Don't forget to close the PocketOutlook session when done!
AppSession.Dispose();

Running the Completed Project

 


he completed code for this sample project looks like the following:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Microsoft.WindowsMobile;
using Microsoft.WindowsMobile.PocketOutlook;

namespace OutlookMobileAPI
{
public partial class Form1 : Form
{
private OutlookSession AppSession;
private AppointmentCollection AppAppts;
private ListViewItem lviAppt;

public Form1()
{
InitializeComponent();

//Create an instance of the Pocket Outlook session
AppSession = new OutlookSession();

//Capture the AppointmentCollection into a variable
AppAppts = AppSession.Appointments.Items;

//We now iterate through the entire collection with a
//foreach, using an appointment object...
foreach (Appointment appt in AppAppts)
{
//Create a ListViewItem object
lviAppt = new ListViewItem();

//Add the appointment date to the ListViewItem, and
//the time and subject to ListViewItem SubItems
lviAppt.Text = appt.Start.ToShortDateString();
lviAppt.SubItems.Add(
appt.Start.ToShortTimeString()
);
lviAppt.SubItems.Add(appt.Subject);

//Add the ListViewItem to the ListView
lvAppts.Items.Add(lviAppt);
}

//Don't forget to close the PocketOutlook session
//when done!
AppSession.Dispose();

}
}
}

Before running the application in the emulator, you will need to add some data for appointments. You can do this easily by first bringing up the emulator using the Tools -> Connect to Device. option from the Visual Studio menu. I added three appointments to the emulator, as shown in Figure 5.


Figure 5: Test Data for the Sample Project

When the project is compiled and run in the emulator, it displays the three appointments, as shown in Figure 6.


Figure 6: Sample Data Dsiplayed in the Sample Application

As you can see, very little code is required to expose Pocket Outlook data to your .NET Compact Framework application!

Using the ChooseContactDialog Class

Another useful class in the new managed APIs is the ChooseContactDialog class (also referred to as the Contact Picker). Simply put, use this class in your application to bring up a Contact selection dialog and return the selected contact to your application. This can be extremely useful when you want to quickly provide your user with a means of selecting contact information.

To use the Contact Picker, you will need to add a reference to the Microsoft.WindowsMobile.Forms.dll assembly to your project (this is where the ChooseContactDialog class resides.). To demonstrate this functionality, I created a simple Smart Device project consisting of one form. The form contains holders for information in the form of TextBox and Label objects, and it has one button (see Figure 7).


Figure 7: Contact Picker Demonstration Form

When the user chooses the Select. button in the application, the Contact Picker is displayed and the user can choose a contact. Once selected, the application populates information from the associated Contact object into the fields for display.

To accomplish this, I added the following code to the button's Click event handler to display the Contact Picker:

//Create the instance of the Contact Picker and disable the
//ability to create new contacts from it.
ChooseContactDialog appContactDialog = new ChooseContactDialog();
appContactDialog.HideNew = true;
appContactDialog.ShowDialog();

I then created logic (surrounded by a try...catch block in case the user backs out of the process) to capture the selected contact into an instance variable (named AppContact) and assign the form fields:

try
{
appContact = appContactDialog.SelectedContact;

textBox1.Text = appContact.FileAs;
lblMobile.Text = appContact.MobileTelephoneNumber.ToString();
lblPhone.Text = appContact.HomeTelephoneNumber;
}
catch
{
MessageBox.Show("No contact selected");
}

Before running this code in the emulator, I once again need to make sure that I have some contact records available. I used the Connect to Device. menu option in Visual Studio 2005 to populate two records.

When I run the application in the emulator and tap on the button, the Contact Picker appears (see Figure 8).


Figure 8: Contact Picker Displayed

Selecting a contact then returns control to my application, resulting in the contact data being displayed (see Figure 9).


Figure 9: Contact Information Displayed in the Application

Once again, the total amount of coding required for this functionality was very minimal. The following is the complete code for the form class:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.WindowsMobile;
using Microsoft.WindowsMobile.Forms;
using Microsoft.WindowsMobile.PocketOutlook;

namespace ContactPickerDemo
{
public partial class Form1 : Form
{
//Contact object instance
private Contact appContact;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
//Create the instance of the Contact Picker and disable
//the ability to create new contacts from it.
ChooseContactDialog appContactDialog =
new ChooseContactDialog();
appContactDialog.HideNew = true;
appContactDialog.ShowDialog();

try
{
//Assign the selected contact to a Contact object
appContact = appContactDialog.SelectedContact;

//Populate the form fields
textBox1.Text = appContact.FileAs;
lblMobile.Text =
appContact.MobileTelephoneNumber.ToString();
lblPhone.Text = appContact.HomeTelephoneNumber;
}
catch
{
//If the user backed out, display a message.
MessageBox.Show("No contact selected");
}
}
}
}
 

Give Users an Invaluable Resource

For applications that require either extending the existing functionality of Pocket Outlook applications or integrating with Pocket Outlook data, the new managed classes exposed in Windows Mobile 5.0 and the .NET Compact Framework are an invaluable resource. With a minimal amount of time and effort, your Smart Device project can read and manipulate task, contact, and appointment information. If you have been hesitant to add this functionality to your application before, I strongly urge you to reconsider. For others, now might be a good time to evaluate the benefits of providing this type of functionality to your end users.