WCF Outlook Demo - in VB.NET

[Updated: I added the source as a post attachment (thanks, Robert, for the suggestion).]

I often hear a lament that there exists too few examples for .NET 3.0 technologies using VB.NET.  Here is a cool sample that shows how you can separate the service, contracts, and hosting code.  The sample calls into Outlook and creates a contact, and exposes the service using named pipes.

Contoso.Contracts

The Contoso.Contracts project contains the DataContract and ServiceContract decorated types. 

References:  System.ServiceModel.dll, System.Runtime.Serialization.dll

Contact.vb

Imports System.Runtime.Serialization

Namespace Contoso.Contracts

<DataContract()> _
Public Class Contact
Private _imAddress As String

<DataMember()> _
Public Property IMAddress() As String
Get
Return _imAddress
End Get
Set(ByVal value As String)
_imAddress = value
End Set
End Property

Private _companyName As String

<DataMember()> _
Public Property CompanyName() As String
Get
Return _companyName
End Get
Set(ByVal value As String)
_companyName = value
End Set
End Property

Private _fullName As String
<DataMember()> _
Public Property FullName() As String
Get
Return _fullName
End Get
Set(ByVal value As String)
_fullName = value
End Set
End Property

Private _businessPhone As String
<DataMember()> _
Public Property BusinessPhone() As String
Get
Return _businessPhone
End Get
Set(ByVal value As String)
_businessPhone = value
End Set
End Property

Private _mobilePhone As String
<DataMember()> _
Public Property MobilePhone() As String
Get
Return _mobilePhone
End Get
Set(ByVal value As String)
_mobilePhone = value
End Set
End Property

Private _homePhone As String
<DataMember()> _
Public Property HomePhone() As String
Get
Return _homePhone
End Get
Set(ByVal value As String)
_homePhone = value
End Set
End Property

End Class

End Namespace

IContactService.vb

Imports System
Imports System.ServiceModel

Namespace Contoso.Contracts

<ServiceContract()> _
Public Interface IContactService
<OperationContract()> _
Sub CreateContact(ByVal c As Contact)

End Interface
End Namespace

Contoso.Outlook

This library contains the actual implementation logic.  Think of this assembly as "business logic", or the meat behind the service facade.

References:  Office.dll, Microsoft.Office.Interop.Outlook.dll

Contact.vb

Namespace Contoso.Outlook

Public Class Contact
Private _imAddress As String

Public Property IMAddress() As String
Get
Return _imAddress
End Get
Set(ByVal value As String)
_imAddress = value
End Set
End Property

Private _companyName As String
Public Property CompanyName() As String
Get
Return _companyName
End Get
Set(ByVal value As String)
_companyName = value
End Set
End Property

Private _fullName As String
Public Property FullName() As String
Get
Return _fullName
End Get
Set(ByVal value As String)
_fullName = value
End Set
End Property

Private _businessPhone As String
Public Property BusinessPhone() As String
Get
Return _businessPhone
End Get
Set(ByVal value As String)
_businessPhone = value
End Set
End Property

Private _mobilePhone As String
Public Property MobilePhone() As String
Get
Return _mobilePhone
End Get
Set(ByVal value As String)
_mobilePhone = value
End Set
End Property

Private _homePhone As String
Public Property HomePhone() As String
Get
Return _homePhone
End Get
Set(ByVal value As String)
_homePhone = value
End Set
End Property

End Class
End Namespace

Contacts.vb

Imports Microsoft.Office.Interop.Outlook

Namespace Contoso.Outlook
Public Class Contacts

Public Sub StoreContact(ByVal c As Contact)
Dim outlookApp As Microsoft.Office.Interop.Outlook.Application = New Microsoft.Office.Interop.Outlook.Application()
Dim newContact As Microsoft.Office.Interop.Outlook.ContactItem = CType(outlookApp.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olContactItem), Microsoft.Office.Interop.Outlook.ContactItem)

With newContact
.FullName = c.FullName
.FileAs = c.FullName
.CompanyName = c.CompanyName
.BusinessTelephoneNumber = c.BusinessPhone
.HomeTelephoneNumber = c.HomePhone
.IMAddress = c.IMAddress
.MobileTelephoneNumber = c.MobilePhone
End With

newContact.Save()

End Sub

End Class
End Namespace

Contoso.Services

This assembly contains the implementation of the service contracts.  This is separated from the contracts assembly because you could distribute the Contoso.Contracts assembly to consumers of your service and use the ChannelFactory.CreateChannel method instead of generating a service proxy.  If the service logic were contained in that assembly, you would potentially expose sensitive code.

References:  Contoso.Contracts.dll, Contoso.Outlook.dll, System.ServiceModel.dll, System.Runtime.Serialization.dll

ContactService.vb

Imports System
Imports System.ServiceModel
Imports Contoso.Contracts
Imports OutlookLib = Contoso.Outlook

Namespace Contoso.Services

Public Class ContactService
Implements IContactService

Public Sub CreateContact(ByVal c As Contact) Implements IContactService.CreateContact

Dim c2 As OutlookLib.Contact = New OutlookLib.Contact()
c2.BusinessPhone = c.BusinessPhone
c2.CompanyName = c.CompanyName
c2.FullName = c.FullName
c2.HomePhone = c.HomePhone
c2.IMAddress = c.IMAddress
c2.MobilePhone = c.MobilePhone

Dim contacts As OutlookLib.Contacts = New OutlookLib.Contacts()
contacts.StoreContact(c2)

End Sub
End Class

End Namespace

Contoso.Hosting

This assembly hosts the WCF service in a Console application.

References:  Contoso.Contracts.dll, Contoso.Services.dll, System.ServiceModel.dll, System.Runtime.Serialization.dll

ServiceHost.vb

Imports System
Imports System.ServiceModel
Imports System.Configuration
Imports Contoso.Services

Public Class Host
Friend Shared myHost As ServiceHost = Nothing
Friend Shared Sub StartService()
Dim baseAddress As Uri = New Uri(ConfigurationManager.AppSettings("baseAddress"))

myHost = New ServiceHost(GetType(ContactService), baseAddress)
myHost.Open()
End Sub

Friend Shared Sub StopService()
If myHost.State <> CommunicationState.Closed Then
myHost.Close()
End If
End Sub
End Class

Program.vb

Namespace Contoso.Hosting

Module Program

Public Sub Main()
Console.WriteLine("starting the service...")
Host.StartService()
Console.WriteLine("service started.  Press ENTER to continue.")
Console.ReadLine()
Host.StopService()
End Sub
End Module
End Namespace

app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="baseAddress" value="net.pipe://localhost/Contoso"/>
</appSettings>
<system.serviceModel>
<services>
<service name="Contoso.Services.ContactService">
<endpoint address="Outlook" binding="netNamedPipeBinding" contract="Contoso.Contracts.IContactService" />
</service>
</services>
<behaviors>
<behavior name="returnFaults" returnUnknownExceptionsAsFaults="true" />
</behaviors>
</system.serviceModel>
</configuration>

client

This assembly is a simple client.  Instead of using Add Service Reference in Visual Studio, we take advantage of the fact that the contracts were implemented in a DLL that we can share out to consumers.  The client references the contracts and uses this to consume the service.  Run the client, then check your Contacts in Outlook and see that you have a new contact.

References:  Contoso.Contracts.dll, System.ServiceModel.dll, System.Runtime.Serialization.dll

Program.vb

Imports Contoso.Contracts
Imports System.ServiceModel

Module Program

Sub Main()

Dim c As Contact = New Contact()
c.BusinessPhone = "4045551212"
c.CompanyName = "Contoso"
c.FullName = "John Jacob Jingleheimerschmidt"
c.HomePhone = "4048675309"
c.IMAddress = "freeporn@hotmail.com"
c.MobilePhone = "7705551212"

Dim factory As ChannelFactory(Of IContactService) = New ChannelFactory(Of IContactService)("default")
Dim proxy As IContactService = factory.CreateChannel()
proxy.CreateContact(c)

End Sub

End Module

app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address="net.pipe://localhost/Contoso/Outlook"
binding="netNamedPipeBinding"
contract="Contoso.Contracts.IContactService"
name="default"/>
</client>
</system.serviceModel>
</configuration>

OutlookDemo.zip