How do I get access to SOAP response - c#

(If anything here needs clarification/ more detail please let me know.)
I have an application (C#, 2.* framework) that interfaces with a third-party webservice using SOAP. I used thinktecture's WSCF add-in against a supplied WSDL to create the client-side implementation. For reasons beyond my control the SOAP message exchange uses WSE2.0 for security (the thinctecture implementation had to be modified to include the WSE2.0 reference). In addition to the 'normal' data package I attach a stored X509 cert and a binary security token from a previous call to a different web service. We are using SSL encryption of some sort - I don't know the details.
All the necessary serialization/deserialization is contained in the web service client - meaning when control is returned to me after calling the client the entire XML string contained in the SOAP response is not available to me - just the deserialized components. Don't get me wrong - I think that's good because it means I don't have to do it myself.
However, in order for me to have something worth storing/archiving I am having to re-serialize the data at the root element. This seems like a waste of resources since my result was in the SOAP response.
Now for my question:
How can I get access to a 'clear' version of the SOAP response so that I don't have to re-serialize everything for storage/archiving?
Edit- My application is a 'formless' windows app running as a network service - triggered by a WebsphereMQ client trigger monitor. I don't think ASP.NET solutions will apply.
Edit - Since the consensus so far is that it doesn't matter whether my app is ASP.NET or not then I will give CodeMelt's (and by extension Chris's) solution a shot.

You can utilize SoapExtension from existing WSE2.0 framework to intercept the responses from the server.
public class MyClientSOAPExtension : SoapExtension
{
Stream oldStream;
Stream newStream;
// Save the Stream representing the SOAP request or SOAP response into
// a local memory buffer.
public override Stream ChainStream( Stream stream )
{
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
// before the XML deserialized into object.
break;
case SoapMessageStage.AfterDeserialize:
break;
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
break;
default:
throw new Exception("Invalid stage...");
}
}
}
At stage of SoapMessageStage.BeforeDeserialize,
You can read the expected data you want from oldstream (e.g. use XmlReader).
Then store the expected data somewhere for yourself to use and also you need
forward the old stream data to the newstream for web service later stage to use the data, e.g. deserialize XML into objects.
The sample of logging all the traffic for the web service from MSDN

Here is an example you can setup using Visual studio web reference to http://footballpool.dataaccess.eu/data/info.wso?WSDL
Basically, you must insert in the webservice call chain a XmlReader spyer that will reconstruct the raw XML.
I believe this way is somehow simpler that using SoapExtensions.
Solution solution was inspired by http://orbinary.com/blog/2010/01/getting-the-raw-soap-xml-sent-via-soaphttpclientprotocol/
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Reflection;
using System.Xml;
namespace ConsoleApplication1 {
public class XmlReaderSpy : XmlReader {
XmlReader _me;
public XmlReaderSpy(XmlReader parent) {
_me = parent;
}
/// <summary>
/// Extracted XML.
/// </summary>
public string Xml;
#region Abstract method that must be implemented
public override XmlNodeType NodeType {
get {
return _me.NodeType;
}
}
public override string LocalName {
get {
return _me.LocalName;
}
}
public override string NamespaceURI {
get {
return _me.NamespaceURI;
}
}
public override string Prefix {
get {
return _me.Prefix;
}
}
public override bool HasValue {
get { return _me.HasValue; }
}
public override string Value {
get { return _me.Value; }
}
public override int Depth {
get { return _me.Depth; }
}
public override string BaseURI {
get { return _me.BaseURI; }
}
public override bool IsEmptyElement {
get { return _me.IsEmptyElement; }
}
public override int AttributeCount {
get { return _me.AttributeCount; }
}
public override string GetAttribute(int i) {
return _me.GetAttribute(i);
}
public override string GetAttribute(string name) {
return _me.GetAttribute(name);
}
public override string GetAttribute(string name, string namespaceURI) {
return _me.GetAttribute(name, namespaceURI);
}
public override void MoveToAttribute(int i) {
_me.MoveToAttribute(i);
}
public override bool MoveToAttribute(string name) {
return _me.MoveToAttribute(name);
}
public override bool MoveToAttribute(string name, string ns) {
return _me.MoveToAttribute(name, ns);
}
public override bool MoveToFirstAttribute() {
return _me.MoveToFirstAttribute();
}
public override bool MoveToNextAttribute() {
return _me.MoveToNextAttribute();
}
public override bool MoveToElement() {
return _me.MoveToElement();
}
public override bool ReadAttributeValue() {
return _me.ReadAttributeValue();
}
public override bool Read() {
bool res = _me.Read();
Xml += StringView();
return res;
}
public override bool EOF {
get { return _me.EOF; }
}
public override void Close() {
_me.Close();
}
public override ReadState ReadState {
get { return _me.ReadState; }
}
public override XmlNameTable NameTable {
get { return _me.NameTable; }
}
public override string LookupNamespace(string prefix) {
return _me.LookupNamespace(prefix);
}
public override void ResolveEntity() {
_me.ResolveEntity();
}
#endregion
protected string StringView() {
string result = "";
if (_me.NodeType == XmlNodeType.Element) {
result = "<" + _me.Name;
if (_me.HasAttributes) {
_me.MoveToFirstAttribute();
do {
result += " " + _me.Name + "=\"" + _me.Value + "\"";
} while (_me.MoveToNextAttribute());
//Let's put cursor back to Element to avoid messing up reader state.
_me.MoveToElement();
}
if (_me.IsEmptyElement) {
result += "/";
}
result += ">";
}
if (_me.NodeType == XmlNodeType.EndElement) {
result = "</" + _me.Name + ">";
}
if (_me.NodeType == XmlNodeType.Text || _me.NodeType == XmlNodeType.Whitespace) {
result = _me.Value;
}
if (_me.NodeType == XmlNodeType.XmlDeclaration) {
result = "<?" + _me.Name + " " + _me.Value + "?>";
}
return result;
}
}
public class MyInfo : ConsoleApplication1.eu.dataaccess.footballpool.Info {
protected XmlReaderSpy _xmlReaderSpy;
public string Xml {
get {
if (_xmlReaderSpy != null) {
return _xmlReaderSpy.Xml;
}
else {
return "";
}
}
}
protected override XmlReader GetReaderForMessage(System.Web.Services.Protocols.SoapClientMessage message, int bufferSize) {
XmlReader rdr = base.GetReaderForMessage(message, bufferSize);
_xmlReaderSpy = new XmlReaderSpy((XmlReader)rdr);
return _xmlReaderSpy;
}
}
class Program {
static void Main(string[] args) {
MyInfo info = new MyInfo();
string[] rest = info.Cities();
System.Console.WriteLine("RAW Soap XML response :\n"+info.Xml);
System.Console.ReadLine();
}
}
}

Old thread, but in case others are looking to do this today: these ideas of leveraging SoapExtension or creating 'spy' classes are great, but don't work in .NET Core.
#mting923's suggestion to use IClientMessageInspector approach works in .NET Core 3.1; see here: Get SOAP Message before sending it to the WebService in .NET.
A generated SOAP proxy class is still just a WCF client under the hood, and so the IClientMessageInspector approach works a treat, even for an .NET Core Azure Function calling an older SOAP web service. The following works for me in a .NET Core 3.1 Azure Function:
public class SoapMessageInspector : IClientMessageInspector
{
public string LastRequestXml { get; private set; }
public string LastResponseXml { get; private set; }
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
LastRequestXml = request.ToString();
return request;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
LastResponseXml = reply.ToString();
}
}
public class SoapInspectorBehavior : IEndpointBehavior
{
private readonly SoapMessageInspector inspector_ = new SoapMessageInspector();
public string LastRequestXml => inspector_.LastRequestXml;
public string LastResponseXml => inspector_.LastResponseXml;
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(inspector_);
}
}
And then it can be set up like this:
var client = new ServiceClient();
var soapInspector = new SoapInspectorBehavior();
client.Endpoint.EndpointBehaviors.Add(soapInspector);
After invoking a web service call on the client proxy, soapInspector.LastRequestXml and soapInspector.LastResponseXml will contain the raw SOAP request and response (as strings).

Inspired by jfburdet, I wanted to see if it was possible to directly intercept at stream/byte level rather than reconstructing XML. And it is! See code below:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;
using System.Xml;
using Test.MyWebReference;
namespace Test {
/// <summary>
/// Adds the ability to retrieve the SOAP request/response.
/// </summary>
public class ServiceSpy : OriginalService {
private StreamSpy writerStreamSpy;
private XmlTextWriter xmlWriter;
private StreamSpy readerStreamSpy;
private XmlTextReader xmlReader;
public MemoryStream WriterStream {
get { return writerStreamSpy == null ? null : writerStreamSpy.ClonedStream; }
}
public XmlTextWriter XmlWriter {
get { return xmlWriter; }
}
public MemoryStream ReaderStream {
get { return readerStreamSpy == null ? null : readerStreamSpy.ClonedStream; }
}
public XmlTextReader XmlReader {
get { return xmlReader; }
}
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
DisposeWriterStreamSpy();
DisposeReaderStreamSpy();
}
protected override XmlWriter GetWriterForMessage(SoapClientMessage message, int bufferSize) {
// Dispose previous writer stream spy.
DisposeWriterStreamSpy();
writerStreamSpy = new StreamSpy(message.Stream);
// XML should always support UTF8.
xmlWriter = new XmlTextWriter(writerStreamSpy, Encoding.UTF8);
return xmlWriter;
}
protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize) {
// Dispose previous reader stream spy.
DisposeReaderStreamSpy();
readerStreamSpy = new StreamSpy(message.Stream);
xmlReader = new XmlTextReader(readerStreamSpy);
return xmlReader;
}
private void DisposeWriterStreamSpy() {
if (writerStreamSpy != null) {
writerStreamSpy.Dispose();
writerStreamSpy.ClonedStream.Dispose();
writerStreamSpy = null;
}
}
private void DisposeReaderStreamSpy() {
if (readerStreamSpy != null) {
readerStreamSpy.Dispose();
readerStreamSpy.ClonedStream.Dispose();
readerStreamSpy = null;
}
}
/// <summary>
/// Wrapper class to clone read/write bytes.
/// </summary>
public class StreamSpy : Stream {
private Stream wrappedStream;
private long startPosition;
private MemoryStream clonedStream = new MemoryStream();
public StreamSpy(Stream wrappedStream) {
this.wrappedStream = wrappedStream;
startPosition = wrappedStream.Position;
}
public MemoryStream ClonedStream {
get { return clonedStream; }
}
public override bool CanRead {
get { return wrappedStream.CanRead; }
}
public override bool CanSeek {
get { return wrappedStream.CanSeek; }
}
public override bool CanWrite {
get { return wrappedStream.CanWrite; }
}
public override void Flush() {
wrappedStream.Flush();
}
public override long Length {
get { return wrappedStream.Length; }
}
public override long Position {
get { return wrappedStream.Position; }
set { wrappedStream.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count) {
long relativeOffset = wrappedStream.Position - startPosition;
int result = wrappedStream.Read(buffer, offset, count);
if (clonedStream.Position != relativeOffset) {
clonedStream.Position = relativeOffset;
}
clonedStream.Write(buffer, offset, result);
return result;
}
public override long Seek(long offset, SeekOrigin origin) {
return wrappedStream.Seek(offset, origin);
}
public override void SetLength(long value) {
wrappedStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count) {
long relativeOffset = wrappedStream.Position - startPosition;
wrappedStream.Write(buffer, offset, count);
if (clonedStream.Position != relativeOffset) {
clonedStream.Position = relativeOffset;
}
clonedStream.Write(buffer, offset, count);
}
public override void Close() {
wrappedStream.Close();
base.Close();
}
protected override void Dispose(bool disposing) {
if (wrappedStream != null) {
wrappedStream.Dispose();
wrappedStream = null;
}
base.Dispose(disposing);
}
}
}
}

The MSDN Library includes example code for obtaining the XML of both the request and the response that you can use to archive it. Obviously you'll have to make some changes since the example stores data in a text file, but it isn't too complicated.

Related

How do you (de)serialize a list of strings as CDATA using XmlSerializer

I need to serialize a list of strings as CDATA and thought I would follow an answer of How do you serialize a string as CDATA using XmlSerializer.
It works like a charm for serializing. My XML file looks as desired:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<tlist>
<item><![CDATA[First string]]></item>
<item><![CDATA[Second string]]></item>
</tlist>
</root>
But deserialization does not work. The TestList remains empty; value in the setter has count 0. What have I missed?
[XmlRootAttribute("root")]
public class TestConfig
{
public TestConfig()
{
TestList = new List<string>();
CdataList = new List<XmlCDataSection>();
}
[XmlIgnore]
public List<string> TestList { get; set; }
[XmlArray("tlist")]
[XmlArrayItem("item")]
public List<XmlCDataSection> CdataList
{
get { return TestList.Select(a => new XmlDocument().CreateCDataSection(a)).ToList(); }
set
{
TestList = value.Select(s => s.Value).ToList();
}
}
public void Save(string path)
{
var serializer = new XmlSerializer(GetType());
using (var stream = new StreamWriter(path))
{
serializer.Serialize(stream, this);
}
}
public static TestConfig Load(string path)
{
var serializer = new XmlSerializer(typeof(TestConfig));
using (var stream = new StreamReader(path))
{
return (TestConfig)serializer.Deserialize(stream);
}
}
}
Executing:
var t = new TestConfig();
t.TestList.Add("First string");
t.TestList.Add("Second string");
t.Save(#"C:\Test\cdatatest.xml");
var r = TestConfig.Load(#"C:\Test\cdatatest.xml");
Console.WriteLine("Testlist size is {0}", r.TestList.Count);
I thought I would "improve" on the answer by softwariness by reducing the length of the XMLWriter subclass.
/// <summary>
/// Custom XmlWriter.
/// Wraps up another XmlWriter to intercept string writes within
/// elements and writes them as CDATA instead.
/// </summary>
public class XmlCDataWriter : XmlTextWriter
{
public override void WriteString(string text)
{
if (WriteState == WriteState.Element)
{
WriteCData(text);
}
else
{
base.WriteString(text);
}
}
/// <summary>
/// Creates an instance of the XmlTextWriter class using the specified <see cref="T:System.IO.TextWriter"/>.
/// </summary>
/// <param name="w">The TextWriter to write to. It is assumed that the TextWriter is already set to the correct encoding. </param>
public XmlCDataWriter( [NotNull] TextWriter w ) : base( w )
{
}
}
It can then be used with a StringBuffer like so:
using (StringWriter textWriter = new StringWriter())
{
XmlSerializer serializer = new XmlSerializer( typeof( ... ) );
serializer.Serialize(new XmlCDataWriter(textWriter), ... );
return textWriter.ToString();
}
Seems to work so far for me, and it is a MUCH smaller subclass :)
Whilst simple proxies work with single values, you have to do a deeper proxying for collections, because of the way the .NET XML serialization machinery works:
[XmlRootAttribute("root")]
public class TestConfig
{
public TestConfig()
{
TestList = new List<string>();
}
private List<string> testList;
[XmlIgnore]
public List<string> TestList
{
get
{
if (this.testList == null)
{
var newCollection = new List<string>();
if (this.cdataList != null)
{
foreach (var x in this.cdataList)
{
newCollection.Add(x.Value);
}
}
this.testList = newCollection;
this.cdataList = null;
}
return this.testList;
}
set
{
this.testList = value;
this.cdataList = null;
}
}
private List<XmlCDataSection> cdataList;
[XmlArray("tlist")]
[XmlArrayItem("item")]
public List<XmlCDataSection> CdataList
{
get
{
if (this.cdataList == null)
{
var newCollection = new List<XmlCDataSection>();
if (this.testList != null)
{
foreach (var x in this.testList)
{
newCollection.Add(new XmlDocument().CreateCDataSection(x));
}
}
this.cdataList = newCollection;
this.testList = null;
}
return this.cdataList;
}
set
{
this.cdataList = value;
this.testList = null;
}
}
public void Save(string path)
{
var serializer = new XmlSerializer(GetType());
using (var stream = new StreamWriter(path))
{
serializer.Serialize(stream, this);
}
}
public static TestConfig Load(string path)
{
var serializer = new XmlSerializer(typeof(TestConfig));
using (var stream = new StreamReader(path))
{
return (TestConfig)serializer.Deserialize(stream);
}
}
}
The problem is that the serialization code doesn't just get and set the collections in one go. For example, when it's deserializing, it either creates a new collection, or gets one that's already set on the property, and adds to it. If you've created a new collection here computed from the "real" collection that your application needs to deal with, then any changes to the computed collection won't be reflected in the "real" collection.
To work around this, what I've done in the code above is to transfer ownership of the collection from the "real" collection to the "proxy" collection, and back again, depending on which collection property is being accessed. The cost of transferring ownership is incurred only when switching from one property to the other, so successive accesses to the "real" TestList collection in your application won't incur that expense.
This is somewhat inelegant though if you have many such collections. If you wanted to have all your element text serialized as CDATA, you could implement a custom XmlWriter, like the following:
/// <summary>
/// Custom XmlWriter.
/// Wraps up another XmlWriter to intercept string writes within
/// elements and writes them as CDATA instead.
/// </summary>
public class XmlCDataWriter : XmlWriter
{
XmlWriter w;
public XmlCDataWriter(XmlWriter baseWriter)
{
this.w = baseWriter;
}
public override void Close()
{
w.Close();
}
public override void Flush()
{
w.Flush();
}
public override string LookupPrefix(string ns)
{
return w.LookupPrefix(ns);
}
public override void WriteBase64(byte[] buffer, int index, int count)
{
w.WriteBase64(buffer, index, count);
}
public override void WriteCData(string text)
{
w.WriteCData(text);
}
public override void WriteCharEntity(char ch)
{
w.WriteCharEntity(ch);
}
public override void WriteChars(char[] buffer, int index, int count)
{
w.WriteChars(buffer, index, count);
}
public override void WriteComment(string text)
{
w.WriteComment(text);
}
public override void WriteDocType(string name, string pubid, string sysid, string subset)
{
w.WriteDocType(name, pubid, sysid, subset);
}
public override void WriteEndAttribute()
{
w.WriteEndAttribute();
}
public override void WriteEndDocument()
{
w.WriteEndDocument();
}
public override void WriteEndElement()
{
w.WriteEndElement();
}
public override void WriteEntityRef(string name)
{
w.WriteEntityRef(name);
}
public override void WriteFullEndElement()
{
w.WriteFullEndElement();
}
public override void WriteProcessingInstruction(string name, string text)
{
w.WriteProcessingInstruction(name, text);
}
public override void WriteRaw(string data)
{
w.WriteRaw(data);
}
public override void WriteRaw(char[] buffer, int index, int count)
{
w.WriteRaw(buffer, index, count);
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
w.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteStartDocument(bool standalone)
{
w.WriteStartDocument(standalone);
}
public override void WriteStartDocument()
{
w.WriteStartDocument();
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
w.WriteStartElement(prefix, localName, ns);
}
public override WriteState WriteState
{
get { return w.WriteState; }
}
public override void WriteString(string text)
{
if (WriteState == WriteState.Element)
{
w.WriteCData(text);
}
else
{
w.WriteString(text);
}
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
{
w.WriteSurrogateCharEntity(lowChar, highChar);
}
public override void WriteWhitespace(string ws)
{
w.WriteWhitespace(ws);
}
}
You'd then use it like follows:
var serializer = new XmlSerializer(...));
using (var cdataWriter = new XmlCDataWriter(XmlWriter.Create("somepath.xml")))
{
serializer.Serialize(cdataWriter, myDocumentObject);
}
Again, this only makes sense as an option if you want to write everything as CDATA.

Is it possible to return a response DTO that matches what is expected in the Contract using IErrorHandler

I want to be able to catch all unhandled exceptions and return the expected DTO but with some error information filled in. For example
public class CreateFooRequest
{
public string Name { get; set; }
}
public class CreateFooResponse
{
public Foo Created { get; set; }
public string Error { get; set; } // If call was successful then this will be null
public string Detail { get; set; }
}
public interface IFooService
{
CreateFooResponse Create(CreateFooRequest request);
}
public ErrorHandler: IErrorHandler
{
public bool Handle(Exception ex)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// Some how figure out that IFooService.Create was called.
// Inspect the method signature and see that there is an input called CreateFooRequest
// Use reflection to initialize response objects that will replace the "Request" with "Response"
var response = new CreateFooResponse();
response.Error = error.GetType().Name;
// I think i need one of the following overloads
fault = Message.CreateMessage(version, action, response);
}
}
Is doing something like this even possible? We are using NetTCP as our binding if that makes a difference.
IErrorHandler is designed to generate fault contracts. If you don't want to return a fault, you are better off taking an interceptor approach and using a the IOperationInvoker extension point instead.
The operation invoker is the part of the WCF framework that actually calls the service method. When you extend it, you can effectively "intercept" the call to the service. Note the Invoker does have responsibilities. You can't simply replace the WCF invoker implementation. Instead you chain them (see below).
At a high level the steps are:
Create an IOperationInvoker.Invoke() that implements a try/catch block. Catch the exceptions you want to be Response messages instead of FaultExceptions.
Create an IOperationBehavior (that's optionally also an attribute) to apply the behavior to your service.
The approach has a couple of advantages:
The exception is caught before WCF sees it.
In a IOperationBehavior.ApplyDispatchBehavior() you have access to the OperationDescription at the time of service start up. If you save this in the Invoker, you don't need to use reflection to capture the method's return type.
The IOperationBehavior.Validate() allows robust checks to ensure that the return type can actually be processed.
Below is a complete windows console application that demonstrates the approach. Paste it into Visual Studio, add the obvious assembly references, and run it.
My apologizes for the large amount of code and excessive use of base classes. I'm cutting down from actual production code.
If you want a better understanding of the IOperationInvoker extension point and what the example InvokerBase class is doing see Carlos Figueira's blog.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Threading.Tasks;
namespace WcfErrorResponse
{
/// <summary>
/// Provides a base IOperationInvoker implementation that stores and passes through calls to the exisiting (old) invoker
/// </summary>
public abstract class InvokerBase : IOperationInvoker
{
private readonly IOperationInvoker m_OldInvoker;
protected IOperationInvoker OldInvoker
{
get { return m_OldInvoker; }
}
public InvokerBase(IOperationInvoker oldInvoker)
{
m_OldInvoker = oldInvoker;
}
public virtual object[] AllocateInputs()
{
return OldInvoker.AllocateInputs();
}
public virtual object Invoke(object instance, object[] inputs, out object[] outputs)
{
return OldInvoker.Invoke(instance, inputs, out outputs);
}
public virtual IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return OldInvoker.InvokeBegin(instance, inputs, callback, state);
}
public virtual object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return OldInvoker.InvokeEnd(instance, out outputs, result);
}
public virtual bool IsSynchronous
{
get { return OldInvoker.IsSynchronous; }
}
}
/// <summary>
/// Base implementation for a Method level attribte that applies a <see cref="InvokerBase"/> inherited behavior.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public abstract class InvokerOperationBehaviorAttribute : Attribute, IOperationBehavior
{
protected abstract InvokerBase CreateInvoker(IOperationInvoker oldInvoker, OperationDescription operationDescription, DispatchOperation dispatchOperation);
public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{ }
public virtual void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
// chain invokers.
IOperationInvoker oldInvoker = dispatchOperation.Invoker;
dispatchOperation.Invoker = CreateInvoker(oldInvoker, operationDescription, dispatchOperation);
}
public virtual void Validate(OperationDescription operationDescription)
{
return;
}
}
public class ResponseExceptionInvoker : InvokerBase
{
private Type returnType;
public ResponseExceptionInvoker(IOperationInvoker oldInvoker, OperationDescription operationDescription)
: base(oldInvoker)
{
// save the return type for creating response messages
this.returnType = operationDescription.GetReturnType();
if (this.returnType == null)
{
throw new InvalidOperationException("The operation '" + operationDescription.SyncMethod.DeclaringType.Name + "' does not define a return type.");
}
}
public override object Invoke(object instance, object[] inputs, out object[] outputs)
{
object returnedValue = null;
object[] outputParams = new object[] { };
outputs = new object[] { };
try
{
returnedValue = OldInvoker.Invoke(instance, inputs, out outputParams);
outputs = outputParams;
return returnedValue;
}
catch (Exception ex)
{
Logger.Debug("ResponseExceptionInvoker() - Caught Exception. A Response Message will be returned. Message='" + ex.Message + "'");
// there was an excpetion. Do not assign output params... their state is undefined.
//outputs = outputParams;
try
{
// assumes the behavior only used for return types that inherit from Response, as verified by ResponseExceptionOperationBehaviorAttribute.Validate()
Response response = (Response)Activator.CreateInstance(this.returnType);
response.Success = false;
response.ErrorMessage = ex.Message;
return response;
}
catch (Exception exCreateResponse)
{
// Log that the Response couldn't be created and throw the original exception.
// Probably preferable to wrap and throw.
Logger.Error("Caught ResponseException, but unable to create the Response object. Likely indicates a bug or misconfiguration. Exception will be rethrown." + exCreateResponse.Message);
}
throw;
}
}
}
public class ResponseExceptionOperationBehaviorAttribute : InvokerOperationBehaviorAttribute
{
protected override InvokerBase CreateInvoker(IOperationInvoker oldInvoker, OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
return new ResponseExceptionInvoker(oldInvoker, operationDescription);
}
public override void Validate(OperationDescription operationDescription)
{
// validate that this attribute can be applied to the service behavior.
Type returnType = operationDescription.GetReturnType();
if (!typeof(Response).IsAssignableFrom(returnType))
{
throw new InvalidOperationException("'" + returnType.FullName + "' does not inherit from '" + typeof(Response).FullName +
"'. ImplicitResponse behavior applied to '" + operationDescription.SyncMethod.DeclaringType.Name + "." + operationDescription.Name +
"' requires the method return type inherit from '" + typeof(Response).FullName);
}
}
}
static class OperationDescriptionExtensions
{
public static Type GetReturnType(this OperationDescription operationDescription)
{
if (operationDescription.SyncMethod == null)
throw new InvalidOperationException("These behaviors have only been tested with Sychronous methods.");
// !! Warning: This does NOT work for Asynch or Task based implementations.
System.Reflection.MethodInfo method = operationDescription.SyncMethod ?? operationDescription.EndMethod;
return method.ReturnType;
}
}
// When not using FaultContracts, return success/fail as a part of all responses via some base class properties.
[DataContract]
public class Response
{
[DataMember]
public bool Success { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
}
public class ChildResponse : Response
{
[DataMember]
public string Foo { get; set; }
}
[DataContract]
public class Request
{
[DataMember]
public string Name { get; set; }
}
[ServiceContract]
public interface ISimple
{
[OperationContract]
ChildResponse Work(Request request);
[OperationContract]
ChildResponse Fail(Request request);
}
public class SimpleService : ISimple
{
public ChildResponse Work(Request request) {
return new ChildResponse() { Success = true };
}
[ResponseExceptionOperationBehavior]
public ChildResponse Fail(Request request)
{
throw new NotImplementedException("This method isn't done");
}
}
class Program
{
static void Main(string[] args)
{
ServiceHost simpleHost = new ServiceHost(typeof(SimpleService), new Uri("http://localhost/Simple"));
simpleHost.Open();
ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(simpleHost.Description.Endpoints[0]);
ISimple proxy = factory.CreateChannel();
Logger.Debug("Calling Work...");
var response1 = proxy.Work(new Request() { Name = "Foo" });
Logger.Debug("Work() returned Success=" + response1.Success + " message='" + response1.ErrorMessage + "'");
Logger.Debug("Calling Fail...");
var response2 = proxy.Fail(new Request() { Name = "FooBar" });
Logger.Debug("Fail() returned Success=" + response2.Success + " message='" + response2.ErrorMessage + "'");
Console.WriteLine("Press ENTER to close the host.");
Console.ReadLine();
((ICommunicationObject)proxy).Shutdown();
simpleHost.Shutdown();
}
}
public static class CommunicationObjectExtensions
{
static public void Shutdown(this ICommunicationObject obj)
{
try
{
obj.Close();
}
catch (Exception ex)
{
Console.WriteLine("Shutdown exception: {0}", ex.Message);
obj.Abort();
}
}
}
public static class Logger
{
public static void Debug(string message) { Console.WriteLine(message); }
public static void Error(string message) { Console.WriteLine(message); }
}
}
In your place, I would implement this as simple as possible by using general try/catch block. Using custom exception handler to observe the invoked service method and create a corresponding response using reflection looks like an overkill for me.
Make your life easier:
public CreateFooResponse Create(CreateFooRequest request)
{
try
{
// Create Foo
var foo = CreateFoo();
// Return successful CreateFooResponse
return new CreateFooResponse
{
Created = foo,
Error = null,
Detail = "Created successfully"
};
}
catch (Exception ex)
{
// Return CreateFooResponse with an error
return new CreateFooResponse
{
Created = null,
Error = CreateError(ex),
Detail = "Unable to create Foo."
};
}
}
A good example of using custom WCF error handler is to log the error, convert it to the FaultContract and return to the caller. You have a different scenario and I would suggest a different approach.
First of all, I would like to say that it is much better to use faultcontracts. Below I will give an example for service GetDataUsingDataContract:
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
[DataContract]
public class CompositeType
{
[DataMember]
public bool BoolValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
Then, you create a bodyWriter equivalent to a normal response:
public class MyBodyWriter : BodyWriter
{
public CompositeType CompositeType { get; private set; }
public MyBodyWriter(CompositeType composite)
: base(false)
{
CompositeType = composite;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("GetDataUsingDataContractResponse", "http://tempuri.org/");
writer.WriteStartElement("GetDataUsingDataContractResult");
writer.WriteAttributeString("xmlns", "a", null, "http://schemas.datacontract.org/2004/07/WcfService1");
writer.WriteAttributeString("xmlns", "i", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteStartElement("a:BoolValue");
writer.WriteString(CompositeType.BoolValue.ToString().ToLower());
writer.WriteEndElement();
writer.WriteStartElement("a:StringValue");
writer.WriteString(CompositeType.StringValue);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
And finally, you use it in your IErrorHandler:
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// TODO: parse error and gets response
var response = new CompositeType {BoolValue = true, StringValue = "a"};
fault = Message.CreateMessage(version, "http://tempuri.org/", new MyBodyWriter(response));
}
I did a test and I can get a correct answer if the service throws an exception or if the service responds normally:
var response1 = client.GetDataUsingDataContract(null);
var response2 = client.GetDataUsingDataContract(new CompositeType { StringValue = "a", BoolValue = true });

How to send multiple images from android to a WCF Rest Service as a stream to write to a network drive?

After much googling and searching, I managed to send an image using multiparsers from android to my WCF service, but ideally, I'd like to send several images at once, instead of calling the method over and over again, since it'd take a lot longer, and add a bunch more overhead.
This is my current code
Android (Taken from code found on here somewhere):
public static String postFile(Bitmap bitmap, String urlString) throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(urlString);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 30, bao);
byte[] data = bao.toByteArray();
//filename
String fileName = String.format("File_%d.png",new Date().getTime());
ByteArrayBody bab = new ByteArrayBody(data, fileName);
builder.addPart("image", bab);
final HttpEntity yourEntity = builder.build();
class ProgressiveEntity implements HttpEntity {
#Override
public void consumeContent() throws IOException {
yourEntity.consumeContent();
}
#Override
public InputStream getContent() throws IOException,
IllegalStateException {
return yourEntity.getContent();
}
#Override
public Header getContentEncoding() {
return yourEntity.getContentEncoding();
}
#Override
public long getContentLength() {
return yourEntity.getContentLength();
}
#Override
public Header getContentType() {
return yourEntity.getContentType();
}
#Override
public boolean isChunked() {
return yourEntity.isChunked();
}
#Override
public boolean isRepeatable() {
return yourEntity.isRepeatable();
}
#Override
public boolean isStreaming() {
return yourEntity.isStreaming();
} // CONSIDER put a _real_ delegator into here!
#Override
public void writeTo(OutputStream outstream) throws IOException {
class ProxyOutputStream extends FilterOutputStream {
/**
* #author Stephen Colebourne
*/
public ProxyOutputStream(OutputStream proxy) {
super(proxy);
}
public void write(int idx) throws IOException {
out.write(idx);
}
public void write(byte[] bts) throws IOException {
out.write(bts);
}
public void write(byte[] bts, int st, int end) throws IOException {
out.write(bts, st, end);
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
} // CONSIDER import this class (and risk more Jar File Hell)
class ProgressiveOutputStream extends ProxyOutputStream {
public ProgressiveOutputStream(OutputStream proxy) {
super(proxy);
}
public void write(byte[] bts, int st, int end) throws IOException {
// FIXME Put your progress bar stuff here!
out.write(bts, st, end);
}
}
yourEntity.writeTo(new ProgressiveOutputStream(outstream));
}
};
ProgressiveEntity myEntity = new ProgressiveEntity();
post.setEntity(myEntity);
HttpResponse response = client.execute(post);
return getContent(response);
}
public static String getContent(HttpResponse response) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String body = "";
String content = "";
while ((body = rd.readLine()) != null)
{
content += body + "\n";
}
return content.trim();
}
C# WCF Service method to take it
[WebInvoke(UriTemplate = "UploadPicture/{filename}", Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public String UploadPicture(string filename, Stream fileStream)
{
WriteLog("Uploading picture...");
try
{
MultipartParser parser = new MultipartParser(fileStream);
if (parser.Success)
{
string fileName = parser.Filename;
string contentType = parser.ContentType;
byte[] fileContent = parser.FileContents;
FileStream fileToupload = new FileStream("\\\\OHS-SUN\\Tracker\\robbie\\" + filename, FileMode.Create);
fileToupload.Write(fileContent, 0, fileContent.Length);
fileToupload.Close();
fileToupload.Dispose();
fileStream.Close();
return "Success !!!";
}
else
{
return "Exception!!!";
}
}
catch (Exception ex)
{
WriteLog("Uploading picture exception: " + ex.Message);
}
return "Picture uploaded!";
}
I'd like to go from sending one image, to sending several, each with 2 text attributes; the filename, and the project number they're associated with. Essentially, both is what I need it for. At the moment, I'm just trying to do put another addPart on to the android bit, but then I don't know how to add metadata to that and I wouldn't know how to parse it based on the name. I'm fine with using any third party libraries, the one I'm using on C# at the moment is already one.
Thanks a lot!
Instead of sending multiple images in one thing, I just stuck it in an asynchronous class and sent them concurrently with a max of 10 at a time until all the images are sent in that particular session. Seems to work fine, the implementation's the same, so I've not had to change any of that, which is good. If anyone would like me to post the code I did to do that, I'd be happy to. It's just small snippets here and there added to the above code, though.
Well, the main bit I added was:
public static class FileUploader extends AsyncTask<UploadFile , Void , String> implements Future<String>
{
#Override
protected void onPreExecute() {
filesUploading ++;
}
#Override
protected String doInBackground(UploadFile... uploadFile)
{
try
{
return postFile(uploadFile[0].file, uploadFile[0].projectNo, uploadFile[0].filename);
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
filesUploading --;
}
#Override
public boolean isDone() {
return AsyncTask.Status.FINISHED == getStatus();
}
}
This allows me to send each image separately, and handle them separately.

ASP.NET MVC C# Razor Minification

Does anybody have any idea about how to output minified HTML and JavaScript from the Razor engine while keeping custom coding styles?
For example: i want the following code:
<div
#if (Model.Name != string.Empty)
#:id="#Model.Name"
>
</div>
To be outputted as <div id="DivId"></div> .
Look at http://arranmaclean.wordpress.com/2010/08/10/minify-html-with-net-mvc-actionfilter/.
there is an example for creating custom action filter witch clear html from WhiteSpaces
Update: The source code quoted from above.
The stream class for removing "blanks"
using System;
using System.IO;
using System.Text;
using System.Web.Mvc;
using System.Text.RegularExpressions;
namespace RemoveWhiteSpace.ActionFilters
{
public class WhiteSpaceFilter : Stream
{
private Stream _shrink;
private Func<string, string> _filter;
public WhiteSpaceFilter(Stream shrink, Func<string, string> filter)
{
_shrink = shrink;
_filter = filter;
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return true; } }
public override bool CanWrite { get { return true; } }
public override void Flush() { _shrink.Flush(); }
public override long Length { get { return 0; } }
public override long Position { get; set; }
public override int Read(byte[] buffer, int offset, int count)
{
return _shrink.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _shrink.Seek(offset, origin);
}
public override void SetLength(long value)
{
_shrink.SetLength(value);
}
public override void Close()
{
_shrink.Close();
}
public override void Write(byte[] buffer, int offset, int count)
{
// capture the data and convert to string
byte[] data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
string s = Encoding.Default.GetString(buffer);
// filter the string
s = _filter(s);
// write the data to stream
byte[] outdata = Encoding.Default.GetBytes(s);
_shrink.Write(outdata, 0, outdata.GetLength(0));
}
}
}
The ActionFilter class:
public class WhitespaceFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
var response = filterContext.HttpContext.Response;
response.Filter = new WhiteSpaceFilter(response.Filter, s =>
{
s = Regex.Replace(s, #"\s+", " ");
s = Regex.Replace(s, #"\s*\n\s*", "\n");
s = Regex.Replace(s, #"\s*\>\s*\<\s*", "><");
s = Regex.Replace(s, #"<!--(.*?)-->", ""); //Remove comments
// single-line doctype must be preserved
var firstEndBracketPosition = s.IndexOf(">");
if (firstEndBracketPosition >= 0)
{
s = s.Remove(firstEndBracketPosition, 1);
s = s.Insert(firstEndBracketPosition, ">");
}
return s;
});
}
}
And in the end the usage of above:
[HandleError]
[WhitespaceFilter]
public class HomeController : Controller
{
...
}
Maybe you looking for Meleze.Web
Meleze.Web is a toolbox to optimize ASP.NET MVC 3.0 and MVC 4.0 applications.
It provides HTML, JS and CSS minification of Razor views and caching of the returned pages.
Darin Dimitrov write about it here: ASP.Net MVC Razor Views - Minifying HTML at build time
But I think enabling gzip is better solution, you could read about it here: Minify HTML output from an ASP.Net MVC Application
I don't think that there is any way to achieve that. To avoid the tag soup I usually prefer writing custom helpers:
#using(Html.MyDiv(Model.Name))
{
... put the contents of the div here
}
and here's how the custom helper might look like:
public static class HtmlExtensions
{
private class Div : IDisposable
{
private readonly ViewContext context;
private bool disposed;
public Div(ViewContext context)
{
this.context = context;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
this.disposed = true;
context.Writer.Write("</div>");
}
}
}
public static IDisposable MyDiv(this HtmlHelper html, string id)
{
var div = new TagBuilder("div");
if (!string.IsNullOrEmpty(id))
{
div.GenerateId(id);
}
html.ViewContext.Writer.Write(div.ToString(TagRenderMode.StartTag));
return new Div(html.ViewContext);
}
}
Alternatively you could also do a tag soup:
<div#Html.Raw(Model.Name != string.Empty ? string.Format(" id=\"{0}\"", Html.AttributeEncode(Model.Name)) : string.Empty)>
</div>
For anybody interested in this, I built a simple HTML minification library that can be used with MVC 5:
https://github.com/tompazourek/RazorHtmlMinifier.Mvc5
It operates in compile-time instead of runtime, so it doesn't add any performance overhead. The minification is very simple (just replaces lots of spaces with one space).
Even with GZIP enabled on top of the minified HTML, it can still reduce the payload size.

How do I close a database connection being used to produce a streaming result in a WCF service?

I have been unable to find any documentation on properly closing database connections in WCF service operations. I have a service that returns a streamed response through the following method.
public virtual Message GetData()
{
string sqlString = BuildSqlString();
SqlConnection conn = Utils.GetConnection();
SqlCommand cmd = new SqlCommand(sqlString, conn);
XmlReader xr = cmd.ExecuteXmlReader();
Message msg = Message.CreateMessage(
OperationContext.Current.IncomingMessageVersion,
GetResponseAction(),
xr);
return msg;
}
I cannot close the connection within the method or the streaming of the response message will be terminated. Since control returns to the WCF system after the completion of that method, I don't know how I can close that connection afterwards. Any suggestions or pointers to additional documentation would be appreciated.
Good question, actually. Unfortunately, one for which I believe there is no good answer. There's actually an active Microsoft Connect ticket about this very issue.
Normally, if you want to stream results and you just need a regular SqlDataReader, you can use the ExecuteReader overload that takes a CommandBehavior, and specifically CommandBehavior.CloseConnection. If a reader is created using this command behavior, then when you Close (or Dispose) the reader, it also closes the underlying connection, so you never have to worry about disposing the SqlConnection.
Unfortunately, there's no equivalent overload of ExecuteXmlReader. You have to dispose the SqlConnection explicitly.
One way around this would be to implement your own XmlReader descendant, wrapping the real XmlReader obtained from ExecuteXmlReader and forcing the connection closed on close.
The basic idea is just to derive from XmlReader and wrap both the real XmlReader and the SqlConnection itself. Something like this:
class SqlXmlReader : XmlReader
{
private SqlConnection connection;
private XmlReader reader;
public SqlXmlReader(SqlCommand cmd)
{
if (cmd == null)
throw new ArgumentNullException("cmd");
this.connection = cmd.Connection;
this.reader = cmd.ExecuteXmlReader();
}
public override void Close()
{
reader.Close();
connection.Close();
}
}
This takes the connection and the reader directly from the SqlCommand so there's no chance of a connection/reader mismatch. You need to implement the rest of the XmlReader methods and properties too - it's just a lot of boring method proxying:
public override int AttributeCount
{
get { return reader.AttributeCount; }
}
public override string BaseURI
{
get { return reader.BaseURI; }
}
public override int Depth
{
get { return reader.Depth; }
}
public override bool EOF
{
get { return reader.EOF; }
}
public override string GetAttribute(int i)
{
return reader.GetAttribute(i);
}
public override string GetAttribute(string name, string namespaceURI)
{
return reader.GetAttribute(name, namespaceURI);
}
public override string GetAttribute(string name)
{
return reader.GetAttribute(name);
}
public override bool HasValue
{
get { return reader.HasValue; }
}
public override bool IsEmptyElement
{
get { return reader.IsEmptyElement; }
}
public override string LocalName
{
get { return reader.LocalName; }
}
public override string LookupNamespace(string prefix)
{
return reader.LookupNamespace(prefix);
}
public override bool MoveToAttribute(string name, string ns)
{
return reader.MoveToAttribute(name, ns);
}
public override bool MoveToAttribute(string name)
{
return reader.MoveToAttribute(name);
}
public override bool MoveToElement()
{
return reader.MoveToElement();
}
public override bool MoveToFirstAttribute()
{
return reader.MoveToFirstAttribute();
}
public override bool MoveToNextAttribute()
{
return reader.MoveToNextAttribute();
}
public override XmlNameTable NameTable
{
get { return reader.NameTable; }
}
public override string NamespaceURI
{
get { return reader.NamespaceURI; }
}
public override XmlNodeType NodeType
{
get { return reader.NodeType; }
}
public override string Prefix
{
get { return reader.Prefix; }
}
public override bool Read()
{
return reader.Read();
}
public override bool ReadAttributeValue()
{
return reader.ReadAttributeValue();
}
public override ReadState ReadState
{
get { return reader.ReadState; }
}
public override void ResolveEntity()
{
reader.ResolveEntity();
}
public override string Value
{
get { return reader.Value; }
}
Dull, dull, dull, but it works. This reader will close the connection for you when it's done, same as a SqlDataReader opened with CommandBehavior.CloseConnection.
Last thing to do would be to create an extension method to make this easier to use:
public static class SqlExtensions
{
public static XmlReader ExecuteSafeXmlReader(this SqlCommand cmd)
{
return new SqlXmlReader(cmd);
}
}
Once you have this, instead of writing:
XmlReader xr = cmd.ExecuteXmlReader();
You write:
XmlReader xr = cmd.ExecuteSafeXmlReader();
That's it. Now when WCF closes your reader, it will automatically close the underlying connection.
(Disclaimer: This hasn't officially been tested, but I can see no reason why it wouldn't work, unless WCF does not actually close the reader. Be sure to actually test this against a live SQL connection to make sure that it really doesn't leak connections.)
You could try some form of a Duplex Service or Session based service. This would allow you to make the request in one call and keep the SqlConnection opened until a Disconnect() style call is made. This disconnect could .Dispose() of the related SQL objects.
You might look into making your service class implement the IDispose

Categories

Resources