Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Web Exporting Contact Details to a vCard

0.00/5 (No votes)
27 Jun 2006 1  
Exporting contact details into a vCard format on the fly from a website.

Overview

The article below explains how to create an Outlook vCard on the fly from a website. The example in the article uses some static data as it's easier to explain, but it is simple to make it more dynamic.

History

I've been doing a little work on our company's intranet system. Interestingly, the company doesn't have a global contacts solution, so each individual group company has implemented their own. Some of these solutions consist of having an Excel spreadsheet with a list of names and numbers on. My little bit of work was to create an intranet based contacts solution to replace one of these Excel based systems. The other interesting thing about this company is that they don't use Exchange, the French owners having decided that everything Microsoft is bad. This has obviously been ignored at a desktop level, so instead of using Netscape Communicator, everyone uses Outlook. The sad fact is without Exchange or even a group-wide Active Directory solution, the contact information is missing. The only way to hold employees contact details is to create your own contacts list in Outlook.

The Solution

To make people's lives easier, I decided that it would be helpful if they can export the contact details they have just found to the Outlook vCard format, which would then allow them to save it to their contacts list. Having decided that I was going to do that, I had to think about how best to get the desired response. I didn't want the site to have to create a local copy of the vCard for the client to download. I decided that changing the response stream of a page would be best. The vCard could then be generated on the fly. So below is how I achieved this solution.

vCard

The first thing I had to do is work out the format that vCards are held in. Luckily, this was as simple as opening it in Notepad.

The format looks pretty much like this:

BEGIN:VCARD
VERSION:2.1
N:Davey;Chris;J S;Mr
URL;WORK:www.chemlock.co.uk
END:VCARD

You will notice that basically the field identifiers are split from the data with a colon ":", and any identifiers or data that is split into parts is split using the semi-colon ";". Apart from that, it's pretty much plain text. This obviously made me think the task would be fairly simple.

Creating a new page

I decided previously that I wanted to generate the vCard on the fly rather than have the server save a file somewhere. To do this, I would need to change the output stream of the page HTTP response. I didn't want to do this on the original page as it would obviously trash my existing page data, so I needed a way of creating a new page and having that page's HTTP response stream changed. To do this, I needed to revert back to good old JavaScript. I have a DataGrid ItemCommand event that calls the following:

private void bdgResults_ItemCommand(object source,DataGridCommandEventArgs e)
{
    switch(e.CommandName)
    {
        case "vCardExport":
            Response.Write(@"<script language = "'Javascript'">var" + 
                           @" win=window.open('vCard.aspx',null,'width=50,height=50," + 
                           @"top=100,left=100','true');</script>");
            break;
    }
}

All this code does is create a new window with whatever content vCard.aspx holds. So now, we need to create vCard.aspx.

vCard.aspx HTML

For the HTML, I didn't change a thing. See, there is nothing there:.

<%@ Page language="c#" Codebehind="vCard.aspx.cs" 
   AutoEventWireup="false" Inherits="TISContacts.vCard" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>vCard</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET
7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name=vs_defaultClientScript content="JavaScript">
<meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body MS_POSITIONING="GridLayout">

<form id="Form1" method="post" runat="server">
 </form>

</body>
</html>

vCard.aspx code-behind

OK, here is where the magic occurs. In this code, we need to clear the HTTP response stream and then write our own. Here is the full code. I'll explain after you've had a look at it.

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace TISContacts
{

    /// <summary>
    /// Summary description for vCard.
    /// </summary>
    public class vCard : System.Web.UI.Page
    {
        private void Page_Load(object sender, System.EventArgs e)
        {
            cmpVCard.VCard(Response);
        }
#region Web Form Designer generated code
        override protected void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.Load += new System.EventHandler(this.Page_Load);
        }
#endregion
    }

public class cmpVCard : System.ComponentModel.Component
{
#region Attributes
    private const string nameFirst = "Chris";
    private const string nameLast = "Davey";
    private const string nameMiddle = "J S";
    private const string nameTitle = "Mr";
    private const string email = "chris.davey@chemlock.co.uk";
    private const string uRL = "www.chemlock.co.uk";
    private const string telephone = "(0) 1555 555555";
    private const string fax = "(0) 1555 555555";
    private const string mobile = "(0) 7555 555555";
    private const string company = "Chemlock";
    private const string department = "Owner";
    private const string title = "Managing Director";
    private const string profession = "Developer";
    private const string office = "Bedroom";
    private const string addressTitle = "Chemlock";
    private const string streetName = "25 Nowhere Str";
    private const string city = "London";
    private const string region = "Surrey";
    private const string postCode = "GU30 7BZ";
    private const string country = "ENGLAND";
#endregion Attributes

#region Component Designer generated code
    public cmpVCard(System.ComponentModel.IContainer Container)
    {
        //Required for Windows.Forms Class Composition Designer support
        Container.Add(this);
    }

    public cmpVCard()
    {
        //This call is required by the Component Designer.
        InitializeComponent();
        //Add any initialization after the InitializeComponent() call
    }

    //Component overrides dispose to clean up the component list.
    protected override void Dispose(Boolean disposing)
    {
        if (disposing)
        {
            if(components != null)
            {
                components.Dispose();
            }
        }
        base.Dispose(disposing);
    }
    //Required by the Component Designer
    private System.ComponentModel.IContainer components;

    //NOTE: The following procedure is required by the Component Designer
    //It can be modified using the Component Designer.
    //Do not modify it using the code editor.
    [System.Diagnostics.DebuggerStepThrough()]
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
    }
#endregion

    public static void VCard(HttpResponse response)
    {
        //clear response.object
        response.Clear();
        response.Charset = "";
        //set the response mime type for vCard

        response.ContentType = "text/x-vCard";
        //create a string writer

        System.IO.StringWriter stringWrite = new System.IO.StringWriter();
        //create an htmltextwriter which uses the stringwriter

        System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
        //vCard Begin
        stringWrite.WriteLine("BEGIN:VCARD");
        stringWrite.WriteLine("VERSION:2.1");
        //Name
        stringWrite.WriteLine("N:" + nameLast + ";" + nameFirst + 
                              ";" + nameMiddle + ";" + nameTitle);
        //Full Name
        stringWrite.WriteLine("FN:" + nameFirst + " " + 
                              nameMiddle + " " + nameLast);
        //Organisation
        stringWrite.WriteLine("ORG:" + company + ";" + department);
        //URL
        stringWrite.WriteLine("URL;WORK:" + uRL);
        //Title
        stringWrite.WriteLine("TITLE:" + title);
        //Profession
        stringWrite.WriteLine("ROLE:" + profession);
        //Telephone
        stringWrite.WriteLine("TEL;WORK;VOICE:" + telephone);
        //Fax
        stringWrite.WriteLine("TEL;WORK;FAX:" + fax);
        //Mobile
        stringWrite.WriteLine("TEL;CELL;VOICE:" + mobile);
        //Email
        stringWrite.WriteLine("EMAIL;PREF;INTERNET:" + email);
        //Address
        stringWrite.WriteLine("ADR;WORK;ENCODING=QUOTED-PRINTABLE:" + ";" +
                              office + ";" + addressTitle + "=0D" + 
                              streetName + ";" + city + ";" + 
                              region + ";" + postCode + ";" + country);

        //Revision Date
        //Not needed
        //stringWrite.WriteLine("REV:" + DateTime.Today.Year.ToString() +
        //            DateTime.Today.Month.ToString() + DateTime.Today.Day.ToString() + "T" +
        //            DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + 
        //            DateTime.Now.Second.ToString() + "Z");
        //vCard End
        stringWrite.WriteLine("END:VCARD");
        response.Write(stringWrite.ToString());
        response.End();
    }
}
}

To start with, it's all fairly simple. Our vCard Page_Load instantiates a component that we've called cmpVCard. It's this component that strips out the response stream and then writes our new stream. The meat of the thing is in a component so that it could be exported into a separate file and used through-out the application. At present, I've put the code in vCard.aspx.cs so you can see what it does. It's not that confusing. You can pretty much copy the "#region Component Designer generated code" as is into your code. The part that does the fancy stuff is the vCard method. This, as you can see, first kills anything in the response stream.

//clear response.object
response.Clear();
response.Charset = "";

Then, it changes the response type to be in the vCard MIME format.

//set the response mime type for vCard
response.ContentType = "text/x-vCard";

The rest is just building up the StringWriter with our desired output and then writing it to the response. Simple as that. With Internet Explorer, this simply opens the vCard. In something like Firefox, you get prompted for a program to open the file with. This, by default, should be set to Microsoft Outlook.

Obviously, I've used some const strings to put my results in, but in the real world solution, a Data Transfer Object is passed in via a Session variable that is set on the previous page. I'm sure you can see how this can be made dynamic. If you have any questions, please post them below or on my blog.

Job done. www.chemlock.co.uk

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here