none
Passing parameter to [WebInvoke] Method

    Question

  • Consider following example :

    public class SomeBusinessLayerService : DataService<MyEntityContainer>
    {
     [WebInvoke]
     void DoSomething(string someParam)
     {
     }
    }

    I can not find example or any help on how can I pass parameter to the function!
    Using WebClient (or goodinfg around with fiddler) I can trigger the function call, but no matter what I try the parameter someParam is always null
    What's worse - f I change the type to int - all my attempts end in following error:

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
      <code></code>
      <message xml:lang="en-US">Bad Request - Error in query syntax.</message>
    </error>

    Can anyone please help with working example of post content on how I can call it ?
    NOTE: This is DataService, and not WCF service. I can get it working in separate WCF method without any problems.


    Monday, December 22, 2008 10:48 PM

Answers

  • Well, as of V1, we only accept primitive type parameters (no streams). So you can either keep the parameter as a String, or an XElement (NOT XmlElement)

    The following code would work:

    [WebInvoke]  
    public void DoSomething(System.Xml.Linq.XElement el)  
    {  
      //...  

    and POST to it with:

    System.Net.WebClient webclient = new System.Net.WebClient();  
    webclient.Headers["Content-Type"] = "application/xml";  
    string xElement = "<?xml version = \"1.0\" encoding = \"UTF-8\"?><Book><Author>Foo</Author><Title>Astoria Data Services</Title></Book>";  
     
    webclient.UploadString(String.Format("http://localhost:26299/WebSite1/WebDataService.svc/DoSomething?el='{0}'", xElement), String.Empty);  
     

    What exactly are you trying to accomplish with this service op?

    Regards,

    PQ
    Peter Q.
    Tuesday, December 23, 2008 6:53 AM

All replies

  • You should just be able to issue a POST, DELETE, or PUT to DoSomething?someParam='string param'

    What are some of the things you have tried?
    Peter Q.
    Tuesday, December 23, 2008 3:08 AM
  • Passing it as parameter is not acceptable for two reasons:
    (1) it can be very long
    (2) I would like to avoid sanitizing it (converting all ?=:' to %XX I guess would get me by?)

    Here is the code I use to do POST :
               
    string payload = calculatePayload();
    WebClient client = new WebClient();
    client.Headers["Content-type"] = "application/xml";
    client.UploadStringAsync(new Uri(@"http://localhost:1927/SomeBusinessLayerService.svc/DoSomething"), payload);      

    I tried also many different variations of
    <Request>
     <someParam>payLoad</someParam>
    </Request>
    and
    <DoSomething>
     <someParam>payLoad</someParam>
    </DoSomething>
    with several different headers,
    SOAP formatting:
    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><DoSomething xmlns="http://tempuri.org/"><someParam>payload</someParam></DoSomething></s:Body></s:Envelope>
    Simple parameter passing:
    someParam=payload
    ...
    Nothing seemed to work - the function is called every time but "payload" is always null.
    Moreover changing parameter type from string to int makes all the calls fail.

    Tuesday, December 23, 2008 3:20 AM
  • Followup question : please post example that will work passing following string as parameter:

    <?xml version = "1.0" encoding = "UTF-8"?>
    <orders>
       <order>
          <po>
                <![CDATA[TestPO2009]]>
          </po>
        </order>
    </orders>


    This simple code works fine:
    client.UploadStringAsync(new Uri(@"http://localhost:1927/SomeBusinessLayerService.svc/DoSomething?someParam='test'"), "");   

    However trying to pass a string as above fails:

    client.UploadStringAsync(new Uri(string.Format(@"http://localhost:1927/SomeBusinessLayerService.svc/DoSomething?someParam='{0}'", payload)), "")

    I tried doing

    payload = Url.EscapeDataString(payload)

    and getting same error:

    -        base    {System.Reflection.TargetInvocationException: An exception occurred during the operation, making the result invalid.  Check InnerException for exception details. ---> System.Net.WebException: An exception occurred during a WebClient request. ---> System.Exception ---> System.Exception: Error HRESULT E_FAIL has been returned from a call to a COM component.
       at System.Net.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
       at System.Net.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
       at System.Net.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
       --- End of inner exception stack trace ---
       at System.Net.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
       at System.Net.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
       at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
       at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)
       --- End of inner exception stack trace ---
       --- End of inner exception stack trace ---
       at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
       at System.Net.UploadStringCompletedEventArgs.get_Result()}    System.Exception {System.Reflection.TargetInvocationException}






    Tuesday, December 23, 2008 5:00 AM
  • Well, as of V1, we only accept primitive type parameters (no streams). So you can either keep the parameter as a String, or an XElement (NOT XmlElement)

    The following code would work:

    [WebInvoke]  
    public void DoSomething(System.Xml.Linq.XElement el)  
    {  
      //...  

    and POST to it with:

    System.Net.WebClient webclient = new System.Net.WebClient();  
    webclient.Headers["Content-Type"] = "application/xml";  
    string xElement = "<?xml version = \"1.0\" encoding = \"UTF-8\"?><Book><Author>Foo</Author><Title>Astoria Data Services</Title></Book>";  
     
    webclient.UploadString(String.Format("http://localhost:26299/WebSite1/WebDataService.svc/DoSomething?el='{0}'", xElement), String.Empty);  
     

    What exactly are you trying to accomplish with this service op?

    Regards,

    PQ
    Peter Q.
    Tuesday, December 23, 2008 6:53 AM
  • Conceptually I am trying to have one service for my data and business logic.

    From implementation point of view (since v1 is rather limited) I am trying to pass long string or Xml Element (which is serialized object) to the service method.

    The problems I am having is that there are limitations to using URI to make such calls:
    - A limitation on size of the URI (once the object reaches over 2000 bytes - the request no longer can be even made)
    - A requirement to sanitize URI - because even such simple example as posted above does NOT work without EscapeDataString , and that function itself has problems as it does not escape brackets which has to be done manually

    So I would like to use POST method the way it is intended to be used with payload coming separately, but I have no luck figuring out what would acceptable format for payload be.


    What would help is example with POST body not being passed in URI:

    webclient.UploadString(String.Format("http://localhost:26299/WebSite1/WebDataService.svc/DoSomething"),  xElement);   



    Tuesday, December 23, 2008 7:49 PM
  • This thread looks old, but after trying to extend the data services with WebInvoke in .NET 4, I still have this same problems as described here.

    After searching Google and Bing for quite a while I did not find any great code samples to show a POST that actually work.

    The service call goes through to the server, but the arguments passed to the server method are always null. The WebInvoke is alluded to but missing from the help file here http://msdn.microsoft.com/en-us/library/cc668788.aspx 

    Can someone from the Data Services team please show a code example of doing a client POST to a WebInvoke method that has more than one string argument? Let's assume that one of the strings could be very large, so it has to be in the body of the request.

    Examples of POST to these to interfaces would help using either the client proxy, HttpWebRequest, or WebClient.UploadString

    [

     

    WebInvoke(Method="POST")]

     

     

    public bool MyCustomOperation(string arg1, string arg2)

     

    [WebInvoke(Method="POST", UriTemplate = "/MyCustomOperation/{arg1})]

     

     

    public bool MyCustomOperation(string arg1, string arg2)

     

    Thanks

    Thursday, June 24, 2010 4:08 PM
  • Hi,

    A sample of working service operation with POST method and two arguments... on the server:

        [WebInvoke(Method="POST")]
        public bool MyCustomOperation(string arg1, string arg2)
        {
          if (arg1 == arg2) return true;
          return false;
        }

    On the client:

          HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:54163/WcfDataService1.svc/MyCustomOperation?arg1='some'&arg2='other'");
          request.Method = "POST";
          HttpWebResponse response = (HttpWebResponse)request.GetResponse();
          XDocument doc = XDocument.Load(response.GetResponseStream());
          Console.WriteLine(doc);

    Few notes:

    - There's no support for service operations in our client. In some cases it is possible to use DataServiceContext.Execute to invoke a service operation, but that only works for GET service operations. For POST service operations there's really no support.

    - WCF Data Services don't support passing parameters in the request body or headers, they have to be present in the URL of the request. This makes it hard to pass long values.

    - It is possible to overcome size limitations of URL through usage of $batch requests (where the URL itself is in the body of another request). Even though DataServiceContext does support batch requests it doesn't allow the caller to specify any request as part of the batch. As a result it is not possible to use the batching support in DataServiceContext to perform the POST request to a service operation. You would have to build the $batch request payload yourself (not that hard, just annoying).

    In general if you find these limitations too much for you, I would suggest you consider using a second separate WCF Service (not WCF Data Service) which would provide these special operations for your data. Using WCF services all of these problems can be solved easily.

    Thanks,


    Vitek Karas [MSFT]
    Thursday, June 24, 2010 4:35 PM
  • Hi,

    A sample of working service operation with POST method and two arguments... on the server:

      [WebInvoke(Method="POST")]
    
      public bool MyCustomOperation(string arg1, string arg2)
    
      {
    
       if (arg1 == arg2) return true;
    
       return false;
    
      }
    
    

    On the client:

       HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:54163/WcfDataService1.svc/MyCustomOperation?arg1='some'&arg2='other'");
    
       request.Method = "POST";
    
       HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    
       XDocument doc = XDocument.Load(response.GetResponseStream());
    
       Console.WriteLine(doc);
    
    

    Few notes:

    - There's no support for service operations in our client. In some cases it is possible to use DataServiceContext.Execute to invoke a service operation, but that only works for GET service operations. For POST service operations there's really no support.

    - WCF Data Services don't support passing parameters in the request body or headers, they have to be present in the URL of the request. This makes it hard to pass long values.

    - It is possible to overcome size limitations of URL through usage of $batch requests (where the URL itself is in the body of another request). Even though DataServiceContext does support batch requests it doesn't allow the caller to specify any request as part of the batch. As a result it is not possible to use the batching support in DataServiceContext to perform the POST request to a service operation. You would have to build the $batch request payload yourself (not that hard, just annoying).

    In general if you find these limitations too much for you, I would suggest you consider using a second separate WCF Service (not WCF Data Service) which would provide these special operations for your data. Using WCF services all of these problems can be solved easily.

    Thanks,


    Vitek Karas [MSFT]

    Error 2 'System.Xml.Linq.XDocument.Load(string)' is a 'method' but is used like a
    'type' how to overcome it sir plz reply me
    Tuesday, August 17, 2010 3:15 AM
  • Hi,

    Please show us the piece of code which fails to compile... we really can't guess what's wrong with it just from the error message.

    Thanks,


    Vitek Karas [MSFT]
    Tuesday, August 17, 2010 8:24 AM
  • @Peter :

    Can you please show what the raw POST looks like. For example, this doesn't seem right

     

    POST http://localhost:2483/Foo.svc/RemoveItem?pid='<?xml version = "1.0" encoding = "UTF-8"?><Foos><Foo>2</Foo></Foos>' HTTP/1.1
    User-Agent: Fiddler
    Host: localhost:2483
    DataServiceVersion: 2.0
    MaxDataServiceVersion: 2.0
    Content-Type: application/xml
    Content-Length: 0

     

    Tuesday, November 16, 2010 4:05 PM
  • I don't think you need the <? xml ... ?> declaration, since it's an XElement.

    You would also need to encode/escape the string properly, use Uri.EscapeUriString.

    Regards,

    PQ


    Peter Q. http://blogs.msdn.com/peter_qian
    Tuesday, November 16, 2010 11:58 PM