none
WCF - How to choose the right binding and contracts when the request and response data is given? RRS feed

  • Question

  • The Microsoft enterprise device management protocol for Windows Phone 8 document tells to "Implement discovery web service.  The service is a restful web service over HTTPS (server authentication only)”.

    If I implement REST service I have trouble in getting request and response data as soap xml. If I use soap based binding I  have trouble in making GET request. Also I can't have multiple bindings with different address, this breaks the protocol uri defined by MSFT.

    I new to WCF and have trouble in implementing my right WCF Service so that it can be called from Microsoft Phone 8 enrollment client.

    Also I could not find any link which talks about implementing WCF service based on such webservice request and response data. 

    Please can you suggest me how does the contracts should look and what kind binding do I need to use achieve below HTTP GET and HTTP POST request and response.

    Below are the request and response of the web service defined by Microsoft.


    HTTP GET

    Request:
    Request Full Url: http://EnterpriseEnrollment.ds.test.com/EnrollmentServer/Discovery.svc
    Content Type: unknown
    Header Byte Count: 153
    Body Byte Count:0 
    
    Header:
    GET /EnrollmentServer/Discovery.svc HTTP/1.1
    User-Agent: WIndows Phone 8 Enrollment Client
    Host: EnterpriseEnrollment.ds.test.com
    Pragma: no-cache


    Response:
    Request Full Url: http://EnterpriseEnrollment.ds.test.com/EnrollmentServer/Discovery.svc
    Content Type: text/html
    Header Byte Count: 248
    Body Byte Count: 0
    
    Header:
    HTTP/1.1 200 OK
    Connection: Keep-Alive
    Pragma: no-cache
    Cache-Control: no-cache
    Content-Type: text/html
    Content-Length: 0

    HTTP POST

    Request:
    Header:
    POST /EnrollmentServer/Discovery.svc HTTP/1.1
    Content-Type: application/soap+xml; charset=utf-8
    User-Agent: Windows Phone 8 Enrollment Client
    Host: EnterpriseEnrollment.ds.test.com
    Content-Length: xxx
    Cache-Control: no-cache
    
    <?xml version="1.0"?>
    <s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
    <a:Action s:mustUnderstand="1">ttp://schemas.microsoft.com/windows/management/2012/01/enrollment/IDiscoveryService/Discover</a:Action>
    <a:MessageID>urn:uuid: 748132ec-a575-4329-b01b-6171a9cf8478</a:MessageID>
    <a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo><a:To s:mustUnderstand="1">https:// EnterpriseEnrollment.ds.test.com/EnrollmentServer/Discovery.svc</a:To>
    </s:Header>
    <s:Body>
    <Discover xmlns="http://schemas.microsoft.com/windows/management/2012/01/enrollment/">
    <request xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <EmailAddress>user@ds.test.com</EmailAddress>
    <RequestVersion>1.0</RequestVersion>
    </request>
    </Discover>
    </s:Body>
    </s:Envelope>

    Response:
    
    Header
    HTTP/1.1 200 OK
    Content-Length: 865
    Content-Type: application/soap+xml; charset=utf-8
    Server: EnterpriseEnrollment.ds.mot.com
    Date: Tue, 02 Aug 2012 00:32:56 GMT
    
    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
    <a:Action s:mustUnderstand="1">http://schemas.microsoft.com/windows/management/2012/01/enrollment/IDiscoveryService/DiscoverResponse</a:Action>
    <ActivityId>d9eb2fdd-e38a-46ee-bd93-aea9dc86a3b8</ActivityId>
    <a:RelatesTo>urn:uuid: 748132ec-a575-4329-b01b-6171a9cf8478</a:RelatesTo>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><DiscoverResponse xmlns="http://schemas.microsoft.com/windows/management/2012/01/enrollment">
    <DiscoverResult>
    <AuthPolicy>OnPremise</AuthPolicy>
    <EnrollmentPolicyServiceUrl>https:// EnterpriseEnrollment.ds.test.com/ENROLLMENTSERVER/DEVICEENROLLMENTWEBSERVICE.SVC</EnrollmentPolicyServiceUrl>
    <EnrollmentServiceUrl>https:// EnterpriseEnrollment.ds.test.com/ENROLLMENTSERVER/DEVICEENROLLMENTWEBSERVICE.SVC</EnrollmentServiceUrl>
    </DiscoverResult>
    </DiscoverResponse>
    </s:Body>
    </s:Envelope>

    Currently my service contract looks as below:

      

      [ServiceContract(Namespace = "http://schemas.microsoft.com/windows/management/2012/01/enrollment/")]  
    [XmlSerializerFormat]  
    public interface IDiscoveryService    
    {        
    [OperationContract]        
    [WebGet(UriTemplate = "")]        
    string GetRequest();        
    [OperationContract]        
    [WebInvoke(Method = "POST", UriTemplate = "", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]        
    Result Discover(Request request);   //Where Result and Request are DataContracts
    }
    
    

    Thanks,



    Friday, June 28, 2013 2:02 PM

All replies

  • Hi,

    Thanks for your post.

    I am trying to involve someone familiar with this topic to further look at this issue. There might be some time delay. Appreciate your patience.

    Best Regards.


    Amy Peng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, July 1, 2013 7:12 AM
    Moderator
  • Hi,

    First we have to make sure that you have right security and binding. I read the pdf file of "The Microsoft enterprise device management protocol for Windows Phone 8" and understood it requires Message level security. In addition I can see that its expecting certificate and user credentials. The best way to configure the service for SOAP level messages is to use custom binding.

    Please go through the below link for WCF Rest client application

    http://tech.pro/tutorial/981/creating-a-rest-client-using-wcf

    http://msdn.microsoft.com/en-us/library/bb412178.aspx

    http://www.dotnetspark.com/kb/1373-step-by-step-tutorial-rest-enabled-service.aspx

    Thanks

    Wednesday, July 3, 2013 7:45 PM
  • Hi,

    I have already created a web service with custom binding, the service and client code looks as below. With this implementation for WebInvoke "POST" request works fine, I am able to send and receive the soap xml.

    But the WebGet "GET" fails with the error "The remote server returned an error: (400) Bad Request.". Could you suggest me what is wrong?

    Service Contract Code:

    [ServiceContract(Namespace = "http://schemas.microsoft.com/windows/management/2012/01/enrollment/")] 
    [XmlSerializerFormat]
    public interface IDiscoveryService   
    {        
    [OperationContract]        
    [WebGet(UriTemplate = "")]        
    string GetRequest();        
    
    [OperationContract]        
    [WebInvoke(Method = "POST", UriTemplate = "", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]        
    Result Discover(Request request);    
    }

    Server Web config file:

    <system.serviceModel>
        <bindings>
          <customBinding>
            <binding name="customBinding0">
              <textMessageEncoding messageVersion="Default" />
              <httpTransport />
            </binding>
          </customBinding>
        </bindings>
        <services>
          <service behaviorConfiguration="Behavior1" name="DiscoveryWebService.DiscoveryService">
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
            <endpoint address="" behaviorConfiguration="" binding="customBinding"
              bindingConfiguration="customBinding0" name="custom" contract="DiscoveryWebService.IDiscoveryService" />
          </service>
        </services>
        <behaviors>
          <endpointBehaviors>
            <behavior name="webEndpointBehavior">
              <webHttp />
            </behavior>
          </endpointBehaviors>
          <serviceBehaviors>
            <behavior name="Behavior1">
              <serviceMetadata httpGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>

    The Client Code:

    For WebGet : The below code gives error as "The remote server returned an error: (400) Bad Request."

    string wsUri = URITextBox.Text ;
    
    HttpWebRequest req = WebRequest.Create(wsUri) as HttpWebRequest;
    req.ContentType = "unknown";
    req.Method = "GET";
    req.UserAgent = "Windows Phone 8 Enrollment Client";
    req.Headers.Add("Pragma", "no-cache");
    
    HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
    if (resp.StatusCode != HttpStatusCode.OK)
    {
    throw new Exception("Error calling Service. \nStatus:" + resp.StatusCode.ToString() + "\nDescription:" + resp.StatusDescription.ToString());
    }
    StreamReader loResponseStream = new StreamReader(resp.GetResponseStream(), false);
    
    string enrollResponse = loResponseStream.ReadToEnd();
    
    loResponseStream.Close();
    resp.Close();

    For WebInvoke Post: // The below code works for POST request

    string wsUri = URITextBox.Text; //TODO - remove custom"
    HttpWebRequest req = WebRequest.Create(wsUri) as HttpWebRequest;
    req.Method = "POST";
    req.ContentLength = 0;
    req.ContentType = "application/soap+xml; charset=utf-8";
    req.UserAgent = "Windows Phone 8 Enrollment Client";
    //req.Host = "enterpriseenrollment.motorolasolutions.com"; 
    //TODO: Provide the actual host name
    req.Headers.Add("Cache-Control", "no-cache");
    req.Headers.Add("SOAPAction", "http://schemas.microsoft.com/windows/management/2012/01/enrollment/IDiscoveryService/Discover");
    UTF8Encoding encode = new UTF8Encoding();
    
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load("..\\..\\EnrollmentRequest.xml");
    string strXML = xmlDoc.InnerXml;
    req.ContentLength = encode.GetByteCount(strXML);
    Stream writer = req.GetRequestStream();
    writer.Write(encode.GetBytes(strXML), 0, encode.GetByteCount(strXML));
    writer.Close();
    
    HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
    if (resp.StatusCode != HttpStatusCode.OK)
    {
          throw new Exception("Error calling Service. \nStatus:" + resp.StatusCode.ToString() + "\nDescription:" + resp.StatusDescription.ToString());
    }
    StreamReader loResponseStream = new StreamReader(resp.GetResponseStream(), false);
    string enrollResponse = loResponseStream.ReadToEnd();
    loResponseStream.Close();
    resp.Close();



    K Raj

    Wednesday, July 3, 2013 8:33 PM
  • Hi Amy,

    Any update on this?

    Thanks,


    K Raj

    Wednesday, July 3, 2013 8:37 PM