Using PowerShell to call a WCF service

PowerShell lets you create web service proxies from WSDLs via the New-WebServiceProxy cmdlet. However, it only works for SOAP web services running on HTTP endpoints. If you have a WCF service using only non http protocols, such as NetTcp, you cannot use New-WebServiceProxy.

Now, I’ve created and consumed my fair share of web services. So when I began to use PowerShell, I quickly figured out this unfortunate fact. I always knew that I could make use of WCF API to generate the proxies, but I never bothered to figure out how. The annoyance was pretty academic to me. At some point I event told someone on stackoverflow that it can’t be done.

Then on Friday, I accidentally discovered that a Sharepoint MVP by the name of Christian Glessner solved this problem in 2008 while visiting the excellent site Christian explains his solution in detail on his blog.

His solution was a very elegant PowerShell 1.0 solution. However, I felt it could be improved by adding some PowerShell 2.0 features such as parameter collections. I also was really intrigued and wanted to dig into his solution. He was supportive of my initial modifications so I put the git repo of my changes on the justaprogrammer github organization.

Using my version

My version of the script creates three functions:

  • Get-WsdlImporter
  • Get-WcfProxyType
  • Get-WcfProxy

The function that is most analogous to New-WebServiceProxy is Get-WcfProxy. I kept the name from Christian’s version of the code, despite the fact that New-WcfProxy would be more appropriate. In Christian’s version of the code, Get-WcfProxy only returned a System.Type of the generated proxy, not an instance of it. I renamed that to Get-WcfProxyType. Finally. Get-WsdlImporter takes a wsdl or mex endpoint and returns an instance of a System.ServiceModel.Description.WsdlImporter that represents that metadata.

By default Get-WsdlImporter tries to generate the WsdlImporter via metadata exchange, but it can parse a wsdl with the -HttpGet switch. Below are some examples illustrating its usage:

$wsdlImporter = Get-WsdlImporter 'http://localhost:14232/EchoService.svc/mex' # Mex endpoint
Get-WsdlImporter 'http://localhost:14232/EchoService.svc' -HttpGet # WDSL endpoint
Get-WsdlImporter 'http://localhost:14232/EchoService.svc?wsdl' -HttpGet # WSD: endpoint 

I don’t see much point for calling Get-WcfProxyType directly so I will not illustrate how to use it here. Get-WcfProxy is the function you want to call. Its main parameter is either a url or a WsdlImporter. You can either let Get-WcfProxy pick the first endpoint it finds in the WsdlImporter, or specify an endpoint and url you want to use as parameters as illustrated below:.

$wsdlImporter = Get-WsdlImporter "http://localhost:14232/EchoService.svc/mex"
$proxy = Get-WcfProxy $wsdlImporter # using a WsdlImporter object
$proxy = Get-WcfProxy "http://$($hostname):14232/EchoService.svc/mex" # using a url
$proxy = Get-WcfProxy $wsdlImporter "http://localhost:14232/EchoService.svc/WCF" (New-Object System.ServiceModel.WSHttpBinding) # using a WsdlImporter and specifying the endpoint and binding.
$proxy = Get-WcfProxy 'net.tcp://localhost:8732/EchoService/mex' 'net.tcp://localhost:8732/EchoService/' (New-Object System.ServiceModel.NetTcpBinding) # using a metadata url and specifying the endpoint and binding.
$proxy.Echo("Justin Dearing"); # calling a service function

As you might have guessed from my examples I used the justaprogrammer EchoService in my tests.

The code itself

I recommend you refer to the github repo for the latest version of the code. However, the version I used here is posted on and embedded below.

Future directions

My fork is released under the MIT license and I’d be happy to review patches and consider bug reports and feature requests.

IIS7 Web Application Enabled Protocols: Yet Another WCF Gotcha!

One of the cool things about IIS 7.0  and WCF is the ability to serve WCF endpoints with non-http bindings. Naturally, this new feature presents new opportunities for the developer to get frustrated by WCF configuration headaches. This blog post is about one of them.

I was writing a WCF web service that had three endpoints, Json, Soap 1.1, and net.tcp. This services primary purpose was to be the middleware for the mongo database where my applications data was held. In the end, I didn’t need the net.tcp endpoint, making this exercise a complete waste of time.  The reasons for my architectural decisions for this app are the subject of another blog post. For now, lets just say if you are supposed to learn more from your failures than your successes, I should get an honorary doctorate for this app.

In the past I’ve mixed soap and net.tcp in EXE hosted WCF services with great success. However, since I’ve yet to find a JSONP endpoint solution for WCF that allows request parameters, I needed to host this in IIS on the same site as my project. So I made a .svc file in my website, added the service dll as a reference, and ran it. I promptly got the the following error:

Could not find a base address that matches scheme

It was a bit frustrating to find the solution, but I did eventually. In IIS manager you have to select Advanced Settings in the applications Application folder, or website if the app is running at the root. In the advanced settings dialog is an option called Enabled Protocols. It probably contains the value http or http,https. You simple have to append ,net.tcp to the current value.

IIS Manager

IIS Application Advanced Settings

After that, everything works.

WCF Service

As an epilogue to this adventure, since I forgot to take all the screenshots needed for this blog article at work, I ended up having to make an example project to reproduce the error at home. As such I took an older example WCF project I wrote called EchoService and adding a website host to it in addition to the exe host. This improved version of EchoService can be found at the justaprogrammer github org. Feel free to use this service s the basis for any WCF related instructional materials. The code is licensed under the very permissive MIT license.