Category Archives: VMware

Extracting VMware Web Service Proxies for .NET

The current VMware 5.1 SDK no longer redistributes pre-built .NET proxies, just the source WSDL. If you follow the documentation you are directed to complete a complicated procedure to generate and your own signed proxies.

Fortunately, there is an easier way to extract official signed assemblies from a VMware PowerCLI (PowerShell extensions) installation. This is much better than the previous method as you are using original DLLs provided (and supported by) VMware.

  1. Download and install the current VMware PowerCLI.
  2. Install the PowerCLI which includes the VMware VIX infrastructure components.
  3. Although the PowerCLI documentation suggests you reference VMware.Vim.dll in the program files infrastructure path, we won’t do this because some additional files are missing and we want a full stand-alone copy. The VMware VIX setup installs everything primarily in the GAC. So we will run one command to extract  the files we need from the GAC and copy them into the source so they can be referenced locally and checked-in. Change the “.” at the end of the following command to your own target path, else it copies into the current directory:
    for /f %i in ('dir %WinDir%\assembly\GAC_MSIL\*Vim*.dll /s /b') do copy %i .
  4. This will find several files of which the following are necessary to call VMware web services:
    VimService25.dll
    VimService25.XmlSerializers.dll
    VimService40.dll
    VimService40.XmlSerializers.dll
    VimService41.dll
    VimService41.XmlSerializers.dll
    VimService50.dll
    VimService50.XmlSerializers.dll
    VimService51.dll
    VimService51.XmlSerializers.dll
    VMware.Vim.dll
  5. Add a reference to VMware.Vim.dll then use the proxy classes there to call the web services, according to the VMware Web Services SDK documentation. Note that the main VIM assembly will load the relevant VimService## proxy according to the version it detects when connecting to the server (factory pattern), so you need them all including the XML serialization assemblies (it’s hard-coded, they are not optional)!

As a best practice I like to check-in all stand-alone dependencies into a “Dependencies” folder of the solution/checked-in source tree. Make sure you also redistribute these files with your application. I prefer this “local copy” method because this enables your code to compile on any developer PC or build server and be deployed as a stand-alone package.

Generating VMware Web Service Proxies for .NET

The current VMware 5.1 SDK no longer redistributes pre-built .NET proxies, just the source WSDL. Not a problem you may think (the WSDL tool or Visual Studio “Add Service Reference” is not so hard use). However, according to their documentation, unless you manually edit the WSDL generated files you could suffer long hangs when your application connects to a VMware server! And you should use XML serialization assemblies anyway to ensure maximum performance.

EDIT 2013.04.24 – The easiest way is to extract the official proxy assemblies from a VMware PowerCLI installation. But if you want to generate your own proxies you can still use this method.

Further examination shows that there are 100s of lines to change in order to complete the process properly. So I decided to script this up to avoid human error and save time when new versions are released.

It deals with the following issues:

  • Automation of the tedious post-processing of WSDL generated proxy file according to VMware SDK 5.1 documentation.
  • Strong name signing.
  • Adds missing version and other common assembly information.

You need only the “wsdl” subdirectory from the current 5.1 SDK ZIP then the following three files copied into the parent directory (so “wsdl” is below them):

Build.cmd – runs the build…


@echo off
setlocal
echo *** Adding paths to .NET SDK tools from Visual Studio 2012...
call "%vs110comntools%vsvars32"
if %errorlevel% neq 0 goto Error

echo *** Subtituting drive for path to avoid long name and space issues...
set PathDrive=X:
subst %PathDrive% "%~dp0."
if %errorlevel% neq 0 goto Error

echo *** Checking (or generating) strong name key...
if not exist "%PathDrive%\Vmware.snk" sn -k "%PathDrive%\Vmware.snk"

echo *** Cleaning-up any old files...
if exist "%TempPath%\Vim*.cs" del "%TempPath%\Vim*.cs"

echo *** Building old "VimApi" proxy (ESX 3 and vCenter 2)...
wsdl /n:VimApi "%PathDrive%\wsdl\Vim\vim.wsdl" "%PathDrive%\wsdl\Vim\vimService.wsdl" /out:"%PathDrive%\VimService2012.cs"
if %errorlevel% neq 0 goto Error
csc /t:library /out:"%PathDrive%\VimService2012.dll" "%PathDrive%\VimService2012.cs" "%PathDrive%\AssemblyInfo.cs" /keyfile:"%PathDrive%\Vmware.snk"
if %errorlevel% neq 0 goto Error
sgen /p "%PathDrive%\VimService2012.dll" /force /compiler:"/keyfile:""%PathDrive%\VMware.snk""
if %errorlevel% neq 0 goto Error
powershell -File "%PathDrive%\FixVmwareWsdlSource.ps1" "%PathDrive%\VimService2012.cs" VimService2012.XmlSerializers "%PathDrive%\VimService2012WithXmlSerializers.cs"
if %errorlevel% neq 0 goto Error
csc /t:library /out:"%PathDrive%\VimService2012.dll" "%PathDrive%\VimService2012WithXmlSerializers.cs" "%PathDrive%\AssemblyInfo.cs" /keyfile:"%PathDrive%\Vmware.snk"
if %errorlevel% neq 0 goto Error

echo *** Building new "Vim25Api" proxy (ESXi 4-5, ESX 3.5 and vCenter 4-5)...
wsdl /n:Vim25Api "%PathDrive%\wsdl\Vim25\vim.wsdl" "%PathDrive%\wsdl\Vim25\vimService.wsdl" /out:"%PathDrive%\Vim25Service2012.cs"
if %errorlevel% neq 0 goto Error
csc /t:library /out:"%PathDrive%\Vim25Service2012.dll" "%PathDrive%\Vim25Service2012.cs" "%PathDrive%\AssemblyInfo.cs" /keyfile:"%PathDrive%\Vmware.snk"
if %errorlevel% neq 0 goto Error
sgen /p "%PathDrive%\Vim25Service2012.dll" /force /compiler:"/keyfile:""%PathDrive%\VMware.snk"""
if %errorlevel% neq 0 goto Error
powershell -File "%PathDrive%\FixVmwareWsdlSource.ps1" "%PathDrive%\Vim25Service2012.cs" Vim25Service2012.XmlSerializers "%PathDrive%\Vim25Service2012WithXmlSerializers.cs"
if %errorlevel% neq 0 goto Error
csc /t:library /out:"%PathDrive%\Vim25Service2012.dll" "%PathDrive%\Vim25Service2012WithXmlSerializers.cs" "%PathDrive%\AssemblyInfo.cs" /keyfile:"%PathDrive%\Vmware.snk"
if %errorlevel% neq 0 goto Error

echo *** Completed successfully
subst %PathDrive% /d
endlocal
exit /b 0

:Error
set result=%errorlevel%
echo *** Error %result%!
subst %PathDrive% /d
endlocal
exit /b %result%

FixVmwareWsdlSource.ps1 – automatically applies corrections to the WSDL output…


# Check syntax
If ($args.Count -lt 3)
{
    Write-Host "Syntax: FixVmwareWdslSource <Input WSDL CS File> <SGEN File Name> <Output WSDL CS File>"
    Exit 1
}

# Parse arguments
$filePath = $args[0]
$serializerFileName = $args[1]
$outputFilePath = $args[2]
Write-Host "Processing $filePath with $serializerFileName into $outputFilePath..."

# Delete output file if already exists
If (Test-Path $outputFilePath) { del $outputFilePath }

# Process file
Get-Content $filePath |
ForEach-Object {
    $line = $_
    If ($line -match "\[System.Xml.Serialization.XmlIncludeAttribute")
    {
        # Comment XmlInclude attributes which cause hang
        Write-Output "//$_" 
    }
    Else
    {
        If ($_ -match "public partial class VimService")
        {
            # Add reference to previously generated XML serialization assembly
            Write-Output "[System.Xml.Serialization.XmlSerializerAssemblyAttribute(AssemblyName = ""$serializerFileName"")]"
            Write-Output $line
        }
        Else
        {
            # Copy other lines without change
            Write-Output $line
        }
    }
} |
Out-File $outputFilePath -Append

AssemblyInfo.cs – gives us sensible assembly level attributes, at least required to avoid having version “0.0.0.0” built…


using System;
using System.Reflection;
using System.Runtime.InteropServices;

// Information
[assembly: AssemblyDescription("VMware managenent web service proxy.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("VMware")]
[assembly: AssemblyProduct("Management SDK")]
[assembly: AssemblyCopyright("Copyright © VMware")]
[assembly: AssemblyTrademark("All Rights Reserved")]
[assembly: AssemblyCulture("")]

// COM Interop
[assembly: ComVisible(false)]

// Version
[assembly: AssemblyVersion("5.1.0.0")]

// Language compliance
// Not complaint due to use of underscores in parameter and member names, e.g. "_this".
[assembly: CLSCompliant(false)]

Run Build.cmd and wait about 5 minutes.

Following this you only need the Vim25Service.dll and Vim25Service.XmlSerializers.dll for new projects. The VimService.dll and VimService.XmlSerializers.dll are only required if you still have to support very old ESX or vCenter servers. You might want to keep the generated Vmware.snk or adjust the scripts to use your own so you have a persistent strong name key in the future.