Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJb Evain <jbevain@gmail.com>2008-08-21 01:25:05 +0400
committerJb Evain <jbevain@gmail.com>2008-08-21 01:25:05 +0400
commit982e3b35a4b715fa86ef2037501bfa1c89dd5038 (patch)
tree1ba1f442ea12faa4ffbb8fca8c6e429a53f6cfc9 /mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher
parentbdd0809c70020fc9c381c4310c346368e195fe76 (diff)
move to from olive to mcs
svn path=/trunk/mcs/; revision=111188
Diffstat (limited to 'mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher')
-rw-r--r--mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/ChangeLog81
-rw-r--r--mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/JsonQueryStringConverter.cs213
-rw-r--r--mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/QueryStringConverter.cs135
-rw-r--r--mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebHttpDispatchOperationSelector.cs106
-rw-r--r--mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebMessageFormatter.cs332
5 files changed, 867 insertions, 0 deletions
diff --git a/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/ChangeLog b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/ChangeLog
new file mode 100644
index 00000000000..eb919ace3b2
--- /dev/null
+++ b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/ChangeLog
@@ -0,0 +1,81 @@
+2008-04-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : now that ReadObject() verifies
+ by default, it broke deserialization. Fixed it.
+
+2008-02-18 Atsushi Enomoto <atsushi@ximian.com>
+
+ * JsonQueryStringConverter.cs : implemented.
+
+2008-02-17 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : implement WebOperationContext support.
+
+2008-02-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebHttpDispatchOperationSelector.cs : some code cleanup.
+
+2008-02-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : fixed content-type typo.
+
+2008-02-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : implemented DeserializeReply().
+ It was wrong to have one MessageDescription in a formatter, as
+ they are different between serialization and deserialization.
+
+2008-02-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : oops oops. not "encoding" but "charset".
+
+2008-02-15 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : hack SerializeReply().
+ Add WebBodyFormat property
+
+2008-02-15 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : implement DeserializeRequest().
+
+2008-02-15 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : attach a HttpRequestMessageProperty when
+ creating a request Message.
+
+2008-02-15 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebHttpDispatchOperationSelector.cs : implemented large part of it.
+ * WebMessageFormatter.cs : moved BuildUriTemplate to WebAttributeInfo.
+
+2008-02-14 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : pass WebHttpBehavior too.
+
+2008-02-14 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : pass QueryStringConverter which is used to
+ convert parameter objects to the components of the request URI.
+
+2008-02-14 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebMessageFormatter.cs : new message formatter that is created
+ from WebHttpBehavior and handles [WebGet] or [WebInvoke]. Not done.
+
+2008-02-13 Atsushi Enomoto <atsushi@ximian.com>
+
+ * QueryStringConverter.cs : I could just check null parameter.
+
+2008-02-13 Atsushi Enomoto <atsushi@ximian.com>
+
+ * QueryStringConverter.cs: CanConvert() supports cpl more types.
+ Implemented ConvertStringToValue() and ConvertValueToString().
+
+2008-02-12 Atsushi Enomoto <atsushi@ximian.com>
+
+ * WebHttpDispatchOperationSelector.cs : stubbed members.
+
+2008-02-07 Atsushi Enomoto <atsushi@ximian.com>
+
+ * JsonQueryStringConverter.cs, QueryStringConverter.cs,
+ WebHttpDispatchOperationSelector.cs : mostly stubs.
diff --git a/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/JsonQueryStringConverter.cs b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/JsonQueryStringConverter.cs
new file mode 100644
index 00000000000..121bc13541c
--- /dev/null
+++ b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/JsonQueryStringConverter.cs
@@ -0,0 +1,213 @@
+//
+// JsonQueryStringConverter.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Globalization;
+using System.IO;
+using System.Runtime.Serialization.Json;
+using System.ServiceModel;
+using System.ServiceModel.Description;
+using System.Text;
+using System.Xml;
+
+namespace System.ServiceModel.Dispatcher
+{
+ public class JsonQueryStringConverter : QueryStringConverter
+ {
+ DataContractJsonSerializer serializer = new DataContractJsonSerializer (typeof (object));
+
+ public override bool CanConvert (Type type)
+ {
+ // almost copy from QueryStringConverter, except that DBNull and XmlQualifiedName are supported
+ switch (Type.GetTypeCode (type)) {
+ //case TypeCode.DBNull:
+ case TypeCode.Empty:
+ return false;
+ case TypeCode.Object:
+ if (type == typeof (TimeSpan))
+ return true;
+ if (type == typeof (DateTimeOffset))
+ return true;
+ if (type == typeof (Guid))
+ return true;
+ if (type == typeof (XmlQualifiedName))
+ return true;
+ if (type == typeof (object))
+ return true;
+// if (type.GetCustomAttributes (typeof (TypeConverterAttribute), true).Length > 0)
+// return true;
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ public override object ConvertStringToValue (string parameter, Type parameterType)
+ {
+ if (parameterType == null)
+ throw new ArgumentNullException ("parameterType");
+
+ if (!CanConvert (parameterType))
+ throw new NotSupportedException (String.Format ("Conversion from the argument parameterType '{0}' is not supported", parameterType));
+
+ // In general .NET JSON parser is sloppy. It accepts
+ // such a string that is actually invalid in terms of
+ // the target type in JSON context.
+
+ switch (Type.GetTypeCode (parameterType)) {
+ //case TypeCode.String:
+ // return parameter;
+ case TypeCode.Char:
+ return parameter != null ? Char.Parse (parameter): default (char);
+ case TypeCode.SByte:
+ return parameter != null ? SByte.Parse (parameter, CultureInfo.InvariantCulture): default (sbyte);
+ case TypeCode.Byte:
+ return parameter != null ? Byte.Parse (parameter, CultureInfo.InvariantCulture): default (byte);
+ case TypeCode.Int16:
+ return parameter != null ? Int16.Parse (parameter, CultureInfo.InvariantCulture): default (short);
+ case TypeCode.Int32:
+ return parameter != null ? Int32.Parse (parameter, CultureInfo.InvariantCulture): default (int);
+ case TypeCode.Int64:
+ return parameter != null ? Int64.Parse (parameter, CultureInfo.InvariantCulture): default (long);
+ case TypeCode.UInt16:
+ return parameter != null ? UInt16.Parse (parameter, CultureInfo.InvariantCulture): default (ushort);
+ case TypeCode.UInt32:
+ return parameter != null ? UInt32.Parse (parameter, CultureInfo.InvariantCulture): default (uint);
+ case TypeCode.UInt64:
+ return parameter != null ? UInt64.Parse (parameter, CultureInfo.InvariantCulture): default (ulong);
+ case TypeCode.DateTime:
+ return parameter != null ? DateTime.Parse (parameter, CultureInfo.InvariantCulture): default (DateTime);
+ case TypeCode.Boolean:
+ return parameter != null ? Boolean.Parse (parameter): default (bool);
+ case TypeCode.Single:
+ return parameter != null ? Single.Parse (parameter, CultureInfo.InvariantCulture): default (float);
+ case TypeCode.Double:
+ return parameter != null ? Double.Parse (parameter, CultureInfo.InvariantCulture): default (double);
+ case TypeCode.Decimal:
+ return parameter != null ? Decimal.Parse (parameter, CultureInfo.InvariantCulture): default (decimal);
+ }
+
+ if (parameter == null)
+ return null;
+
+
+ DataContractJsonSerializer serializer =
+ new DataContractJsonSerializer (parameterType);
+ // hmm, it costs so silly though.
+ return serializer.ReadObject (new MemoryStream (Encoding.UTF8.GetBytes (parameter)));
+ }
+
+ bool IsKnownType (Type t)
+ {
+ switch (Type.GetTypeCode (t)) {
+ case TypeCode.Object:
+ if (t == typeof (Guid) ||
+ t == typeof (DBNull) ||
+ t == typeof (DateTimeOffset) ||
+ t == typeof (TimeSpan) ||
+ t == typeof (XmlQualifiedName))
+ return true;
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ public override string ConvertValueToString (object parameter, Type parameterType)
+ {
+ if (parameterType == null)
+ throw new ArgumentNullException ("parameterType");
+
+ if (!CanConvert (parameterType))
+ throw new NotSupportedException (String.Format ("Conversion from the argument parameterType '{0}' is not supported", parameterType));
+
+ if (parameter == null)
+ return null;
+
+ if (parameter is DBNull)
+ return "{}";
+
+ parameterType = ToActualType (parameterType);
+
+ if (parameter is IConvertible)
+ parameter = ((IConvertible) parameter).ToType (parameterType, CultureInfo.InvariantCulture);
+
+ switch (Type.GetTypeCode (parameterType)) {
+ case TypeCode.String:
+ string s = parameter is IFormattable ?
+ ((IFormattable) parameter).ToString (null, CultureInfo.InvariantCulture) :
+ parameter.ToString ();
+ StringBuilder sb = new StringBuilder (s);
+ sb.Replace ("\"", "\\\"");
+ sb.Insert (0, '\"');
+ sb.Append ('\"');
+ return sb.ToString ();
+ default:
+ if (parameterType == typeof (XmlQualifiedName)) {
+ var qname = (XmlQualifiedName) parameter;
+ return String.Concat ("\"", qname.Name, ":", qname.Namespace, "\"");
+ }
+ return parameter.ToString ();
+ }
+
+ throw new NotImplementedException ();
+ }
+
+ Type ToActualType (Type t)
+ {
+ switch (Type.GetTypeCode (t)) {
+ case TypeCode.DBNull: // though DBNull.Value input is converted to "{}". This result is used for String input.
+ case TypeCode.Char:
+ case TypeCode.String:
+ return typeof (string);
+ case TypeCode.SByte:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Int64:
+// return typeof (long);
+ return typeof (decimal);
+ case TypeCode.Byte:
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ case TypeCode.UInt64:
+// return typeof (ulong);
+ return typeof (decimal);
+ case TypeCode.DateTime:
+ case TypeCode.Boolean:
+ return t;
+ case TypeCode.Single:
+ case TypeCode.Double:
+// return typeof (double);
+ return typeof (decimal);
+ case TypeCode.Decimal:
+ return typeof (decimal);
+ default:
+ return t;
+ }
+ }
+ }
+}
diff --git a/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/QueryStringConverter.cs b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/QueryStringConverter.cs
new file mode 100644
index 00000000000..8bc37253976
--- /dev/null
+++ b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/QueryStringConverter.cs
@@ -0,0 +1,135 @@
+//
+// QueryStringConverter.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.ServiceModel;
+using System.ServiceModel.Description;
+
+namespace System.ServiceModel.Dispatcher
+{
+ public class QueryStringConverter
+ {
+ // "Service Operation Parameters and URLs"
+ // http://msdn2.microsoft.com/en-us/library/bb412172.aspx
+ public virtual bool CanConvert (Type type)
+ {
+ switch (Type.GetTypeCode (type)) {
+ case TypeCode.DBNull:
+ case TypeCode.Empty:
+ return false;
+ case TypeCode.Object:
+ if (type == typeof (TimeSpan))
+ return true;
+ if (type == typeof (DateTimeOffset))
+ return true;
+ if (type == typeof (Guid))
+ return true;
+ if (type == typeof (object))
+ return true;
+// if (type.GetCustomAttributes (typeof (TypeConverterAttribute), true).Length > 0)
+// return true;
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ public virtual object ConvertStringToValue (string parameter, Type parameterType)
+ {
+ if (parameterType == null)
+ throw new ArgumentNullException ("parameterType");
+
+ if (!CanConvert (parameterType))
+ throw new NotSupportedException (String.Format ("Conversion from the argument parameterType '{0}' is not supported", parameterType));
+
+ switch (Type.GetTypeCode (parameterType)) {
+ case TypeCode.String:
+ return parameter;
+ case TypeCode.Char:
+ return parameter != null ? Char.Parse (parameter): default (char);
+ case TypeCode.SByte:
+ return parameter != null ? SByte.Parse (parameter, CultureInfo.InvariantCulture): default (sbyte);
+ case TypeCode.Byte:
+ return parameter != null ? Byte.Parse (parameter, CultureInfo.InvariantCulture): default (byte);
+ case TypeCode.Int16:
+ return parameter != null ? Int16.Parse (parameter, CultureInfo.InvariantCulture): default (short);
+ case TypeCode.Int32:
+ return parameter != null ? Int32.Parse (parameter, CultureInfo.InvariantCulture): default (int);
+ case TypeCode.Int64:
+ return parameter != null ? Int64.Parse (parameter, CultureInfo.InvariantCulture): default (long);
+ case TypeCode.UInt16:
+ return parameter != null ? UInt16.Parse (parameter, CultureInfo.InvariantCulture): default (ushort);
+ case TypeCode.UInt32:
+ return parameter != null ? UInt32.Parse (parameter, CultureInfo.InvariantCulture): default (uint);
+ case TypeCode.UInt64:
+ return parameter != null ? UInt64.Parse (parameter, CultureInfo.InvariantCulture): default (ulong);
+ case TypeCode.DateTime:
+ return parameter != null ? DateTime.Parse (parameter, CultureInfo.InvariantCulture): default (DateTime);
+ case TypeCode.Boolean:
+ return parameter != null ? Boolean.Parse (parameter): default (bool);
+ case TypeCode.Single:
+ return parameter != null ? Single.Parse (parameter, CultureInfo.InvariantCulture): default (float);
+ case TypeCode.Double:
+ return parameter != null ? Double.Parse (parameter, CultureInfo.InvariantCulture): default (double);
+ case TypeCode.Decimal:
+ return parameter != null ? Decimal.Parse (parameter, CultureInfo.InvariantCulture): default (decimal);
+ case TypeCode.Object:
+ if (parameterType == typeof (TimeSpan))
+ return TimeSpan.Parse (parameter);
+ if (parameterType == typeof (DateTimeOffset))
+ return DateTimeOffset.Parse (parameter, CultureInfo.InvariantCulture);
+ if (parameterType == typeof (Guid))
+ return new Guid (parameter);
+ break;
+ }
+ throw new NotSupportedException (String.Format ("Cannot convert parameter string '{0}' to parameter type '{1}'", parameter, parameterType));
+ }
+
+ public virtual string ConvertValueToString (object parameter, Type parameterType)
+ {
+ if (parameterType == null)
+ throw new ArgumentNullException ("parameterType");
+ if (parameterType.IsValueType && parameter == null)
+ throw new ArgumentNullException ("parameter");
+
+ if (parameter == null)
+ return null;
+
+ if (parameter.GetType () != parameterType)
+ throw new InvalidCastException (String.Format ("This QueryStringConverter does not support cast from {0} to {1}", parameter.GetType (), parameterType));
+
+ if (!CanConvert (parameterType))
+ throw new NotSupportedException (String.Format ("Conversion from the argument parameterType '{0}' is not supported", parameterType));
+
+ if (parameter is IFormattable)
+ ((IFormattable) parameter).ToString (null, CultureInfo.InvariantCulture);
+ return parameter.ToString ();
+ }
+ }
+}
diff --git a/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebHttpDispatchOperationSelector.cs b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebHttpDispatchOperationSelector.cs
new file mode 100644
index 00000000000..beec9cdd5ad
--- /dev/null
+++ b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebHttpDispatchOperationSelector.cs
@@ -0,0 +1,106 @@
+//
+// WebHttpDispatchOperationSelector.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Description;
+using System.ServiceModel.Web;
+
+using TemplateTablePair = System.Collections.Generic.KeyValuePair<System.UriTemplate, object>;
+
+namespace System.ServiceModel.Dispatcher
+{
+ public class WebHttpDispatchOperationSelector : IDispatchOperationSelector
+ {
+ public const string HttpOperationSelectorUriMatchedPropertyName = "UriMatched";
+
+ UriTemplateTable table;
+
+ protected WebHttpDispatchOperationSelector ()
+ {
+ }
+
+ public WebHttpDispatchOperationSelector (ServiceEndpoint endpoint)
+ {
+ if (endpoint == null)
+ throw new ArgumentNullException ("endpoint");
+ if (endpoint.Address == null)
+ throw new InvalidOperationException ("EndpointAddress must be set in the argument ServiceEndpoint");
+
+ table = new UriTemplateTable (endpoint.Address.Uri);
+
+ foreach (OperationDescription od in endpoint.Contract.Operations) {
+ WebAttributeInfo info = GetWebAttributeInfo (od);
+ if (info != null)
+ table.KeyValuePairs.Add (new TemplateTablePair (info.BuildUriTemplate (od, null), od));
+ }
+ }
+
+ public string SelectOperation (ref Message message)
+ {
+ bool dummy;
+ return SelectOperation (ref message, out dummy);
+ }
+
+ protected virtual string SelectOperation (ref Message message, out bool uriMatched)
+ {
+ if (message == null)
+ throw new ArgumentNullException ("message");
+ if (message.Properties.ContainsKey (WebBodyFormatMessageProperty.Name))
+ throw new ArgumentException ("There is already message property for Web body format");
+ uriMatched = false;
+ Uri to = message.Headers.To;
+ if (to == null)
+ return String.Empty;
+
+ UriTemplateMatch match = table.MatchSingle (to);
+ OperationDescription od = null;
+ if (match != null) {
+ uriMatched = true;
+ foreach (TemplateTablePair p in table.KeyValuePairs)
+ if (p.Key == match.Template)
+ od = p.Value as OperationDescription;
+ }
+ return od != null ? od.Name : String.Empty;
+ }
+
+ WebAttributeInfo GetWebAttributeInfo (OperationDescription od)
+ {
+ foreach (IOperationBehavior ob in od.Behaviors) {
+ WebAttributeInfo info = null;
+ var wg = ob as WebGetAttribute;
+ if (wg != null)
+ return wg.Info;
+ var wi = ob as WebInvokeAttribute;
+ if (wi != null)
+ return wi.Info;
+ }
+ return null;
+ }
+ }
+}
diff --git a/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebMessageFormatter.cs b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebMessageFormatter.cs
new file mode 100644
index 00000000000..43461125fe6
--- /dev/null
+++ b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebMessageFormatter.cs
@@ -0,0 +1,332 @@
+//
+// WebMessageFormatter.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Specialized;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Json;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Dispatcher;
+using System.ServiceModel.Web;
+using System.Text;
+
+namespace System.ServiceModel.Description
+{
+ internal abstract class WebMessageFormatter
+ {
+ OperationDescription operation;
+ ServiceEndpoint endpoint;
+ QueryStringConverter converter;
+ WebHttpBehavior behavior;
+ UriTemplate template;
+ WebAttributeInfo info = null;
+
+ public WebMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
+ {
+ this.operation = operation;
+ this.endpoint = endpoint;
+ this.converter = converter;
+ this.behavior = behavior;
+ ApplyWebAttribute ();
+ }
+
+ void ApplyWebAttribute ()
+ {
+ MethodInfo mi = operation.SyncMethod ?? operation.BeginMethod;
+
+ object [] atts = mi.GetCustomAttributes (typeof (WebGetAttribute), false);
+ if (atts.Length > 0)
+ info = ((WebGetAttribute) atts [0]).Info;
+ atts = mi.GetCustomAttributes (typeof (WebInvokeAttribute), false);
+ if (atts.Length > 0)
+ info = ((WebInvokeAttribute) atts [0]).Info;
+ if (info == null)
+ info = new WebAttributeInfo ();
+
+ template = info.BuildUriTemplate (Operation, GetMessageDescription (MessageDirection.Input));
+ }
+
+ public WebHttpBehavior Behavior {
+ get { return behavior; }
+ }
+
+ public WebAttributeInfo Info {
+ get { return info; }
+ }
+
+ public OperationDescription Operation {
+ get { return operation; }
+ }
+
+ public QueryStringConverter Converter {
+ get { return converter; }
+ }
+
+ public ServiceEndpoint Endpoint {
+ get { return endpoint; }
+ }
+
+ public UriTemplate UriTemplate {
+ get { return template; }
+ }
+
+ protected WebContentFormat ToContentFormat (WebMessageFormat src)
+ {
+ switch (src) {
+ case WebMessageFormat.Xml:
+ return WebContentFormat.Xml;
+ case WebMessageFormat.Json:
+ return WebContentFormat.Json;
+ }
+ throw new SystemException ("INTERNAL ERROR: should not happen");
+ }
+
+ protected void CheckMessageVersion (MessageVersion messageVersion)
+ {
+ if (messageVersion == null)
+ throw new ArgumentNullException ("messageVersion");
+
+ if (!MessageVersion.None.Equals (messageVersion))
+ throw new ArgumentException ("Only MessageVersion.None is supported");
+ }
+
+ protected MessageDescription GetMessageDescription (MessageDirection dir)
+ {
+ foreach (MessageDescription md in operation.Messages)
+ if (md.Direction == dir)
+ return md;
+ throw new SystemException ("INTERNAL ERROR: no corresponding message description for the specified direction: " + dir);
+ }
+
+ internal class RequestClientFormatter : WebClientMessageFormatter
+ {
+ public RequestClientFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
+ : base (operation, endpoint, converter, behavior)
+ {
+ }
+ }
+
+ internal class ReplyClientFormatter : WebClientMessageFormatter
+ {
+ public ReplyClientFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
+ : base (operation, endpoint, converter, behavior)
+ {
+ }
+ }
+
+ internal class RequestDispatchFormatter : WebDispatchMessageFormatter
+ {
+ public RequestDispatchFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
+ : base (operation, endpoint, converter, behavior)
+ {
+ }
+ }
+
+ internal class ReplyDispatchFormatter : WebDispatchMessageFormatter
+ {
+ public ReplyDispatchFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
+ : base (operation, endpoint, converter, behavior)
+ {
+ }
+ }
+
+ internal abstract class WebClientMessageFormatter : WebMessageFormatter, IClientMessageFormatter
+ {
+ protected WebClientMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
+ : base (operation, endpoint, converter, behavior)
+ {
+ }
+
+ public Message SerializeRequest (MessageVersion messageVersion, object [] parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException ("parameters");
+ CheckMessageVersion (messageVersion);
+
+ var c = new NameValueCollection ();
+
+ MessageDescription md = GetMessageDescription (MessageDirection.Input);
+
+ if (parameters.Length != md.Body.Parts.Count)
+ throw new ArgumentException ("Parameter array length does not match the number of message body parts");
+
+ for (int i = 0; i < parameters.Length; i++) {
+ var p = md.Body.Parts [i];
+ string name = p.Name.ToUpperInvariant ();
+ if (UriTemplate.PathSegmentVariableNames.Contains (name) ||
+ UriTemplate.QueryValueVariableNames.Contains (name))
+ c.Add (name, parameters [i] != null ? Converter.ConvertValueToString (parameters [i], parameters [i].GetType ()) : null);
+ else
+ // FIXME: bind as a message part
+ throw new NotImplementedException (String.Format ("parameter {0} is not contained in the URI template {1} {2} {3}", p.Name, UriTemplate, UriTemplate.PathSegmentVariableNames.Count, UriTemplate.QueryValueVariableNames.Count));
+ }
+
+ Uri to = UriTemplate.BindByName (Endpoint.Address.Uri, c);
+
+ Message ret = Message.CreateMessage (messageVersion, (string) null);
+ ret.Headers.To = to;
+
+ var hp = new HttpRequestMessageProperty ();
+ hp.Method = Info.Method;
+ // FIXME: set hp.SuppressEntityBody for some cases.
+ ret.Properties.Add (HttpRequestMessageProperty.Name, hp);
+
+ var wp = new WebBodyFormatMessageProperty (ToContentFormat (Info.IsRequestFormatSetExplicitly ? Info.RequestFormat : Behavior.DefaultOutgoingRequestFormat));
+ ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
+
+ return ret;
+ }
+
+ public object DeserializeReply (Message message, object [] parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException ("parameters");
+ CheckMessageVersion (message.Version);
+
+ string pname = WebBodyFormatMessageProperty.Name;
+ if (!message.Properties.ContainsKey (pname))
+ throw new SystemException ("INTERNAL ERROR: it expects WebBodyFormatMessageProperty existence");
+ var wp = (WebBodyFormatMessageProperty) message.Properties [pname];
+ MessageDescription md = GetMessageDescription (MessageDirection.Output);
+
+ XmlObjectSerializer serializer = null;
+ switch (wp.Format) {
+ case WebContentFormat.Xml:
+ serializer = new DataContractSerializer (md.Body.ReturnValue.Type);
+ break;
+ case WebContentFormat.Json:
+ serializer = new DataContractJsonSerializer (md.Body.ReturnValue.Type);
+ break;
+ case WebContentFormat.Raw:
+ default:
+ throw new NotImplementedException ();
+ }
+
+ // FIXME: handle ref/out parameters
+
+ return serializer.ReadObject (message.GetReaderAtBodyContents (), false);
+ }
+ }
+
+ internal abstract class WebDispatchMessageFormatter : WebMessageFormatter, IDispatchMessageFormatter
+ {
+ protected WebDispatchMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
+ : base (operation, endpoint, converter, behavior)
+ {
+ }
+
+ public Message SerializeReply (MessageVersion messageVersion, object [] parameters, object result)
+ {
+ try {
+ return SerializeReplyCore (messageVersion, parameters, result);
+ } finally {
+ if (WebOperationContext.Current != null)
+ OperationContext.Current.Extensions.Remove (WebOperationContext.Current);
+ }
+ }
+
+ Message SerializeReplyCore (MessageVersion messageVersion, object [] parameters, object result)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException ("parameters");
+ CheckMessageVersion (messageVersion);
+
+ MessageDescription md = GetMessageDescription (MessageDirection.Output);
+
+ // FIXME: use them.
+ // var dcob = Operation.Behaviors.Find<DataContractSerializerOperationBehavior> ();
+ // XmlObjectSerializer xos = dcob.CreateSerializer (result.GetType (), md.Body.WrapperName, md.Body.WrapperNamespace, null);
+ // var xsob = Operation.Behaviors.Find<XmlSerializerOperationBehavior> ();
+ // XmlSerializer [] serializers = XmlSerializer.FromMappings (xsob.GetXmlMappings ().ToArray ());
+
+ WebMessageFormat msgfmt = Info.IsResponseFormatSetExplicitly ? Info.ResponseFormat : Behavior.DefaultOutgoingResponseFormat;
+
+ string mediaType = null;
+ XmlObjectSerializer serializer = null;
+ switch (msgfmt) {
+ case WebMessageFormat.Xml:
+ serializer = new DataContractSerializer (md.Body.ReturnValue.Type);
+ mediaType = "application/xml";
+ break;
+ case WebMessageFormat.Json:
+ serializer = new DataContractJsonSerializer (md.Body.ReturnValue.Type);
+ mediaType = "application/json";
+ break;
+ }
+
+ // FIXME: serialize ref/out parameters as well.
+
+ Message ret = Message.CreateMessage (MessageVersion.None, null, result, serializer);
+
+ // Message properties
+
+ var hp = new HttpResponseMessageProperty ();
+ // FIXME: get encoding from somewhere
+ hp.Headers ["Content-Type"] = mediaType + "; charset=utf-8";
+
+ // apply user-customized HTTP results via WebOperationContext.
+ WebOperationContext.Current.OutgoingResponse.Apply (hp);
+
+ // FIXME: fill some properties if required.
+ ret.Properties.Add (HttpResponseMessageProperty.Name, hp);
+
+ var wp = new WebBodyFormatMessageProperty (ToContentFormat (msgfmt));
+ ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
+
+ return ret;
+ }
+
+ public void DeserializeRequest (Message message, object [] parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException ("parameters");
+ CheckMessageVersion (message.Version);
+
+ OperationContext.Current.Extensions.Add (new WebOperationContext (OperationContext.Current));
+
+ IncomingWebRequestContext iwc = WebOperationContext.Current.IncomingRequest;
+
+ Uri to = message.Headers.To;
+ UriTemplateMatch match = UriTemplate.Match (Endpoint.Address.Uri, to);
+ if (match == null)
+ // not sure if it could happen
+ throw new SystemException (String.Format ("INTERNAL ERROR: UriTemplate does not match with the request: {0} / {1}", UriTemplate, to));
+ iwc.UriTemplateMatch = match;
+
+ MessageDescription md = GetMessageDescription (MessageDirection.Input);
+
+ for (int i = 0; i < parameters.Length; i++) {
+ var p = md.Body.Parts [i];
+ string name = p.Name.ToUpperInvariant ();
+ parameters [i] = match.BoundVariables [name];
+ }
+ }
+ }
+ }
+}