none
Custom Messaging in WCF service

    Question

  • One of my WCF consuming client(non .net client) only accept and process the values in the below format.

    <Start-Data>Value1;value2;value3;........value60;<End-Data>

    Is it possible to send the response as above from my WCF service. Please provide some code. I tried with stream that is my operation contract return type as System.IO.Stream but its not working properly. Give some best way to achieve this one.

    My Code is

     

     [ServiceContract]
        public interface IService1
        {

             [OperationContract]
            Stream GetValue(string values);

         }

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
        public class Service1 : IService1
        {

           public Stream GetValue(string values)
            {
               
                try
                {
                  
                    byte[] resultBytes = Encoding.UTF8.GetBytes(values);
                    Encoding encoding = Encoding.GetEncoding("ISO-8859-1");
                    WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
                    return new MemoryStream(resultBytes);
                }
                catch (Exception ex)
                {
                    return null;
                }
            }

       }

    My Consume Page

    ServiceReference1.Service1Client obj = new ServiceReference1.Service1Client("BasicHttpBinding_IService1");

    System.IO.Stream ss = obj.GetValue("test");

     

    I am getting the error as

    The content type text/plain of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 236 bytes of the response were: '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetValueResponse xmlns="http://tempuri.org/"><GetValueResult>PFN0YXJ0LURhdGE+dGVzdDE7dGVzdDI8RW5kLURhdGE+</GetValueResult></GetValueResponse></s:Body></s:Envelope>'.

     

    Thanks in Advance

    George.Santhosh

     

    Thursday, January 12, 2012 5:15 PM

All replies

  • Hello George.Santhosh,

    There are a few problems in your scenario.

    First of all, if you want to use the "Raw" programming model to return arbitrary data from a WCF service, the endpoint which you consume must be configured to use the WebHttpBinding *and* the WebHttpBehavior. In your case, it's using the BasicHttpBinding, so you won't get the "Stream" treatment which you want.

    Second, endpoints configured with WebHttpBinding do not have their metadata exposed in the service description (the language used to describe the services, WSDL, is used to describe SOAP services; "web" endpoint do not use SOAP), so you won't be able to generate a client using a tool such as Add Service Reference (which is how I imagine you got your Service1Client class generated).

    If you really want a client (and are willing to share the interface to the client), you can do that, as shown below: derive from the ClientBase<T> and your interface; then delegate all methods from that interface, then pass the expected binding (WebHttpBinding) and behavior (WebHttpBehavior) to the class.

    The code below shows the server and some possible clients for this scenario.

        public class Post_f363c1d5_40db_49c9_9878_9a6ce5d72202
        {
            static readonly string BaseAddress = "http://" + Environment.MachineName + ":8000/Service";
    
            [ServiceContract]
            public interface IService1
            {
                [OperationContract]
                Stream GetValue(string values);
                [OperationContract, WebGet]
                Stream GetValuesViaGet(string values);
            }
    
            public class Service1 : IService1
            {
                public Stream GetValue(string values)
                {
                    string[] allValues = values.Split(',');
                    StringBuilder sb = new StringBuilder();
                    sb.Append("<Start-Data>");
                    foreach (var value in allValues)
                    {
                        sb.Append(value);
                        sb.Append(";");
                    }
    
                    sb.Append("<End-Data>");
    
                    byte[] resultBytes = Encoding.UTF8.GetBytes(sb.ToString());
                    WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
                    return new MemoryStream(resultBytes);
                }
                public Stream GetValuesViaGet(string values)
                {
                    return GetValue(values);
                }
            }
    
            class Service1Client : ClientBase<IService1>, IService1
            {
                public Service1Client()
                    : base(new WebHttpBinding(), new EndpointAddress(BaseAddress))
                {
                    this.Endpoint.Behaviors.Add(new WebHttpBehavior());
                }
    
                public Stream GetValue(string values)
                {
                    return this.Channel.GetValue(values);
                }
    
                public Stream GetValuesViaGet(string values)
                {
                    return this.Channel.GetValuesViaGet(values);
                }
            }
    
            public static void Test()
            {
                ServiceHost host = new ServiceHost(typeof(Service1), new Uri(BaseAddress));
                host.AddServiceEndpoint(typeof(IService1), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
                host.Open();
                Console.WriteLine("Host opened");
    
                Console.WriteLine("Downloading using a 'normal' HTTP client (POST version)");
                SendRequest(BaseAddress + "/GetValue", "POST", "application/json", "\"one,two,three,four\"");
    
                Console.WriteLine("Downloading using a 'normal' HTTP client (GET version)");
                SendRequest(BaseAddress + "/GetValuesViaGet?values=one,two,three,four", "GET", null, null);
    
                Console.WriteLine("Downloading using a WCF client; using POST request");
                Service1Client client = new Service1Client();
                Stream s1 = client.GetValue("one,two,three,four");
                Console.WriteLine(new StreamReader(s1).ReadToEnd());
                Console.WriteLine();
    
                Console.WriteLine("Downloading using a WCF client; using GET request");
                s1 = client.GetValuesViaGet("one,two,three,four");
                Console.WriteLine(new StreamReader(s1).ReadToEnd());
                Console.WriteLine();
    
                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
    
            public static void SendRequest(string uri, string method, string contentType = null, string body = null)
            {
                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
                req.Method = method;
    
                if (!String.IsNullOrEmpty(contentType))
                {
                    req.ContentType = contentType;
                }
    
                if (body != null)
                {
                    byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
                    req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
                    req.GetRequestStream().Close();
                }
    
                HttpWebResponse resp;
                try
                {
                    resp = (HttpWebResponse)req.GetResponse();
                }
                catch (WebException e)
                {
                    resp = (HttpWebResponse)e.Response;
                }
    
                Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
                foreach (string headerName in resp.Headers.AllKeys)
                {
                    Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
                }
                Console.WriteLine();
                Stream respStream = resp.GetResponseStream();
                Console.WriteLine(new StreamReader(respStream).ReadToEnd());
    
                Console.WriteLine();
                Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
                Console.WriteLine();
            }
        }
    
    

     


    Carlos Figueira
    Thursday, January 12, 2012 10:28 PM
    Moderator
  • @Carlos

    Hi Thanks for your update.

    Still i am not able to found the solution for that.

    i am getting Error, not able to create HttpWebResponse, its always null while running the code, because the request is closed.

    Give some tips to ride out.

     


    santhosh kumar
    Friday, January 13, 2012 11:59 AM
  • Can you print out the exception caught when calling HttpWebRequest.GetResponse and see what it says?


    Carlos Figueira
    Friday, January 13, 2012 5:19 PM
    Moderator
  • while reaching this line

     HttpWebResponse resp;
                try
                {
                    resp = (HttpWebResponse)req.GetResponse();
                }
                catch (WebException e)
                {
                    resp = (HttpWebResponse)e.Response;
                }

     

    i got the following error

    The underlying connection was closed: An unexpected error occurred on a receive.
       at System.Net.HttpWebRequest.GetResponse()
       at WebApplication1.WebForm1.SendRequest(String uri, String method, String contentType, String body) in


    santhosh kumar
    Friday, January 13, 2012 5:32 PM
  • In this case the server is closing the connection. Please enable tracing (http://msdn.microsoft.com/en-us/library/ms733025.aspx) at the server and the traces will have an exception which should explain what is going on.
    Carlos Figueira
    Friday, January 13, 2012 5:33 PM
    Moderator
  • In my client project i added the reference and also added the dll of my service and used the code what you provided for creating service host and SendRequest method and also i configured in the trace log there is no log found after i run the app. Is my proceeding way is right or i have to follow some other things.

    Thanks for your support

    George.Santhosh


    santhosh kumar
    Friday, January 13, 2012 5:57 PM
  • As I mentioned before - you cannot add a reference in the client project to a non-SOAP endpoint, which is what you have in the service. This just is not supported. Can you post your service and client code?


    Carlos Figueira
    Friday, January 13, 2012 5:58 PM
    Moderator
  • In IService

     [ServiceContract]
        public interface IService2
        {
            [OperationContract]
            Stream GetValue(string values);
            [OperationContract, WebGet]
            Stream GetValuesViaGet(string values);
        }

    In Service Class

    public class Service2 : IService2
        {
          

            public Stream GetValue(string values)
            {
                string[] allValues = values.Split(',');
                StringBuilder sb = new StringBuilder();
                sb.Append("<Start-Data>");
                foreach (var value in allValues)
                {
                    sb.Append(value);
                    sb.Append(";");
                }

                sb.Append("<End-Data>");

                byte[] resultBytes = Encoding.UTF8.GetBytes(sb.ToString());
                WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
                return new MemoryStream(resultBytes);
            }
            public Stream GetValuesViaGet(string values)
            {
                return GetValue(values);
            }
        }

    In UI (RestService is my Namespace)

    static readonly string BaseAddress = "http://" + Environment.MachineName + ":8000/Service";

            protected void Button1_Click(object sender, EventArgs e)
            {
                Test();
            }

    public static void Test()
            {
                ServiceHost host = new ServiceHost(typeof(RestService.Service2), new Uri(BaseAddress));
                host.AddServiceEndpoint(typeof(RestService.IService2), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
                host.Open();
                //Console.WriteLine("Host opened");

                //Console.WriteLine("Downloading using a 'normal' HTTP client (POST version)");
                SendRequest(BaseAddress + "/GetValue", "POST", "application/json", "\"one,two,three,four\"");

                //Console.WriteLine("Downloading using a 'normal' HTTP client (GET version)");
                SendRequest(BaseAddress + "/GetValuesViaGet?values=one,two,three,four", "GET", null, null);

                //Console.WriteLine("Downloading using a WCF client; using POST request");
                RestService.Service2 client = new RestService.Service2();
                Stream s1 = client.GetValue("one,two,three,four");
                //Console.WriteLine(new StreamReader(s1).ReadToEnd());
               // Console.WriteLine();

                //Console.WriteLine("Downloading using a WCF client; using GET request");
                s1 = client.GetValuesViaGet("one,two,three,four");
                //Console.WriteLine(new StreamReader(s1).ReadToEnd());
                //Console.WriteLine();

               // Console.Write("Press ENTER to close the host");
               //Console.ReadLine();
                host.Close();
            }

            public static void SendRequest(string uri, string method, string contentType = null, string body = null)
            {
                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
                req.Method = method;

                if (!String.IsNullOrEmpty(contentType))
                {
                    req.ContentType = contentType;
                }

                if (body != null)
                {
                    byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
                    req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
                    req.GetRequestStream().Close();
                }

                HttpWebResponse resp;
                try
                {
                    resp = (HttpWebResponse)req.GetResponse();
                }
                catch (WebException e)
                {
                    resp = (HttpWebResponse)e.Response;
                }

                //Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
                foreach (string headerName in resp.Headers.AllKeys)
                {
                    Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
                }
                //Console.WriteLine();
                Stream respStream = resp.GetResponseStream();
               // Console.WriteLine(new StreamReader(respStream).ReadToEnd());

               // Console.WriteLine();
                //Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
                //Console.WriteLine();
            }


    In Service Web.config

     

    <configuration>

      <system.diagnostics>
        <sources>
          <source name="System.ServiceModel"
                  switchValue="Information, ActivityTracing"
                  propagateActivity="true">
            <listeners>
              <add name="traceListener"
                  type="System.Diagnostics.XmlWriterTraceListener"
                  initializeData= "c:\log\Traces.svclog" />
            </listeners>
          </source>
        </sources>
      </system.diagnostics>
      <system.web>
        <compilation debug="true" targetFramework="4.0" />
      </system.web>

      <system.serviceModel>
        <bindings>
          <webHttpBinding>
          
          </webHttpBinding>
        </bindings>
        <client>
         
        </client>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
              <serviceMetadata httpGetEnabled="true"/>
              <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
          <!--<endpointBehaviors>
            <behavior name="webhttp">
              <webHttp/>
            </behavior>
          </endpointBehaviors>-->

        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
      </system.serviceModel>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>
    </configuration>


    santhosh kumar
    Monday, January 16, 2012 11:16 AM
  • @Carlos Is there any way to achieve. Expecting your response.

    santhosh kumar
    Wednesday, January 18, 2012 2:51 PM