Passing a class as parameter in RESTful WCF Service
Asked Answered
C

2

9

In my RESTful WCF Serice I need to pass a class as a parameter for URITemplate. I was able to pass a string or multiple strings as parameters. But I have a lot of fields are there to pass to WCF Service. So I have created a class and added all the fields as properties and then I want to pass this class as one paramenter to the URITemplate. When I am trying to pass class to the URITemplate I am getting error "Path segment must have type string". Its not accepting class as a parameter. Any idea how to pass class as a parameter. Here is my code (inputData is class)


    [OperationContract]
    [WebGet(UriTemplate = "/InsertData/{param1}")]
    string saveData(inputData param1);
Chlorophyll answered 21/7, 2011 at 21:50 Comment(0)
T
17

You actually can pass a complex type (class) in a GET request, but you need to "teach" WCF how to use it, via a QueryStringConverter. However, you usually shouldn't do that, especially in a method which will change something in the service (GET should be for read-only operations).

The code below shows both passing a complex type in a GET (with a custom QueryStringConverter) and POST (the way it's supposed to be done).

public class StackOverflow_6783264
{
    public class InputData
    {
        public string FirstName;
        public string LastName;
    }
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        [WebGet(UriTemplate = "/InsertData?param1={param1}")]
        string saveDataGet(InputData param1);
        [OperationContract]
        [WebInvoke(UriTemplate = "/InsertData")]
        string saveDataPost(InputData param1);
    }
    public class Service : ITest
    {
        public string saveDataGet(InputData param1)
        {
            return "Via GET: " + param1.FirstName + " " + param1.LastName;
        }
        public string saveDataPost(InputData param1)
        {
            return "Via POST: " + param1.FirstName + " " + param1.LastName;
        }
    }
    public class MyQueryStringConverter : QueryStringConverter
    {
        public override bool CanConvert(Type type)
        {
            return (type == typeof(InputData)) || base.CanConvert(type);
        }
        public override object ConvertStringToValue(string parameter, Type parameterType)
        {
            if (parameterType == typeof(InputData))
            {
                string[] parts = parameter.Split(',');
                return new InputData { FirstName = parts[0], LastName = parts[1] };
            }
            else
            {
                return base.ConvertStringToValue(parameter, parameterType);
            }
        }
    }
    public class MyWebHttpBehavior : WebHttpBehavior
    {
        protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
        {
            return new MyQueryStringConverter();
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "").Behaviors.Add(new MyWebHttpBehavior());
        host.Open();
        Console.WriteLine("Host opened");

        WebClient client = new WebClient();
        Console.WriteLine(client.DownloadString(baseAddress + "/InsertData?param1=John,Doe"));

        client = new WebClient();
        client.Headers[HttpRequestHeader.ContentType] = "application/json";
        Console.WriteLine(client.UploadString(baseAddress + "/InsertData", "{\"FirstName\":\"John\",\"LastName\":\"Doe\"}"));

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
Truism answered 22/7, 2011 at 2:49 Comment(3)
Is it possible to provide a custom QueryStringConverter to a webHttpBehaviour already defined in Web.config?Response
No, you need a new class for that. You can expose that class in config if you want, though - see blogs.msdn.com/b/carlosfigueira/archive/2011/06/28/… for details.Truism
Your personal displeasure with configuration helped me. Thanks.Response
P
5

Passing a class (data contract) is only possible with POST or PUT request (WebInvoke). GET request allows only simple types where each must be part of UriTemplate to be mapped to parameter in the method.

Pyoid answered 21/7, 2011 at 21:52 Comment(3)
I tried using webinvoke with post method. Still its not working. here is my code ************ [OperationContract] [WebInvoke(UriTemplate= "/InsertData/param1",Method="POST")] string saveData(inputData param1); Here is how I am passing values to WCF service localhost:64475/RESTService1.svc/insertData/… in BrowserChlorophyll
The class must be in request's body. Not in URL.Pyoid
is it possible, can you provide some code or example. Thanks for ur timeChlorophyll

© 2022 - 2024 — McMap. All rights reserved.