I’ve written a fairly simple little C# web service, hosted from a standalone EXE via WCF. The code – somewhat simplified – looks like this:
namespace VMProvisionEXE
{
class EXEWrapper
{
static void Main(string[] args)
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.None;
Uri baseAddress = new Uri("http://bernard3:8000/VMWareProvisioning/Service");
ServiceHost selfHost = new ServiceHost(typeof(VMPService), baseAddress);
try
{
selfHost.AddServiceEndpoint(typeof(IVMProvisionCore), myBinding, "CoreServices");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy12;
selfHost.Description.Behaviors.Add(smb);
// Add MEX endpoint
selfHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
selfHost.Open();
Console.WriteLine("The service is ready.");
Console.ReadLine();
The rest of the C# code; the class VMPService above implements VMProvisionCore.IVMProvisionCore.
namespace VMProvisionCore
{
[ServiceContract(Namespace = "http://Cisco.VMProvision.Core", ProtectionLevel = System.Net.Security.ProtectionLevel.None)]
public interface IVMProvisionCore
{
[OperationContract]
bool AuthenticateUser(string username, string password);
}
I can easily create a Visual Studio 2008 client application that consumes this service. No problems. But using Delphi 2007 is a different issue. I can use the WSDL importer in Delphi to retrieve the WSDL from (in this case) http://bernard3:8000/VMWareProvisioning/Service?wsdl The import unit compiles just fine. I have to initialize the proxy by hand since the WSDL doesn’t contain a URL (notice the extra “/CoreServices” as shown in the C# code):
var
Auth: AuthenticateUser;
AuthResponse: AuthenticateUserResponse;
CoreI: IVMProvisionCore;
begin
CoreI:= GetIVMProvisionCore(False, 'http://bernard3:8000/VMWareProvisioning/Service/CoreServices');
Auth:= AuthenticateUser.Create;
try
Auth.username:= 'test';
Auth.password:= 'test';
AuthResponse:= CoreI.AuthenticateUser(Auth);
finally
FreeAndNIL(Auth);
end;
The above code will generate an error when it hits the “CoreI.AuthenticateUser(Auth);”. The error is “Cannot process the message because the content type ‘text/xml; charset=”utf-8″ was not the expected type ‘application/soap+xml; charset=utf-8.“
I suspect that I’ve got a stupid little error somewhere, perhaps during the import of the WSDL or in the connection options or something. Can anyone help?
Found the solution. It’s multiple parts and requires a few changes to the C# side, more to the Delphi side. Note that this was tested with Delphi 2007 and Visual Studio 2008.
C# side:
Use BasicHttpBinding rather than WSHttpBinding.
Fix Step 1
This change will resolve the application/soap+xml errors on the Delphi side.
Delphi 2007 side:
Running against the modified C# web service will now generate errors like this:
To resolve this problem, add SOAPActions to all your supported interfaces. Here’s the example from my code; this must be done AFTER all of the InvRegistry changes made by the import-from-WSDL-PAS-file’s initialization section:
Fix Step 2
The type name and URL should be obtainable from the Delphi generated import file from the WSDL and/or an inspection of the actual WSDL. The above example was for my own project. After these code changes, then you’ll the error:
This error is resolved by adding the following code (credits to http://www.bobswart.nl/weblog/Blog.aspx?RootId=5:798). Again, this new code must be after all the InvRegistry stuff in the initialization of the WSDL-to-PAS file.
Fix Step 3
At this point, packets will go back and forth between Delphi and C# – but parameters won’t work properly. The C# will receive all parameters as nulls and Delphi doesn’t seem to be receiving response parameters properly. The final code step is to use a slightly customized THTTPRIO object that will allow for literal parameters. The trick to this part is to make sure that the option is applied AFTER the interface has been obtained; doing it before won’t work. Here’s the code from my example (just snippets).
Fix Step 4
And now – my Delphi 2007 app can talk to the C#, stand-alone, non-IIS, WCF web service!