Auto-Generate SOAP Proxies from Web Service Projects

Generating WSDL from the Web Service Project

The first step is to automatically generate of any method is to be able to generate the wsdl directly from the project files without the need to publish them to a web service first.  While this seems like something that Microsoft should have right out of the box, it took some searching to come up with the CmdHelper application from Stephan Brenner.  This utility is able to generate the WSDL from a web service assembly, without the need to start a web server.

To use this utility, simply install a copy locally and run the command:

CmdHelper.exe GetWsdl /AssemblyPath:c:\myWebApp\bin\myWebApp.dll /OutputDirectory:c:\output

This generates the WSDL for all web services in the assembly.  Alternately there is a command line version to selective output specific instances.

Generating Proxies from the WSDL

Now that we have the WSDL file, we can generate the proxy class.  However, instead of using the Web References to generate the proxy and add it to our project, we need to use the wsdl.exe command line utility.  This is simply a matter of calling the command:

wsdl  /namespace:my.namepace Service.wsdl /out:proxy.cs

Generating Proxies for .NET CF

If the proxies are going to be used with .NET CF 2.0 and .NET CF 3.5, which has a reduced set of .NET functionality including some async methods used in the generated proxy.  To avoid these conflicts, you can build the proxy with the “oldAsync” method (using BeginMethod/EndMethod syntax which is supported.

To do this the wsdl.exe must be called with an XML parameters file to set the “oldAsync” properties as described in Creating a Web Service Proxy for a .Net 2.0 Web Service.  Additional details for configuring parameters are provided at the MSDN Web Services Description Language Tool (Wsdl.exe) and CodeGenerationOptions Enumeration pages.

My wsdl command line becomes:

%wsdl% /v /parameters:"%~dp0\oldwsdlconfig.xml"  /namespace:%NameSpace% %ProjectPath%\proxy\Service.wsdl /out:%ProjectPath%\proxy\%ProxyName%

and my parameter file, “oldwsdlconfig.xml” is:

<wsdlParameters xmlns='http://microsoft.com/webReference/'>
  <language>c#</language>
  <protocol>Soap</protocol>
  <nologo>true</nologo>
  <sharetypes>false</sharetypes>
  <webReferenceOptions>
    <codeGenerationOptions>properties oldAsync</codeGenerationOptions>
  </webReferenceOptions>
</wsdlParameters>

Automating the Process

Finally to automate the entire process is a matter of run a batch file as a post-build step in each of the web service projects.

The batch file I use is called GenProxy.bat:

if NOT "%~1" == "" goto start
echo "usage: GenProxy    "
goto end
 
:start
set wsdl="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\wsdl"
set ProjectPath=%~1
set AssemblyPath=%2
set NameSpace=%3
set ProxyName=%4
set cmdhelper="%~dp0\..\Tools\CmdHelper\cmdhelper"
 
echo "Project Path: %ProjectPath%"
echo "Assembly Path: %AssemblyPath%"
echo "Name Space: %NameSpace%"
echo "Proxy Name: %ProxyName%"
echo "CmdHelper: %cmdhelper%"
 
cd %ProjectPath%
if NOT exist proxy mkdir proxy
%cmdhelper% GetWsdl /AssemblyPath:%AssemblyPath% /OutputDirectory:%ProjectPath%\proxy
%wsdl% /v /parameters:"%~dp0\oldwsdlconfig.xml"  /namespace:%NameSpace% %ProjectPath%\proxy\Service.wsdl /out:%ProjectPath%\proxy\%ProxyName%
 
:end

Which requires the helper oldwsdlconfig.xml file from above.

Then finally include running the GenProxy.bat command as a post-build step in the project:

call $(ProjectDir)..\..\..\Scripts\GenProxy.bat "$(ProjectDir)" $(TargetPath) my.namespace wsProxy.cs

Now the wsdl file and the associated proxy will be included in the proxy directory of the project and can now be used by other projects to access the web service.  For this I typically just add a link to the existing item.

 

 

IIS Debugging Terminated

When debugging web applications I often get distracted or busy working on understanding a problem and after 90 seconds get the message.
The web server process that was being debugged has been terminated by Internet Information Services (IIS). This can be avoided by configuring Application Pool ping settings in IIS.  See help for further detailsThis is caused by IIS monitoring and shutting down unresponsive processes.  The default is 90 seconds, but when debugging it is easy to exceed this time and get the above message.

The simple solution is to disable ping in IIS Advanced settings for the application poll.  This is done by setting “Ping Enabled” to false.  You can also increase the timeout to a longer interval with “Ping Maximum Response Time”.

VS2008 Multiple Web Projects Launch on Debug

In one of our VS2008 Solutions we have 17 web projects.  Each time you try to debug one of them they all launch an instance of the ASP.NET Development Server even though I only want to debug one of them.

To avoid having them all launch, set the project property “Always Start When Debugging” to False.  This prevents the project from launching when another project is started.  From SO: How can I stop Visual Studio running all my web services.

Note that this setting is actually store in the user project file which we don’t check in, so it must be reset each time the project is checked out.   But at least you can select all of the web projects and toggle them in one shot.

<AlwaysStartWebServerOnDebug>True</AlwaysStartWebServerOnDebug>

If you do actually want multiple projects to run at startup you can configure this with the solution property.  See also:  Tips & Tricks: Start-Up Options and Instances of ASP.Net Development Server in a Multi-project Solution.

How to Debug a Microsoft Service

Here is a cool trick for debugging a running Microsoft Service.

Create a debug version of the service and where you want to start debugging (usually the first line of the Main method) add the line:

System.Diagnostics.Debugger.Launch();

When the line is executed it will display a message to attach a debugger such as this one:

Select, “Yes debug the <ServiceName>”.  This will display a form to select the debugger you want to use.

And you will be stopped at the System.Diagnostics.Debugger.Launch() method in the debugger.