Posted at: 2:44 PM on 28 January 2011 by Muhimbi
When we developed the Web Services Interface for our PDF Conversion engine, one of our goals was to make it as compatible as possible with legacy and non Visual Studio 2008 environments, e.g. Java and other Web Services capable systems.
Although we succeeded in making it compatible, we recently found out that when using the standard version of the aging Visual Studio 2005 environment, there are some problems with the XML serialisation of web service data.
This article explains how to invoke the Muhimbi PDF Conversion Services from a Visual Studio 2005 environment. It also provides a VB version of the C# based sample code used in our main Web Services tutorial. If you use Visual Studio 2008 or newer then please use this tutorial, unless you have some interest in the vb.net based sample code at the end of this post.
Ok, so the situation is as follows: your organisation still uses Visual Studio 2005, for whatever valid reason, and you wish to invoke the Muhimbi PDF Converter from a Visual Studio 2005 based application. Unfortunately the facility in Visual Studio 2005 that adds web references is not too happy with the default DataContractSerializer used by our WCF based service. Visual Studio 2005 uses the standard XmlSerializer, which is quite compatible, but not completely. Switching serialisers at runtime is not possible either as they are part of the data contract, which makes sense.
Solution 1 – Visual Studio 2005 extensions for .net 3.0
The easiest solution is to download the latest Visual Studio 2005 extensions for the .net framework 3.0. Don’t be put off by the fact that it is still a CTP, Microsoft never bothered to update it and instead pushed people to Visual Studio 2008.
Once installed you can add a Service Reference using the following URL. Please do not use the Add Web Reference option, as that uses the old way of doing it.
If not already added automatically, you will need to add a regular .net reference to the following .net 3.0 assemblies as well:
Once the service reference has been added you can either use the sample VB.NET code listed at the end of this post or the C# code in our regular tutorial. Please note that depending on how you have named things, you may need to manually change the names of the sample namespaces.
Solution 2 – Create web service proxy manually using SVCUTIL.EXE
If Solution 1 doesn’t work for you, or you don’t want to install the VS2005 extensions, then you can also take the manual approach that uses svcutil.exe to create the web service proxy classes in the language of your choice. If you wish you can skip steps 1 to 4 and download the pre-generated proxies for VB and C#, as well as some other sample code, here.
The procedure is as follows:
- You will need an updated version of svcutil.exe as the one that ships with VS2005 is not suitable, so download and install the Windows SDK.
- If not already the case, please make sure the .net framework 3.0 is installed on your system as well. An easy way to check if it has already been installed is by checking if the following directory exists:
"%WINDIR%\Microsoft.NET\Framework\v3.0\Windows Communication Foundation"
Download it from here if needed.
- Make sure svcutil.exe is on your path (It is most likely located at C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin), and open the command prompt.
- Create a folder or navigate to the directory where you want to create the proxy classes, e.g. c:\ws_proxy and execute the following command to generate the web service proxy classes:
svcutil.exe http://localhost:41734/Muhimbi.DocumentConverter.WebService/?wsdl /language:vb /serializer:DataContractSerializer /namespace:*,DocumentConverter
This will result in the following output (note the version number of svcutil.exe).
You can read about the various parameters, including targeting different languages, in the svcutil documentation.
- If you haven’t already created a Visual Studio 2005 project, then do so now (this sample uses vb.net for a change) and add the generated proxy file to the project.
- Create a new WinForm, add a TextBox as well as a Button to it. Please accept the default names.
- Double click the button and replace all code with the code displayed below.
- Run the application, enter the name of an MS-Word file including the full path and click the button to convert the file and display the PDF.
Public Class Form1
' ** The URL where the Web Service is located. Amend host name if needed.
Dim SERVICE_URL As String = "http://localhost:41734/Muhimbi.DocumentConverter.WebService/"
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Dim client As DocumentConverterServiceClient = Nothing
' ** Determine the source file and read it into a byte array.
Dim sourceFileName As String = TextBox1.Text
Dim sourceFile As Byte() = File.ReadAllBytes(sourceFileName)
' ** Open the service and configure the bindings
client = OpenService(SERVICE_URL)
'** Set the absolute minimum open options
Dim openOptions As New OpenOptions()
openOptions.OriginalFileName = Path.GetFileName(sourceFileName)
openOptions.FileExtension = Path.GetExtension(sourceFileName)
' ** Set the absolute minimum conversion settings.
Dim conversionSettings As New ConversionSettings()
conversionSettings.Fidelity = ConversionFidelities.Full
conversionSettings.Quality = ConversionQuality.OptimizeForPrint
' ** Carry out the conversion.
Dim convFile As Byte() = client.Convert(sourceFile, openOptions, conversionSettings)
' ** Write the converted file back to the file system with a PDF extension.
Dim destinationFileName As String = Path.GetDirectoryName(sourceFileName) & "\" & _
Path.GetFileNameWithoutExtension(sourceFileName) & "." & _
Using fs As FileStream = File.Create(destinationFileName)
fs.Write(convFile, 0, convFile.Length)
MessageBox.Show("File converted to " & destinationFileName)
' ** Launch the PDF file in the registered viewer
Catch ex As FaultException(Of WebServiceFaultException)
MessageBox.Show("FaultException occurred: ExceptionType: " & _
Catch ex As Exception
''' Configure the Bindings, endpoints and open the service using the specified address.
''' <returns>An instance of the Web Service.</returns>
Public Shared Function OpenService(ByVal address As String) As DocumentConverterServiceClient
Dim client As DocumentConverterServiceClient = Nothing
Dim binding As New BasicHttpBinding()
' ** Use standard Windows Security.
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows
' ** Increase the Timeout to deal with (very) long running requests.
binding.SendTimeout = TimeSpan.FromMinutes(30)
binding.ReceiveTimeout = TimeSpan.FromMinutes(30)
' ** Set the maximum document size to 40MB
binding.MaxReceivedMessageSize = 50 * 1024 * 1024
binding.ReaderQuotas.MaxArrayLength = 50 * 1024 * 1024
binding.ReaderQuotas.MaxStringContentLength = 50 * 1024 * 1024
' ** Specify an identity (any identity) in order to get it past .net3.5 sp1
Dim epi As EndpointIdentity = EndpointIdentity.CreateUpnIdentity("unknown")
Dim epa As New EndpointAddress(New Uri(address), epi)
client = New DocumentConverterServiceClient(binding, epa)
Catch generatedExceptionName As Exception
''' Check if the client is open and then close it.
''' <param name="client">The client to close</param>
Public Shared Sub CloseService(ByVal client As DocumentConverterServiceClient)
If client IsNot Nothing AndAlso client.State = CommunicationState.Opened Then
This concludes our rather long and boring story. We’ll promise that the next blog post will contain some colourful pictures.