This is some sample code for you to adapt and make your own vcard.

In this example, we are calling a contact repository to load a contact model and we are using the properties of the contact to fill out the vcard.

We return the vCard bytes so they can be returned to the controller calling it for whichever purpose it needs.

    public static byte[] GetVCardBytes(string id, out string contactName)
    {
        contactName = "Unknown";
        var contact = new ContactsRepository().GetContact(id);
        if (contact == null) return null;
        contactName = contact.Name;
        var vCard = new StringBuilder();
        vCard.AppendLine("BEGIN:VCARD");
        vCard.AppendLine("VERSION:2.1");
        vCard.AppendLine($"N;LANGUAGE=en-gb:{contact.Name}");
        if (!string.IsNullOrWhiteSpace(contact.CompanyName))
        {
            vCard.AppendLine($"ORG:{contact.CompanyName}");
        }
        if (!string.IsNullOrWhiteSpace(contact.Title))
        {
            vCard.AppendLine($"TITLE:{contact.Title}");
        }
        if (!string.IsNullOrWhiteSpace(contact.Notes))
        {
            vCard.AppendLine($"NOTE:{contact.Notes}");
        }
        if (!string.IsNullOrWhiteSpace(contact.Mobile))
        {
            vCard.AppendLine($"TEL;CELL;VOICE:{contact.Mobile}");
        }
        vCard.AppendLine("X-MS-OL-DEFAULT-POSTAL-ADDRESS:0");
        if (!string.IsNullOrWhiteSpace(contact.Email))
        {
            vCard.AppendLine($"EMAIL;PREF;INTERNET:{contact.Email}");
        }
        vCard.AppendLine("END:VCARD");
        var vCardBytes = Encoding.UTF8.GetBytes(vCard.ToString());
        return vCardBytes;
    }

Next we have an ActionResult on a Surface Controller which calls the method and uses the bytes to return a file.

    public ActionResult DownloadVCard([FromUriAttribute] string id)
    {
        if (string.IsNullOrWhiteSpace(id)) return null;
        var vCardBytes = ContactsHandler.GetVCardBytes(id, out string contactName);
        if (vCardBytes == null || vCardBytes.Length == 0) return null;
        return File(vCardBytes, "text/calendar", contactName + ".vcf");
    }

And in the view we have a link like this:

    vCard: <a href="/umbraco/surface/ContactFinder/DownloadVCard/@item.AccountId">@item.Name</a>

I hope this helps you.

Paul Seal

Umbraco MVP and .NET Web Developer from Derby (UK) who specialises in building Content Management System (CMS) websites using MVC with Umbraco as a framework. Paul is passionate about web development and programming as a whole. Apart from when he's with his wife and son, if he's not writing code, he's thinking about it or listening to a podcast about it.

Proudly sponsored by

Moriyama

  • Moriyama build, support and deploy Umbraco, Azure and ASP.NET websites and applications.
AppVeyor

  • CI/CD service for Windows, Linux and macOS
  • Build, test, deploy your apps faster, on any platform.
elmah.io

  • elmah.io is the easy error logging and uptime monitoring service for .NET.
  • Take back control of your errors with support for all .NET web and logging frameworks.
uSync Complete

  • uSync.Complete gives you all the uSync packages, allowing you to completely control how your Umbraco settings, content and media is stored, transferred and managed across all your Umbraco Installations.
uSkinned

  • More than a theme for Umbraco CMS, take full control of your content and design with a feature-rich, award-nominated & content editor focused website platform.
UmbHost

  • Affordable, Geo-Redundant, Umbraco hosting which gives back to the community by sponsoring an Umbraco Open Source Developer with each hosting package sold.