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,14 @@
namespace System.Web.Script {
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
[
AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false),
SuppressMessage("Microsoft.Performance","CA1813:AvoidUnsealedAttributes", Justification="Intentially allowing for ajax assemblies to have a custom attribute type in order to override the virtual members. Result of looking for this attribute is cached.")
]
public class AjaxFrameworkAssemblyAttribute : Attribute {
protected internal virtual Assembly GetDefaultAjaxFrameworkAssembly(Assembly currentAssembly) {
return currentAssembly;
}
}
}

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <copyright file="JavaScriptConverter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Serialization {
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Web;
public abstract class JavaScriptConverter {
public abstract IEnumerable<Type> SupportedTypes {
get;
}
public abstract object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer);
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj",
Justification = "Cannot change parameter name as would break binary compatibility with legacy apps.")]
public abstract IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer);
}
}

View File

@@ -0,0 +1,411 @@
//------------------------------------------------------------------------------
// <copyright file="JavaScriptObjectDeserializer.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Serialization {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Resources;
using AppSettings = System.Web.Util.AppSettings;
using Debug = System.Web.Util.Debug;
using Utf16StringValidator = System.Web.Util.Utf16StringValidator;
internal class JavaScriptObjectDeserializer {
private const string DateTimePrefix = @"""\/Date(";
private const int DateTimePrefixLength = 8;
private const string DateTimeSuffix = @"\/""";
private const int DateTimeSuffixLength = 3;
internal JavaScriptString _s;
private JavaScriptSerializer _serializer;
private int _depthLimit;
internal static object BasicDeserialize(string input, int depthLimit, JavaScriptSerializer serializer) {
JavaScriptObjectDeserializer jsod = new JavaScriptObjectDeserializer(input, depthLimit, serializer);
object result = jsod.DeserializeInternal(0);
if (jsod._s.GetNextNonEmptyChar() != null) {
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.JSON_IllegalPrimitive, jsod._s.ToString()));
}
return result;
}
private JavaScriptObjectDeserializer(string input, int depthLimit, JavaScriptSerializer serializer) {
_s = new JavaScriptString(input);
_depthLimit = depthLimit;
_serializer = serializer;
}
private object DeserializeInternal(int depth) {
if (++depth > _depthLimit) {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_DepthLimitExceeded));
}
Nullable<Char> c = _s.GetNextNonEmptyChar();
if (c == null) {
return null;
}
_s.MovePrev();
if (IsNextElementDateTime()) {
return DeserializeStringIntoDateTime();
}
if (IsNextElementObject(c)) {
IDictionary<string, object> dict = DeserializeDictionary(depth);
// Try to coerce objects to the right type if they have the __serverType
if (dict.ContainsKey(JavaScriptSerializer.ServerTypeFieldName)) {
return ObjectConverter.ConvertObjectToType(dict, null, _serializer);
}
return dict;
}
if (IsNextElementArray(c)) {
return DeserializeList(depth);
}
if (IsNextElementString(c)) {
return DeserializeString();
}
return DeserializePrimitiveObject();
}
private IList DeserializeList(int depth) {
IList list = new ArrayList();
Nullable<Char> c = _s.MoveNext();
if (c != '[') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidArrayStart));
}
bool expectMore = false;
while ((c = _s.GetNextNonEmptyChar()) != null && c != ']') {
_s.MovePrev();
object o = DeserializeInternal(depth);
list.Add(o);
expectMore = false;
// we might be done here.
c = _s.GetNextNonEmptyChar();
if (c == ']') {
break;
}
expectMore = true;
if (c != ',') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidArrayExpectComma));
}
}
if (expectMore) {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidArrayExtraComma));
}
if (c != ']') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidArrayEnd));
}
return list;
}
private IDictionary<string, object> DeserializeDictionary(int depth) {
IDictionary<string, object> dictionary = null;
Nullable<Char> c = _s.MoveNext();
if (c != '{') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_ExpectedOpenBrace));
}
// Loop through each JSON entry in the input object
while ((c = _s.GetNextNonEmptyChar()) != null) {
_s.MovePrev();
if (c == ':') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidMemberName));
}
string memberName = null;
if (c != '}') {
// Find the member name
memberName = DeserializeMemberName();
c = _s.GetNextNonEmptyChar();
if (c != ':') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidObject));
}
}
if (dictionary == null) {
dictionary = new Dictionary<string, object>();
// If the object contains nothing (i.e. {}), we're done
if (memberName == null) {
// Move the cursor to the '}' character.
c = _s.GetNextNonEmptyChar();
Debug.Assert(c == '}');
break;
}
}
ThrowIfMaxJsonDeserializerMembersExceeded(dictionary.Count);
// Deserialize the property value. Here, we don't know its type
object propVal = DeserializeInternal(depth);
dictionary[memberName] = propVal;
c = _s.GetNextNonEmptyChar();
if (c == '}') {
break;
}
if (c != ',') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidObject));
}
}
if (c != '}') {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_InvalidObject));
}
return dictionary;
}
// MSRC 12038: limit the maximum number of entries that can be added to a Json deserialized dictionary,
// as a large number of entries potentially can result in too many hash collisions that may cause DoS
private void ThrowIfMaxJsonDeserializerMembersExceeded(int count) {
if (count >= AppSettings.MaxJsonDeserializerMembers) {
throw new InvalidOperationException(SR.GetString(SR.CollectionCountExceeded_JavaScriptObjectDeserializer, AppSettings.MaxJsonDeserializerMembers));
}
}
// Deserialize a member name.
// e.g. { MemberName: ... }
// e.g. { 'MemberName': ... }
// e.g. { "MemberName": ... }
private string DeserializeMemberName() {
// It could be double quoted, single quoted, or not quoted at all
Nullable<Char> c = _s.GetNextNonEmptyChar();
if (c == null) {
return null;
}
_s.MovePrev();
// If it's quoted, treat it as a string
if (IsNextElementString(c)) {
return DeserializeString();
}
// Non-quoted token
return DeserializePrimitiveToken();
}
private object DeserializePrimitiveObject() {
string input = DeserializePrimitiveToken();
if (input.Equals("null")) {
return null;
}
if (input.Equals("true")) {
return true;
}
if (input.Equals("false")) {
return false;
}
// Is it a floating point value
bool hasDecimalPoint = input.IndexOf('.') >= 0;
// DevDiv 56892: don't try to parse to Int32/64/Decimal if it has an exponent sign
bool hasExponent = input.LastIndexOf("e", StringComparison.OrdinalIgnoreCase) >= 0;
// [Last]IndexOf(char, StringComparison) overload doesn't exist, so search for "e" as a string not a char
// Use 'Last'IndexOf since if there is an exponent it would be more quickly found starting from the end of the string
// since 'e' is always toward the end of the number. e.g. 1.238907598768972987E82
if (!hasExponent) {
// when no exponent, could be Int32, Int64, Decimal, and may fall back to Double
// otherwise it must be Double
if (!hasDecimalPoint) {
// No decimal or exponent. All Int32 and Int64s fall into this category, so try them first
// First try int
int n;
if (Int32.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out n)) {
// NumberStyles.Integer: AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign
return n;
}
// Then try a long
long l;
if (Int64.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out l)) {
// NumberStyles.Integer: AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign
return l;
}
}
// No exponent, may or may not have a decimal (if it doesn't it couldn't be parsed into Int32/64)
decimal dec;
if (decimal.TryParse(input, NumberStyles.Number, CultureInfo.InvariantCulture, out dec)) {
// NumberStyles.Number: AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign,
// AllowTrailingSign, AllowDecimalPoint, AllowThousands
return dec;
}
}
// either we have an exponent or the number couldn't be parsed into any previous type.
Double d;
if (Double.TryParse(input, NumberStyles.Float, CultureInfo.InvariantCulture, out d)) {
// NumberStyles.Float: AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowDecimalPoint, AllowExponent
return d;
}
// must be an illegal primitive
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.JSON_IllegalPrimitive, input));
}
private string DeserializePrimitiveToken() {
StringBuilder sb = new StringBuilder();
Nullable<Char> c = null;
while ((c = _s.MoveNext()) != null) {
if (Char.IsLetterOrDigit(c.Value) || c.Value == '.' ||
c.Value == '-' || c.Value == '_' || c.Value == '+') {
sb.Append(c.Value);
}
else {
_s.MovePrev();
break;
}
}
return sb.ToString();
}
private string DeserializeString() {
StringBuilder sb = new StringBuilder();
bool escapedChar = false;
Nullable<Char> c = _s.MoveNext();
// First determine which quote is used by the string.
Char quoteChar = CheckQuoteChar(c);
while ((c = _s.MoveNext()) != null) {
if (c == '\\') {
if (escapedChar) {
sb.Append('\\');
escapedChar = false;
}
else {
escapedChar = true;
}
continue;
}
if (escapedChar) {
AppendCharToBuilder(c, sb);
escapedChar = false;
}
else {
if (c == quoteChar) {
return Utf16StringValidator.ValidateString(sb.ToString());
}
sb.Append(c.Value);
}
}
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_UnterminatedString));
}
private void AppendCharToBuilder(char? c, StringBuilder sb) {
if (c == '"' || c == '\'' || c == '/') {
sb.Append(c.Value);
}
else if (c == 'b') {
sb.Append('\b');
}
else if (c == 'f') {
sb.Append('\f');
}
else if (c == 'n') {
sb.Append('\n');
}
else if (c == 'r') {
sb.Append('\r');
}
else if (c == 't') {
sb.Append('\t');
}
else if (c == 'u') {
sb.Append((char)int.Parse(_s.MoveNext(4), NumberStyles.HexNumber, CultureInfo.InvariantCulture));
}
else {
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_BadEscape));
}
}
private char CheckQuoteChar(char? c) {
Char quoteChar = '"';
if (c == '\'') {
quoteChar = c.Value;
}
else if (c != '"') {
// Fail if the string is not quoted.
throw new ArgumentException(_s.GetDebugString(AtlasWeb.JSON_StringNotQuoted));
}
return quoteChar;
}
private object DeserializeStringIntoDateTime() {
// DivDiv 41127: Never confuse atlas serialized strings with dates.
// DevDiv 74430: JavasciptSerializer will need to handle date time offset - following WCF design
// serialized dates look like: "\/Date(123)\/" or "\/Date(123A)" or "Date(123+4567)" or Date(123-4567)"
// the A, +14567, -4567 portion in the above example is ignored
int pos = _s.IndexOf(DateTimeSuffix);
Match match = Regex.Match(_s.Substring(pos + DateTimeSuffixLength),
@"^""\\/Date\((?<ticks>-?[0-9]+)(?:[a-zA-Z]|(?:\+|-)[0-9]{4})?\)\\/""");
string ticksStr = match.Groups["ticks"].Value;
long ticks;
if (long.TryParse(ticksStr, out ticks)) {
_s.MoveNext(match.Length);
// The javascript ticks start from 1/1/1970 but FX DateTime ticks start from 1/1/0001
DateTime dt = new DateTime(ticks * 10000 + JavaScriptSerializer.DatetimeMinTimeTicks, DateTimeKind.Utc);
return dt;
}
else {
// If we failed to get a DateTime, treat it as a string
return DeserializeString();
}
}
private static bool IsNextElementArray(Nullable<Char> c) {
return c == '[';
}
private bool IsNextElementDateTime() {
String next = _s.MoveNext(DateTimePrefixLength);
if (next != null) {
_s.MovePrev(DateTimePrefixLength);
return String.Equals(next, DateTimePrefix, StringComparison.Ordinal);
}
return false;
}
private static bool IsNextElementObject(Nullable<Char> c) {
return c == '{';
}
private static bool IsNextElementString(Nullable<Char> c) {
return c == '"' || c == '\'';
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
//------------------------------------------------------------------------------
// <copyright file="JavaScriptString.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Serialization {
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
internal class JavaScriptString {
private string _s;
private int _index;
internal JavaScriptString(string s) {
_s = s;
}
internal Nullable<char> GetNextNonEmptyChar() {
while (_s.Length > _index) {
char c = _s[_index++];
if (!Char.IsWhiteSpace(c)) {
return c;
}
}
return null;
}
internal Nullable<char> MoveNext() {
if (_s.Length > _index) {
return _s[_index++];
}
return null;
}
internal string MoveNext(int count) {
if (_s.Length >= _index + count) {
string result = _s.Substring(_index, count);
_index += count;
return result;
}
return null;
}
internal void MovePrev() {
if (_index > 0) {
_index--;
}
}
internal void MovePrev(int count) {
while (_index > 0 && count > 0) {
_index--;
count--;
}
}
public override string ToString() {
if (_s.Length > _index) {
return _s.Substring(_index);
}
return String.Empty;
}
internal string GetDebugString(string message) {
return message + " (" + _index + "): " + _s;
}
internal int IndexOf(string substr) {
if (_s.Length > _index) {
return _s.IndexOf(substr, _index, StringComparison.CurrentCulture) - _index;
}
return -1;
}
internal string Substring(int length) {
if (_s.Length > _index + length) {
return _s.Substring(_index, length);
}
return ToString();
}
}
}

View File

@@ -0,0 +1,15 @@
//------------------------------------------------------------------------------
// <copyright file="JavaScriptTypeResolver.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Serialization {
using System;
using System.Web;
public abstract class JavaScriptTypeResolver {
public abstract Type ResolveType(string id);
public abstract string ResolveTypeId(Type type);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
//------------------------------------------------------------------------------
// <copyright file="ScriptIgnoreAttribute.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Serialization {
using System;
using System.Web;
[
AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple=false, Inherited=true)
]
public sealed class ScriptIgnoreAttribute : Attribute {
public ScriptIgnoreAttribute() {
}
public bool ApplyToOverrides {
get;
set;
}
}
}

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <copyright file="SimpleTypeResolver.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Script.Serialization {
using System;
using System.Web;
public class SimpleTypeResolver : JavaScriptTypeResolver {
public override Type ResolveType(string id) {
return Type.GetType(id);
}
public override string ResolveTypeId(Type type) {
if (type == null) {
throw new ArgumentNullException("type");
}
return type.AssemblyQualifiedName;
}
}
}

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() {
}
}
}

Some files were not shown because too many files have changed in this diff Show More