Language: C#
WCF Data Service / OData IDispatchBehavior to decode a string-encoded XML fragment and insert it back into the output message.
1: namespace PersistConfigSettings 2: { 3: using System; 4: using System.Collections.ObjectModel; 5: using System.Linq; 6: using System.ServiceModel; 7: using System.ServiceModel.Channels; 8: using System.ServiceModel.Description; 9: using System.ServiceModel.Dispatcher; 10: using System.Text; 11: using System.Xml; 12: using System.Xml.Linq; 13: using System.Xml.XPath; 14: 15: [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 16: public sealed class ContentToXmlBehaviorAttribute : Attribute, IDispatchMessageInspector, IServiceBehavior 17: { 18: private const string BareUriKeyword = "$bare"; 19: private const string UriTemplateMatchResultsKey = "UriTemplateMatchResults"; 20: private const string DataServicesUri = "http://schemas.microsoft.com/ado/2007/08/dataservices"; 21: private const string DataServicesUriPrefix = "d"; 22: private const string ContentXPathExpression = "//d:Content/*[1]"; 23: 24: /// <summary> 25: /// Provides the ability to pass custom data to binding elements to support the contract implementation. 26: /// </summary> 27: /// <param name="serviceDescription">The service description of the service.</param><param name="serviceHostBase">The host of the service.</param><param name="endpoints">The service endpoints.</param><param name="bindingParameters">Custom objects to which binding elements have access.</param> 28: public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) 29: { 30: // no op. 31: } 32: 33: /// <summary> 34: /// Provides the ability to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects. 35: /// </summary> 36: /// <param name="serviceDescription">The service description.</param><param name="serviceHostBase">The host that is currently being built.</param> 37: public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 38: { 39: foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) 40: { 41: foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints) 42: { 43: endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this); 44: } 45: } 46: } 47: 48: /// <summary> 49: /// Provides the ability to inspect the service host and the service description to confirm that the service can run successfully. 50: /// </summary> 51: /// <param name="serviceDescription">The service description.</param><param name="serviceHostBase">The service host that is currently being constructed.</param> 52: public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 53: { 54: // no op. 55: } 56: 57: public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 58: { 59: if (request.Properties.ContainsKey(UriTemplateMatchResultsKey)) 60: { 61: var match = (UriTemplateMatch)request.Properties[UriTemplateMatchResultsKey]; 62: if (match.QueryParameters.AllKeys.Contains(BareUriKeyword)) 63: { 64: match.QueryParameters.Remove(BareUriKeyword); 65: return BareUriKeyword; 66: } 67: } 68: return null; 69: } 70: 71: public void BeforeSendReply(ref Message reply, object correlationState) 72: { 73: var httpResponse = reply.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty; 74: if (httpResponse == null) 75: throw new InvalidOperationException(); 76: 77: if (httpResponse.StatusCode != System.Net.HttpStatusCode.OK) 78: return; 79: 80: var reader = reply.GetReaderAtBodyContents(); 81: reader.ReadStartElement(); 82: var content = Encoding.UTF8.GetString(reader.ReadContentAsBase64()); 83: 84: var oldReply = reply; 85: var xmlString = content.DecodeToXml(); 86: var bare = correlationState as string; 87: if (bare != null && bare.Equals(BareUriKeyword, StringComparison.InvariantCultureIgnoreCase)) 88: { 89: var nsMgr = new XmlNamespaceManager(new NameTable()); 90: nsMgr.AddNamespace(DataServicesUriPrefix, DataServicesUri); 91: var bareContent = XElement.Parse(xmlString).XPathSelectElement(ContentXPathExpression, nsMgr); 92: reply = Message.CreateMessage(MessageVersion.None, string.Empty, new Writer(bareContent.ToString())); 93: } 94: else 95: { 96: reply = Message.CreateMessage(MessageVersion.None, string.Empty, new Writer(xmlString)); 97: } 98: reply.Properties.CopyProperties(oldReply.Properties); 99: } 100: 101: class Writer : BodyWriter 102: { 103: const string BinaryElementName = "Binary"; 104: private readonly string _content; 105: 106: public Writer(string content) 107: : base(false) 108: { 109: _content = content; 110: } 111: 112: protected override void OnWriteBodyContents(XmlDictionaryWriter writer) 113: { 114: writer.WriteStartElement(BinaryElementName); 115: var buffer = Encoding.UTF8.GetBytes(_content); 116: writer.WriteBase64(buffer, 0, buffer.Length); 117: writer.WriteEndElement(); 118: } 119: } 120: } 121: 122: static class StringExtensions 123: { 124: /// <summary> 125: /// Poor man"s XML decoder. 126: /// </summary> 127: /// <param name="string">String to decode to XML.</param> 128: /// <returns>XML (as string).</returns> 129: public static string DecodeToXml(this string @string) 130: { 131: return @string.Replace("<", "<") 132: .Replace(">", ">") 133: .Replace(""", "\""); 134: } 135: } 136: }
by
Lars Wilhelmsen
April 04, 2010 @ 1:01pm
April 04, 2010 @ 1:01pm
Tags:
Report Abuse
Subscribe
Discuss
What's new
What is it
New Snippet
Recent Snippets
My Snippets
Web Code
Search

