views:

214

answers:

4

I'm trying to test code around a web service that is not available yet. I'm trying to dummy up my own version. According to the specs it will be called like this.

var service = new Service();
service.SD = new ServiceData();
service.SD.ID = "ABC123";
service.SD.Auth = "00000";
string result = service.DoMyThing();

This is the closest I've gotten.

var service = new Service();
service.set_SD(new ServiceData());
service.get_SD().ID = "ABC123";
service.get_SD().Auth = "00000";
service.DoMyThing();

The problem is with the SD property. How do I write the service so that Visual Studio 2008 generates the web reference correctly?

Here is my current dummy web service code.

public class Service : System.Web.Services.WebService
{
    // This doesn't show up in the generated proxy at all
    public static ServiceData SDTest;

    // For extra credit explain why this needs to be static for it to work
    private static ServiceData _sd;
    public ServiceData SD
    {
        [WebMethod(EnableSession = true)]
        get { return _sd; }
        [WebMethod(EnableSession = true)]
        set { _sd = value; }
    }

    [WebMethod]
    public string DoMyThing()
    {
        // Presumably the real service accesses SD in here
        return "";
    }
}

public class ServiceData
{
    public string ID { get; set; }
    public string Auth { get; set; }
}
+3  A: 

Your design is flawed. Web services are not meant to have properties. They should only expose methods, the reason being that the HTTP protocol is stateless (and web services assume this too), so exposing a property doesn't make sense unless you want it to apply to all callers of the instance (and still, even in that situation, it doesn't make sense to expose it).

Rather, what you want to do is have the DoMyThing method take the instance of ServiceData (if required) and operate on that, returning the appropriate result set.

If you really have a need to expose properties of the service, you would have a GetProperties method (or something like that) which takes no parameters and returns the appropriate data structure with the service information.

casperOne
+1  A: 

I'm with casperOne on this. I think using fakie properties are more annoying than useful.

Still, if you're married to this just eliminate the getter for the property. You don't need it. Do this instead:

var service = new Service();
ServiceData sd = new ServiceData();
sd.ID = "ABC123";
sd.Auth = "00000";
service.SD = sd;
string result = service.DoMyThing();

If Visual Studio still names the setter property incorrectly you can use one of the soap attributes to rename it.

EDIT: You'll also need to define SD as a SOAP Header.

Spencer Ruport
That doesn't work. There can be no SD property. Pass "sd" as a method parameter.
John Saunders
No I'm pretty sure it works in .Net. It gets sent along as a custom SOAP header. See: http://www.codeproject.com/KB/webservices/SOAPHeaderAuthentication.aspx
Spencer Ruport
It works only if there _is_ a custom SOAP header. It must be declared by the WSDL.
John Saunders
Ah, forgot to mention that.
Spencer Ruport
Thanks all, the code project link had the details. The actual property in the spec has the "Value" suffix which seals the deal.
+1  A: 

You can't do this, so don't try to "fake it". The best you can do is:

var service = new Service();
ServiceData sd = new ServiceData();
sd.ID = "ABC123";
sd.Auth = "00000";
string result = service.DoMyThing(sd);
John Saunders
A: 

For those that may be interested. This more accurately reflects the spec than my sanitized version above (I didn't know "TypeNameValue" was a key clue, sorry!).

var service = new Service();
service.ServiceDetailsValue = new ServiceDetails();
service.ServiceDetailsValue.ID = "ABC123";
service.ServiceDetailsValue.Auth = "00000";
string result = service.DoMyThing();

And this is the dummy web service code that works.

using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(Name="TestService", ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    public ServiceDetails SDTest;

    [WebMethod]
    [SoapDocumentMethod(Binding = "TestService")]
    [SoapHeader("SDTest", Required = true)]
    public string DoMyThing()
    {
        return "";
    }
}

public class ServiceDetails : System.Web.Services.Protocols.SoapHeader
{
    public string ID { get; set; }
    public string Auth { get; set; }
}
Note that the service does not have properties. An instance of another class (ServiceDetails) was allocated by the proxy class, and is being filled in before the web service call. When the call is made, that instance is serialized as the <Header> of the SOAP Message. The service will be able to read it as a public field.
John Saunders