PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/SimpleWebDiscoveryInspector.cs

http://odataswd.codeplex.com
C# | 172 lines | 126 code | 27 blank | 19 comment | 10 complexity | 6664f5da37cecba23588565ce00ac9e0 MD5 | raw file
  1. // Copyright 2011 Microsoft Corporation
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. using System;
  15. using System.Collections.Generic;
  16. using System.ServiceModel;
  17. using System.ServiceModel.Channels;
  18. using System.ServiceModel.Description;
  19. using System.ServiceModel.Dispatcher;
  20. using System.Text;
  21. using System.Xml;
  22. namespace Microsoft.Data.Services.Client
  23. {
  24. class SimpleWebDiscoveryInspector : IDispatchMessageInspector
  25. {
  26. // Assume utf-8, note that Data Services supports
  27. // charset negotation, so this needs to be more
  28. // sophisticated (and per-request) if clients will
  29. // use multiple charsest
  30. private static Encoding encoding = Encoding.UTF8;
  31. private IDictionary<string, string[]> endpoints;
  32. private const string swdPath = "/$wellknown/simple-web-discovery";
  33. public SimpleWebDiscoveryInspector(IDictionary<string, string[]> endpoints)
  34. : base()
  35. {
  36. this.endpoints = endpoints;
  37. }
  38. #region IDispatchMessageInspector Members
  39. public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
  40. {
  41. if (request.Properties.ContainsKey("UriTemplateMatchResults"))
  42. {
  43. HttpRequestMessageProperty httpmsg = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
  44. UriTemplateMatch match = (UriTemplateMatch)request.Properties["UriTemplateMatchResults"];
  45. string pathAfterSvc = match.RequestUri.AbsolutePath.Replace(match.BaseUri.AbsolutePath, "");
  46. if (pathAfterSvc.Equals(swdPath))
  47. {
  48. httpmsg.Headers["Accept"] = "application/json";
  49. string service = match.QueryParameters["service"];
  50. if (this.endpoints.ContainsKey(service))
  51. {
  52. return this.endpoints[service];
  53. }
  54. }
  55. }
  56. return null;
  57. }
  58. public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
  59. {
  60. if (correlationState != null && correlationState is string[])
  61. {
  62. string[] addresses = correlationState as string[];
  63. string content = "{ \"locations\" : " + ToJsonArray(addresses) + " }";
  64. Message newreply = Message.CreateMessage(MessageVersion.None, "", new Writer(content));
  65. newreply.Properties["WebBodyFormatMessageProperty"] = new WebBodyFormatMessageProperty(WebContentFormat.Raw);
  66. HttpResponseMessageProperty prop = (HttpResponseMessageProperty)reply.Properties["httpResponse"];
  67. prop.StatusCode = System.Net.HttpStatusCode.OK;
  68. newreply.Properties["httpResponse"] = prop;
  69. reply = newreply;
  70. }
  71. }
  72. private string ToJsonArray(string[] array)
  73. {
  74. string content = "[ ";
  75. if (array.Length > 0)
  76. {
  77. content += "\"" + array[0] + "\"";
  78. for (int i = 1; i < array.Length; ++i)
  79. {
  80. content += ", \"" + array[i] + "\"";
  81. }
  82. }
  83. return content + " ]";
  84. }
  85. #endregion
  86. class Writer : BodyWriter
  87. {
  88. private string content;
  89. public Writer(string content)
  90. : base(false)
  91. {
  92. this.content = content;
  93. }
  94. protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
  95. {
  96. writer.WriteStartElement("Binary");
  97. byte[] buffer = SimpleWebDiscoveryInspector.encoding.GetBytes(this.content);
  98. writer.WriteBase64(buffer, 0, buffer.Length);
  99. writer.WriteEndElement();
  100. }
  101. }
  102. }
  103. // Simply apply this attribute to a DataService-derived class to allow
  104. // simple web discovery support in that service
  105. [AttributeUsage(AttributeTargets.Class)]
  106. public class SimpleWebDiscoveryBehaviorAttribute : Attribute, IServiceBehavior
  107. {
  108. private IDictionary<string, string[]> endpoints;
  109. public SimpleWebDiscoveryBehaviorAttribute(Type type) : base()
  110. {
  111. Endpoints endpointDictionary = (type.GetConstructor(new Type[] { }).Invoke(new object[] { })) as Endpoints;
  112. if (endpointDictionary == null)
  113. {
  114. throw new ArgumentException("Argument must be a subclass of the Endpoints class.");
  115. }
  116. endpoints = new Dictionary<string, string[]>();
  117. foreach (KeyValuePair<string, List<string>> p in endpointDictionary.EndpointDictionary)
  118. {
  119. this.endpoints[p.Key] = p.Value.ToArray();
  120. }
  121. }
  122. #region IServiceBehavior Members
  123. void IServiceBehavior.AddBindingParameters(
  124. ServiceDescription serviceDescription,
  125. ServiceHostBase serviceHostBase,
  126. System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
  127. System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
  128. {
  129. }
  130. void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
  131. {
  132. foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
  133. {
  134. foreach (EndpointDispatcher ed in cd.Endpoints)
  135. {
  136. ed.DispatchRuntime.MessageInspectors.Add(new SimpleWebDiscoveryInspector(this.endpoints));
  137. }
  138. }
  139. }
  140. void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
  141. {
  142. }
  143. #endregion
  144. }
  145. }