e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
456 lines
25 KiB
C#
456 lines
25 KiB
C#
//------------------------------------------------------------------------------
|
|
// <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);
|
|
}
|
|
}
|
|
}
|
|
}
|