Mar 272008
 

I was looking for guidance on this topic, and came up with nothing. I’m sure people are doing this, but can’t find any info. For anyone looking like I was, here’s how to do it.


It’s much simpler than I imagined, thanks to WCF. You can programmatically create your endpoint, binding, and channel inside your service. This would require that the address be hard-coded and require a recompile to change the address or binding. As long as your host’s app.config or web.config has a client endpoint specifying the contract, you don’t have to go through all that work. Your service is simply a client of another service, so your code looks just like that of a client of your service. Furthermore, changing the address or binding is as simple as changing config file values.


Service code:




    1 using System;


    2 using System.ServiceModel;


    3 using DataContracts;


    4 namespace ServiceImplementation


    5 {


    6     [ServiceContract]


    7     public interface IEmailService


    8     {


    9         [OperationContract]


   10         void Send(DataContracts.MailMessage msg);


   11     }


   12 


   13     public class EmailService : IEmailService


   14     {


   15         [OperationBehavior]


   16         public void Send(DataContracts.MailMessage msg)


   17         {


   18             // Open client proxy for legacy web service


   19             using (LegacyEmailServiceClient proxy =


   20                 new LegacyEmailServiceClient())


   21             {


   22                 proxy.SendEmail(msg.To,


   23                     msg.CC,


   24                     msg.Bcc,


   25                     msg.Body,


   26                     msg.Attachments);


   27             }


   28         }


   29     }


   30 }


   31 



Host’s app.config:




    1 <?xml version=1.0 encoding=utf-8?>


    2 <configuration>


    3   <system.serviceModel>


    4     <bindings>


    5       <basicHttpBinding>


    6         <binding name=BasicHttpBinding_Common>


    7           <security mode=None/>


    8         </binding>


    9       </basicHttpBinding>


   10       <netTcpBinding>


   11         <binding name=NetTcpBinding_Common>


   12           <security mode=None/>


   13         </binding>


   14       </netTcpBinding>


   15     </bindings>


   16     <client>


   17       <endpoint address=http://www.gotjeep.net/legacy/email.asmx


   18           binding=basicHttpBinding


   19                 bindingConfiguration=BasicHttpBinding_Common


   20           contract=LegacyEmailServiceClient


   21                 name=LegacyEmailServiceClient />


   22     </client>


   23     <services>


   24       <service name=ServiceImplementation.EmailService


   25               behaviorConfiguration=returnFaults>


   26         <host>


   27           <baseAddresses>


   28             <add baseAddress=http://localhost:8080/EmailService />


   29             <add baseAddress=net.tcp://localhost:8088/EmailService />


   30           </baseAddresses>


   31         </host>


   32         <endpoint name=NetTcpBinding_EmailService


   33                   binding=netTcpBinding


   34                   bindingConfiguration=NetTcpBinding_Common


   35                   contract=ServiceImplementation.IEmailService/>


   36         <endpoint name=BasicHttpBinding_EmailService


   37                   binding=basicHttpBinding


   38                   bindingConfiguration=BasicHttpBinding_Common


   39                   contract=ServiceImplementation.IEmailService/>


   40       </service>


   41     </services>


   42     <behaviors>


   43       <serviceBehaviors>


   44         <behavior name=returnFaults >


   45           <serviceMetadata httpGetEnabled=true />


   46         </behavior>


   47       </serviceBehaviors>


   48     </behaviors>


   49   </system.serviceModel>


   50 </configuration>


Mar 252008
 

Before you try running a Console Application or Windows Service application that hosts a WCF service with basicHttpBinding or wsHttpBinding, see this MSDN article about “Configuring HTTP and HTTPS”. If you are WAS-hosted or Web App-hosted, the urlacl entries are made on your behalf.


You can view the current entries with “netsh http show urlacl“. To make the changes, you’ll need to “Run as Administrator” when going into your Command Prompt.


I decided to use the following command:



netsh http add urlacl url=http://+:8080/ user=Everyone


You should adjust the ports and/or path as necessary for your situation:



netsh http add urlacl url=http://+:8080/MyConsoleAppHostedService user=DOMAINuser


netsh http add urlacl url=http://+:8091/MyWindowsServiceHostedService user=SYSTEM

Mar 232008
 

WCF is seamless, powerful, and (YES) interoperable. Here is a quick walkthrough detailing steps to call your legacy PHP web services from a WCF client. All of the binding types and security options are, of course, not available. But for those of you following the old “security through obscurity” model, this will work fine.

The procedure is just as simple as a WCF-WCF call:

  1. Create client proxy
  2. Add client endpoint to your client config file
  3. Write your proxy-consuming client code

Create the client proxy:


Nusoap provides a similar UI when navigating to your PHP web service to that provided by ASMX services. You can view the WSDL, and copy the URL for svcutil.exe.



From the Visual Studio 2005 Command Prompt, type:


svcutil <url> /out:<name>Proxy.cs /noconfig
svcutil http://gotjeep.net/services/ApproachAngleService.php?wsdl /out:ApproachAngleServiceProxy.cs /noconfig



This generates a file named ApproachAngleServiceProxy.cs.




    1 //——————————————————————————


    2 // <auto-generated>


    3 //    This code was generated by a tool.


    4 //    Runtime Version:2.0.50727.1433


    5 //


    6 //    Changes to this file may cause incorrect behavior and will be lost if


    7 //    the code is regenerated.


    8 // </auto-generated>


    9 //——————————————————————————


   10 


   11 


   12 


   13 [System.CodeDom.Compiler.GeneratedCodeAttribute(“System.ServiceModel”, “3.0.0.0″)]


   14 [System.ServiceModel.ServiceContractAttribute(Namespace=“http://www.gotjeep.net/tech”, ConfigurationName=“GotJeepApproachAngleCalculatorPortType”)]


   15 public interface GotJeepApproachAngleCalculatorPortType


   16 {


   17 


   18     [System.ServiceModel.OperationContractAttribute(Action=“http://www.gotjeep.net/services/approachAngleService.php/CalculateApproachAngle”, ReplyAction=“*”)]


   19     [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]


   20     [return: System.ServiceModel.MessageParameterAttribute(Name=“return”)]


   21     decimal CalculateApproachAngle(decimal height, decimal diameter, decimal distance);


   22 }


   23 


   24 [System.CodeDom.Compiler.GeneratedCodeAttribute(“System.ServiceModel”, “3.0.0.0″)]


   25 public interface GotJeepApproachAngleCalculatorPortTypeChannel : GotJeepApproachAngleCalculatorPortType, System.ServiceModel.IClientChannel


   26 {


   27 }


   28 


   29 [System.Diagnostics.DebuggerStepThroughAttribute()]


   30 [System.CodeDom.Compiler.GeneratedCodeAttribute(“System.ServiceModel”, “3.0.0.0″)]


   31 public partial class GotJeepApproachAngleCalculatorPortTypeClient : System.ServiceModel.ClientBase<GotJeepApproachAngleCalculatorPortType>, GotJeepApproachAngleCalculatorPortType


   32 {


   33 


   34     public GotJeepApproachAngleCalculatorPortTypeClient()


   35     {


   36     }


   37 


   38     public GotJeepApproachAngleCalculatorPortTypeClient(string endpointConfigurationName) :


   39             base(endpointConfigurationName)


   40     {


   41     }


   42 


   43     public GotJeepApproachAngleCalculatorPortTypeClient(string endpointConfigurationName, string remoteAddress) :


   44             base(endpointConfigurationName, remoteAddress)


   45     {


   46     }


   47 


   48     public GotJeepApproachAngleCalculatorPortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :


   49             base(endpointConfigurationName, remoteAddress)


   50     {


   51     }


   52 


   53     public GotJeepApproachAngleCalculatorPortTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :


   54             base(binding, remoteAddress)


   55     {


   56     }


   57 


   58     public decimal CalculateApproachAngle(decimal height, decimal diameter, decimal distance)


   59     {


   60         return base.Channel.CalculateApproachAngle(height, diameter, distance);


   61     }


   62 }


 


Add client endpoint to your config file:


You have the option of letting svcutil create your config file or using “Generate Service Reference”, but I prefer to avoid the extra 20+ lines of config file defaults included by svcutil. It’s not hard to write it yourself, and it ensures a much more readable config file.




    1 <?xml version=1.0 encoding=utf-8?>


    2 <configuration>


    3     <system.serviceModel>


    4         <bindings>


    5             <basicHttpBinding>


    6               <binding name=GotJeepApproachAngleCalculatorBinding>


    7                 <security mode=None/>


    8               </binding>


    9             </basicHttpBinding>


   10         </bindings>


   11         <client>


   12             <endpoint address=http://www.gotjeep.net/services/approachAngleService.php


   13                 binding=basicHttpBinding


   14                 bindingConfiguration=GotJeepApproachAngleCalculatorBinding


   15                 contract=GotJeepApproachAngleCalculatorPortType


   16                 name=GotJeepApproachAngleCalculatorPort />


   17         </client>


   18     </system.serviceModel>


   19 </configuration>


 


Write the client code:


    1 using System;

    2 

    3 namespace Client

    4 {

    5     class Program

    6     {

    7         static void Main(string[] args)

    8         {

    9             using (GotJeepApproachAngleCalculatorPortTypeClient proxy =

   10                 new GotJeepApproachAngleCalculatorPortTypeClient())

   11             {

   12                 decimal result = proxy.CalculateApproachAngle(25.6m, 33.2m, 17.75m);

   13                 Console.WriteLine(“decimal result = proxy.CalculateApproachAngle(25.6m, 33.2m, 17.75m);”);

   14                 Console.WriteLine(“result = “ + result.ToString(“0.00″));

   15             }

   16         }

   17     }

   18 }


 


Check it out:


A request-reply call between WCF and a Nusoap PHP web service.