none
How do you do a call to a WCF REST POST method?

    Question

  • Hi!

    I'm trying to find out how to call a POST method in a WCF REST webservice... where do I have to put the body?

    I've declared a method like this:

            [WebInvoke(UriTemplate = "/{communityId}/Login", Method = "POST")]
            [OperationContract]
            Boolean Login(String communityId, UserLogin login);

     

    But... how do I call it now? :D

    I've tried several things, but I always get a bad request :(

     

                Guid g = Guid.NewGuid();
                String user = "<UserLogin><Name>vt</Name><Password>lalala</Password></UserLogin>";

                XmlSerializer s = new XmlSerializer(typeof(UserLogin), "ConsoleApplication1");
                UserLogin ul = new UserLogin() { Name = "vt", Password = "lalala" };

                WebRequest req = WebRequest.Create("http://localhost/RESTfulService/Service1.svc/" + g.ToString() + "/Login");
                req.Method = "POST";
                req.ContentType = "application/x-www-form-urlencoded";
               
               
                MemoryStream ms = new MemoryStream();
                s.Serialize(ms, ul);
                Byte[] array = ms.ToArray();

                req.ContentLength = array.Length;
                Stream reqStream = req.GetRequestStream();
                reqStream.Write(array, 0, array.Length);
                reqStream.Close();

                //StreamWriter sw = new StreamWriter(reqStream,Encoding.UTF8);
                //sw.WriteLine(user);
                //sw.Dispose();
               
                Stream responseStream = req.GetResponse().GetResponseStream();

     

    Cheers.


    .: Valeriano Tórtola MCTS WPF :.: http://www.vtortola.net :.
    Monday, March 29, 2010 9:24 PM

Answers

  • Hi Valeriano,

    So the service doesn't report error and just get empty value for the UserLogin object's Username field, correct? In my test service, I also declare the UserLogin class in both client and service project twice, but they are identical, so if you make sure the class definition in both projects are identical(even the namespace) then it should be no problem on that.

    Try using the method I mentioned earlier, define a WebGet operation to return the UserLogin and compare its generated XML with the one you send (for the webInvoke operation) to see whether there is difference. You can use fiddler tool to capture message for http service(without message layer security):

    http://www.fiddler2.com/Fiddler2/version.asp

    or you can even try using WebChannelFactory to call REST service to see whether it works. If works, also try capturing its SOAP message to compare it with your current one.

    #WebChannelFactory(TChannel) Class
    http://msdn.microsoft.com/en-us/library/bb908674.aspx

    If necessary, I can send you my test solution so that you can try running it on your side. You can reach me at the following address:

    stcheng (AT) microsoft.com





    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    • Marked as answer by Mog Liang Monday, April 05, 2010 2:57 AM
    Thursday, April 01, 2010 3:07 AM

All replies

  • hi,

     Are your sure your URL is correct?

    can you open  "http://localhost/RESTfulService/Service1.svc/" + g.ToString() + "/Login" in  IE?

    additionally, Whatis the bad request data?

     


    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
    Tuesday, March 30, 2010 1:23 AM
  • Yes, the url is correct because I have other methods with a similar uritemplate.

    I get a "400 Bad Request" when I post this: "<UserLogin><Name>vt</Name><Password>lalala</Password></UserLogin>" or I serialize the class with a XmlSerializer.

    How would you call this method?:

            [WebInvoke(UriTemplate = "/{communityId}/Login", Method = "POST")]
            [OperationContract]
            Boolean Login(String communityId, UserLogin login);

    Considering:

        public class UserLogin
        {
            public String Name { get; set; }
            public String Password { get; set; }
        }

    Cheers.


    .: Valeriano Tórtola MCTS WPF :.: http://www.vtortola.net :.
    Tuesday, March 30, 2010 10:57 AM
  • Yes, the url is correct because I have other methods with a similar uritemplate.

    I get a "400 Bad Request" when I post this: "<UserLogin><Name>vt</Name><Password>lalala</Password></UserLogin>" or I serialize the class with a XmlSerializer.

    How would you call this method?:

            [WebInvoke(UriTemplate = "/{communityId}/Login", Method = "POST")]
            [OperationContract]
            Boolean Login(String communityId, UserLogin login);

    Considering:

        public class UserLogin
        {
            public String Name { get; set; }
            public String Password { get; set; }
        }

    Cheers.


    .: Valeriano Tórtola MCTS WPF :.: http://www.vtortola.net :.
    Tuesday, March 30, 2010 10:57 AM
  • Hi vtortola,

    The problem you encounter is probably due the default serialization behavior of WCF.

    * WCF by default use DataContractSerializer to serialize object into XML, for the UserLogin class you provided, you can try define a WebGet operation and let it return a UserLogin object. e.g.

        [OperationContract]
        [WebGet]
        UserLogin GetUserLogin();

     You will find that it returns the following xml:

    <UserLogin xmlns="http://schemas.datacontract.org/2004/07/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Name>user1</Name><Password>password1</Password></UserLogin>

    the default output will use the http://schemas.datacontract.org/2004/07/  as a root namespace for your object. And if you do not add this namespace when using webrequest client, it will mismatch the server-side expected xml format. If you want to make the WCF service use XML serialization, you can add the "XmlSerializerFormatAttribute" on the serviceContract like below:

    [ServiceContract]
    [XmlSerializerFormat]
    public interface IRESTService
    {
    
        [OperationContract]
        [WebInvoke]
        string SendUserLogin(UserLogin ul);
    }

    Then, it will generate XmlSerializer compatible xml content from object. Here is the test client code I used:

    private static void WebRequestClient()
            {
                var httpwebrequest = WebRequest.Create("http://localhost:8388/testapp/RESTService.svc/SendUserLogin");
                httpwebrequest.Method = "POST";
                httpwebrequest.ContentType = "application/xml";
    
                //generated xml object
                XmlSerializer serializer = new XmlSerializer(typeof(UserLogin));
    
                UserLogin ul = new UserLogin() { Name = "user1", Password = "password1" };
                MemoryStream ms = new MemoryStream();
                serializer.Serialize(ms, ul);
                var bytes = ms.ToArray();
                ms.Close();
    
                //write xml into request stream
                var requestStream = httpwebrequest.GetRequestStream();
                requestStream.Write(bytes, 0, bytes.Length);
                requestStream.Close();
    
                //extract resposne result
                var responseStream = httpwebrequest.GetResponse().GetResponseStream();
                StreamReader sr = new StreamReader(responseStream);
    
                Console.WriteLine(sr.ReadToEnd());
                sr.Close();
                responseStream.Close();
                
    
            }


     


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    • Proposed as answer by DChernin Friday, October 26, 2012 3:09 AM
    Wednesday, March 31, 2010 6:23 AM
  • Hi,

    Something is not working (at least in my computer :P)

     

    I've done this:

        [ServiceContract(Namespace="http://www.dk.com")]
        [XmlSerializerFormat]
        public interface IRESTfulService
        {
            [WebInvoke(UriTemplate = "/{communityId}/Login", Method = "POST")]
            [OperationContract]
            String Login(String communityId, UserLogin login);
        }

     

        public class RESTfulService : RESTful_Service.IRESTfulService 
        {

            public String Login(String communityId, UserLogin login)
            {
                return "login=" + login.UserName;
            }

        }

     

    I use you code to perform a call, but I always get this:

    <?xml version="1.0" encoding="utf-8"?><string>login=</string>

     

    Maybe the difference... is that I have the class UserLogin declared in the client and in the server... but the serialization output should be the same, shoudn't it?

    .: Valeriano Tórtola MCTS WPF :.: http://www.vtortola.net :.
    Wednesday, March 31, 2010 11:05 AM
  • Hi,

    Something is not working (at least in my computer :P)

     

    I've done this:

        [ServiceContract(Namespace="http://www.dk.com")]
        [XmlSerializerFormat]
        public interface IRESTfulService
        {
            [WebInvoke(UriTemplate = "/{communityId}/Login", Method = "POST")]
            [OperationContract]
            String Login(String communityId, UserLogin login);
        }

     

        public class RESTfulService : RESTful_Service.IRESTfulService 
        {

            public String Login(String communityId, UserLogin login)
            {
                return "login=" + login.UserName;
            }

        }

     

    I use you code to perform a call, but I always get this:

    <?xml version="1.0" encoding="utf-8"?><string>login=</string>

     

    Maybe the difference... is that I have the class UserLogin declared in the client and in the server... but the serialization output should be the same, shoudn't it?

    .: Valeriano Tórtola MCTS WPF :.: http://www.vtortola.net :.
    Wednesday, March 31, 2010 11:05 AM
  • Hi Valeriano,

    So the service doesn't report error and just get empty value for the UserLogin object's Username field, correct? In my test service, I also declare the UserLogin class in both client and service project twice, but they are identical, so if you make sure the class definition in both projects are identical(even the namespace) then it should be no problem on that.

    Try using the method I mentioned earlier, define a WebGet operation to return the UserLogin and compare its generated XML with the one you send (for the webInvoke operation) to see whether there is difference. You can use fiddler tool to capture message for http service(without message layer security):

    http://www.fiddler2.com/Fiddler2/version.asp

    or you can even try using WebChannelFactory to call REST service to see whether it works. If works, also try capturing its SOAP message to compare it with your current one.

    #WebChannelFactory(TChannel) Class
    http://msdn.microsoft.com/en-us/library/bb908674.aspx

    If necessary, I can send you my test solution so that you can try running it on your side. You can reach me at the following address:

    stcheng (AT) microsoft.com





    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    • Marked as answer by Mog Liang Monday, April 05, 2010 2:57 AM
    Thursday, April 01, 2010 3:07 AM
  • Awesome job Steven.  I've been looking for hours for an answer to how to do this! 

    Thanks...Dan


    Dan

    Friday, October 26, 2012 3:08 AM