[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.
The Contoso.Contracts project contains the DataContract and ServiceContract decorated types.
References: System.ServiceModel.dll, System.Runtime.Serialization.dll
Imports System.Runtime.Serialization
Namespace Contoso.Contracts
<DataContract()> _Public Class ContactPrivate _imAddress As String
<DataMember()> _Public Property IMAddress() As StringGetReturn _imAddressEnd GetSet(ByVal value As String)_imAddress = valueEnd SetEnd Property
Private _companyName As String
<DataMember()> _Public Property CompanyName() As StringGetReturn _companyNameEnd GetSet(ByVal value As String)_companyName = valueEnd SetEnd Property
Private _fullName As String<DataMember()> _Public Property FullName() As StringGetReturn _fullNameEnd GetSet(ByVal value As String)_fullName = valueEnd SetEnd Property
Private _businessPhone As String<DataMember()> _Public Property BusinessPhone() As StringGetReturn _businessPhoneEnd GetSet(ByVal value As String)_businessPhone = valueEnd SetEnd Property
Private _mobilePhone As String<DataMember()> _Public Property MobilePhone() As StringGetReturn _mobilePhoneEnd GetSet(ByVal value As String)_mobilePhone = valueEnd SetEnd Property
Private _homePhone As String<DataMember()> _Public Property HomePhone() As StringGetReturn _homePhoneEnd GetSet(ByVal value As String)_homePhone = valueEnd SetEnd Property
End Class
End Namespace
Imports SystemImports System.ServiceModel
<ServiceContract()> _Public Interface IContactService<OperationContract()> _Sub CreateContact(ByVal c As Contact)
End InterfaceEnd Namespace
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
Namespace Contoso.Outlook
Public Class ContactPrivate _imAddress As String
Public Property IMAddress() As StringGetReturn _imAddressEnd GetSet(ByVal value As String)_imAddress = valueEnd SetEnd Property
Private _companyName As StringPublic Property CompanyName() As StringGetReturn _companyNameEnd GetSet(ByVal value As String)_companyName = valueEnd SetEnd Property
Private _fullName As StringPublic Property FullName() As StringGetReturn _fullNameEnd GetSet(ByVal value As String)_fullName = valueEnd SetEnd Property
Private _businessPhone As StringPublic Property BusinessPhone() As StringGetReturn _businessPhoneEnd GetSet(ByVal value As String)_businessPhone = valueEnd SetEnd Property
Private _mobilePhone As StringPublic Property MobilePhone() As StringGetReturn _mobilePhoneEnd GetSet(ByVal value As String)_mobilePhone = valueEnd SetEnd Property
Private _homePhone As StringPublic Property HomePhone() As StringGetReturn _homePhoneEnd GetSet(ByVal value As String)_homePhone = valueEnd SetEnd Property
End ClassEnd Namespace
Imports Microsoft.Office.Interop.Outlook
Namespace Contoso.OutlookPublic 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.MobilePhoneEnd With
newContact.Save()
End Sub
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
Imports SystemImports System.ServiceModelImports Contoso.ContractsImports OutlookLib = Contoso.Outlook
Namespace Contoso.Services
Public Class ContactServiceImplements IContactService
Public Sub CreateContact(ByVal c As Contact) Implements IContactService.CreateContact
Dim c2 As OutlookLib.Contact = New OutlookLib.Contact()c2.BusinessPhone = c.BusinessPhonec2.CompanyName = c.CompanyNamec2.FullName = c.FullNamec2.HomePhone = c.HomePhonec2.IMAddress = c.IMAddressc2.MobilePhone = c.MobilePhone
Dim contacts As OutlookLib.Contacts = New OutlookLib.Contacts()contacts.StoreContact(c2)
End SubEnd Class
This assembly hosts the WCF service in a Console application.
References: Contoso.Contracts.dll, Contoso.Services.dll, System.ServiceModel.dll, System.Runtime.Serialization.dll
Imports SystemImports System.ServiceModelImports System.ConfigurationImports Contoso.Services
Public Class HostFriend Shared myHost As ServiceHost = NothingFriend 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 ThenmyHost.Close()End IfEnd SubEnd Class
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 SubEnd ModuleEnd Namespace
<?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>
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
Imports Contoso.ContractsImports System.ServiceModel
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 Module
<?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>