Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,455 @@
//------------------------------------------------------------------------------
// <copyright file="ClientProxyGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;
internal abstract class ClientProxyGenerator {
private static string DebugXmlComments = @"/// <param name=""succeededCallback"" type=""Function"" optional=""true"" mayBeNull=""true""></param>
/// <param name=""failedCallback"" type=""Function"" optional=""true"" mayBeNull=""true""></param>
/// <param name=""userContext"" optional=""true"" mayBeNull=""true""></param>
";
private Hashtable _registeredNamespaces = new Hashtable();
private Hashtable _ensuredObjectParts = new Hashtable();
protected StringBuilder _builder;
protected bool _debugMode;
// comments are the same in the instance methods as they are in the static methods
// this cache is used when calculating comments for instance methods, then re-used when
// writing out static methods.
private Dictionary<string, string> _docCommentCache;
internal string GetClientProxyScript(WebServiceData webServiceData) {
if (webServiceData.MethodDatas.Count == 0) return null;
_builder = new StringBuilder();
if (_debugMode) {
_docCommentCache = new Dictionary<string, string>();
}
// Constructor
GenerateConstructor(webServiceData);
// Prototype functions
GeneratePrototype(webServiceData);
GenerateRegisterClass(webServiceData);
GenerateStaticInstance(webServiceData);
GenerateStaticMethods(webServiceData);
// Generate some client proxy to make some types instantiatable on the client
GenerateClientTypeProxies(webServiceData);
GenerateEnumTypeProxies(webServiceData.EnumTypes);
return _builder.ToString();
}
protected void GenerateRegisterClass(WebServiceData webServiceData) {
// Generate registerClass: Foo.NS.WebService.registerClass('Foo.NS.WebService', Sys.Net.WebServiceProxy);
string typeName = GetProxyTypeName(webServiceData);
_builder.Append(typeName).Append(".registerClass('").Append(typeName).Append("',Sys.Net.WebServiceProxy);\r\n");
}
protected virtual void GenerateConstructor(WebServiceData webServiceData) {
GenerateTypeDeclaration(webServiceData, false);
_builder.Append("function() {\r\n");
_builder.Append(GetProxyTypeName(webServiceData)).Append(".initializeBase(this);\r\n");
GenerateFields();
_builder.Append("}\r\n");
}
protected virtual void GeneratePrototype(WebServiceData webServiceData) {
GenerateTypeDeclaration(webServiceData, true);
_builder.Append("{\r\n");
// private method to return the path to be used , returns _path from current instance if set, otherwise returns _path from static instance.
_builder.Append("_get_path:function() {\r\n var p = this.get_path();\r\n if (p) return p;\r\n else return ");
_builder.Append(GetProxyTypeName(webServiceData)).Append("._staticInstance.get_path();},\r\n");
bool first = true;
foreach (WebServiceMethodData methodData in webServiceData.MethodDatas) {
if (!first) {
_builder.Append(",\r\n");
}
first = false;
GenerateWebMethodProxy(methodData);
}
_builder.Append("}\r\n");
}
protected virtual void GenerateTypeDeclaration(WebServiceData webServiceData, bool genClass) {
AppendClientTypeDeclaration(webServiceData.TypeData.TypeNamespace, webServiceData.TypeData.TypeName, genClass, true);
}
protected void GenerateFields() {
_builder.Append("this._timeout = 0;\r\n");
_builder.Append("this._userContext = null;\r\n");
_builder.Append("this._succeeded = null;\r\n");
_builder.Append("this._failed = null;\r\n");
}
protected virtual void GenerateMethods() {
}
protected void GenerateStaticMethods(WebServiceData webServiceData) {
string className = GetProxyTypeName(webServiceData);
// Now generate static methods NS.Service.MyMethod = function()
foreach (WebServiceMethodData methodData in webServiceData.MethodDatas) {
string methodName = methodData.MethodName;
_builder.Append(className).Append('.').Append(methodName).Append("= function(");
StringBuilder argBuilder = new StringBuilder();
bool first = true;
foreach (WebServiceParameterData paramData in methodData.ParameterDatas) {
if (!first) argBuilder.Append(',');
else first = false;
argBuilder.Append(paramData.ParameterName);
}
if (!first) argBuilder.Append(',');
argBuilder.Append("onSuccess,onFailed,userContext");
_builder.Append(argBuilder.ToString()).Append(") {");
if (_debugMode) {
// doc comments should have been computed already
_builder.Append("\r\n");
_builder.Append(_docCommentCache[methodName]);
}
_builder.Append(className).Append("._staticInstance.").Append(methodName).Append('(');
_builder.Append(argBuilder.ToString()).Append("); }\r\n");
}
}
protected abstract string GetProxyPath();
protected virtual string GetJsonpCallbackParameterName() {
return null;
}
protected virtual bool GetSupportsJsonp() {
return false;
}
protected void GenerateStaticInstance(WebServiceData data) {
string typeName = GetProxyTypeName(data);
_builder.Append(typeName).Append("._staticInstance = new ").Append(typeName).Append("();\r\n");
// Generate the static properties
if (_debugMode) {
_builder.Append(typeName).Append(".set_path = function(value) {\r\n");
_builder.Append(typeName).Append("._staticInstance.set_path(value); }\r\n");
_builder.Append(typeName).Append(".get_path = function() { \r\n/// <value type=\"String\" mayBeNull=\"true\">The service url.</value>\r\nreturn ");
_builder.Append(typeName).Append("._staticInstance.get_path();}\r\n");
_builder.Append(typeName).Append(".set_timeout = function(value) {\r\n");
_builder.Append(typeName).Append("._staticInstance.set_timeout(value); }\r\n");
_builder.Append(typeName).Append(".get_timeout = function() { \r\n/// <value type=\"Number\">The service timeout.</value>\r\nreturn ");
_builder.Append(typeName).Append("._staticInstance.get_timeout(); }\r\n");
_builder.Append(typeName).Append(".set_defaultUserContext = function(value) { \r\n");
_builder.Append(typeName).Append("._staticInstance.set_defaultUserContext(value); }\r\n");
_builder.Append(typeName).Append(".get_defaultUserContext = function() { \r\n/// <value mayBeNull=\"true\">The service default user context.</value>\r\nreturn ");
_builder.Append(typeName).Append("._staticInstance.get_defaultUserContext(); }\r\n");
_builder.Append(typeName).Append(".set_defaultSucceededCallback = function(value) { \r\n ");
_builder.Append(typeName).Append("._staticInstance.set_defaultSucceededCallback(value); }\r\n");
_builder.Append(typeName).Append(".get_defaultSucceededCallback = function() { \r\n/// <value type=\"Function\" mayBeNull=\"true\">The service default succeeded callback.</value>\r\nreturn ");
_builder.Append(typeName).Append("._staticInstance.get_defaultSucceededCallback(); }\r\n");
_builder.Append(typeName).Append(".set_defaultFailedCallback = function(value) { \r\n");
_builder.Append(typeName).Append("._staticInstance.set_defaultFailedCallback(value); }\r\n");
_builder.Append(typeName).Append(".get_defaultFailedCallback = function() { \r\n/// <value type=\"Function\" mayBeNull=\"true\">The service default failed callback.</value>\r\nreturn ");
_builder.Append(typeName).Append("._staticInstance.get_defaultFailedCallback(); }\r\n");
_builder.Append(typeName).Append(".set_enableJsonp = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_enableJsonp(value); }\r\n");
_builder.Append(typeName).Append(".get_enableJsonp = function() { \r\n/// <value type=\"Boolean\">Specifies whether the service supports JSONP for cross domain calling.</value>\r\nreturn ");
_builder.Append(typeName).Append("._staticInstance.get_enableJsonp(); }\r\n");
_builder.Append(typeName).Append(".set_jsonpCallbackParameter = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_jsonpCallbackParameter(value); }\r\n");
_builder.Append(typeName).Append(".get_jsonpCallbackParameter = function() { \r\n/// <value type=\"String\">Specifies the parameter name that contains the callback function name for a JSONP request.</value>\r\nreturn ");
_builder.Append(typeName).Append("._staticInstance.get_jsonpCallbackParameter(); }\r\n");
}
else {
_builder.Append(typeName).Append(".set_path = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_path(value); }\r\n");
_builder.Append(typeName).Append(".get_path = function() { return ");
_builder.Append(typeName).Append("._staticInstance.get_path(); }\r\n");
_builder.Append(typeName).Append(".set_timeout = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_timeout(value); }\r\n");
_builder.Append(typeName).Append(".get_timeout = function() { return ");
_builder.Append(typeName).Append("._staticInstance.get_timeout(); }\r\n");
_builder.Append(typeName).Append(".set_defaultUserContext = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_defaultUserContext(value); }\r\n");
_builder.Append(typeName).Append(".get_defaultUserContext = function() { return ");
_builder.Append(typeName).Append("._staticInstance.get_defaultUserContext(); }\r\n");
_builder.Append(typeName).Append(".set_defaultSucceededCallback = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_defaultSucceededCallback(value); }\r\n");
_builder.Append(typeName).Append(".get_defaultSucceededCallback = function() { return ");
_builder.Append(typeName).Append("._staticInstance.get_defaultSucceededCallback(); }\r\n");
_builder.Append(typeName).Append(".set_defaultFailedCallback = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_defaultFailedCallback(value); }\r\n");
_builder.Append(typeName).Append(".get_defaultFailedCallback = function() { return ");
_builder.Append(typeName).Append("._staticInstance.get_defaultFailedCallback(); }\r\n");
_builder.Append(typeName).Append(".set_enableJsonp = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_enableJsonp(value); }\r\n");
_builder.Append(typeName).Append(".get_enableJsonp = function() { return ");
_builder.Append(typeName).Append("._staticInstance.get_enableJsonp(); }\r\n");
_builder.Append(typeName).Append(".set_jsonpCallbackParameter = function(value) { ");
_builder.Append(typeName).Append("._staticInstance.set_jsonpCallbackParameter(value); }\r\n");
_builder.Append(typeName).Append(".get_jsonpCallbackParameter = function() { return ");
_builder.Append(typeName).Append("._staticInstance.get_jsonpCallbackParameter(); }\r\n");
}
// the path has to be the full absolete path if this is a JSONP enabled service. But it is the responsibility
// of the caller to GetClientProxyScript to pass the full path if appropriate since determining it may be
// dependant on the specific technology.
string proxyPath = GetProxyPath();
if (!String.IsNullOrEmpty(proxyPath) && (proxyPath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || proxyPath.StartsWith("https://", StringComparison.OrdinalIgnoreCase))) {
// DevDiv 91322: avoid url encoding the domain portion of an IDN url
// find the first "/" after the scheme, and only encode after that.
int domainStart = proxyPath.IndexOf("://", StringComparison.OrdinalIgnoreCase) + "://".Length;
int domainEnd = proxyPath.IndexOf("/", domainStart, StringComparison.OrdinalIgnoreCase);
// if no slash after :// was found, it could be a domain only url, http://[some service].com, don't encode any of it
if (domainEnd != -1) {
proxyPath = proxyPath.Substring(0, domainEnd) + HttpUtility.UrlPathEncode(proxyPath.Substring(domainEnd));
}
}
else {
// it doesn't appear to be an absolute url, at least not an http or https one. All relative paths
// and other oddities are safely encoded with UrlPathEncode.
proxyPath = HttpUtility.UrlPathEncode(proxyPath);
}
_builder.Append(typeName).Append(".set_path(\"").Append(proxyPath).Append("\");\r\n");
if (GetSupportsJsonp()) {
_builder.Append(typeName).Append(".set_enableJsonp(true);\r\n");
string jsonpParameterName = GetJsonpCallbackParameterName();
if (!String.IsNullOrEmpty(jsonpParameterName) && !jsonpParameterName.Equals("callback", StringComparison.Ordinal)) {
_builder.Append(typeName).Append(".set_jsonpCallbackParameter(").Append(JavaScriptSerializer.SerializeInternal(jsonpParameterName)).Append(");\r\n");
}
}
}
private void BuildArgsDictionary(WebServiceMethodData methodData, StringBuilder args, StringBuilder argsDict, StringBuilder docComments) {
argsDict.Append('{');
foreach (WebServiceParameterData paramData in methodData.ParameterDatas) {
string name = paramData.ParameterName;
if (docComments != null) {
// looks like: /// <param name="foo" type="ClientType">Namespace.ServerType</param>
// client type may not match server type for built in js types like date, number, etc.
// client type may be omitted for type Object.
docComments.Append("/// <param name=\"").Append(name).Append("\"");
Type serverType = ServicesUtilities.UnwrapNullableType(paramData.ParameterType);
string clientType = GetClientTypeNamespace(ServicesUtilities.GetClientTypeFromServerType(methodData.Owner, serverType));
if (!String.IsNullOrEmpty(clientType)) {
docComments.Append(" type=\"").Append(clientType).Append("\"");
}
docComments.Append(">").Append(serverType.FullName).Append("</param>\r\n");
}
if (args.Length > 0) {
args.Append(',');
argsDict.Append(',');
}
args.Append(name);
argsDict.Append(name).Append(':').Append(name);
}
if (docComments != null) {
// append the built-in comments that all methods have (success, failed, usercontext parameters)
docComments.Append(DebugXmlComments);
}
argsDict.Append("}");
if (args.Length > 0) {
args.Append(',');
}
args.Append("succeededCallback, failedCallback, userContext");
}
private void GenerateWebMethodProxy(WebServiceMethodData methodData) {
string methodName = methodData.MethodName;
string typeName = GetProxyTypeName(methodData.Owner);
string useGet = methodData.UseGet ? "true" : "false";
_builder.Append(methodName).Append(':');
// e.g. MyMethod : function(param1, param2, ..., OnSuccess, OnFailure)
StringBuilder args = new StringBuilder();
StringBuilder argsDict = new StringBuilder();
StringBuilder docComments = null;
string docCommentsString = null;
if (_debugMode) {
docComments = new StringBuilder();
}
BuildArgsDictionary(methodData, args, argsDict, docComments);
if (_debugMode) {
// Remember the doc comments for the static instance case
docCommentsString = docComments.ToString();
_docCommentCache[methodName] = docCommentsString;
}
// Method calls look like this.invoke(FooNS.Sub.Method.get_path(), 'MethodName', true[useGet], {'arg1':'val1', 'arg2':'val2' }, onComplete, onError, userContext, 'FooNS.Sub.Method')
_builder.Append("function(").Append(args.ToString()).Append(") {\r\n");
if (_debugMode) {
// docCommentsString always end in \r\n
_builder.Append(docCommentsString);
}
_builder.Append("return this._invoke(this._get_path(), ");
_builder.Append("'").Append(methodName).Append("',");
_builder.Append(useGet).Append(',');
_builder.Append(argsDict.ToString()).Append(",succeededCallback,failedCallback,userContext); }");
}
/* e.g
var Qqq = function() { this.__type = "Qqq"; }
*/
private void GenerateClientTypeProxies(WebServiceData data) {
bool first = true;
foreach (WebServiceTypeData t in data.ClientTypes) {
if (first) {
_builder.Append("var gtc = Sys.Net.WebServiceProxy._generateTypedConstructor;\r\n");
first = false;
}
string typeID = data.GetTypeStringRepresentation(t);
string typeNameWithClientNamespace = GetClientTypeNamespace(t.TypeName);
string typeName = ServicesUtilities.GetClientTypeName(typeNameWithClientNamespace);
string clientTypeNamespace = GetClientTypeNamespace(t.TypeNamespace);
EnsureNamespace(t.TypeNamespace);
EnsureObjectGraph(clientTypeNamespace, typeName);
_builder.Append("if (typeof(").Append(typeName).Append(") === 'undefined') {\r\n");
AppendClientTypeDeclaration(clientTypeNamespace, typeNameWithClientNamespace, false, false);
// Need to use the _type id, which isn't necessarly the real name
_builder.Append("gtc(\"");
_builder.Append(typeID);
_builder.Append("\");\r\n");
_builder.Append(typeName).Append(".registerClass('").Append(typeName).Append("');\r\n}\r\n");
}
}
// Create client stubs for all the enums
private void GenerateEnumTypeProxies(IEnumerable<WebServiceEnumData> enumTypes) {
foreach (WebServiceEnumData t in enumTypes) {
EnsureNamespace(t.TypeNamespace);
string typeNameWithClientNamespace = GetClientTypeNamespace(t.TypeName);
string typeName = ServicesUtilities.GetClientTypeName(typeNameWithClientNamespace);
string[] enumNames = t.Names;
long[] enumValues = t.Values;
Debug.Assert(enumNames.Length == enumValues.Length);
EnsureObjectGraph(GetClientTypeNamespace(t.TypeNamespace), typeName);
_builder.Append("if (typeof(").Append(typeName).Append(") === 'undefined') {\r\n");
if (typeName.IndexOf('.') == -1) {
_builder.Append("var ");
}
_builder.Append(typeName).Append(" = function() { throw Error.invalidOperation(); }\r\n");
_builder.Append(typeName).Append(".prototype = {");
for (int i = 0; i < enumNames.Length; i++) {
if (i > 0) _builder.Append(',');
_builder.Append(enumNames[i]);
_builder.Append(": ");
if (t.IsULong) {
_builder.Append((ulong)enumValues[i]);
}
else {
_builder.Append(enumValues[i]);
}
}
_builder.Append("}\r\n");
_builder.Append(typeName).Append(".registerEnum('").Append(typeName).Append('\'');
_builder.Append(", true);\r\n}\r\n");
}
}
protected virtual string GetClientTypeNamespace(string ns) {
return ns;
}
private void AppendClientTypeDeclaration(string ns, string typeName, bool genClass, bool ensureNS) {
// Register the namespace if any
// e.g. registerNamespace('MyNS.MySubNS');
string name = GetClientTypeNamespace(ServicesUtilities.GetClientTypeName(typeName));
if (!String.IsNullOrEmpty(ns)) {
if (ensureNS) EnsureNamespace(ns);
}
else if (!genClass) {
// If there is no namespace, we need a var to declare the variable
if (!name.Contains(".")) {
// if name contains '.', an object graph was already ensured and we dont need 'var'.
_builder.Append("var ");
}
}
_builder.Append(name);
if (genClass) {
_builder.Append(".prototype");
}
_builder.Append('=');
_ensuredObjectParts[name] = null;
}
// Normally returns MyNS.MySubNS.MyWebService OR var MyWebService, PageMethods will return PageMethods
protected virtual string GetProxyTypeName(WebServiceData data) {
return ServicesUtilities.GetClientTypeName(data.TypeData.TypeName);
}
private void EnsureNamespace(string ns) {
//Give derived proxy generator a chance to transform namespace ( used by WCF)
ns = GetClientTypeNamespace(ns);
if (String.IsNullOrEmpty(ns)) return;
// Don't register a given namespace more than once
if (!_registeredNamespaces.Contains(ns)) {
_builder.Append("Type.registerNamespace('").Append(ns).Append("');\r\n");
_registeredNamespaces[ns] = null;
}
}
private void EnsureObjectGraph(string namespacePart, string typeName) {
// When a type name includes dots, such as 'MyNamespace.MyClass.MyNestedClass',
// this method writes code that ensures all the parts leading up to the actual class name
// are either already namespaces or are at least Objects.
// namespacePart is here so we dont unnecessarily ensure the first part that contains the
// namespace is checked for. For example, if we have NS1.NS2.NS3.TYPE, the check for
// _registeredNamespaces will find NS1.NS2.NS3 but not NS1 and NS1.NS2, so we'd insert
// checks that NS1 and NS1.NS2 are objects, unnecessarily.
int startFrom = 0;
bool first = true;
if (!String.IsNullOrEmpty(namespacePart)) {
int nsIndex = typeName.IndexOf(namespacePart + ".", StringComparison.Ordinal);
// in wcf services, the typeName starts with the namespace,
// in asmx services, it doesnt.
if (nsIndex > -1) {
startFrom = nsIndex + namespacePart.Length + 1;
first = false;
}
}
int dotIndex = typeName.IndexOf('.', startFrom);
while (dotIndex > -1) {
string fullPath = typeName.Substring(0, dotIndex);
if (!_registeredNamespaces.Contains(fullPath) && !_ensuredObjectParts.Contains(fullPath)) {
_ensuredObjectParts[fullPath] = null;
_builder.Append("if (typeof(" + fullPath + ") === \"undefined\") {\r\n ");
if (first) {
// var foo = {};
_builder.Append("var ");
first = false;
}
// foo.bar = {};
_builder.Append(fullPath + " = {};\r\n}\r\n");
}
dotIndex = typeName.IndexOf('.', dotIndex + 1);
}
}
}
}

View File

@@ -0,0 +1,45 @@
//------------------------------------------------------------------------------
// <copyright file="GenerateScriptTypeAttribute.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.Diagnostics.CodeAnalysis;
using System.Web;
[
AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method, AllowMultiple = true)
]
public sealed class GenerateScriptTypeAttribute : Attribute {
// Constructors
public GenerateScriptTypeAttribute(Type type) {
if (type == null) {
throw new ArgumentNullException("type");
}
_type = type;
}
// Instance Properties
private Type _type;
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
Justification = "Distinguishable from Object.GetType()")]
public Type Type {
get {
return _type;
}
}
private string _typeId;
public string ScriptTypeId {
get {
return _typeId ?? String.Empty;
}
set {
_typeId = value;
}
}
}
}

View File

@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <copyright file="PageClientProxyGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System.Web;
using System.Web.UI;
internal class PageClientProxyGenerator : ClientProxyGenerator {
private string _path;
internal PageClientProxyGenerator(IPage page, bool debug)
: this(VirtualPathUtility.MakeRelative(page.Request.Path, page.Request.FilePath), debug) {
// Dev10 Bug 597146: Use VirtualPathUtility to build a relative path from the path to the file.
// Previously just Page.Request.FilePath was used, which was for example, /app/foo/page.aspx,
// but this breaks with cookieless sessions since the url is /app/foo/(sessionid)/page.aspx.
// We need to make a relative path from page.Request.Path (e.g. /app/foo) to page.Request.FilePath
// (e.g. /app/foo/page.aspx) rather than just strip off 'page.aspx' with Path.GetFileName, because
// the url may include PathInfo, such as "/app/foo/page.aspx/pathinfo1/pathinfo2", and in that case
// we need the path to be ../../page.aspx
}
internal PageClientProxyGenerator(string path, bool debug) {
_path = path;
_debugMode = debug;
}
internal static string GetClientProxyScript(HttpContext context, IPage page, bool debug) {
// Do nothing during unit tests which have no context or page
if (context == null || page == null) return null;
WebServiceData webServiceData = WebServiceData.GetWebServiceData(context,
page.AppRelativeVirtualPath,
false /*failIfNoData*/,
true /*pageMethods */);
if (webServiceData == null)
return null;
PageClientProxyGenerator proxyGenerator = new PageClientProxyGenerator(page, debug);
return proxyGenerator.GetClientProxyScript(webServiceData);
}
protected override void GenerateTypeDeclaration(WebServiceData webServiceData, bool genClass) {
if (genClass) {
_builder.Append("PageMethods.prototype = ");
}
else {
_builder.Append("var PageMethods = ");
}
}
protected override string GetProxyTypeName(WebServiceData data) {
return "PageMethods";
}
protected override string GetProxyPath() {
return _path;
}
}
}

View File

@@ -0,0 +1,82 @@
//------------------------------------------------------------------------------
// <copyright file="ProxyGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.Globalization;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Web.Resources;
public static class ProxyGenerator {
const string WCFProxyTypeName = "System.ServiceModel.Description.WCFServiceClientProxyGenerator";
const string WCFProxyMethodName = "GetClientProxyScript";
public static string GetClientProxyScript(Type type, string path, bool debug) {
return GetClientProxyScript(type, path, debug, null);
}
public static string GetClientProxyScript(Type type, string path, bool debug, ServiceEndpoint serviceEndpoint) {
if (type == null) {
throw new ArgumentNullException("type");
}
if (path == null) {
throw new ArgumentNullException("path");
}
WebServiceData webServiceData = null;
ClientProxyGenerator proxyGenerator = null;
if (IsWebServiceType(type)) {
proxyGenerator = new WebServiceClientProxyGenerator(path, debug);
webServiceData = new WebServiceData(type, false);
}
else if (IsPageType(type)) {
proxyGenerator = new PageClientProxyGenerator(path, debug);
webServiceData = new WebServiceData(type, true);
}
else if(IsWCFServiceType(type)) {
// invoke the WCFServiceClientProxyGenerator.GetClientProxyScript method using reflection
Assembly wcfWebAssembly = Assembly.Load(AssemblyRef.SystemServiceModelWeb);
if (wcfWebAssembly != null) {
Type wcfProxyType = wcfWebAssembly.GetType(WCFProxyTypeName);
if (wcfProxyType != null) {
MethodInfo getClientProxyMethod = wcfProxyType.GetMethod(WCFProxyMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (getClientProxyMethod != null) {
return getClientProxyMethod.Invoke(null, new object[] { type, path, debug, serviceEndpoint }) as string;
}
}
}
// in case the reflection fails, we should throw unsupported exception
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
AtlasWeb.ProxyGenerator_UnsupportedType,
type.FullName));
}
else {
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
AtlasWeb.ProxyGenerator_UnsupportedType,
type.FullName));
}
return proxyGenerator.GetClientProxyScript(webServiceData);
}
private static bool IsPageType(Type type) {
return typeof(System.Web.UI.Page).IsAssignableFrom(type);
}
private static bool IsWCFServiceType(Type type) {
object[] attribs = type.GetCustomAttributes(typeof(ServiceContractAttribute), true);
return (attribs.Length != 0);
}
private static bool IsWebServiceType(Type type) {
object[] attribs = type.GetCustomAttributes(typeof(ScriptServiceAttribute), true);
return (attribs.Length != 0);
}
}
}

View File

@@ -0,0 +1,13 @@
//------------------------------------------------------------------------------
// <copyright file="ResponseFormat.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
public enum ResponseFormat {
Json = 0,
Xml = 1
}
}

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
// <copyright file="RestClientProxyHandler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
internal class RestClientProxyHandler : IHttpHandler {
public void ProcessRequest(HttpContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
string clientProxyString = WebServiceClientProxyGenerator.GetClientProxyScript(context);
if (clientProxyString != null) {
context.Response.ContentType = "application/x-javascript";
context.Response.Write(clientProxyString);
}
}
public bool IsReusable {
get {
return false;
}
}
}
}

View File

@@ -0,0 +1,261 @@
//------------------------------------------------------------------------------
// <copyright file="RestHandler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Security;
using System.Text;
using System.Web;
using System.Web.Resources;
using System.Web.Script.Serialization;
using System.Web.SessionState;
internal class RestHandler : IHttpHandler {
private WebServiceMethodData _webServiceMethodData;
internal static IHttpHandler CreateHandler(HttpContext context) {
// Expectation is that we got a PathInfo of form /MethodName
if (context.Request.PathInfo.Length < 2 || context.Request.PathInfo[0] != '/') {
throw new InvalidOperationException(AtlasWeb.WebService_InvalidWebServiceCall);
}
// Get the data about the web service being invoked
WebServiceData webServiceData = WebServiceData.GetWebServiceData(context, context.Request.FilePath);
string methodName = context.Request.PathInfo.Substring(1);
return CreateHandler(webServiceData, methodName);
}
private static IHttpHandler CreateHandler(WebServiceData webServiceData, string methodName) {
// Get the data about the method being called
WebServiceMethodData methodData = webServiceData.GetMethodData(methodName);
// Create the proper handler, depending on whether we need session state
RestHandler handler;
if (methodData.RequiresSession)
handler = new RestHandlerWithSession();
else
handler = new RestHandler();
// Save the method data in the handler
handler._webServiceMethodData = methodData;
return handler;
}
// This is very similar to WebService caching, the differences are
// 1) Here we explicitely SetValidUntilExpires(true) because in an XmlHttp there is
// "pragma:no-cache" in header which would result in cache miss on the server.
// 2) Here we don't vary on header "Content-type" or "SOAPAction" because the former
// is specific to soap 1.2, which puts action in the content-type param; and the
// later is used by soap calls.
private static void InitializeCachePolicy(WebServiceMethodData methodData, HttpContext context) {
int cacheDuration = methodData.CacheDuration;
if (cacheDuration > 0) {
context.Response.Cache.SetCacheability(HttpCacheability.Server);
context.Response.Cache.SetExpires(DateTime.Now.AddSeconds(cacheDuration));
context.Response.Cache.SetSlidingExpiration(false);
context.Response.Cache.SetValidUntilExpires(true);
// DevDiv 23596: Don't set VaryBy* if the method takes no parameters
if (methodData.ParameterDatas.Count > 0) {
context.Response.Cache.VaryByParams["*"] = true;
}
else {
context.Response.Cache.VaryByParams.IgnoreParams = true;
}
}
else {
context.Response.Cache.SetNoServerCaching();
context.Response.Cache.SetMaxAge(TimeSpan.Zero);
}
}
private static IDictionary<string, object> GetRawParamsFromGetRequest(HttpContext context, JavaScriptSerializer serializer, WebServiceMethodData methodData) {
// Get all the parameters from the query string
NameValueCollection queryString = context.Request.QueryString;
Dictionary<string, object> rawParams = new Dictionary<string, object>();
foreach (WebServiceParameterData param in methodData.ParameterDatas) {
string name = param.ParameterInfo.Name;
string val = queryString[name];
if (val != null) {
rawParams.Add(name, serializer.DeserializeObject(val));
}
}
return rawParams;
}
private static IDictionary<string, object> GetRawParamsFromPostRequest(HttpContext context, JavaScriptSerializer serializer) {
// Read the entire body as a string
TextReader reader = new StreamReader(context.Request.InputStream);
string bodyString = reader.ReadToEnd();
// If there is no body, treat it as an empty object
if (String.IsNullOrEmpty(bodyString)) {
return new Dictionary<string, object>();
}
// Deserialize the javascript request body
return serializer.Deserialize<IDictionary<string, object>>(bodyString);
}
private static IDictionary<string, object> GetRawParams(WebServiceMethodData methodData, HttpContext context) {
if (methodData.UseGet) {
if (context.Request.HttpMethod == "GET") {
return GetRawParamsFromGetRequest(context, methodData.Owner.Serializer, methodData);
}
else {
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture, AtlasWeb.WebService_InvalidVerbRequest,
methodData.MethodName, "POST"));
}
}
else if (context.Request.HttpMethod == "POST") {
return GetRawParamsFromPostRequest(context, methodData.Owner.Serializer);
} else {
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture, AtlasWeb.WebService_InvalidVerbRequest,
methodData.MethodName, "GET"));
}
}
private static void InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary<string, object> rawParams) {
// Initialize HttpCachePolicy
InitializeCachePolicy(methodData, context);
// Create an new instance of the class
object target = null;
if (!methodData.IsStatic) target = Activator.CreateInstance(methodData.Owner.TypeData.Type);
// Make the actual method call on it
object retVal = methodData.CallMethodFromRawParams(target, rawParams);
string contentType;
string responseString = null;
if (methodData.UseXmlResponse) {
responseString = retVal as string;
// If it's a string, output it as is unless XmlSerializeString is set
if (responseString == null || methodData.XmlSerializeString) {
// Use the Xml Serializer
try {
responseString = ServicesUtilities.XmlSerializeObjectToString(retVal);
}
catch (Exception e) {
// Throw a better error if Xml serialization fails
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture, AtlasWeb.WebService_InvalidXmlReturnType,
methodData.MethodName, retVal.GetType().FullName, e.Message));
}
}
contentType = "text/xml";
}
else {
// Convert the result to a JSON string
// DevDiv 88409:Change JSON wire format to prevent CSRF attack
// We wrap the returned value inside an object , and assign the returned value
// to member "d" of the object. We do so as JSOM for object will never be parsed
// as valid Javascript , unlike arrays.
responseString =@"{""d"":" + methodData.Owner.Serializer.Serialize(retVal) + "}";
contentType = "application/json";
}
// Set the response content-type
context.Response.ContentType = contentType;
// Write the string to the response
if (responseString != null)
context.Response.Write(responseString);
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification="All exceptions need to be reported to the client")]
[SuppressMessage("Microsoft.Security", "CA2107:ReviewDenyAndPermitOnlyUsage",
Justification = "Fix for DevDiv 39162 GAC'd non-APTCA types can instantiate in networking stack in Medium trust")]
internal static void ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData) {
try {
NamedPermissionSet s_permissionSet = HttpRuntime.NamedPermissionSet;
if (s_permissionSet != null) {
s_permissionSet.PermitOnly();
}
// Deserialize the javascript request body
IDictionary<string, object> rawParams = GetRawParams(methodData, context);
InvokeMethod(context, methodData, rawParams);
}
catch (Exception ex) {
WriteExceptionJsonString(context, ex);
}
}
private static object BuildWebServiceError(string msg, string stack, string type) {
var result = new OrderedDictionary();
result["Message"] = msg;
result["StackTrace"] = stack;
result["ExceptionType"] = type;
return result;
}
internal static void WriteExceptionJsonString(HttpContext context, Exception ex) {
WriteExceptionJsonString(context, ex, (int)HttpStatusCode.InternalServerError);
}
internal static void WriteExceptionJsonString(HttpContext context, Exception ex, int statusCode) {
// Record the charset before we call ClearHeaders(). (DevDiv Bugs 158401)
string charset = context.Response.Charset;
context.Response.ClearHeaders();
context.Response.ClearContent();
context.Response.Clear();
context.Response.StatusCode = statusCode;
context.Response.StatusDescription = HttpWorkerRequest.GetStatusDescription(statusCode);
context.Response.ContentType = "application/json";
context.Response.AddHeader("jsonerror", "true");
// Maintain the Charset from before. (DevDiv Bugs 158401)
context.Response.Charset = charset;
//Devdiv Bug: 118619:When accessed remotely, an Ajax web service that throws an error doesn't return the error string in the proper format on IIS7
//For IIS 7.0 integrated mode we need to set TrySkipIisCustomErrors to override IIS custom error handling. This has no functional/perf impact on
//IIS 7.0 classic mode or earlier versions.
context.Response.TrySkipIisCustomErrors = true;
using (StreamWriter writer = new StreamWriter(context.Response.OutputStream, new UTF8Encoding(false))) {
if (ex is TargetInvocationException) {
ex = ex.InnerException;
}
// Don't show any error stack or sensitive info when custom error is enabled.
if (context.IsCustomErrorEnabled) {
writer.Write(JavaScriptSerializer.SerializeInternal(BuildWebServiceError(AtlasWeb.WebService_Error, String.Empty, String.Empty)));
}
else {
writer.Write(JavaScriptSerializer.SerializeInternal(BuildWebServiceError(ex.Message, ex.StackTrace, ex.GetType().FullName)));
}
writer.Flush();
}
}
public void ProcessRequest(HttpContext context) {
ExecuteWebServiceCall(context, _webServiceMethodData);
}
public bool IsReusable {
get {
return false;
}
}
}
// Same handler, but implementing IRequiresSessionState to allow session state use
internal class RestHandlerWithSession: RestHandler, IRequiresSessionState {
}
}

View File

@@ -0,0 +1,55 @@
//------------------------------------------------------------------------------
// <copyright file="RestHandlerFactory.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
internal class RestHandlerFactory : IHttpHandlerFactory {
internal const string ClientProxyRequestPathInfo = "/js";
internal const string ClientDebugProxyRequestPathInfo = "/jsdebug";
public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) {
if (context == null) {
throw new ArgumentNullException("context");
}
if (IsClientProxyRequest(context.Request.PathInfo)) {
// It's a request for client side proxies
return new RestClientProxyHandler();
}
else {
// The request is an actual call to a server method
return RestHandler.CreateHandler(context);
}
}
public virtual void ReleaseHandler(IHttpHandler handler) {
}
// Detects if this is a request we want to intercept, i.e. invocation or proxy request
internal static bool IsRestRequest(HttpContext context) {
return IsRestMethodCall(context.Request) || IsClientProxyRequest(context.Request.PathInfo);
}
// Detects if this is a method invocation, i.e. webservice call or page method call
internal static bool IsRestMethodCall(HttpRequest request) {
return
!String.IsNullOrEmpty(request.PathInfo) &&
(request.ContentType.StartsWith("application/json;", StringComparison.OrdinalIgnoreCase) ||
string.Equals(request.ContentType, "application/json", StringComparison.OrdinalIgnoreCase));
}
internal static bool IsClientProxyDebugRequest(string pathInfo) {
return string.Equals(pathInfo, ClientDebugProxyRequestPathInfo, StringComparison.OrdinalIgnoreCase);
}
internal static bool IsClientProxyRequest(string pathInfo) {
return (string.Equals(pathInfo, ClientProxyRequestPathInfo, StringComparison.OrdinalIgnoreCase) ||
IsClientProxyDebugRequest(pathInfo));
}
}
}

View File

@@ -0,0 +1,106 @@
//------------------------------------------------------------------------------
// <copyright file="ScriptHandlerFactory.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System.Web.SessionState;
using System.Security.Permissions;
using System.Security;
namespace System.Web.Script.Services {
internal class ScriptHandlerFactory : IHttpHandlerFactory {
IHttpHandlerFactory _restHandlerFactory;
IHttpHandlerFactory _webServiceHandlerFactory;
internal class HandlerWrapper : IHttpHandler {
protected IHttpHandler _originalHandler;
private IHttpHandlerFactory _originalFactory;
internal HandlerWrapper(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory) {
_originalFactory = originalFactory;
_originalHandler = originalHandler;
}
internal void ReleaseHandler() {
_originalFactory.ReleaseHandler(_originalHandler);
}
public bool IsReusable {
get {
return _originalHandler.IsReusable;
}
}
public void ProcessRequest(HttpContext context) {
_originalHandler.ProcessRequest(context);
}
}
internal class HandlerWrapperWithSession : HandlerWrapper, IRequiresSessionState {
internal HandlerWrapperWithSession(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory)
: base(originalHandler, originalFactory) {}
}
private class AsyncHandlerWrapper : HandlerWrapper, IHttpAsyncHandler {
internal AsyncHandlerWrapper(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory)
:
base(originalHandler, originalFactory) { }
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
return ((IHttpAsyncHandler)_originalHandler).BeginProcessRequest(context, cb, extraData);
}
public void EndProcessRequest(IAsyncResult result) {
((IHttpAsyncHandler)_originalHandler).EndProcessRequest(result);
}
}
private class AsyncHandlerWrapperWithSession : AsyncHandlerWrapper, IRequiresSessionState {
internal AsyncHandlerWrapperWithSession(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory)
: base(originalHandler, originalFactory) { }
}
public ScriptHandlerFactory() {
_restHandlerFactory = new RestHandlerFactory();
_webServiceHandlerFactory = new System.Web.Services.Protocols.WebServiceHandlerFactory();
}
[SecuritySafeCritical]
public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) {
IHttpHandler handler;
IHttpHandlerFactory factory;
if (RestHandlerFactory.IsRestRequest(context)) {
// It's a REST request
factory = _restHandlerFactory;
}
else {
// It's a regular asmx web request, so delegate to the WebServiceHandlerFactory
factory = _webServiceHandlerFactory;
}
handler = factory.GetHandler(context, requestType, url, pathTranslated);
bool requiresSession = handler is IRequiresSessionState;
if (handler is IHttpAsyncHandler) {
if (requiresSession)
return new AsyncHandlerWrapperWithSession(handler, factory);
else
return new AsyncHandlerWrapper(handler, factory);
}
if (requiresSession)
return new HandlerWrapperWithSession(handler, factory);
else
return new HandlerWrapper(handler, factory);
}
public virtual void ReleaseHandler(IHttpHandler handler) {
if (handler == null) {
throw new ArgumentNullException("handler");
}
((HandlerWrapper)handler).ReleaseHandler();
}
}
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
// <copyright file="ScriptMethodAttribute.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.Web;
[
AttributeUsage(AttributeTargets.Method)
]
public sealed class ScriptMethodAttribute : Attribute {
private ResponseFormat _responseFormat;
private bool _useHttpGet;
private bool _xmlSerializeString;
public ResponseFormat ResponseFormat {
get {
return _responseFormat;
}
set {
_responseFormat = value;
}
}
public bool UseHttpGet {
get {
return _useHttpGet;
}
set {
_useHttpGet = value;
}
}
public bool XmlSerializeString {
get {
return _xmlSerializeString;
}
set {
_xmlSerializeString = value;
}
}
}
}

View File

@@ -0,0 +1,18 @@
//------------------------------------------------------------------------------
// <copyright file="ScriptServiceAttribute.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.Web;
[
AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)
]
public sealed class ScriptServiceAttribute : Attribute {
public ScriptServiceAttribute() {
}
}
}

View File

@@ -0,0 +1,125 @@
//------------------------------------------------------------------------------
// <copyright file="ServicesUtilities.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace System.Web.Script.Services {
internal static class ServicesUtilities {
internal static string GetClientTypeName(string name) {
// e.g. MyNS.MySubNS.MyWebService OR var MyWebService
return name.Replace('+', '_');
}
[SuppressMessage("Microsoft.Usage", "CA2301:EmbeddableTypesInContainersRule", MessageId = "System.Collections.Generic.Dictionary`2<System.Type,System.String>", Justification = "This is used by ASP.Net web services which is a legacy technology.")]
internal static string GetClientTypeFromServerType(WebServiceData webServiceData, Type type)
{
// For intellisense purposes, returns a best estimate of what the appropriate client-side type is for a given server type.
// Takes generated client proxies and enum proxies into consideration.
// The rest is a best guess.
// If all else fails we use "", to indicate "any" client side type. "Object" is not the same as any type on the client since
// string, for example, is not considered an object. "Object" is equiv to a .net dictionary.
if (webServiceData.ClientTypeNameDictionary.ContainsKey(type)) {
// if it exists in the client type dictionary, it will have a proxy generated for it
//get the client based on type.FullName for ASMX, and schema qualified name and namespace for WCF
return webServiceData.ClientTypeNameDictionary[type];
}
if (type.IsEnum) {
// there will be a proxy for this enum
return GetClientTypeName(type.FullName);
}
// there is no client proxy for it, so it either maps to a built-in js type or it could be "anything"
// take care of the most common types
if (type == typeof(string) || type == typeof(char)) {
return "String";
}
else if (type.IsPrimitive) {
// The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64 (long), UInt64, IntPtr, Char, Double, and Single (float).
if (type == typeof(bool)) {
// bool is the only primitive we shouldnt treat as a number
return "Boolean";
}
else {
// takes care of all ints, float, double, but not decimal since it isnt a primitive
// we also consider byte, sbyte, and intptr to be numbers
return "Number";
}
}
if (type.IsValueType) {
if (type == typeof(DateTime)) {
return "Date";
}
else if (type == typeof(Guid)) {
return "String";
}
else if (type == typeof(Decimal)) {
return "Number";
}
}
if (typeof(IDictionary).IsAssignableFrom(type)) {
return "Object";
}
// might still be IDictionary<K,T>
if (type.IsGenericType) {
Type gtd = type;
if (!type.IsGenericTypeDefinition) {
gtd = type.GetGenericTypeDefinition();
}
if (gtd == typeof(IDictionary<,>)) {
return "Object";
}
}
if (type.IsArray || typeof(IEnumerable).IsAssignableFrom(type)) {
return "Array";
}
// dont know what it is (e.g., TimeSpan), or it is type Object, so allow any client type.
return "";
}
internal static Type UnwrapNullableType(Type type) {
// check for nullable<t> and pull out <t>
if (type.IsGenericType && !type.IsGenericTypeDefinition) {
Type genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(Nullable<>)) {
return type.GetGenericArguments()[0];
}
}
return type;
}
// Serialize an object to an XML string
internal static string XmlSerializeObjectToString(object obj) {
//
XmlSerializer xs = new XmlSerializer(obj.GetType());
MemoryStream ms = new MemoryStream();
using (XmlTextWriter writer = new XmlTextWriter(ms, Encoding.UTF8)) {
xs.Serialize(writer, obj);
ms.Position = 0;
using (StreamReader reader = new StreamReader(ms)) {
return reader.ReadToEnd();
}
}
}
}
}

View File

@@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
// <copyright file="WebServiceClientProxyGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.IO;
using System.Reflection;
using System.Web;
using System.Security.Permissions;
using System.Security;
internal class WebServiceClientProxyGenerator : ClientProxyGenerator {
private string _path;
// Called by ScriptManager to generate the proxy inline
internal static string GetInlineClientProxyScript(string path, HttpContext context, bool debug) {
WebServiceData webServiceData = WebServiceData.GetWebServiceData(context, path, true, false, true);
WebServiceClientProxyGenerator proxyGenerator = new WebServiceClientProxyGenerator(path, debug);
return proxyGenerator.GetClientProxyScript(webServiceData);
}
private static DateTime GetAssemblyModifiedTime(Assembly assembly) {
AssemblyName assemblyName = assembly.GetName();
DateTime writeTime = File.GetLastWriteTime(new Uri(assemblyName.CodeBase).LocalPath);
// DevDiv 52056: include writeTime.Second in the date, otherwise if you modify it within the same minute it we'd still respond with http status 304 not modified
return new DateTime(writeTime.Year, writeTime.Month, writeTime.Day, writeTime.Hour, writeTime.Minute, writeTime.Second);
}
// This is called thru the RestClientProxyHandler
[SecuritySafeCritical]
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
internal static string GetClientProxyScript(HttpContext context) {
WebServiceData webServiceData = WebServiceData.GetWebServiceData(context, context.Request.FilePath);
DateTime lastModifiedDate = GetAssemblyModifiedTime(webServiceData.TypeData.Type.Assembly);
// If the browser sent this header, we can check if we need to resend
string modifiedSince = context.Request.Headers["If-Modified-Since"];
if (modifiedSince != null) {
DateTime header;
if (DateTime.TryParse(modifiedSince, out header)) {
// We are done if the assembly hasn't been modified
if (header >= lastModifiedDate) {
context.Response.StatusCode = 304;
return null;
}
}
}
bool debug = RestHandlerFactory.IsClientProxyDebugRequest(context.Request.PathInfo);
// Only cache for release proxy script (/js)
if (!debug) {
// Only cache if we get a reasonable last modified date
if (lastModifiedDate.ToUniversalTime() < DateTime.UtcNow) {
// Cache the resource so we don't keep processing the same requests
HttpCachePolicy cachePolicy = context.Response.Cache;
cachePolicy.SetCacheability(HttpCacheability.Public);
cachePolicy.SetLastModified(lastModifiedDate);
// expires is necessary so that the browser at least does an If-Modified-Since request on every request.
// without that, the browser wouldn't request a new proxy until the user hits refresh.
// Use one year ago to reasonably ensure "past" interpretation
cachePolicy.SetExpires(lastModifiedDate.AddYears(-1));
}
}
WebServiceClientProxyGenerator proxyGenerator = new WebServiceClientProxyGenerator(context.Request.FilePath, debug);
return proxyGenerator.GetClientProxyScript(webServiceData);
}
internal WebServiceClientProxyGenerator(string path, bool debug) {
// internal because ExtensionsTest needs this path to bypass httpcontext
_path = path;
_debugMode = debug;
}
protected override string GetProxyPath() {
return _path;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
// <copyright file="WebServiceEnumData.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System.Globalization;
namespace System.Web.Script.Services {
using System;
internal class WebServiceEnumData : WebServiceTypeData {
bool isULong;
string[] names;
long[] values;
internal WebServiceEnumData(string typeName, string typeNamespace, string[] names, long[] values, bool isULong)
: base(typeName, typeNamespace) {
InitWebServiceEnumData(names, values, isULong);
}
internal WebServiceEnumData(string typeName, string typeNamespace, Type t, string[] names, long[] values, bool isULong)
: base(typeName, typeNamespace, t) {
InitWebServiceEnumData(names, values, isULong);
}
internal WebServiceEnumData(string typeName, string typeNamespace, string[] names, Array values, bool isULong)
: base(typeName, typeNamespace) {
InitWebServiceEnumData(names, values, isULong);
}
internal WebServiceEnumData(string typeName, string typeNamespace, Type t, string[] names, Array values, bool isULong)
: base(typeName, typeNamespace) {
InitWebServiceEnumData(names, values, isULong);
}
internal bool IsULong {
get {
return isULong;
}
}
internal string[] Names {
get {
return names;
}
}
internal long[] Values {
get {
return values;
}
}
private void InitWebServiceEnumData(string[] names, long[] values, bool isULong) {
System.Diagnostics.Debug.Assert(names != null);
System.Diagnostics.Debug.Assert(values != null);
System.Diagnostics.Debug.Assert(names.Length == values.Length);
this.names = names;
this.values = values;
this.isULong = isULong;
}
private void InitWebServiceEnumData(string[] names, Array values, bool isULong) {
System.Diagnostics.Debug.Assert(names != null);
System.Diagnostics.Debug.Assert(values != null);
System.Diagnostics.Debug.Assert(names.Length == values.Length);
this.names = names;
this.values = new long[values.Length];
for (int i = 0; i < values.Length; i++) {
object enumValue = values.GetValue(i);
if (isULong) {
this.values[i] = (long)((IConvertible)enumValue).ToUInt64(CultureInfo.InvariantCulture);
}
else {
this.values[i] = ((IConvertible)enumValue).ToInt64(CultureInfo.InvariantCulture);
}
}
this.isULong = isULong;
}
}
}

View File

@@ -0,0 +1,201 @@
//------------------------------------------------------------------------------
// <copyright file="WebServiceMethodData.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Web.Resources;
using System.Web.Script.Serialization;
using System.Web.Services;
namespace System.Web.Script.Services {
internal class WebServiceMethodData {
private MethodInfo _methodInfo;
private WebMethodAttribute _webMethodAttribute;
private ScriptMethodAttribute _scriptMethodAttribute;
private string _methodName;
private Dictionary<string, WebServiceParameterData> _parameterData;
private WebServiceData _owner;
private bool? _useHttpGet;
internal WebServiceMethodData(WebServiceData owner, MethodInfo methodInfo, WebMethodAttribute webMethodAttribute, ScriptMethodAttribute scriptMethodAttribute) {
_owner = owner;
_methodInfo = methodInfo;
_webMethodAttribute = webMethodAttribute;
_methodName = _webMethodAttribute.MessageName;
_scriptMethodAttribute = scriptMethodAttribute;
if (String.IsNullOrEmpty(_methodName)) {
_methodName = methodInfo.Name;
}
}
// This constructor is only used by WCF. Owener, MethodName, ParameterDataDictionary, ParamterData
// are the only valid properties in WCF case.
internal WebServiceMethodData(WebServiceData owner, string methodName, Dictionary<string, WebServiceParameterData> parameterData, bool useHttpGet) {
_owner = owner;
_methodName = methodName;
_parameterData = parameterData;
_useHttpGet = useHttpGet;
}
internal WebServiceData Owner {
get {
return _owner;
}
}
private void EnsureParameters() {
// Build the parameters collection on demand
if (_parameterData != null)
return;
lock (this) {
Dictionary<string, WebServiceParameterData> parameterData = new Dictionary<string, WebServiceParameterData>();
int index = 0;
foreach (ParameterInfo param in _methodInfo.GetParameters()) {
parameterData[param.Name] = new WebServiceParameterData(param, index);
index++;
}
_parameterData = parameterData;
}
}
internal string MethodName {
get {
return _methodName;
}
}
internal MethodInfo MethodInfo {
get {
return _methodInfo;
}
}
internal IDictionary<string, WebServiceParameterData> ParameterDataDictionary {
get {
EnsureParameters();
return _parameterData;
}
}
internal ICollection<WebServiceParameterData> ParameterDatas {
get {
return ParameterDataDictionary.Values;
}
}
internal int CacheDuration {
get {
Debug.Assert(_webMethodAttribute != null); // If fails: WebserviceMethodData corrosponding to WCF is being used by ASMX JSON handler
return _webMethodAttribute.CacheDuration;
}
}
internal bool RequiresSession {
get {
Debug.Assert(_webMethodAttribute != null); // If fails: WebserviceMethodData corrosponding to WCF is being used by ASMX JSON handler
return _webMethodAttribute.EnableSession;
}
}
internal bool IsStatic {
get {
Debug.Assert(_methodInfo != null); // If fails: WebserviceMethodData corrosponding to WCF is being used by ASMX JSON handler
return _methodInfo.IsStatic;
}
}
internal Type ReturnType {
get {
Debug.Assert(_methodInfo != null); // If fails: WebserviceMethodData corrosponding to WCF is being used by ASMX JSON handler
return (_methodInfo == null) ? null : _methodInfo.ReturnType;
}
}
internal bool UseXmlResponse {
get {
if (_scriptMethodAttribute != null) {
return _scriptMethodAttribute.ResponseFormat == ResponseFormat.Xml;
}
return false;
}
}
internal bool XmlSerializeString {
get {
if (_scriptMethodAttribute != null) {
return _scriptMethodAttribute.XmlSerializeString;
}
return false;
}
}
internal bool UseGet {
get {
if (_useHttpGet != null) {
return _useHttpGet.Value;
}
if (_scriptMethodAttribute != null) {
return _scriptMethodAttribute.UseHttpGet;
}
return false;
}
}
internal object CallMethodFromRawParams(object target, IDictionary<string, object> parameters) {
// Process the 'raw' parameters so that we use strongly typed objects when possible
parameters = StrongTypeParameters(parameters);
return CallMethod(target, parameters);
}
private object CallMethod(object target, IDictionary<string, object> parameters) {
// Make sure we have all the data about this method's parameters
EnsureParameters();
// Allocate an object array for all the formal parameters (whether passed in or not)
object[] actualParams = new object[_parameterData.Count];
// Go through all the actual parameters
foreach (WebServiceParameterData paramData in _parameterData.Values) {
object value;
if (parameters.TryGetValue(paramData.ParameterInfo.Name, out value)) {
actualParams[paramData.Index] = value;
}
else {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.WebService_MissingArg, paramData.ParameterInfo.Name));
}
}
// Make the actual method call
return _methodInfo.Invoke(target, actualParams);
}
private IDictionary<string, object> StrongTypeParameters(IDictionary<string, object> rawParams) {
Debug.Assert(ParameterDataDictionary != null);
IDictionary<string, WebServiceParameterData> paramDataDictionary = ParameterDataDictionary;
// Allocate a dictionary to hold the processed parameters.
IDictionary<string, object> result = new Dictionary<string, object>(rawParams.Count);
// Go through all the raw parameters
foreach (KeyValuePair<string, object> pair in rawParams) {
string memberName = pair.Key;
if (paramDataDictionary.ContainsKey(memberName)) {
// Get the type of the formal parameter
Type paramType = paramDataDictionary[memberName].ParameterInfo.ParameterType;
// Convert the raw parameter based on that type
result[memberName] = ObjectConverter.ConvertObjectToType(pair.Value, paramType, Owner.Serializer);
}
}
return result;
}
}
}

View File

@@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
// <copyright file="WebServiceParameterData.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System.Reflection;
namespace System.Web.Script.Services {
internal class WebServiceParameterData {
private ParameterInfo _param;
private int _index; // Index of the parameter in the method
private string _paramName;
private Type _paramType;
internal WebServiceParameterData(ParameterInfo param, int index) {
_param = param;
_index = index;
}
// This constructor is only used by indigo
internal WebServiceParameterData(string paramName, Type paramType, int index) {
_paramName = paramName;
_paramType = paramType;
_index = index;
}
internal int Index {
get { return _index; }
}
internal ParameterInfo ParameterInfo {
get { return _param; }
}
internal string ParameterName {
get {
if (_param != null) {
return _param.Name;
}
else {
return _paramName;
}
}
}
internal Type ParameterType {
get {
if (_param != null) {
return _param.ParameterType;
}
else {
return _paramType;
}
}
}
}
}

View File

@@ -0,0 +1,327 @@
//------------------------------------------------------------------------------
// <copyright file="WebServiceTypeData.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Services {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Schema;
internal class WebServiceTypeData {
// Actual type is needed for ResolveType in WebServiceData (not relevant in Indigo)
private Type _actualType;
// The custom string reprensenation used for WCF case
private string _stringRepresentation;
private string _typeName;
private string _typeNamespace;
static Dictionary<XmlQualifiedName, Type> _nameToType = new Dictionary<XmlQualifiedName, Type>();
// constants carried over for internal System.Runtime.Seriliazation.Globals class.
private const string SerializationNamespace = "http://schemas.microsoft.com/2003/10/Serialization/";
private const string StringLocalName = "string";
private const string SchemaNamespace = XmlSchema.Namespace;
private const string ActualTypeLocalName = "ActualType";
private const string ActualTypeNameAttribute = "Name";
private const string ActualTypeNamespaceAttribute = "Namespace";
private const string EnumerationValueLocalName = "EnumerationValue";
private const string OccursUnbounded = "unbounded";
static WebServiceTypeData() {
Add(typeof(sbyte), "byte");
Add(typeof(byte), "unsignedByte");
Add(typeof(short), "short");
Add(typeof(ushort), "unsignedShort");
Add(typeof(int), "int");
Add(typeof(uint), "unsignedInt");
Add(typeof(long), "long");
Add(typeof(ulong), "unsignedLong");
}
// type is null for WCF
internal WebServiceTypeData(string name, string ns, Type type) {
if (String.IsNullOrEmpty(ns)) {
_typeName = name;
if (type == null) { // for WCF known types
_stringRepresentation = name;
}
}
else {
_typeName = ns + "." + name;
if (type == null) { // for WCF known types
_stringRepresentation = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", name, ns);
}
}
_typeNamespace = ns;
_actualType = type;
}
internal WebServiceTypeData(string name, string ns)
: this(name, ns, null) {
}
private static XmlQualifiedName actualTypeAnnotationName;
private static XmlQualifiedName ActualTypeAnnotationName {
get {
if (actualTypeAnnotationName == null)
actualTypeAnnotationName = new XmlQualifiedName(ActualTypeLocalName, SerializationNamespace);
return actualTypeAnnotationName;
}
}
static XmlQualifiedName enumerationValueAnnotationName;
private static XmlQualifiedName EnumerationValueAnnotationName {
get {
if (enumerationValueAnnotationName == null)
enumerationValueAnnotationName = new XmlQualifiedName(EnumerationValueLocalName, SerializationNamespace);
return enumerationValueAnnotationName;
}
}
internal string StringRepresentation {
get { return _stringRepresentation; }
}
internal string TypeName {
get { return _typeName; }
}
internal string TypeNamespace {
get { return _typeNamespace; }
}
internal Type Type {
get { return _actualType; }
}
private static void Add(Type type, string localName) {
XmlQualifiedName stableName = new XmlQualifiedName(localName, XmlSchema.Namespace);
_nameToType.Add(stableName, type);
}
private static bool CheckIfCollection(XmlSchemaComplexType type) {
if (type == null) {
return false;
}
bool isCollection = false;
if (type.ContentModel == null) {
isCollection = CheckIfCollectionSequence(type.Particle as XmlSchemaSequence);
}
return isCollection;
}
private static bool CheckIfCollectionSequence(XmlSchemaSequence rootSequence) {
// No support for versioning since schema is not persisted; unknown serialization elements are not removed
if (rootSequence.Items == null || rootSequence.Items.Count == 0)
return false;
if (rootSequence.Items.Count != 1)
return false;
XmlSchemaObject o = rootSequence.Items[0];
if (!(o is XmlSchemaElement))
return false;
XmlSchemaElement localElement = (XmlSchemaElement)o;
return (localElement.MaxOccursString == OccursUnbounded || localElement.MaxOccurs > 1);
}
private static bool CheckIfEnum(XmlSchemaSimpleType simpleType, out XmlSchemaSimpleTypeRestriction simpleTypeRestriction) {
simpleTypeRestriction = null;
if (simpleType == null) {
return false;
}
// check enum
XmlSchemaSimpleTypeRestriction restriction = simpleType.Content as XmlSchemaSimpleTypeRestriction;
if (restriction != null) {
simpleTypeRestriction = restriction;
return CheckIfEnumRestriction(restriction);
}
// check flags enum
XmlSchemaSimpleTypeList list = simpleType.Content as XmlSchemaSimpleTypeList;
XmlSchemaSimpleType anonymousType = list.ItemType;
if (anonymousType != null) {
restriction = anonymousType.Content as XmlSchemaSimpleTypeRestriction;
if (restriction != null) {
simpleTypeRestriction = restriction;
return CheckIfEnumRestriction(restriction);
}
}
return false;
}
static bool CheckIfEnumRestriction(XmlSchemaSimpleTypeRestriction restriction) {
foreach (XmlSchemaFacet facet in restriction.Facets) {
if (!(facet is XmlSchemaEnumerationFacet)) {
return false;
}
}
// Does not check for non-string name or anonymous base type
// because these are exported types and do not use those constructs.
if (restriction.BaseTypeName != XmlQualifiedName.Empty) {
return (restriction.BaseTypeName.Name == StringLocalName
&& restriction.BaseTypeName.Namespace == SchemaNamespace
&& restriction.Facets.Count > 0);
}
return false;
}
private static string GetInnerText(XmlQualifiedName typeName, XmlElement xmlElement) {
if (xmlElement != null) {
XmlNode child = xmlElement.FirstChild;
while (child != null) {
if (child.NodeType == XmlNodeType.Element) {
throw new InvalidOperationException();
//
}
child = child.NextSibling;
}
return xmlElement.InnerText;
}
return null;
}
internal static List<WebServiceTypeData> GetKnownTypes(Type type, WebServiceTypeData typeData) {
List<WebServiceTypeData> knownTypes = new List<WebServiceTypeData>();
XsdDataContractExporter exporter = new XsdDataContractExporter();
exporter.Export(type);
ICollection schemas = exporter.Schemas.Schemas();
foreach (XmlSchema schema in schemas) {
// DataContractSerializer always exports built-in types into a fixed schema that can be ignored.
if (schema.TargetNamespace == SerializationNamespace) {
continue;
}
foreach (XmlSchemaObject schemaObj in schema.Items) {
XmlSchemaType schemaType = schemaObj as XmlSchemaType;
string schemaTargetNamespace = XmlConvert.DecodeName(schema.TargetNamespace);
if (schemaType != null
&& !(schemaType.Name == typeData.TypeName && schemaTargetNamespace == typeData.TypeNamespace)
&& !String.IsNullOrEmpty(schemaType.Name)) {
WebServiceTypeData knownTypeData = null;
XmlSchemaSimpleTypeRestriction simpleTypeRestriction;
if (CheckIfEnum(schemaType as XmlSchemaSimpleType, out simpleTypeRestriction)) {
knownTypeData = ImportEnum(XmlConvert.DecodeName(schemaType.Name), schemaTargetNamespace, schemaType.QualifiedName, simpleTypeRestriction, schemaType.Annotation);
}
else if (CheckIfCollection(schemaType as XmlSchemaComplexType)) {
continue;
}
else if (!(schemaType is XmlSchemaSimpleType)) {
knownTypeData = new WebServiceTypeData(XmlConvert.DecodeName(schemaType.Name), schemaTargetNamespace);
}
if (knownTypeData != null) {
knownTypes.Add(knownTypeData);
}
}
}
}
return knownTypes;
}
//used for WCF known types
internal static WebServiceTypeData GetWebServiceTypeData(Type type) {
WebServiceTypeData typeData = null;
XsdDataContractExporter exporter = new XsdDataContractExporter();
XmlQualifiedName qname = exporter.GetSchemaTypeName(type);
if (!qname.IsEmpty) {
if (type.IsEnum) {
bool isUlong = (Enum.GetUnderlyingType(type) == typeof(ulong));
typeData = new WebServiceEnumData(XmlConvert.DecodeName(qname.Name), XmlConvert.DecodeName(qname.Namespace), Enum.GetNames(type), Enum.GetValues(type), isUlong);
}
else {
typeData = new WebServiceTypeData(XmlConvert.DecodeName(qname.Name), XmlConvert.DecodeName(qname.Namespace));
}
}
return typeData;
}
internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation annotation, XmlQualifiedName defaultTypeName, XmlQualifiedName typeName) {
XmlElement actualTypeElement = ImportAnnotation(annotation, ActualTypeAnnotationName);
if (actualTypeElement == null) {
return defaultTypeName;
}
XmlNode nameAttribute = actualTypeElement.Attributes.GetNamedItem(ActualTypeNameAttribute);
Debug.Assert(nameAttribute != null);
Debug.Assert(nameAttribute.Value != null);
string name = nameAttribute.Value;
XmlNode nsAttribute = actualTypeElement.Attributes.GetNamedItem(ActualTypeNamespaceAttribute);
Debug.Assert(nsAttribute != null);
Debug.Assert(nsAttribute.Value != null);
string ns = nsAttribute.Value;
return new XmlQualifiedName(name, ns);
}
static XmlElement ImportAnnotation(XmlSchemaAnnotation annotation, XmlQualifiedName annotationQualifiedName) {
if (annotation != null && annotation.Items != null && annotation.Items.Count > 0 && annotation.Items[0] is XmlSchemaAppInfo) {
XmlSchemaAppInfo appInfo = (XmlSchemaAppInfo)annotation.Items[0];
XmlNode[] markup = appInfo.Markup;
if (markup != null) {
for (int i = 0; i < markup.Length; i++) {
XmlElement annotationElement = markup[i] as XmlElement;
if (annotationElement != null && annotationElement.LocalName == annotationQualifiedName.Name && annotationElement.NamespaceURI == annotationQualifiedName.Namespace) {
return annotationElement;
}
}
}
}
return null;
}
static WebServiceEnumData ImportEnum(string typeName, string typeNamespace, XmlQualifiedName typeQualifiedName, XmlSchemaSimpleTypeRestriction restriction, XmlSchemaAnnotation annotation) {
// CheckIfEnum has already checked if baseType of restriction is string
XmlQualifiedName baseTypeName = ImportActualType(annotation, new XmlQualifiedName("int", XmlSchema.Namespace), typeQualifiedName);
Type baseEnumType = _nameToType[baseTypeName];
bool isULong = (baseEnumType == typeof(ulong));
List<string> enumNames = new List<string>();
List<long> enumValues = new List<long>();
foreach (XmlSchemaFacet facet in restriction.Facets) {
XmlSchemaEnumerationFacet enumFacet = facet as XmlSchemaEnumerationFacet;
Debug.Assert(enumFacet != null);
Debug.Assert(enumFacet.Value != null);
string valueInnerText = GetInnerText(typeQualifiedName, ImportAnnotation(enumFacet.Annotation, EnumerationValueAnnotationName));
long value;
if (valueInnerText == null) {
// ASP .NET AJAX doesn't honor the Flags nature of Flags enums
// If it were to, we would assign Math.Pow(2, nameValues.Count) for Flags enums instead.
value = enumNames.Count;
}
else {
if (isULong) {
value = (long)ulong.Parse(valueInnerText, NumberFormatInfo.InvariantInfo);
}
else {
value = long.Parse(valueInnerText, NumberFormatInfo.InvariantInfo);
}
}
enumNames.Add(enumFacet.Value);
enumValues.Add(value);
}
return new WebServiceEnumData(typeName, typeNamespace, enumNames.ToArray(), enumValues.ToArray(), isULong);
}
}
}