10

I've got a custom HTTP server built in C# which accepts requests for REST services and responds with XML or JSON (depending on what the client needs). The REST services are defined at runtime from a database-based configuration, vary widely in input parameters and output types, and it's working beautifully in production.

However, I'd like to add SOAP access to the same services, with appropriate WSDLs as well. Since the available services aren't hard-coded, this means:

  • Publishing a WSDL generated at runtime from the method definitions in the database
  • Parsing incoming SOAP requests, mapping them to those definitions, and making sure the requests conform to the method signature before handling them
  • Once the response is handled, creating a SOAP response meeting the WDSL to return the results

The MS documentation (and Google) documents using Visual Studio to generate web services (and WSDLs) at design time, exposing stuff using WebMethods, ASP.NET MVC etc. This isn't what I'm looking for, as there are no method definitions from which to generate the bindings at design time.

Does anyone have any ideas (e.g. toolkits for raw SOAP parsing), and thoughts on generation of WSDLs from dynamically created method signatures, etc? Any idea how one might go about building such things if not? I'm looking to avoid re-inventing the wheel if possible.

PS: Clearly there's standardised stuff in the .NET framework for this, since Visual Studio does it for you - any ideas how to access that at a lower level, at runtime?

Richard K.
  • 2,034
  • 1
  • 14
  • 15
  • 1
    _"The REST services are defined at runtime from a database-based configuration"_ - I shivered when I read that. Isn't that a maintenance and troubleshooting hell? – CodeCaster Jul 23 '12 at 10:06
  • I am dealing with a very similar situation wondering if the accepted answer worked for you – np-hard Oct 14 '12 at 06:15
  • np-hard - I did a proof-of-concept and it did what was intended. I've not rolled anything out to production, though, as on balance asking clients to implement the REST service seemed like a more dependable choice than manual parsing, and any bugs which may be introduced through the complex process of manually parsing SOAP requests. – Richard K. Oct 14 '12 at 10:18

3 Answers3

6

To create a wsdl dynamically you can use ServiceDescriptionReflector

For example: for class

public class TestWebService
{
    [WebMethod]
    public string Hello(string namex)
    {
        return "Hello " + namex;
    }
}

you can use this code

StringWriter wr = new StringWriter();
var r = new System.Web.Services.Description.ServiceDescriptionReflector();
r.Reflect(typeof(TestWebService), "http://somewhere.com");
r.ServiceDescriptions[0].Write(wr);
var wsdl = wr.ToString();

But since you've said

Publishing a WSDL generated at runtime from the method definitions in the database

you have to create the Type at runtime

var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("MyAsm"), AssemblyBuilderAccess.Run);
var mod = asm.DefineDynamicModule("MyModule");

TypeBuilder typeBuilder = mod.DefineType("TestWebService");

MethodBuilder mb = typeBuilder.DefineMethod("Hello", MethodAttributes.Public, CallingConventions.Standard, typeof(string), new Type[] { typeof(string) });
var cab = new CustomAttributeBuilder( typeof(WebMethodAttribute).GetConstructor(new Type[]{}), new object[]{} );
mb.SetCustomAttribute(cab);
mb.DefineParameter(1, ParameterAttributes.In, "namex");
mb.GetILGenerator().Emit(OpCodes.Ret);

Type type = typeBuilder.CreateType();

Now you can use type to create wsdl

StringWriter wr = new StringWriter();
var r = new System.Web.Services.Description.ServiceDescriptionReflector();
r.Reflect(type, "http://somewhere.com");
r.ServiceDescriptions[0].Write(wr);
var wsdl = wr.ToString();

For reading request and forming response, you can use Linq2Xml. Fiddler can give you an idea about SOAP(xml) format sent between client and server

L.B
  • 114,136
  • 19
  • 178
  • 224
  • That's great - I've already got the type creation sorted out, but the ServiceDescriptionReflector was exactly what I was looking for. Thanks! – Richard K. Jul 26 '12 at 08:04
2

SOAP is "just" an XML-based protocol for information exchange. Implementing support for it from the ground up would be tedious but not hugely complicated in principle, I don't think.

The official SOAP specifications can be found here.

  • It's mostly the tedium (and potential for bugs) I'm looking to avoid - rather hoping for some kind of toolkit for handling SOAP parsing etc. I know Microsoft had their SOAP Toolkit about 10 years ago, but it was deprecated in favour of VS managing everything... thanks, though! – Richard K. Jul 19 '12 at 08:08
2

Don't parse SOAP unless you really have to, let WCF do the heavy lifting for you, generate service- and datacontracts in C# code from your definitions and compile at runtime . Generate a service implementation that hooks into your "static" code through a well known interface.

Dynamically create endpoints with the correct binding for the new service contracts/data contracts. If bindings don't change dynamically this could be defined in you app.config otherwise set this in runtime as well.

add a Mex endpoint to get the wsdl published.

For "examining" incoming traffic use a MessageInspector

self host the WCF/SOAP service in your HTTP server using ServiceHost -> Self Hosting WCF

Just some ideas on another approach.

Tommy Grovnes
  • 4,126
  • 2
  • 25
  • 40
  • It's possibly not clear enough from my original question, but both data contracts and bindings *do* change at runtime, which is why I'm not using WCF. That's the use case here - a non-WCF/IIS server and contracts which change (and are often created, too) at runtime. – Richard K. Jul 23 '12 at 14:25
  • If both the contracts and the bindings change how does your clients use your service ? Must be hard to locate the service ? – Tommy Grovnes Jul 23 '12 at 15:43
  • I got the dynamic contract bit and it is addressed by dynamically generating the contracts, as for the hosting you could self host the WCF/SOAP service in your HTTP server using ServiceHost http://msdn.microsoft.com/en-us/library/ms730158.aspx . – Tommy Grovnes Jul 23 '12 at 16:06
  • I did something similar with WCF where the contract definition was data driven, but wasn't subject to change once defined in the database. Still needed to be generated at runtime: http://stackoverflow.com/questions/8864296/creating-wcf-service-at-runtime/10407617#10407617 – Sean Chase Nov 22 '12 at 04:49
  • Did the client pieces also get generated from the same data (at runtime as well) ? – Tommy Grovnes Nov 22 '12 at 13:43