Creating vCard in ASP.NET Core
Create vCards in ASP.NET CORE for Outlook.
Join the DZone community and get the full member experience.
Join For FreeIt’s time to get back to the old era of this blog and bring my vCard action result to today’s ASP.NET Core world. There’s support for images, so we can provide really good looking vCards from ASP.NET Core applications. This blog post gives a good base for custom vCard solutions in ASP.NET Core.
vCard Class
Previously, I built a vCard class to be a simple DTO-style class with a ToString() method that builds up a string output of vCard.
public class VCard {
public string FirstName { get; set; }
public string LastName { get; set; }
public string Organization { get; set; }
public string JobTitle { get; set; }
public string StreetAddress { get; set; }
public string Zip { get; set; }
public string City { get; set; }
public string CountryName { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
public string Email { get; set; }
public string HomePage { get; set; }
public byte[] Image { get; set; }
public string GetFullName() {
return FirstName + LastName; }
public override string ToString() {
var builder = new StringBuilder();
builder.AppendLine("BEGIN:VCARD");
builder.AppendLine("VERSION:2.1");
// Name
builder.Append("N:").Append(LastName)
.Append(";").AppendLine(FirstName);
// Full name
builder.Append("FN:").Append(FirstName)
.Append(" ").AppendLine(LastName);
// Address
builder.Append("ADR;HOME;PREF:;;").Append(StreetAddress)
.Append(";").Append(City).Append(";")
.Append(Zip).Append(";").AppendLine(CountryName);
// Other data
builder.Append("ORG:").AppendLine(Organization);
builder.Append("TITLE:").AppendLine(JobTitle);
builder.Append("TEL;WORK;VOICE:").AppendLine(Phone);
builder.Append("TEL;CELL;VOICE:").AppendLine(Mobile);
builder.Append("URL:").AppendLine(HomePage);
builder.Append("EMAIL;PREF;INTERNET:").AppendLine(Email);
// Image
if(Image != null) {
builder.AppendLine("PHOTO;ENCODING=BASE64;TYPE=JPEG:");
builder.AppendLine(Convert.ToBase64String(Image));
builder.AppendLine(string.Empty);
}
builder.AppendLine("END:VCARD");
return builder.ToString();
}
}
There are more attributes that vCard supports, but my code focuses on the most important ones. I left out others, as I have not needed these is practice over last 10 years. Those who need more attributes can take my code and add the ones they need.
vCard Action Result
Creating an action result for vCard is simple. Most of the dirty work is done in the ToString() method of vCard. Our action result must set response headers and write vCard to response stream.
public class vCardActionResult : IActionResult {
private readonly VCard _vCard;
public vCardActionResult(VCard vCard) {
_vCard = vCard;
}
public async Task ExecuteResultAsync(ActionContext context) {
var fileName = _vCard.GetFullName() + ".vcf";
var disposition = "attachment; filename=" + fileName;
var response = context.HttpContext.Response;
response.ContentType = "text/vcard";
response.Headers.Add("Content-disposition", disposition);
var bytes = Encoding.UTF8.GetBytes(_vCard.ToString());
await response.Body.WriteAsync(bytes, 0, bytes.Length);
}
}
Here is my sample controller action to download vCard.
public async Task<IActionResult> vCard() {
var vcard = new VCard();
vcard.FirstName = "Gunnar";
vcard.LastName = "Peipman";
vcard.Email = "gunnar@example.com";
vcard.City = "Tallinn";
vcard.CountryName = "Estonia";
vcard.Phone = "00-12345";
vcard.Mobile = "00-10101";
vcard.Organization = "Freelancer";
vcard.JobTitle = "Chief Everything Office";
vcard.Image = await System.IO.File.ReadAllBytesAsync("gunnar300.jpg");
return new vCardActionResult(vcard);
}
My controller action works. When opening a downloaded vCard with Outlook, it shows a nice business card.
We have a working vCard solution, but it’s not yet very convenient to use.
Using vCard Action Result in Practice
The first annoying thing for me is creating a new instance of vCardActionResult in the controller action. ASP.NET Core action results can be often called by a special method. To follow the same pattern, I created my own base class for controllers.
public class BaseController : Controller {
public IActionResult VCard(VCard vCard) {
return new vCardActionResult(vCard);
}
}
It’s simple, it’s primitive but it makes writing of vCard returning actions more intuitive.
public async Task<IActionResult> Download() {
var vcard = new VCard();
vcard.FirstName = "Gunnar";
vcard.LastName = "Peipman";
vcard.Email = "gunnar@example.com";
vcard.City = "Tallinn";
vcard.CountryName = "Estonia";
vcard.Phone = "00-12345";
vcard.Mobile = "00-10101";
vcard.Organization = "Freelancer";
vcard.JobTitle = "Chief Everything Office";
vcard.Image = await System.IO.File.ReadAllBytesAsync("gunnar300.jpg");
return VCard(vcard);
}
The second annoying thing for me is the code that creates a VCard instance. It can be there in the controller, but I prefer to keep it somewhere else for reusability. Usually, vCard data comes from Customer, Person or Company classes. Let’s write a simple Customer class.
public class Customer {
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }}
It’s up to the concrete solution to keep the following extension method that takes customer infomation and writes it to a vCard, but here’s the code.
public static class VCardExtensions {
public static VCard ToVCard(this Customer customer) {
var vCard = new VCard();
vCard.City = customer.City;
vCard.CountryName = customer.Country;
vCard.Email = customer.Email;
vCard.Mobile = customer.Mobile;
vCard.FirstName = customer.FirstName;
vCard.LastName = customer.LastName;
return vCard;
}
}
Let’s rewrite the vCard controller action, so it uses the Customer class to get a step closer to real a scenario.
public async Task<IActionResult> vCard() {
var customer = new Customer {
FirstName = "Gunnar",
LastName = "Peipman",
Email = "gunnar@example.com",
Mobile = "0012345",
City = "Tallinn",
Country = "Estonia" };
var vcard = customer.ToVCard();
vcard.Image = await System.IO.File.ReadAllBytesAsync("gunnar300.jpg");
return VCard(vcard);
}
This is how our vCard controller action looks in practice.
public async Task<IActionResult> Download(int id) {
var customer = await _dataContext.Customers .FirstOrDefaultAsync(c => c.Id == id); if(customer == null) { return NotFound(); } var vcard = customer.ToVCard(); vcard.Image = await System.IO.File.ReadAllBytesAsync("gunnar300.jpg"); return VCard(vcard);}
About using base controller. Don’t create base controller only to have nice VCard() method. If your application already uses base controller then it’s safe to add vCard() method there. If you don’t have base controller and you don’t plan to use it then just create new instance of vCardActionResult in actions that return vCard.
Wrapping Up
It wasn't hard to take an old vCard action result and update it. We added a VCard() method to the base controller to make it more intuitive for other developers to return vCard from controller actions. To better support real scenarios, we created the ToVCard() extension method that converts our Customer domain class to vCard. This blog post is a good starting point for your own vCard solution in .NET Core.
The post Creating vCard in ASP.NET Core appeared first on Gunnar Peipman - Programming Blog.
Published at DZone with permission of Gunnar Peipman, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments