problem with url when calling wcf service by httpWebRequest - wcf

When I call manually wcf service what should I type in url place :
HttpWebRequest httpWebRequest = WebRequest.Create(url)as HttpWebRequest;
should be there url to my svc file
http://localhost/service/LMTService.svc
or wsdl
http://localhost/service/LMTService.svc?wsdl
or url to service action ?
http://localhost/service/LMTService.svc/soap/GetSerializedSoapData

It depends on the binding of the endpoint. If using a SOAP binding (i.e., basicHttpBinding, wsHttpBinding, etc), the request URI should be the endpoint address (not the service address). Also, in some SOAP versions (such as SOAP11, used in basicHttpBinding), you need to specify the action as a HTTP header. If you're using webHttpBinding (with webHttp behavior) the address is the address of the endpoint, plus the UriTemplate (which by default is just the method name) of the operation you want to call.
The code below shows a HttpWebRequest-based request being sent to two endpoints, a one using BasicHttpBinding, one using WebHttpBinding.
public class StackOverflow_7525850
{
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
int Add(int x, int y);
}
public class Service : ITest
{
public int Add(int x, int y)
{
return x + y;
}
}
public static string SendRequest(string uri, string method, string contentType, string body, Dictionary<string, string> headers)
{
string responseBody = null;
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
req.Method = method;
if (headers != null)
{
foreach (string headerName in headers.Keys)
{
req.Headers[headerName] = headers[headerName];
}
}
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;
}
if (resp == null)
{
responseBody = null;
Console.WriteLine("Response is null");
}
else
{
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();
if (respStream != null)
{
responseBody = new StreamReader(respStream).ReadToEnd();
Console.WriteLine(responseBody);
}
else
{
Console.WriteLine("HttpWebResponse.GetResponseStream returned null");
}
}
Console.WriteLine();
Console.WriteLine(" *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* ");
Console.WriteLine();
return responseBody;
}
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 BasicHttpBinding(), "basic");
host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "web").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Host opened");
string soapBody = #"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
<s:Body>
<Add xmlns=""http://tempuri.org/"">
<x>44</x>
<y>55</y>
</Add>
</s:Body>
</s:Envelope>";
SendRequest(baseAddress + "/basic", "POST", "text/xml", soapBody, new Dictionary<string, string> { { "SOAPAction", "http://tempuri.org/ITest/Add" } });
SendRequest(baseAddress + "/web/Add", "POST", "text/xml", "<Add xmlns=\"http://tempuri.org/\"><x>55</x><y>66</y></Add>", null);
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

Related

WCF REST read URL-encoded response

I'm trying to use WCF to consume a 3rd-party REST service which responds with URL-encoded data:
a=1&b=2&c=3
I have this now:
[DataContract]
class Response {
[DataMember(Name="a")]
public int A { get;set;}
[DataMember(Name="b")]
public int B { get;set;}
[DataMember(Name="c")]
public int C { get;set;}
}
[ServiceContract]
interface IService
{
[OperationContract]
Response Foo();
}
But it comes back with:
There was an error checking start element of object of type Response. The data at the root level is invalid. Line 1, position 1.
WCF does not "understand" forms-data content type (application/x-www-forms-urlencoded), so it won't be able to read that response directly. You can either implement a message formatter which will be able to convert that format into your contract, or you can receive the response as a Stream (which will give you the full bytes of the response), which you can decode into your class.
The code below shows how you could implement a formatter for this operation. It's not generic, but you should get the picture of what needs to be done.
public class StackOverflow_16493746
{
[ServiceContract]
public class Service
{
[WebGet(UriTemplate = "*")]
public Stream GetData()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-www-form-urlencoded";
return new MemoryStream(Encoding.UTF8.GetBytes("a=1&b=2&c=3"));
}
}
[ServiceContract]
interface IService
{
[WebGet]
Response Foo();
}
[DataContract]
class Response
{
[DataMember(Name = "a")]
public int A { get; set; }
[DataMember(Name = "b")]
public int B { get; set; }
[DataMember(Name = "c")]
public int C { get; set; }
}
public class MyResponseFormatter : IClientMessageFormatter
{
private IClientMessageFormatter originalFormatter;
public MyResponseFormatter(IClientMessageFormatter originalFormatter)
{
this.originalFormatter = originalFormatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
HttpResponseMessageProperty httpResp = (HttpResponseMessageProperty)
message.Properties[HttpResponseMessageProperty.Name];
if (httpResp.Headers[HttpResponseHeader.ContentType] == "application/x-www-form-urlencoded")
{
if (parameters.Length > 0)
{
throw new InvalidOperationException("out/ref parameters not supported in this formatter");
}
byte[] bodyBytes = message.GetReaderAtBodyContents().ReadElementContentAsBase64();
NameValueCollection pairs = HttpUtility.ParseQueryString(Encoding.UTF8.GetString(bodyBytes));
Response result = new Response();
foreach (var key in pairs.AllKeys)
{
string value = pairs[key];
switch (key)
{
case "a":
result.A = int.Parse(value);
break;
case "b":
result.B = int.Parse(value);
break;
case "c":
result.C = int.Parse(value);
break;
}
}
return result;
}
else
{
return this.originalFormatter.DeserializeReply(message, parameters);
}
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
throw new NotSupportedException("This is a reply-only formatter");
}
}
public class MyClientBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
return new MyResponseFormatter(base.GetReplyClientFormatter(operationDescription, endpoint));
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<IService> factory = new ChannelFactory<IService>(new WebHttpBinding(), new EndpointAddress(baseAddress));
factory.Endpoint.Behaviors.Add(new MyClientBehavior());
IService proxy = factory.CreateChannel();
Response resp = proxy.Foo();
Console.WriteLine("a={0},b={1},c={2}", resp.A, resp.B, resp.C);
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

How to read WCF message headers in duplex callback?

In a normal WCF request/reply contract, you can read the message headers using something like:
OperationContract.Current.IncomingMessageHeaders
What I can't figure out is how to do this on the callback side of a duplex contract. Inside the callback implementation OperationContext.Current is null.
Edit 4/5/2013:
I'm using a custom binding based on net.tcp, but with a lot of customizations. For example, using protocol buffers message encoding rather than Xml. Also there is some custom security.
What binding are you using? In the SSCCE below the context is not null on the callback implementation.
public class StackOverflow_15769719
{
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface ITest
{
[OperationContract]
string Hello(string text);
}
[ServiceContract]
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void OnHello(string text);
}
public class Service : ITest
{
public string Hello(string text)
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
ThreadPool.QueueUserWorkItem(delegate
{
callback.OnHello(text);
});
return text;
}
}
class MyCallback : ICallback
{
AutoResetEvent evt;
public MyCallback(AutoResetEvent evt)
{
this.evt = evt;
}
public void OnHello(string text)
{
Console.WriteLine("[callback] Headers: ");
foreach (var header in OperationContext.Current.IncomingMessageHeaders)
{
Console.WriteLine("[callback] {0}", header);
}
Console.WriteLine("[callback] OnHello({0})", text);
evt.Set();
}
}
public static void Test()
{
bool useTcp = false;
string baseAddress = useTcp ?
"net.tcp://" + Environment.MachineName + ":8000/Service" :
"http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
Binding binding = useTcp ?
(Binding)new NetTcpBinding(SecurityMode.None) :
new WSDualHttpBinding(WSDualHttpSecurityMode.None)
{
ClientBaseAddress = new Uri("http://" + Environment.MachineName + ":8888/Client")
};
host.AddServiceEndpoint(typeof(ITest), binding, "");
host.Open();
Console.WriteLine("Host opened");
AutoResetEvent evt = new AutoResetEvent(false);
MyCallback callback = new MyCallback(evt);
DuplexChannelFactory<ITest> factory = new DuplexChannelFactory<ITest>(
new InstanceContext(callback),
binding,
new EndpointAddress(baseAddress));
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.Hello("foo bar"));
evt.WaitOne();
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

WCF REST Service: Method parameter (object) is null

why is the parameter of my WCF Rest service method always null?....I do access the service's method and i do get the string returned by the wcf method, but the parameter remains null.
Operation Contract:
[OperationContract]
[WebInvoke(UriTemplate = "AddNewLocation",
Method="POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string AddNewLocation(NearByAttractions newLocation);
Implementation of AddNewLocation method
public string AddNewLocation(NearByAttractions newLocation)
{
if (newLocation == null)
{
//I'm always getting this text in my logfile
Log.Write("In add new location:- Is Null");
}
else
{
Log.Write("In add new location:- " );
}
//String is returned even though parameter is null
return "59";
}
Client code:
WebClient clientNewLocation = new WebClient();
clientNewLocation.Headers[HttpRequestHeader.ContentType] = "application/json";
JavaScriptSerializer js = new JavaScriptSerializer();
js.MaxJsonLength = Int32.MaxValue;
//Serialising location object to JSON
string serialLocation = js.Serialize(newLocation);
//uploading JSOn string and retrieve location's ID
string jsonLocationID = clientNewLocation.UploadString(GetURL() + "AddNewLocation", serialLocation);
I also tried this code in my client but still get a null parameter
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(NearByAttractions));
MemoryStream ms = new MemoryStream();
ser.WriteObject(ms, newLocation);
String json = Encoding.UTF8.GetString(ms.ToArray());
WebClient clientNewLocation = new WebClient();
clientNewLocation.Headers[HttpRequestHeader.ContentType] = "application/json";
string r = clientNewLocation.UploadString(GetURL() + "AddNewLocation", json);
Console.Write(r);
Then i also changed the BodyStyle option to "Bare" but then I got the following error (with both client codes):
The remote server returned an error: (400) Bad Request.
Any help please? thanks
Edit 1:
My GetUrl() method loads the web service IP address from the web config file and returns an object of type Uri
private static Uri GetURL()
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~/web.config");
string sURL = config.AppSettings.Settings["serviceURL"].Value;
Uri url = null;
try
{
url = new Uri(sURL);
}
catch (UriFormatException ufe)
{
Log.Write(ufe.Message);
}
catch (ArgumentNullException ane)
{
Log.Write(ane.Message);
}
catch (Exception ex)
{
Log.Write(ex.Message);
}
return url;
}
service address stored in web config as follows:
<appSettings>
<add key="serviceURL" value="http://192.168.2.123:55666/TTWebService.svc/"/>
</appSettings>
This is how my NearByAttraction class defined
[DataContractAttribute]
public class NearByAttractions
{
[DataMemberAttribute(Name = "ID")]
private int _ID;
public int ID
{
get { return _ID; }
set { _ID = value; }
}
[DataMemberAttribute(Name = "Latitude")]
private string _Latitude;
public string Latitude
{
get { return _Latitude; }
set { _Latitude = value; }
}
[DataMemberAttribute(Name = "Longitude")]
private string _Longitude;
public string Longitude
{
get { return _Longitude; }
set { _Longitude = value; }
}
You seem to be in the right track. You need the Bare body style, otherwise you'd need to wrap the serialized version of your input in another JSON object. The second code should work - but without more information about how the service is set up and what GetURL() returns we can only guess.
One way to find out what to send to a WCF REST service is to use a WCF client itself for that - using the WebChannelFactory<T> class, then use a tool such as Fiddler to see what it's sending. The example below is a SSCCE which shows your scenario working.
public class StackOverflow_15786448
{
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebInvoke(UriTemplate = "AddNewLocation",
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string AddNewLocation(NearByAttractions newLocation);
}
public class NearByAttractions
{
public double Lat { get; set; }
public double Lng { get; set; }
public string Name { get; set; }
}
public class Service : ITest
{
public string AddNewLocation(NearByAttractions newLocation)
{
if (newLocation == null)
{
//I'm always getting this text in my logfile
Console.WriteLine("In add new location:- Is Null");
}
else
{
Console.WriteLine("In add new location:- ");
}
//String is returned even though parameter is null
return "59";
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
Console.WriteLine("Using WCF-based client (WebChannelFactory)");
var factory = new WebChannelFactory<ITest>(new Uri(baseAddress));
var proxy = factory.CreateChannel();
var newLocation = new NearByAttractions { Lat = 12, Lng = -34, Name = "56" };
Console.WriteLine(proxy.AddNewLocation(newLocation));
Console.WriteLine();
Console.WriteLine("Now with WebClient");
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(NearByAttractions));
MemoryStream ms = new MemoryStream();
ser.WriteObject(ms, newLocation);
String json = Encoding.UTF8.GetString(ms.ToArray());
WebClient clientNewLocation = new WebClient();
clientNewLocation.Headers[HttpRequestHeader.ContentType] = "application/json";
string r = clientNewLocation.UploadString(baseAddress + "/AddNewLocation", json);
Console.WriteLine(r);
}
}
Solved and thank you
I changed BodyStyle to "Bare" So my serivce interface is as follows:
[OperationContract]
[WebInvoke(UriTemplate = "AddNewLocation",
Method="POST",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string AddNewLocation(NearByAttractions newLocation);
Then implemented my client as follows:
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer serialToUpload = new DataContractJsonSerializer(typeof(NearByAttractions));
serialToUpload.WriteObject(ms, newLocation);
WebClient client = new WebClient();
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
client.UploadData(GetURL() + "AddNewLocation", "POST", ms.ToArray());
I used WebClient.UploadData instead of UploadString.

call wcf service by HttpWebRequest

When I have that service:
[OperationContract]
ResponseMessage GetData(RequestMessage message);
Where
class RequestMessage
{
public string data
}
class ResponseMessage
{
public string data
}
and call this service
string data2 = ""
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/Service.svc/GetData");
request.ContentType = "application/json";
request.Method = "POST";
request.KeepAlive = true;
using (Stream requestStream = request.GetRequestStream())
{
var bytes = Encoding.UTF8.GetBytes(data2);
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
}
var response = (HttpWebResponse)request.GetResponse();
var abc = new StreamReader(response.GetResponseStream()).ReadToEnd();
as data2 should I send string "mydata" or should I wrap it in json format : {"message": {"data":"mydata"}}
??
I have problem with understand how should be send data on client side by post to get it properly on service side :/
You didn't mention how the service is defined. Assuming your endpoint uses webHttpBinding, and an endpoint behavior with <webHttp/> with default values, then the default value for the body style is "Bare", which means that the request should contain only the serialized version of the parameter. For this case, you can send the string {"data":"hello world"}.
If you want a quick way to find what's the expected format for a WCF service, you can use a WCF client, using the same contract / binding / behaviors, and send a message to the server (and capture it on fiddler). For example, the code below shows a server similar to yours, and a client which sends a request to it.
public class StackOverflow_7492678
{
public class RequestMessage
{
public string data;
}
public class ResponseMessage
{
public string data;
}
[ServiceContract]
public interface ITest
{
[OperationContract]
ResponseMessage GetData(RequestMessage message);
}
public class Service : ITest
{
public ResponseMessage GetData(RequestMessage message)
{
return new ResponseMessage { data = message.data };
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
var endpoint = host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "");
endpoint.Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new WebHttpBinding(), new EndpointAddress(baseAddress));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.GetData(new RequestMessage { data = "mydata" }).data);
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

Using ISO-8859-1 encoding between WCF and Oracle/Linux

I have a WCF service that send/receives data and work perfectly with all my utf-8 clients.
But, one of my customers is trying to access this service with a Oracle 9i/Linux call, that works with ISO-8859-1 encoding, and we are having problems with special characters.
I can't use this suggested solution, since the client is Linux and cannot install DLLs.
Based on this scenario, can anyone please suggest me another solution (wich can involve changes in the client, in the service or in both)?
Thanks in advance.
That solution (using the CustomTextEncoder) should work in your scenario as well? The linux client can continue sending the data as it pleases (i.e., in iso-8859-1), and the encoder, used on the server only, would be able to read it. The encoder then can decide how to encode the response back to the client (UTF-8 or iso-8859-1 again).
If you want the response to be in iso-8859-1 as well you may also need something like a message inspector to update the content-type header with the appropriate charset.
Update: example with the custom encoder using ISO-8859-1
public class StackOverflow_7033442
{
[ServiceContract]
public interface ITest
{
[OperationContract]
string Echo(string text);
}
public class Service : ITest
{
public string Echo(string text)
{
return text;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
CustomBinding binding = new CustomBinding(
new CustomTextMessageBindingElement("iso-8859-1", "text/xml", MessageVersion.Soap11),
new HttpTransportBindingElement());
host.AddServiceEndpoint(typeof(ITest), binding, "");
host.Open();
Console.WriteLine("Host opened");
string request = #"<?xml version=""1.0"" encoding=""iso-8859-1""?>
<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
<s:Body>
<Echo xmlns=""http://tempuri.org/"">
<text>Hello áéíóú</text>
</Echo>
</s:Body>
</s:Envelope>";
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseAddress);
req.Method = "POST";
req.ContentType = "text/xml; charset=iso-8859-1";
req.Headers["SOAPAction"] = "http://tempuri.org/ITest/Echo";
Stream reqStream = req.GetRequestStream();
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
byte[] reqBytes = encoding.GetBytes(request);
reqStream.Write(reqBytes, 0, reqBytes.Length);
reqStream.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
foreach (var header in resp.Headers.AllKeys)
{
Console.WriteLine("{0}: {1}", header, resp.Headers[header]);
}
if (resp.ContentLength > 0)
{
Console.WriteLine(new StreamReader(resp.GetResponseStream(), encoding).ReadToEnd());
}
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
#region Custom Text Message Encoder sample, verbatim
public class CustomTextMessageEncoder : MessageEncoder
{
private CustomTextMessageEncoderFactory factory;
private XmlWriterSettings writerSettings;
private string contentType;
public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
{
this.factory = factory;
this.writerSettings = new XmlWriterSettings();
this.writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
this.contentType = string.Format("{0}; charset={1}",
this.factory.MediaType, this.writerSettings.Encoding.HeaderName);
}
public override string ContentType
{
get
{
return this.contentType;
}
}
public override string MediaType
{
get
{
return factory.MediaType;
}
}
public override MessageVersion MessageVersion
{
get
{
return this.factory.MessageVersion;
}
}
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
byte[] msgContents = new byte[buffer.Count];
Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
bufferManager.ReturnBuffer(buffer.Array);
MemoryStream stream = new MemoryStream(msgContents);
return ReadMessage(stream, int.MaxValue);
}
public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
{
XmlReader reader = XmlReader.Create(stream);
return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);
}
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
MemoryStream stream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
message.WriteMessage(writer);
writer.Close();
byte[] messageBytes = stream.GetBuffer();
int messageLength = (int)stream.Position;
stream.Close();
int totalLength = messageLength + messageOffset;
byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);
ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
return byteArray;
}
public override void WriteMessage(Message message, Stream stream)
{
XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
message.WriteMessage(writer);
writer.Close();
}
}
public class CustomTextMessageEncoderFactory : MessageEncoderFactory
{
private MessageEncoder encoder;
private MessageVersion version;
private string mediaType;
private string charSet;
internal CustomTextMessageEncoderFactory(string mediaType, string charSet,
MessageVersion version)
{
this.version = version;
this.mediaType = mediaType;
this.charSet = charSet;
this.encoder = new CustomTextMessageEncoder(this);
}
public override MessageEncoder Encoder
{
get
{
return this.encoder;
}
}
public override MessageVersion MessageVersion
{
get
{
return this.version;
}
}
internal string MediaType
{
get
{
return this.mediaType;
}
}
internal string CharSet
{
get
{
return this.charSet;
}
}
}
public class CustomTextMessageBindingElement : MessageEncodingBindingElement, IWsdlExportExtension
{
private MessageVersion msgVersion;
private string mediaType;
private string encoding;
private XmlDictionaryReaderQuotas readerQuotas;
CustomTextMessageBindingElement(CustomTextMessageBindingElement binding)
: this(binding.Encoding, binding.MediaType, binding.MessageVersion)
{
this.readerQuotas = new XmlDictionaryReaderQuotas();
binding.ReaderQuotas.CopyTo(this.readerQuotas);
}
public CustomTextMessageBindingElement(string encoding, string mediaType,
MessageVersion msgVersion)
{
if (encoding == null)
throw new ArgumentNullException("encoding");
if (mediaType == null)
throw new ArgumentNullException("mediaType");
if (msgVersion == null)
throw new ArgumentNullException("msgVersion");
this.msgVersion = msgVersion;
this.mediaType = mediaType;
this.encoding = encoding;
this.readerQuotas = new XmlDictionaryReaderQuotas();
}
public CustomTextMessageBindingElement(string encoding, string mediaType)
: this(encoding, mediaType, MessageVersion.Soap11WSAddressing10)
{
}
public CustomTextMessageBindingElement(string encoding)
: this(encoding, "text/xml")
{
}
public CustomTextMessageBindingElement()
: this("UTF-8")
{
}
public override MessageVersion MessageVersion
{
get
{
return this.msgVersion;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
this.msgVersion = value;
}
}
public string MediaType
{
get
{
return this.mediaType;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
this.mediaType = value;
}
}
public string Encoding
{
get
{
return this.encoding;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
this.encoding = value;
}
}
// This encoder does not enforces any quotas for the unsecure messages. The
// quotas are enforced for the secure portions of messages when this encoder
// is used in a binding that is configured with security.
public XmlDictionaryReaderQuotas ReaderQuotas
{
get
{
return this.readerQuotas;
}
}
#region IMessageEncodingBindingElement Members
public override MessageEncoderFactory CreateMessageEncoderFactory()
{
return new CustomTextMessageEncoderFactory(this.MediaType,
this.Encoding, this.MessageVersion);
}
#endregion
public override BindingElement Clone()
{
return new CustomTextMessageBindingElement(this);
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
context.BindingParameters.Add(this);
return context.BuildInnerChannelFactory<TChannel>();
}
public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
return context.CanBuildInnerChannelFactory<TChannel>();
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
context.BindingParameters.Add(this);
return context.BuildInnerChannelListener<TChannel>();
}
public override bool CanBuildChannelListener<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelListener<TChannel>();
}
public override T GetProperty<T>(BindingContext context)
{
if (typeof(T) == typeof(XmlDictionaryReaderQuotas))
{
return (T)(object)this.readerQuotas;
}
else
{
return base.GetProperty<T>(context);
}
}
#region IWsdlExportExtension Members
void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
{
}
void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
{
// The MessageEncodingBindingElement is responsible for ensuring that the WSDL has the correct
// SOAP version. We can delegate to the WCF implementation of TextMessageEncodingBindingElement for this.
TextMessageEncodingBindingElement mebe = new TextMessageEncodingBindingElement();
mebe.MessageVersion = this.msgVersion;
((IWsdlExportExtension)mebe).ExportEndpoint(exporter, context);
}
#endregion
}
#endregion
}