Generate a C# Web Service Proxy from WSDL with wsdl2
You will turn a local WSDL document or service URL into source code for a client proxy, place it in a chosen namespace and check that the generated endpoint is what you expected. The examples use wsdl2 from the Ubuntu mono-devel package, installed here as version 6.8.0.105+dfsg-3.6ubuntu2.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 1. Confirm the installed command
- 2. Choose a WSDL input and an unused destination
- 3. Inspect the generated endpoint and namespace
- 4. Generate Visual Basic when the project needs it
- 5. Select the protocol deliberately
- 6. Keep credentials out of shell history
- 7. Diagnose failures without guessing
- 8. Compile and review as a separate step
Allow about fifteen minutes for a known-good WSDL. You need a shell, Mono's development tools and a WSDL file or URL that you are authorised to access. The command downloads referenced schemas and other WSDL documents, so treat a remote input as network access and review it before generating code.
Checkpoint
This guide generates source files. It does not compile them, call the service or change a system service. No elevated privileges are normally required.
1. Confirm the installed command
The installed man page is headed wsdl and describes Mono's Web Service Proxy Generator. It says that the older wsdl command targets the 1.x API and points to wsdl2 for the 2.x API. On this machine, the wsdl2 executable reports its own usage as the Mono Web Services Description Language Utility:
$ command -v wsdl2
/usr/bin/wsdl2
$ dpkg-query -W -f='${Package} ${Version}\n' mono-devel
mono-devel 6.8.0.105+dfsg-3.6ubuntu2
$ wsdl2 -?
Web Services Description Language Utility
Mono Framework v4.0.30319.42000
wsdl [options] {path | URL} {path | URL} ...
The help output is the most useful option reference for this installed binary. It accepts one or more paths or URLs, and options may use -option, --option or /option. The program rejects --version as an unknown option, so use the package query and the generated header when recording the version.
2. Choose a WSDL input and an unused destination
Use a local path while learning the workflow. A URL is also accepted, but the tool may follow imported schemas or WSDL documents. Do not fetch an untrusted URL merely to see what it contains, and do not generate directly over a maintained source file.
Pick a new destination and make the namespace explicit. The shell redirection trap does not apply here because -o is handled by wsdl2, but the tool still writes the named file. If that file already contains useful code, copy it first or choose another name.
$ WSDL_PATH='/path/to/service.wsdl'
$ OUTPUT_PATH="$PWD/ExampleService.cs"
$ wsdl2 -nologo -o:"$OUTPUT_PATH" -n:Example.Client "$WSDL_PATH"
Writing file '/home/me/project/ExampleService.cs'
Replace both placeholder values. Keep the WSDL path quoted, especially when it contains spaces. A successful command writes a file and returns status 0, but it does not prove that the service endpoint is correct or that the code will compile against your application.
Checkpoint
Confirm the result before editing it:
$ test -s "$OUTPUT_PATH" && printf '%s\n' 'generated file is non-empty'
generated file is non-empty
$ sed -n '1,28p' "$OUTPUT_PATH"
// <auto-generated>
// This code was generated by a tool.
// ...
3. Inspect the generated endpoint and namespace
Search the generated source for the service URL and namespace before compiling or committing it:
$ grep -nE 'namespace |this\.Url' "$OUTPUT_PATH"
14:namespace Example.Client {
29: this.Url = "https://api.example.test/service.asmx";
The URL comes from the WSDL's service address. It is not a safe placeholder added by wsdl2. If it points at a test, development or unexpected host, stop and resolve the WSDL or deployment issue. Do not silently edit the generated constructor and assume that the next regeneration will preserve the change. Regeneration replaces generated work, so keep custom application code in another file.
The -n or -namespace option controls the namespace of generated classes. The -o or -out option controls the output file. C# is the default language, and the output includes a generated-code marker and the Mono framework version used to produce it.
4. Generate Visual Basic when the project needs it
Pass -l:VB for Visual Basic. Use a separate destination rather than replacing the C# file:
$ wsdl2 -nologo -l:VB -o:"$PWD/ExampleService.vb" -n:Example.Client "$WSDL_PATH"
Writing file '/home/me/project/ExampleService.vb'
$ sed -n '1,18p' ExampleService.vb
' <auto-generated>
' This code was generated by a tool.
Option Strict Off
Option Explicit On
The installed help lists CS as the default and VB as the other built-in language. It also permits a fully qualified CodeDom provider name, but that provider must already be available to Mono; do not invent a provider name or add that complexity when C# or VB is sufficient.
5. Select the protocol deliberately
The default protocol is Soap. Use -protocol:HttpGet or -protocol:HttpPost only when the service description and your client requirements call for those protocols:
$ wsdl2 -nologo -protocol:Soap -o:"$PWD/ExampleService.cs" "$WSDL_PATH"
Writing file '/home/me/project/ExampleService.cs'
Do not add an HTTP protocol option as a guess. A WSDL can describe bindings and operations that are not interchangeable, and generating a different client shape does not make the server support that protocol.
6. Keep credentials out of shell history
The utility accepts -u/-username, -p/-password and -d/-domain for contacting a protected service. Passwords placed directly on the command line can appear in shell history and process listings. Prefer a local, permission-controlled input or an authenticated network arrangement that does not require exposing a secret in the command line. Do not paste real credentials into a guide or a shared terminal.
The same caution applies to proxy options. The installed help supports -proxy, -proxyusername, -proxypassword and -proxydomain. Use them only when the network requires them, and treat proxy credentials as credentials for the same purpose: short-lived, carefully scoped and absent from copied command history.
7. Diagnose failures without guessing
A missing or unreadable input is an input problem, not a reason to run as root. Check the path and read permission first:
$ test -r "$WSDL_PATH" && printf '%s\n' 'WSDL is readable'
$ file "$WSDL_PATH"
/path/to/service.wsdl: XML 1.0 document, ASCII text
If the command reports an error while downloading a URL or an imported document, inspect the exact URL, DNS, proxy and TLS path. The tool may need more than the first WSDL document. A network failure is not fixed by changing the output language or namespace.
If you generated a partial or unwanted file, remove only that known output after checking it is the file you meant to discard:
$ test -f "$OUTPUT_PATH" && printf 'review before deleting: %s\n' "$OUTPUT_PATH"
$ rm -- "$OUTPUT_PATH"
Warning
The final command is destructive and irreversible. Use a new output path instead when you need recovery. The WSDL input itself is read, not modified.
8. Compile and review as a separate step
wsdl2 produces source code, not a finished library. Add the generated file to the intended project and compile it with the references that project requires, including the web-service and XML assemblies appropriate to the target framework. Then review the generated service URL, methods, data types and authentication assumptions before making a live call.
Generated code can contain assumptions from the WSDL that deserve normal code review. Treat it as build input, keep the source document and command options recorded, and regenerate into a clean destination when the service contract changes.
Done means
wsdl2and the installedmono-develversion were confirmed.- A readable, authorised WSDL produced a non-empty source file.
- The output language and namespace match the consuming project.
- The generated service URL was inspected before any client call.
- No password was exposed unnecessarily in shell history or process listings.
- Compilation and live service testing remain separate, deliberate steps.