views:

382

answers:

2

I have a WCF service that I am attempting to connect to via a console application for testing (although will move to WPF for the final interface). I have generated the proxy, added the service reference to my project in visual studio and I can see all the methods I have created in my WCF interface:

SupportStaffServiceClient client = new SupportStaffServiceClient("WSHttpBinding_ISupportStaffService");
client.myMethod(message);

However when I call a method, which in the WCF interface is specified as returning a value, the method returns void in the console application.

client.getMethod(message);

The WCF service method is definitely returning a message, I'm just unsure as to why the client cannot "see" the return.

[service code]

[ServiceContract(Namespace="http://localhost/supportstaff")]
public interface ISupportStaffService  
{
[OperationContract]
TutorMessage AddTutor(TutorMessage message);  
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SupportStaff : ISupportStaffService
{
    private ITutorService tutors;

    public SupportStaff()
    {

        // Create the binding
        WSHttpBinding logBind = new WSHttpBinding();
        // Create the channel factory to the logging service
        ChannelFactory<ILogger> logFactory = new ChannelFactory<ILogger>(logBind, "http://localhost:8000/logger");
        // Create the connection to the logging service
        this.logger = logFactory.CreateChannel();

        // Create the binding
        WSHttpBinding tutorBind = new WSHttpBinding();
        // Create the channel factory to the Tutor service
        ChannelFactory<ITutorService> tutorFactory = new ChannelFactory<ITutorService>(tutorBind, "http://localhost:8001/tutors");
        // Create the connection to the Tutor service
        this.tutors = tutorFactory.CreateChannel();
    }
    TutorMessage ISupportStaffService.AddTutor(TutorMessage message)
    {
        // First log that we have received an add Tutor message
        // Create a log message
        LogMessage logMessage = new LogMessage();
        logMessage.Time = message.Time;
        logMessage.Message = "[Supprt Staff Service] Add Tutor message received";
        // Send the log message to the logging service
        logger.Log(logMessage);

        // Create a request to add the Tutor to the Tutor service
        TutorMessage request = new TutorMessage();
        request.Time = DateTime.Now;
        request.Tutor = message.Tutor;
        // Send the add Tutor message to the Tutor message
        tutors.AddTutor(request);

        // Display the message
        Console.WriteLine("Added Tutor " + message.Tutor.Number);
        // Log the message
        logMessage = new LogMessage();
        logMessage.Time = DateTime.Now;
        logMessage.Message = "[Support Staff Service] Added Tutor " + message.Tutor.Number;
        logger.Log(logMessage);

        // Create the return message
        TutorMessage toReturn = new TutorMessage();
        toReturn.Time = DateTime.Now;
        toReturn.Tutor = message.Tutor;
        // Return the return message
        return toReturn;
    }
}

[ServiceContract(Namespace = "http://localhost/tutors")]
public interface ITutorService
{
    [OperationContract]
    void AddTutor(TutorMessage message);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class TutorService : ITutorService
{
    private Dictionary<string, Tutor> tutors = new Dictionary<string, Tutor>();

    void ITutorService.AddTutor(TutorMessage message)
    {
        // First log the fact that we have received an Add message
        // Create the log message
        LogMessage logMessage = new LogMessage();
        logMessage.Time = message.Time;
        logMessage.Message = "[Tutor Service] Tutor add message received";
        // Send the log message to the logging service
        logger.Log(logMessage);

        // Now add the new Tutor to the collection of Tutors
        tutors[message.Tutor.Number] = message.Tutor;

        // Display message that Tutor is added
        Console.WriteLine("Added tutor : " + message.Tutor.Number);
        // Log the new Tutor
        logMessage = new LogMessage();
        logMessage.Time = DateTime.Now;
        logMessage.Message = "[Tutor Service] Added tutor : " + message.Tutor.Number;
        logger.Log(logMessage);
    }
}

[client code]

class Program
{
    static void Main(string[] args)
    {
        SupportStaffServiceClient client = new SupportStaffServiceClient("WSHttpBinding_ISupportStaffService");
        try
        {
            localhost.tutor.tutor t1 = new localhost.tutor.tutor();
            t1.name = "Big Dave";
            t1.number = "t123";
            DateTime time = DateTime.Now;

            client.AddTutor(ref time, ref t1);

            localhost.tutor.tutor t2 = new localhost.tutor.tutor();
            client.RetrieveTutor(ref time, ref t1);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message.ToString());
        }
        finally
        {
            Console.WriteLine("Press <RETURN> to exit");
            Console.ReadLine();
        }
    }
}

[svcutil generated code]

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class SupportStaffServiceClient : System.ServiceModel.ClientBase<ConsoleApplication1.SupportStaffService.ISupportStaffService>, ConsoleApplication1.SupportStaffService.ISupportStaffService {

    public SupportStaffServiceClient() {
    }

    public SupportStaffServiceClient(string endpointConfigurationName) : 
            base(endpointConfigurationName) {
    }

    public SupportStaffServiceClient(string endpointConfigurationName, string remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }

    public SupportStaffServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }

    public SupportStaffServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(binding, remoteAddress) {
    }

    public string HelloWorld(string name) {
        return base.Channel.HelloWorld(name);
    }

    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
    ConsoleApplication1.SupportStaffService.TutorMessage ConsoleApplication1.SupportStaffService.ISupportStaffService.AddTutor(ConsoleApplication1.SupportStaffService.TutorMessage request) {
        return base.Channel.AddTutor(request);
    }

    public void AddTutor(ref System.DateTime time, ref ConsoleApplication1.SupportStaffService.tutor tutor) {
        ConsoleApplication1.SupportStaffService.TutorMessage inValue = new ConsoleApplication1.SupportStaffService.TutorMessage();
        inValue.time = time;
        inValue.tutor = tutor;
        ConsoleApplication1.SupportStaffService.TutorMessage retVal = ((ConsoleApplication1.SupportStaffService.ISupportStaffService)(this)).AddTutor(inValue);
        time = retVal.time;
        tutor = retVal.tutor;
    }
}
+2  A: 

I've never seen svcutil generate a method with ref parameters before - how did it do that? Anyway, it looks like you want to call the method above that in the generated code - this one takes and returns a TutorMessage object. So you could do

TutorObject returnedTutor = client.AddTutor(inputTutorObject);

Or, it looks like if you call the method with the ref parameters, as you're currently doing, the "return" value is put into those same ref parameters. So you pass in time and t1, call AddTutor, and now those variables you've passed in will contain the returned values. So, you could do

t1.name = "Big Dave";
t1.number = "t123";
DateTime time = DateTime.Now;

client.AddTutor(ref time, ref t1);

// time now contains the returned DateTime from the service
// t1 now contains the returned Tutor from the service
Graham Clark
Thanks for your response Graham. Regarding how I managed to generate ref parameters I have no idea. svcutil /language:cs /out:generatedProxy.cs /config:app.config http://localhost:1234Regarding how to access the returned values, if I understand you correct although I cannot do tutorReturn = client.AddTutor(ref time, ref t1); you're saying the returned tutor is automatically assigned to the t1 object?
Abs
@Abs: I've added some code to my answer, hopefully this will make things clearer. Maybe this method with ref parameters got generated because the input and return types are the same? I'm not sure.
Graham Clark
@Graham Clark: The method that you suggest to use that DOES have a return value doesn't have an access modifier, so it will default to private, I'm having a similar problem, I'm obviously not the only one, what's going on, any ideas?
Dog Ears
@Dog Ears: oh yeah, you're right. I guess I don't really understand why svcutil has generated the method with the `ref` parameters in the first place. Is it something to do with the `[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]` attribute?
Graham Clark
A: 

I had a similar problem where we'd forgottent to mark a custom MessageContract on our Response Class with the MessageBodyMemberAttribute our messageResponse Class didn't expose any members in it's data contract thus the Call to the service returned void.

Before...

[MessageContract]
public class MyCustomResponse
{
    public string Response { get; set; }
}
...

After...

[MessageContract]
public class MyCustomResponse
{
    [MessageBodyMember(Namespace = "http://MyNamespace")]
    public string Response { get; set; }
}

After adding the MessageBodyMember to the Response member, the svcutil generates code that hides the details of the custom Message Contract and just returns the Response as a string return value from my service's proxy.

Dog Ears