ContentEncoding in SoapServerMessage.
* LogicalMethodInfo.cs: Implemented AsyncResultParameter, BeginInvoke and
EndInvoke. Fixed ComputeParameters, so it computes the correct parameters
for async logical methods.
* Methods.cs: Check that client proxies have one and only one
WebServiceBindingAttribute.
* PatternMatcher.cs: Implemented (in fact, just moved code from
TextReturnReader.cs)
* SoapDocumentationHandler.cs: Add soap bindings in the generated
discovery document.
* SoapHttpClientProtocol.cs: Implemented method Discover().
* SoapMessage.cs: Implemented property ContentEncoding.
* TextReturnReader.cs: Moved code to PatternMatcher.cs.
svn path=/trunk/mcs/; revision=23855
+2004-03-10 Lluis Sanchez Gual <lluis@ximian.com>
+
+ * HttpSoapWebServiceHandler.cs: Set the properties ContentType and
+ ContentEncoding in SoapServerMessage.
+ * LogicalMethodInfo.cs: Implemented AsyncResultParameter, BeginInvoke and
+ EndInvoke. Fixed ComputeParameters, so it computes the correct parameters
+ for async logical methods.
+ * Methods.cs: Check that client proxies have one and only one
+ WebServiceBindingAttribute.
+ * PatternMatcher.cs: Implemented (in fact, just moved code from
+ TextReturnReader.cs)
+ * SoapDocumentationHandler.cs: Add soap bindings in the generated
+ discovery document.
+ * SoapHttpClientProtocol.cs: Implemented method Discover().
+ * SoapMessage.cs: Implemented property ContentEncoding.
+ * TextReturnReader.cs: Moved code to PatternMatcher.cs.
+
2004-02-27 Lluis Sanchez Gual <lluis@ximian.com>
* Fault.cs: Moved Fault class from Methods.cd to this file. It also includes
SoapServerMessage message = new SoapServerMessage (request, server, stream);
message.SetStage (SoapMessageStage.BeforeDeserialize);
+ message.ContentType = ctype;
+ message.ContentEncoding = encoding.WebName;
// If the routing style is SoapAction, then we can get the method information now
// and set it to the SoapMessage
}\r
\r
public ParameterInfo AsyncResultParameter {\r
- [MonoTODO]\r
- get { throw new NotImplementedException (); }\r
+ get {\r
+ ParameterInfo [] pi = end_method_info.GetParameters ();\r
+ return pi [pi.Length-1];\r
+ }\r
}\r
\r
public ParameterInfo AsyncStateParameter {\r
\r
public bool IsAsync {\r
get {\r
- return IsBeginMethod (method_info) || IsEndMethod (method_info);\r
+ return end_method_info != null;\r
}\r
}\r
\r
public bool IsVoid {\r
get {\r
- return method_info.ReturnType == typeof (void);\r
+ return ReturnType == typeof (void);\r
}\r
}\r
\r
\r
void ComputeParameters ()\r
{\r
- parameters = method_info.GetParameters ();\r
- int out_count = 0;\r
- int in_count = 0;\r
- \r
- foreach (ParameterInfo p in parameters){\r
- Type ptype = p.ParameterType;\r
- if (ptype.IsByRef){\r
- out_count++;\r
- if (!p.IsOut)\r
- in_count++;\r
- } else\r
- in_count++;\r
- }\r
- out_parameters = new ParameterInfo [out_count];\r
- int i = 0;\r
- for (int j = 0; j < parameters.Length; j++){\r
- if (parameters [j].ParameterType.IsByRef)\r
- out_parameters [i++] = parameters [j];\r
+ ParameterInfo[] pars = method_info.GetParameters ();\r
+ if (IsAsync)\r
+ {\r
+ parameters = new ParameterInfo [pars.Length - 2];\r
+ Array.Copy (pars, 0, parameters, 0, pars.Length - 2);\r
+ in_parameters = new ParameterInfo [parameters.Length];\r
+ parameters.CopyTo (in_parameters, 0);\r
+ \r
+ ParameterInfo[] outPars = end_method_info.GetParameters ();\r
+ out_parameters = new ParameterInfo [outPars.Length - 1];\r
+ Array.Copy (outPars, 0, out_parameters, 0, out_parameters.Length);\r
}\r
- in_parameters = new ParameterInfo [in_count];\r
- i = 0;\r
- for (int j = 0; j < parameters.Length; j++){\r
- if (parameters [j].ParameterType.IsByRef){\r
- if (!parameters [j].IsOut)\r
+ else\r
+ {\r
+ parameters = pars;\r
+ int out_count = 0;\r
+ int in_count = 0;\r
+ \r
+ foreach (ParameterInfo p in parameters){\r
+ Type ptype = p.ParameterType;\r
+ if (ptype.IsByRef){\r
+ out_count++;\r
+ if (!p.IsOut)\r
+ in_count++;\r
+ } else\r
+ in_count++;\r
+ }\r
+ out_parameters = new ParameterInfo [out_count];\r
+ int i = 0;\r
+ for (int j = 0; j < parameters.Length; j++){\r
+ if (parameters [j].ParameterType.IsByRef)\r
+ out_parameters [i++] = parameters [j];\r
+ }\r
+ in_parameters = new ParameterInfo [in_count];\r
+ i = 0;\r
+ for (int j = 0; j < parameters.Length; j++){\r
+ if (parameters [j].ParameterType.IsByRef){\r
+ if (!parameters [j].IsOut)\r
+ in_parameters [i++] = parameters [j];\r
+ } else\r
in_parameters [i++] = parameters [j];\r
- } else\r
- in_parameters [i++] = parameters [j];\r
+ }\r
}\r
}\r
\r
\r
public Type ReturnType {\r
get {\r
- return method_info.ReturnType;\r
+ if (IsAsync)\r
+ return end_method_info.ReturnType;\r
+ else\r
+ return method_info.ReturnType;\r
}\r
}\r
\r
\r
#region Methods\r
\r
- [MonoTODO]\r
public IAsyncResult BeginInvoke (object target, object[] values, AsyncCallback callback, object asyncState)\r
{\r
- throw new NotImplementedException ();\r
+ int len = (values!=null) ? values.Length : 0;\r
+ object[] pars = new object [len + 2];\r
+ \r
+ if (len > 0)\r
+ values.CopyTo (pars, 0);\r
+ \r
+ pars [len] = callback;\r
+ pars [len+1] = asyncState;\r
+ \r
+ return (IAsyncResult) method_info.Invoke (target, pars);\r
}\r
\r
public static LogicalMethodInfo[] Create (MethodInfo[] method_infos)\r
return res;\r
}\r
\r
- [MonoTODO]\r
public object[] EndInvoke (object target, IAsyncResult asyncResult)\r
{\r
- throw new NotImplementedException ();\r
+ if (parameters == null)\r
+ ComputeParameters ();\r
+\r
+ object[] values = new object [out_parameters.Length + 1];\r
+ values [values.Length - 1] = asyncResult;\r
+ object res = end_method_info.Invoke (target, values);\r
+ \r
+ int retc = IsVoid ? 0 : 1;\r
+ object [] ret = new object [retc + out_parameters.Length];\r
+ \r
+ if (retc == 1) ret [0] = res;\r
+ \r
+ Array.Copy (values, 0, ret, retc, out_parameters.Length);\r
+ return ret;\r
}\r
\r
public object GetCustomAttribute (Type type)\r
if (OneWay){
if (source.ReturnType != typeof (void))
- throw new Exception ("OneWay methods should not have a return value");
+ throw new Exception ("OneWay methods should not have a return value.");
if (source.OutParameters.Length != 0)
- throw new Exception ("OneWay methods should not have out/ref parameters");
+ throw new Exception ("OneWay methods should not have out/ref parameters.");
}
BindingInfo binfo = parent.GetBinding (Binding);
- if (binfo == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'");
+ if (binfo == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'.");
string serviceNamespace = binfo.Namespace;
for (int i = 0; i < o.Length; i++) {
SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
- if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName);
+ if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName + ".");
Type headerType = (mems[0] is FieldInfo) ? ((FieldInfo)mems[0]).FieldType : ((PropertyInfo)mems[0]).PropertyType;
Headers [i] = new HeaderInfo (mems[0], att);
object [] o;
o = Type.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
+
+ if (typeof (SoapHttpClientProtocol).IsAssignableFrom (Type))
+ {
+ if (o.Length == 0)
+ throw new InvalidOperationException ("WebServiceBindingAttribute is required on proxy class '" + Type + "'.");
+ if (o.Length > 1)
+ throw new InvalidOperationException ("Only one WebServiceBinding attribute may be specified on type '" + Type + "'.");
+
+ // Remove the default binding, it is not needed since there is always
+ // a binding attribute.
+ Bindings.Clear ();
+ }
+
foreach (WebServiceBindingAttribute at in o)
AddBinding (new BindingInfo (at, LogicalType.WebServiceNamespace));
//\r
\r
using System.Web.Services;\r
+using System.Reflection;\r
+using System.Text.RegularExpressions;\r
+using System.Collections;\r
\r
-namespace System.Web.Services.Protocols {\r
- public sealed class PatternMatcher {\r
-\r
- #region Constructors\r
-\r
- [MonoTODO]\r
+namespace System.Web.Services.Protocols \r
+{\r
+ public sealed class PatternMatcher \r
+ {\r
+ Type _returnType;\r
+ MatchInfo[] _matchInfos;\r
+ \r
public PatternMatcher (Type type) \r
{\r
- throw new NotImplementedException ();\r
+ _returnType = type;\r
+ \r
+ FieldInfo[] fields = type.GetFields ();\r
+ ArrayList matchInfos = new ArrayList ();\r
+ \r
+ foreach (FieldInfo field in fields)\r
+ {\r
+ object[] ats = field.GetCustomAttributes (typeof(MatchAttribute), true);\r
+ if (ats.Length == 0) continue;\r
+ \r
+ MatchInfo mi = new MatchInfo ();\r
+ mi.Field = field;\r
+ mi.Match = (MatchAttribute) ats[0];\r
+ \r
+ RegexOptions opts = RegexOptions.Multiline;\r
+ if (mi.Match.IgnoreCase) opts |= RegexOptions.IgnoreCase;\r
+ mi.Regex = new Regex (mi.Match.Pattern, opts);\r
+ \r
+ matchInfos.Add (mi);\r
+ }\r
+ _matchInfos = (MatchInfo[]) matchInfos.ToArray (typeof(MatchInfo));\r
}\r
\r
- #endregion // Constructors\r
-\r
- #region Methods\r
-\r
- [MonoTODO]\r
public object Match (string text)\r
{\r
- throw new NotImplementedException ();\r
+ object ob = Activator.CreateInstance (_returnType);\r
+ \r
+ foreach (MatchInfo mi in _matchInfos)\r
+ {\r
+ MatchCollection matches = mi.Regex.Matches (text);\r
+ \r
+ object res = null;\r
+ \r
+ if (mi.Field.FieldType.IsArray)\r
+ {\r
+ int max = mi.Match.MaxRepeats;\r
+ if (max == -1) max = matches.Count;\r
+ \r
+ Type elemType = mi.Field.FieldType.GetElementType();\r
+ Array array = Array.CreateInstance (elemType, max);\r
+ for (int n=0; n<max; n++)\r
+ array.SetValue (mi.GetMatchValue (matches[n], elemType), n);\r
+ res = array;\r
+ }\r
+ else if (matches.Count > 0)\r
+ res = mi.GetMatchValue (matches[0], mi.Field.FieldType);\r
+ \r
+ mi.Field.SetValue (ob, res);\r
+ }\r
+ return ob;\r
}\r
\r
- #endregion // Methods\r
}\r
+\r
+ class MatchInfo\r
+ {\r
+ public FieldInfo Field;\r
+ public MatchAttribute Match;\r
+ public Regex Regex;\r
+ \r
+ const string GroupError = "{0} is not a valid group index for match '{1}'. The highest valid group index for this match is {2}";\r
+ const string CaptureError = "{0} is not a valid capture index for match '{1}'. The highest valid capture index for this match is {2}";\r
+ \r
+ public object GetMatchValue (Match match, Type castType)\r
+ {\r
+ if (Match.Group >= match.Groups.Count)\r
+ throw new Exception (string.Format (GroupError, Match.Group, Field.Name, match.Groups.Count-1));\r
+ \r
+ Group group = match.Groups [Match.Group];\r
+ if (Match.Capture >= group.Captures.Count)\r
+ throw new Exception (string.Format (CaptureError, Match.Capture, Field.Name, group.Captures.Count-1));\r
+ \r
+ string val = group.Captures [Match.Capture].Value;\r
+ return Convert.ChangeType (val, castType);\r
+ }\r
+ }\r
+\r
}\r
void GenerateDiscoDocument (HttpContext context)
{
+ ServiceDescriptionCollection descs = GetDescriptions ();
+
DiscoveryDocument doc = new DiscoveryDocument ();
ContractReference cref = new ContractReference ();
cref.Ref = _url + "?wsdl";
cref.DocRef = _url;
doc.References.Add (cref);
+
+ foreach (ServiceDescription desc in descs)
+ foreach (Service ser in desc.Services)
+ foreach (Port port in ser.Ports)
+ {
+ SoapAddressBinding sab = port.Extensions.Find (typeof(SoapAddressBinding)) as SoapAddressBinding;
+ if (sab != null)
+ {
+ System.Web.Services.Discovery.SoapBinding dsb = new System.Web.Services.Discovery.SoapBinding ();
+ dsb.Address = sab.Location;
+ dsb.Binding = port.Binding;
+ doc.AdditionalInfo.Add (dsb);
+ }
+ }
context.Response.ContentType = "text/xml; charset=utf-8";
doc.Write (context.Response.OutputStream);
using System.Diagnostics;\r
using System.Runtime.CompilerServices;\r
using System.Web.Services.Description;\r
+using System.Web.Services.Discovery;\r
using System.Xml.Serialization;\r
using System.Xml.Schema;\r
using System.Collections;\r
}\r
}\r
\r
- [MonoTODO]\r
public void Discover ()\r
{\r
- throw new NotImplementedException ();\r
+ BindingInfo bnd = (BindingInfo) type_info.Bindings [0];\r
+ \r
+ DiscoveryClientProtocol discoverer = new DiscoveryClientProtocol ();\r
+ discoverer.Discover (Url);\r
+ \r
+ foreach (object info in discoverer.AdditionalInformation)\r
+ {\r
+ System.Web.Services.Discovery.SoapBinding sb = info as System.Web.Services.Discovery.SoapBinding;\r
+ if (sb != null && sb.Binding.Name == bnd.Name && sb.Binding.Namespace == bnd.Namespace) {\r
+ Url = sb.Address;\r
+ return;\r
+ }\r
+ }\r
+ \r
+ string msg = string.Format ("The binding named '{0}' from namespace '{1}' was not found in the discovery document at '{2}'", bnd.Name, bnd.Namespace, Url);\r
+ throw new Exception (msg);\r
}\r
\r
protected override WebRequest GetWebRequest (Uri uri)\r
"Content is not 'text/xml' but '" + response.ContentType + "'",
response, encoding);
\r
+ message.ContentType = ctype;\r
+ message.ContentEncoding = encoding.WebName;\r
+ \r
Stream stream = response.GetResponseStream ();\r
\r
if (extensions != null) {\r
#region Fields\r
\r
string content_type = "text/xml";\r
+ string content_encoding;\r
SoapException exception = null;\r
SoapHeaderCollection headers;\r
SoapMessageStage stage;\r
}\r
\r
#if NET_1_1\r
- [MonoTODO]\r
public string ContentEncoding\r
{\r
- get { throw new NotImplementedException (); }\r
- set { throw new NotImplementedException (); }\r
+ get { return content_encoding; }\r
+ set { content_encoding = value; }\r
+ }\r
+#else\r
+ internal string ContentEncoding\r
+ {\r
+ get { return content_encoding; }\r
+ set { content_encoding = value; }\r
}\r
#endif\r
\r
//\r
\r
using System;\r
-using System.Text.RegularExpressions;\r
-using System.Collections;\r
using System.IO;\r
-using System.Reflection;\r
using System.Net;\r
\r
namespace System.Web.Services.Protocols {\r
public class TextReturnReader : MimeReturnReader {\r
\r
- ReturnInfo info;\r
+ PatternMatcher _matcher;\r
\r
#region Constructors\r
\r
\r
public override object GetInitializer (LogicalMethodInfo methodInfo)\r
{\r
- Type rt = methodInfo.ReturnType;\r
- FieldInfo[] fields = rt.GetFields ();\r
- ArrayList matchInfos = new ArrayList ();\r
- \r
- foreach (FieldInfo field in fields)\r
- {\r
- object[] ats = field.GetCustomAttributes (typeof(MatchAttribute), true);\r
- if (ats.Length == 0) continue;\r
- \r
- MatchInfo mi = new MatchInfo ();\r
- mi.Field = field;\r
- mi.Match = (MatchAttribute) ats[0];\r
- \r
- RegexOptions opts = RegexOptions.Multiline;\r
- if (mi.Match.IgnoreCase) opts |= RegexOptions.IgnoreCase;\r
- mi.Regex = new Regex (mi.Match.Pattern, opts);\r
- \r
- matchInfos.Add (mi);\r
- }\r
- ReturnInfo info = new ReturnInfo ();\r
- info.ReturnType = rt;\r
- info.MatchInfos = (MatchInfo[]) matchInfos.ToArray (typeof(MatchInfo));\r
- \r
- return info;\r
+ return new PatternMatcher (methodInfo.ReturnType);\r
}\r
\r
public override void Initialize (object o)\r
{\r
- info = (ReturnInfo) o;\r
+ _matcher = (PatternMatcher) o;\r
}\r
\r
public override object Read (WebResponse response, Stream responseStream)\r
{\r
StreamReader sr = new StreamReader (responseStream);\r
string text = sr.ReadToEnd ();\r
- \r
- object ob = Activator.CreateInstance (info.ReturnType);\r
- \r
- foreach (MatchInfo mi in info.MatchInfos)\r
- {\r
- MatchCollection matches = mi.Regex.Matches (text);\r
- \r
- object res = null;\r
- \r
- if (mi.Field.FieldType.IsArray)\r
- {\r
- int max = mi.Match.MaxRepeats;\r
- if (max == -1) max = matches.Count;\r
- \r
- Type elemType = mi.Field.FieldType.GetElementType();\r
- Array array = Array.CreateInstance (elemType, max);\r
- for (int n=0; n<max; n++)\r
- array.SetValue (mi.GetMatchValue (matches[n], elemType), n);\r
- res = array;\r
- }\r
- else if (matches.Count > 0)\r
- res = mi.GetMatchValue (matches[0], mi.Field.FieldType);\r
- \r
- mi.Field.SetValue (ob, res);\r
- }\r
- return ob;\r
+ return _matcher.Match (text);\r
}\r
\r
#endregion // Methods\r
- }\r
- \r
- class ReturnInfo\r
- {\r
- public Type ReturnType;\r
- public MatchInfo[] MatchInfos;\r
- }\r
- \r
- class MatchInfo\r
- {\r
- public FieldInfo Field;\r
- public MatchAttribute Match;\r
- public Regex Regex;\r
- \r
- const string GroupError = "{0} is not a valid group index for match '{1}'. The highest valid group index for this match is {2}";\r
- const string CaptureError = "{0} is not a valid capture index for match '{1}'. The highest valid capture index for this match is {2}";\r
- \r
- public object GetMatchValue (Match match, Type castType)\r
- {\r
- if (Match.Group >= match.Groups.Count)\r
- throw new Exception (string.Format (GroupError, Match.Group, Field.Name, match.Groups.Count-1));\r
- \r
- Group group = match.Groups [Match.Group];\r
- if (Match.Capture >= group.Captures.Count)\r
- throw new Exception (string.Format (CaptureError, Match.Capture, Field.Name, group.Captures.Count-1));\r
- \r
- string val = group.Captures [Match.Capture].Value;\r
- return Convert.ChangeType (val, castType);\r
- }\r
- }\r
+ } \r
}\r
\r