You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user