Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWeb / Server / System / Data / Services / Serializers / JsonDeserializer.cs / 1 / JsonDeserializer.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Provides a deserializer for json content.
//
//
// @owner [....]
//---------------------------------------------------------------------
namespace System.Data.Services.Serializers
{
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Data.Services.Providers;
///
/// Provides a deserializer for json content.
///
internal class JsonDeserializer : Deserializer
{
/// json reader which reads json content
private readonly JsonReader jsonReader;
/// Initializes a new for the specified stream.
/// input stream reader from which json content must be read.
/// indicates whether this is a update operation or not
/// Data service for which the deserializer will act.
/// Tracker to use for modifications.
internal JsonDeserializer(StreamReader request, bool update, IDataService dataService, UpdateTracker tracker)
: base(update, dataService, tracker)
{
Debug.Assert(request != null, "request != null");
this.jsonReader = new JsonReader(request);
}
/// returns the content format for the deserializer
protected override ContentFormat ContentFormat
{
get
{
return ContentFormat.Json;
}
}
///
/// Converts the given value to the expected type as per json reader rules
/// Make sure these rules are in [....] with jsonwriter.
///
/// value to the converted
/// name of the property whose value is getting converted
/// clr type to which the value needs to be converted to
/// object which is in [....] with the properties type
internal static object ConvertValues(object value, string propertyName, Type typeToBeConverted)
{
if (value == null)
{
return null;
}
Type propertyType = Nullable.GetUnderlyingType(typeToBeConverted) ?? typeToBeConverted;
try
{
string stringValue = value as string;
if (stringValue != null)
{
if (propertyType == typeof(byte[]))
{
return Convert.FromBase64String(stringValue);
}
else if (propertyType == typeof(System.Data.Linq.Binary))
{
return new System.Data.Linq.Binary(Convert.FromBase64String(stringValue));
}
else if (propertyType == typeof(System.Xml.Linq.XElement))
{
return System.Xml.Linq.XElement.Parse(stringValue, System.Xml.Linq.LoadOptions.PreserveWhitespace);
}
else if (propertyType == typeof(Guid))
{
return new Guid(stringValue);
}
else
{
// For string types, we support conversion to all possible primitive types
return Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture);
}
}
else if (value is Int32)
{
int intValue = (int)value;
if (propertyType == typeof(Int16))
{
return Convert.ToInt16(intValue);
}
else if (propertyType == typeof(Byte))
{
return Convert.ToByte(intValue);
}
else if (propertyType == typeof(SByte))
{
return Convert.ToSByte(intValue);
}
else if (propertyType == typeof(Single))
{
return Convert.ToSingle(intValue);
}
else if (propertyType == typeof(Double))
{
return Convert.ToDouble(intValue);
}
else if (propertyType == typeof(Decimal) ||
propertyType == typeof(Int64))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ErrorInConvertingNumericValues(propertyName));
}
}
else if (value is Double)
{
Double doubleValue = (Double)value;
if (propertyType == typeof(Single))
{
return Convert.ToSingle(doubleValue);
}
}
}
catch (Exception e)
{
if (WebUtil.IsCatchableExceptionType(e))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ErrorInConvertingPropertyValue(propertyName, propertyType.Name), e);
}
}
// otherwise just return the value without doing any conversion
return value;
}
///
/// Assumes the payload to represent a single object and processes accordingly
///
/// info about the object being created
/// the newly formed object that the payload represents
protected override object CreateSingleObject(SegmentInfo segmentInfo)
{
object jsonObject = this.jsonReader.ReadValue();
bool existingRelationship;
return this.CreateObject(jsonObject, segmentInfo, true /*topLevel*/, out existingRelationship);
}
/// Provides an opportunity to clean-up resources.
///
/// Whether the call is being made from an explicit call to
/// IDisposable.Dispose() rather than through the finalizer.
///
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
this.jsonReader.Dispose();
}
}
///
/// Get the resource referred by the uri in the payload
///
/// resource referred by the uri in the payload.
protected override string GetLinkUriFromPayload()
{
object jsonObject = this.jsonReader.ReadValue();
// Otherwise top level json content must be Hashtable, since we don't allow multiple inserts
// at the top level
Hashtable jsonObjectHashtable = jsonObject as Hashtable;
if (jsonObjectHashtable == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
string uri = ReadUri(jsonObjectHashtable);
if (String.IsNullOrEmpty(uri))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MissingUriForLinkOperation);
}
return uri;
}
///
/// Gets the array list object
///
/// object representing json array
/// strongly type array list object that json object represents
private static ArrayList GetArrayList(object jsonObject)
{
ArrayList arrayList = jsonObject as ArrayList;
if (arrayList == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ResourceSetPropertyMustBeArray);
}
return arrayList;
}
///
/// Verifies if the given element value is a deferred element or not
///
/// element value
/// true if this value is a deferred content else returns false
private static bool IsDeferredElement(object element)
{
Hashtable hashtable = element as Hashtable;
if (hashtable != null && hashtable.Count == 1 && hashtable[XmlConstants.JsonDeferredString] != null)
{
return true;
}
return false;
}
///
/// Returns true if the payload is correct for the top level non-entity target.
///
/// json object representing the data in the payload.
/// information about the last segment in the request uri.
/// resource object as specified in the payload.
/// returns true if the payload is correct for non-entity resource.
private static bool HandleTopLevelNonEntityProperty(Hashtable jsonObject, SegmentInfo segment, out object resource)
{
Debug.Assert(jsonObject != null, "jsonObject != null");
Debug.Assert(segment != null, "segment != null");
resource = null;
if (segment.TargetKind == RequestTargetKind.Primitive ||
#if ASTORIA_OPEN_OBJECT
segment.TargetKind == RequestTargetKind.OpenProperty ||
#endif
segment.TargetKind == RequestTargetKind.ComplexObject)
{
if (jsonObject.Count == 1 && jsonObject.ContainsKey(segment.Identifier))
{
// For open property, assume it to be a primitive or complex payload.
// If its targeting an entity, then the type must be specified
resource = jsonObject[segment.Identifier];
return true;
}
else
#if ASTORIA_OPEN_OBJECT
if (segment.TargetKind != RequestTargetKind.OpenProperty)
#endif
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
}
// its an entity resource payload
return false;
}
///
/// Read the uri from the json object
///
/// metadata object which contains the uri.
/// returns the uri as specified in the object.
private static string ReadUri(Hashtable metadata)
{
string uri = null;
// Get the uri for the metadata element
object uriObject = metadata[XmlConstants.JsonUriString];
if (uriObject != null)
{
uri = uriObject as string;
if (uri == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidUriMetadata);
}
}
return uri;
}
///
/// Create the object given the list of the properties. One of the properties will be __metadata property
/// which will contain type information
///
/// list of the properties and values specified in the payload
/// info about the object being created
/// true if the current object is a top level one, otherwise false
/// does this resource already binded to its parent
/// instance of the object created
private object CreateObject(object jsonObject, SegmentInfo segmentInfo, bool topLevel, out bool existingRelationship)
{
this.RecurseEnter();
existingRelationship = true;
bool existingResource = true;
object resource = null;
ResourceType resourceType;
Hashtable jsonObjectHashtable;
if (topLevel)
{
// Every top level json content must be Hashtable - primitive, complex or entity
jsonObjectHashtable = jsonObject as Hashtable;
if (jsonObjectHashtable == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
object nonEntityResource;
if (HandleTopLevelNonEntityProperty(jsonObjectHashtable, segmentInfo, out nonEntityResource))
{
// if the segment refers to primitive type, then return the value
if (segmentInfo.TargetKind == RequestTargetKind.Primitive ||
#if ASTORIA_OPEN_OBJECT
(segmentInfo.TargetKind == RequestTargetKind.OpenProperty && WebUtil.IsPrimitiveType(nonEntityResource.GetType())) ||
#endif
nonEntityResource == null)
{
return nonEntityResource;
}
jsonObject = nonEntityResource;
}
}
else if (
jsonObject == null ||
#if ASTORIA_OPEN_OBJECT
(segmentInfo.TargetKind == RequestTargetKind.OpenProperty && WebUtil.IsPrimitiveType(jsonObject.GetType())) ||
#endif
segmentInfo.TargetKind == RequestTargetKind.Primitive)
{
// For reference properties, we do not know if there was already some relationship setup
// By setting it to null, we are unbinding the old relationship and hence existing relationship
// is false
// For open properties, if its null, there is no way we will be able to deduce the type
existingRelationship = false;
return jsonObject;
}
// Otherwise top level json content must be Hashtable, since we don't allow multiple inserts
// at the top level
jsonObjectHashtable = jsonObject as Hashtable;
if (jsonObjectHashtable == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
ResourceType targetResourceType = null;
#if ASTORIA_OPEN_OBJECT
if (segmentInfo.TargetKind != RequestTargetKind.OpenProperty)
#endif
{
targetResourceType = this.Service.Provider.GetResourceType(segmentInfo.TargetElementType);
Debug.Assert(targetResourceType != null, "Should be able to resolve type for well known segments");
Debug.Assert(
targetResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType || targetResourceType.ResourceTypeKind == ResourceTypeKind.EntityType,
"targetType must be entity type or complex type");
}
// Get the type and uri from the metadata element, if specified
string uri;
bool metadataElementSpecified;
resourceType = this.GetTypeAndUriFromMetadata(
jsonObjectHashtable,
targetResourceType,
topLevel,
out uri,
out metadataElementSpecified);
Debug.Assert((resourceType != null && resourceType.ResourceTypeKind != ResourceTypeKind.Primitive) || uri != null, "Either uri or resource type must be specified");
this.CheckAndIncrementObjectCount();
if ((resourceType != null && resourceType.ResourceTypeKind != ResourceTypeKind.ComplexType) ||
uri != null)
{
// For inserts/updates, its okay not to specify anything in the payload.
// Someone might just want to create a entity with default values or
// merge nothing or replace everything with default values.
if (this.Update)
{
if (!topLevel)
{
if (metadataElementSpecified && jsonObjectHashtable.Count > 1 ||
!metadataElementSpecified)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_DeepUpdateNotSupported);
}
else if (uri == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_UriMissingForUpdateForDeepUpdates);
}
}
if (topLevel)
{
// Checking for merge vs replace semantics
// Only checking for top level resource entity
// since we don't support update of deep resources
resource = CreateObjectFromUri(
resourceType,
segmentInfo,
(RequestDescription)null,
true /*checkETag*/,
true /*checkForNull*/,
this.Service.RequestParams.AstoriaHttpVerb == AstoriaVerbs.PUT /*replaceResource*/);
}
else
{
// case of binding at the first level.
existingRelationship = false;
return CreateObjectFromUri(resourceType, segmentInfo, uri, false /*checkETag*/, false /*checkForNull*/);
}
}
else
{
// For insert, its a new resource that is getting created or an existing resource
// getting binded. Either case, its a new relationship.
existingRelationship = false;
// For POST operations, the following rules holds true:
// 1> If the uri is specified for navigation properties and no other property is specified, then its a bind operation.
// Otherwise, ignore the uri and insert the new resource.
if (uri != null)
{
if (segmentInfo.TargetSource == RequestTargetSource.Property && jsonObjectHashtable.Count == 1)
{
this.RecurseLeave();
return CreateObjectFromUri(resourceType, null, uri, false /*checkETag*/, false /*checkForNull*/);
}
}
}
}
Debug.Assert(resourceType != null, "resourceType != null");
if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
{
Debug.Assert(resource == null, "resource == null");
resource = this.Service.Provider.CreateResource(null, resourceType.FullName);
existingResource = false;
}
else if (!this.Update)
{
Debug.Assert(resource == null, "resource == null");
if (segmentInfo.TargetKind == RequestTargetKind.Resource)
{
// check for append rights whenever we need to create a resource
this.Service.Configuration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend);
resource = this.Service.Provider.CreateResource(segmentInfo.TargetContainer.Name, resourceType.FullName);
this.Tracker.TrackAction(resource, segmentInfo.TargetContainer, UpdateOperations.Add);
}
#if ASTORIA_OPEN_OBJECT
else
{
Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.OpenProperty, "segmentInfo.TargetKind == RequestTargetKind.OpenProperty");
ResourceContainer container = this.Service.Provider.GetContainerForResourceType(resourceType.Type);
resource = this.Service.Provider.CreateResource(container.Name, resourceType.FullName);
}
#endif
existingResource = false;
}
bool changed = this.PopulateProperties(jsonObjectHashtable, resource, resourceType);
// For put operations, you need not specify any property and that means reset all the properties.
// hence for put operations, change is always true.
changed = changed || this.Service.RequestParams.AstoriaHttpVerb == AstoriaVerbs.PUT;
if (changed && existingResource && segmentInfo.TargetContainer != null)
{
this.Tracker.TrackAction(resource, segmentInfo.TargetContainer, UpdateOperations.Change);
}
this.RecurseLeave();
return resource;
}
///
/// Populate the properties of the given resource
///
/// hashtable containing property name and values
/// instance of the resource whose properties needs to be populated
/// resource type whose properties needs to be populated
/// true if any properties were set; false otherwise.
private bool PopulateProperties(Hashtable jsonObject, object resource, ResourceType parentResourceType)
{
// Update all the properties specified in the payload.
// Don't touch the properties which are not specified. Its upto the provider to interpret
// the meaning of things which are not specified
bool changed = false;
foreach (string propertyName in jsonObject.Keys)
{
// Ignore the metadata property
if (propertyName == XmlConstants.JsonMetadataString)
{
continue;
}
// Check if the property exists and try and set the value
ResourceProperty resourceProperty = parentResourceType.TryResolvePropertyName(propertyName);
if (
#if ASTORIA_OPEN_OBJECT
parentResourceType.OpenTypeKind != OpenTypeKind.CompletelyOpen &&
#endif
resourceProperty == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(propertyName, parentResourceType.FullName));
}
// Get the property value, set it appropriately, and mark the object as changed.
object propertyValue = jsonObject[propertyName];
bool existingRelationship;
// If its a open property
if (resourceProperty == null)
{
#if ASTORIA_OPEN_OBJECT
this.HandleOpenTypeProperties(resource, propertyName, propertyValue);
#endif
changed = true;
}
else if (resourceProperty.TypeKind == ResourceTypeKind.ComplexType)
{
SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, true /* singleResult */);
segmentInfo.TargetKind = RequestTargetKind.ComplexObject;
propertyValue = this.CreateObject(propertyValue, segmentInfo, false /*topLevel*/, out existingRelationship);
SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service.Provider);
changed = true;
}
else if (resourceProperty.TypeKind == ResourceTypeKind.Primitive)
{
// Ignoring the value of key properties in PUT payload
if (!this.Update || !resourceProperty.IsOfKind(ResourcePropertyKind.Key))
{
SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service.Provider);
}
changed = true;
}
else
{
Debug.Assert(ResourceTypeKind.EntityType == resourceProperty.TypeKind, "only expecting nav properties");
if (IsDeferredElement(propertyValue))
{
// Skip the deferred element
continue;
}
else
{
Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb);
if (resourceProperty.Kind == ResourcePropertyKind.ResourceReference)
{
SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, true /* singleResult */);
segmentInfo.TargetKind = RequestTargetKind.Resource;
// For navigation property, allow both inserts and binding in this case
propertyValue = this.CreateObject(propertyValue, segmentInfo, false /*topLevel*/, out existingRelationship);
if (!existingRelationship)
{
this.Service.Provider.SetReference(resource, resourceProperty.Name, propertyValue);
}
changed = true;
}
else if (resourceProperty.Kind == ResourcePropertyKind.ResourceSetReference)
{
if (propertyValue == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName));
}
ArrayList resourceCollection = GetArrayList(propertyValue);
SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, true /* singleResult */);
foreach (object resourceObject in resourceCollection)
{
object resourceInstance = this.CreateObject(resourceObject, segmentInfo, false /*topLevel*/, out existingRelationship);
Debug.Assert(resourceInstance != null, "resourceInstance != null");
if (!existingRelationship)
{
this.Service.Provider.AddReferenceToCollection(resource, resourceProperty.Name, resourceInstance);
}
changed = true;
}
}
}
}
}
return changed;
}
#if ASTORIA_OPEN_OBJECT
///
/// Handle the open type property
///
/// parent resource to which the open property belongs to
/// name of the property
/// value of the property
private void HandleOpenTypeProperties(object parentResource, string propertyName, object propertyValue)
{
bool existingRelationship;
if (IsDeferredElement(propertyValue))
{
// Skip the deferred element
return;
}
// Check if its a collection or not
ArrayList arrayList = propertyValue as ArrayList;
if (arrayList == null)
{
SegmentInfo openPropertySegmentInfo = CreateSegment(null, propertyName, true /* singleResult */);
propertyValue = this.CreateObject(
propertyValue,
openPropertySegmentInfo,
false /*topLevel*/,
out existingRelationship);
// Resolve the type of the value
if (propertyValue == null || WebUtil.IsPrimitiveType(propertyValue.GetType()))
{
// For open properties, just set the value since we only support primitive type properties as
// open properties
SetOpenPropertyValue(parentResource, propertyName, propertyValue, this.Service.Provider);
}
else
{
ResourceType openPropertyResourceType = this.Service.Provider.GetResourceType(propertyValue.GetType());
if (openPropertyResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
{
this.Service.Provider.SetValue(parentResource, propertyName, propertyValue);
}
else
{
Debug.Assert(openPropertyResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "resource must be of entity type");
Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb);
if (!existingRelationship)
{
this.Service.Provider.SetReference(parentResource, propertyName, propertyValue);
}
}
}
}
else
{
Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb);
SegmentInfo openPropertySegmentInfo = CreateSegment(null, propertyName, false /* singleResult */);
foreach (object openPropertyValue in arrayList)
{
propertyValue = this.CreateObject(
openPropertyValue,
openPropertySegmentInfo,
false /*topLevel*/,
out existingRelationship);
if (propertyValue == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName));
}
if (!existingRelationship)
{
this.Service.Provider.AddReferenceToCollection(parentResource, propertyName, propertyValue);
}
}
}
}
#endif
///
/// Gets the type and uri specified in the metadata object in the given json object.
///
/// jsonObject which contains the metadata information
/// expected type that this segment of the uri is targeted to
/// whether the segment represents the top level object.
/// uri as specified in the metadata object. If its not specified, this is set to null
/// returns true if the metadata element was specified
/// typename and uri as specified in the metadata object
private ResourceType GetTypeAndUriFromMetadata(
Hashtable jsonObject,
ResourceType expectedType,
bool topLevel,
out string uri,
out bool metadataElementSpecified)
{
metadataElementSpecified = false;
// Get the metadata object
object metadataObject = jsonObject[XmlConstants.JsonMetadataString];
ResourceType targetType = expectedType;
bool typeNameSpecified = false;
uri = null;
if (metadataObject != null)
{
metadataElementSpecified = true;
Hashtable metadata = metadataObject as Hashtable;
if (metadata == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidMetadataContent);
}
// Get the type information from the metadata object. if the type name is not specified,
// then return the expectedType as the target type
object objectTypeName = metadata[XmlConstants.JsonTypeString];
if (objectTypeName != null)
{
string typeName = objectTypeName as string;
if (string.IsNullOrEmpty(typeName))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidTypeMetadata);
}
// Resolve resource type name
targetType = this.Service.Provider.TryResolveTypeName(typeName);
if (targetType == null || targetType.ResourceTypeKind == ResourceTypeKind.Primitive)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName));
}
if (expectedType != null && !expectedType.Type.IsAssignableFrom(targetType.Type))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeSpecified(typeName, expectedType.FullName));
}
typeNameSpecified = true;
}
uri = JsonDeserializer.ReadUri(metadata);
}
// Type information is optional for bind operations.
// Top level operations cannot be bind operations, since uri need to have $links
// for top level bind operations and that's a different code path.
// For bind operations, uri must be specified and nothing else should be specified.
bool bindOperation = !topLevel && uri != null && jsonObject.Count == 1;
// type name must be specified for POST or PUT/MERGE operations.
if (!typeNameSpecified)
{
if (!bindOperation)
{
if (expectedType == null)
{
// For open properties, you must specify the type information
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingTypeInformationForOpenTypeProperties);
}
else if (expectedType.HasDerivedTypes)
{
// For types that take part in inheritance, type information must be specified.
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance);
}
}
else
{
// If the type name is not specified, we should set the type name to null, since in case of inheritance,
// we don't want to guess the type information.
targetType = null;
}
}
return targetType;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Provides a deserializer for json content.
//
//
// @owner [....]
//---------------------------------------------------------------------
namespace System.Data.Services.Serializers
{
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Data.Services.Providers;
///
/// Provides a deserializer for json content.
///
internal class JsonDeserializer : Deserializer
{
/// json reader which reads json content
private readonly JsonReader jsonReader;
/// Initializes a new for the specified stream.
/// input stream reader from which json content must be read.
/// indicates whether this is a update operation or not
/// Data service for which the deserializer will act.
/// Tracker to use for modifications.
internal JsonDeserializer(StreamReader request, bool update, IDataService dataService, UpdateTracker tracker)
: base(update, dataService, tracker)
{
Debug.Assert(request != null, "request != null");
this.jsonReader = new JsonReader(request);
}
/// returns the content format for the deserializer
protected override ContentFormat ContentFormat
{
get
{
return ContentFormat.Json;
}
}
///
/// Converts the given value to the expected type as per json reader rules
/// Make sure these rules are in [....] with jsonwriter.
///
/// value to the converted
/// name of the property whose value is getting converted
/// clr type to which the value needs to be converted to
/// object which is in [....] with the properties type
internal static object ConvertValues(object value, string propertyName, Type typeToBeConverted)
{
if (value == null)
{
return null;
}
Type propertyType = Nullable.GetUnderlyingType(typeToBeConverted) ?? typeToBeConverted;
try
{
string stringValue = value as string;
if (stringValue != null)
{
if (propertyType == typeof(byte[]))
{
return Convert.FromBase64String(stringValue);
}
else if (propertyType == typeof(System.Data.Linq.Binary))
{
return new System.Data.Linq.Binary(Convert.FromBase64String(stringValue));
}
else if (propertyType == typeof(System.Xml.Linq.XElement))
{
return System.Xml.Linq.XElement.Parse(stringValue, System.Xml.Linq.LoadOptions.PreserveWhitespace);
}
else if (propertyType == typeof(Guid))
{
return new Guid(stringValue);
}
else
{
// For string types, we support conversion to all possible primitive types
return Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture);
}
}
else if (value is Int32)
{
int intValue = (int)value;
if (propertyType == typeof(Int16))
{
return Convert.ToInt16(intValue);
}
else if (propertyType == typeof(Byte))
{
return Convert.ToByte(intValue);
}
else if (propertyType == typeof(SByte))
{
return Convert.ToSByte(intValue);
}
else if (propertyType == typeof(Single))
{
return Convert.ToSingle(intValue);
}
else if (propertyType == typeof(Double))
{
return Convert.ToDouble(intValue);
}
else if (propertyType == typeof(Decimal) ||
propertyType == typeof(Int64))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ErrorInConvertingNumericValues(propertyName));
}
}
else if (value is Double)
{
Double doubleValue = (Double)value;
if (propertyType == typeof(Single))
{
return Convert.ToSingle(doubleValue);
}
}
}
catch (Exception e)
{
if (WebUtil.IsCatchableExceptionType(e))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ErrorInConvertingPropertyValue(propertyName, propertyType.Name), e);
}
}
// otherwise just return the value without doing any conversion
return value;
}
///
/// Assumes the payload to represent a single object and processes accordingly
///
/// info about the object being created
/// the newly formed object that the payload represents
protected override object CreateSingleObject(SegmentInfo segmentInfo)
{
object jsonObject = this.jsonReader.ReadValue();
bool existingRelationship;
return this.CreateObject(jsonObject, segmentInfo, true /*topLevel*/, out existingRelationship);
}
/// Provides an opportunity to clean-up resources.
///
/// Whether the call is being made from an explicit call to
/// IDisposable.Dispose() rather than through the finalizer.
///
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
this.jsonReader.Dispose();
}
}
///
/// Get the resource referred by the uri in the payload
///
/// resource referred by the uri in the payload.
protected override string GetLinkUriFromPayload()
{
object jsonObject = this.jsonReader.ReadValue();
// Otherwise top level json content must be Hashtable, since we don't allow multiple inserts
// at the top level
Hashtable jsonObjectHashtable = jsonObject as Hashtable;
if (jsonObjectHashtable == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
string uri = ReadUri(jsonObjectHashtable);
if (String.IsNullOrEmpty(uri))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MissingUriForLinkOperation);
}
return uri;
}
///
/// Gets the array list object
///
/// object representing json array
/// strongly type array list object that json object represents
private static ArrayList GetArrayList(object jsonObject)
{
ArrayList arrayList = jsonObject as ArrayList;
if (arrayList == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ResourceSetPropertyMustBeArray);
}
return arrayList;
}
///
/// Verifies if the given element value is a deferred element or not
///
/// element value
/// true if this value is a deferred content else returns false
private static bool IsDeferredElement(object element)
{
Hashtable hashtable = element as Hashtable;
if (hashtable != null && hashtable.Count == 1 && hashtable[XmlConstants.JsonDeferredString] != null)
{
return true;
}
return false;
}
///
/// Returns true if the payload is correct for the top level non-entity target.
///
/// json object representing the data in the payload.
/// information about the last segment in the request uri.
/// resource object as specified in the payload.
/// returns true if the payload is correct for non-entity resource.
private static bool HandleTopLevelNonEntityProperty(Hashtable jsonObject, SegmentInfo segment, out object resource)
{
Debug.Assert(jsonObject != null, "jsonObject != null");
Debug.Assert(segment != null, "segment != null");
resource = null;
if (segment.TargetKind == RequestTargetKind.Primitive ||
#if ASTORIA_OPEN_OBJECT
segment.TargetKind == RequestTargetKind.OpenProperty ||
#endif
segment.TargetKind == RequestTargetKind.ComplexObject)
{
if (jsonObject.Count == 1 && jsonObject.ContainsKey(segment.Identifier))
{
// For open property, assume it to be a primitive or complex payload.
// If its targeting an entity, then the type must be specified
resource = jsonObject[segment.Identifier];
return true;
}
else
#if ASTORIA_OPEN_OBJECT
if (segment.TargetKind != RequestTargetKind.OpenProperty)
#endif
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
}
// its an entity resource payload
return false;
}
///
/// Read the uri from the json object
///
/// metadata object which contains the uri.
/// returns the uri as specified in the object.
private static string ReadUri(Hashtable metadata)
{
string uri = null;
// Get the uri for the metadata element
object uriObject = metadata[XmlConstants.JsonUriString];
if (uriObject != null)
{
uri = uriObject as string;
if (uri == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidUriMetadata);
}
}
return uri;
}
///
/// Create the object given the list of the properties. One of the properties will be __metadata property
/// which will contain type information
///
/// list of the properties and values specified in the payload
/// info about the object being created
/// true if the current object is a top level one, otherwise false
/// does this resource already binded to its parent
/// instance of the object created
private object CreateObject(object jsonObject, SegmentInfo segmentInfo, bool topLevel, out bool existingRelationship)
{
this.RecurseEnter();
existingRelationship = true;
bool existingResource = true;
object resource = null;
ResourceType resourceType;
Hashtable jsonObjectHashtable;
if (topLevel)
{
// Every top level json content must be Hashtable - primitive, complex or entity
jsonObjectHashtable = jsonObject as Hashtable;
if (jsonObjectHashtable == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
object nonEntityResource;
if (HandleTopLevelNonEntityProperty(jsonObjectHashtable, segmentInfo, out nonEntityResource))
{
// if the segment refers to primitive type, then return the value
if (segmentInfo.TargetKind == RequestTargetKind.Primitive ||
#if ASTORIA_OPEN_OBJECT
(segmentInfo.TargetKind == RequestTargetKind.OpenProperty && WebUtil.IsPrimitiveType(nonEntityResource.GetType())) ||
#endif
nonEntityResource == null)
{
return nonEntityResource;
}
jsonObject = nonEntityResource;
}
}
else if (
jsonObject == null ||
#if ASTORIA_OPEN_OBJECT
(segmentInfo.TargetKind == RequestTargetKind.OpenProperty && WebUtil.IsPrimitiveType(jsonObject.GetType())) ||
#endif
segmentInfo.TargetKind == RequestTargetKind.Primitive)
{
// For reference properties, we do not know if there was already some relationship setup
// By setting it to null, we are unbinding the old relationship and hence existing relationship
// is false
// For open properties, if its null, there is no way we will be able to deduce the type
existingRelationship = false;
return jsonObject;
}
// Otherwise top level json content must be Hashtable, since we don't allow multiple inserts
// at the top level
jsonObjectHashtable = jsonObject as Hashtable;
if (jsonObjectHashtable == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
}
ResourceType targetResourceType = null;
#if ASTORIA_OPEN_OBJECT
if (segmentInfo.TargetKind != RequestTargetKind.OpenProperty)
#endif
{
targetResourceType = this.Service.Provider.GetResourceType(segmentInfo.TargetElementType);
Debug.Assert(targetResourceType != null, "Should be able to resolve type for well known segments");
Debug.Assert(
targetResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType || targetResourceType.ResourceTypeKind == ResourceTypeKind.EntityType,
"targetType must be entity type or complex type");
}
// Get the type and uri from the metadata element, if specified
string uri;
bool metadataElementSpecified;
resourceType = this.GetTypeAndUriFromMetadata(
jsonObjectHashtable,
targetResourceType,
topLevel,
out uri,
out metadataElementSpecified);
Debug.Assert((resourceType != null && resourceType.ResourceTypeKind != ResourceTypeKind.Primitive) || uri != null, "Either uri or resource type must be specified");
this.CheckAndIncrementObjectCount();
if ((resourceType != null && resourceType.ResourceTypeKind != ResourceTypeKind.ComplexType) ||
uri != null)
{
// For inserts/updates, its okay not to specify anything in the payload.
// Someone might just want to create a entity with default values or
// merge nothing or replace everything with default values.
if (this.Update)
{
if (!topLevel)
{
if (metadataElementSpecified && jsonObjectHashtable.Count > 1 ||
!metadataElementSpecified)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_DeepUpdateNotSupported);
}
else if (uri == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_UriMissingForUpdateForDeepUpdates);
}
}
if (topLevel)
{
// Checking for merge vs replace semantics
// Only checking for top level resource entity
// since we don't support update of deep resources
resource = CreateObjectFromUri(
resourceType,
segmentInfo,
(RequestDescription)null,
true /*checkETag*/,
true /*checkForNull*/,
this.Service.RequestParams.AstoriaHttpVerb == AstoriaVerbs.PUT /*replaceResource*/);
}
else
{
// case of binding at the first level.
existingRelationship = false;
return CreateObjectFromUri(resourceType, segmentInfo, uri, false /*checkETag*/, false /*checkForNull*/);
}
}
else
{
// For insert, its a new resource that is getting created or an existing resource
// getting binded. Either case, its a new relationship.
existingRelationship = false;
// For POST operations, the following rules holds true:
// 1> If the uri is specified for navigation properties and no other property is specified, then its a bind operation.
// Otherwise, ignore the uri and insert the new resource.
if (uri != null)
{
if (segmentInfo.TargetSource == RequestTargetSource.Property && jsonObjectHashtable.Count == 1)
{
this.RecurseLeave();
return CreateObjectFromUri(resourceType, null, uri, false /*checkETag*/, false /*checkForNull*/);
}
}
}
}
Debug.Assert(resourceType != null, "resourceType != null");
if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
{
Debug.Assert(resource == null, "resource == null");
resource = this.Service.Provider.CreateResource(null, resourceType.FullName);
existingResource = false;
}
else if (!this.Update)
{
Debug.Assert(resource == null, "resource == null");
if (segmentInfo.TargetKind == RequestTargetKind.Resource)
{
// check for append rights whenever we need to create a resource
this.Service.Configuration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend);
resource = this.Service.Provider.CreateResource(segmentInfo.TargetContainer.Name, resourceType.FullName);
this.Tracker.TrackAction(resource, segmentInfo.TargetContainer, UpdateOperations.Add);
}
#if ASTORIA_OPEN_OBJECT
else
{
Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.OpenProperty, "segmentInfo.TargetKind == RequestTargetKind.OpenProperty");
ResourceContainer container = this.Service.Provider.GetContainerForResourceType(resourceType.Type);
resource = this.Service.Provider.CreateResource(container.Name, resourceType.FullName);
}
#endif
existingResource = false;
}
bool changed = this.PopulateProperties(jsonObjectHashtable, resource, resourceType);
// For put operations, you need not specify any property and that means reset all the properties.
// hence for put operations, change is always true.
changed = changed || this.Service.RequestParams.AstoriaHttpVerb == AstoriaVerbs.PUT;
if (changed && existingResource && segmentInfo.TargetContainer != null)
{
this.Tracker.TrackAction(resource, segmentInfo.TargetContainer, UpdateOperations.Change);
}
this.RecurseLeave();
return resource;
}
///
/// Populate the properties of the given resource
///
/// hashtable containing property name and values
/// instance of the resource whose properties needs to be populated
/// resource type whose properties needs to be populated
/// true if any properties were set; false otherwise.
private bool PopulateProperties(Hashtable jsonObject, object resource, ResourceType parentResourceType)
{
// Update all the properties specified in the payload.
// Don't touch the properties which are not specified. Its upto the provider to interpret
// the meaning of things which are not specified
bool changed = false;
foreach (string propertyName in jsonObject.Keys)
{
// Ignore the metadata property
if (propertyName == XmlConstants.JsonMetadataString)
{
continue;
}
// Check if the property exists and try and set the value
ResourceProperty resourceProperty = parentResourceType.TryResolvePropertyName(propertyName);
if (
#if ASTORIA_OPEN_OBJECT
parentResourceType.OpenTypeKind != OpenTypeKind.CompletelyOpen &&
#endif
resourceProperty == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(propertyName, parentResourceType.FullName));
}
// Get the property value, set it appropriately, and mark the object as changed.
object propertyValue = jsonObject[propertyName];
bool existingRelationship;
// If its a open property
if (resourceProperty == null)
{
#if ASTORIA_OPEN_OBJECT
this.HandleOpenTypeProperties(resource, propertyName, propertyValue);
#endif
changed = true;
}
else if (resourceProperty.TypeKind == ResourceTypeKind.ComplexType)
{
SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, true /* singleResult */);
segmentInfo.TargetKind = RequestTargetKind.ComplexObject;
propertyValue = this.CreateObject(propertyValue, segmentInfo, false /*topLevel*/, out existingRelationship);
SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service.Provider);
changed = true;
}
else if (resourceProperty.TypeKind == ResourceTypeKind.Primitive)
{
// Ignoring the value of key properties in PUT payload
if (!this.Update || !resourceProperty.IsOfKind(ResourcePropertyKind.Key))
{
SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service.Provider);
}
changed = true;
}
else
{
Debug.Assert(ResourceTypeKind.EntityType == resourceProperty.TypeKind, "only expecting nav properties");
if (IsDeferredElement(propertyValue))
{
// Skip the deferred element
continue;
}
else
{
Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb);
if (resourceProperty.Kind == ResourcePropertyKind.ResourceReference)
{
SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, true /* singleResult */);
segmentInfo.TargetKind = RequestTargetKind.Resource;
// For navigation property, allow both inserts and binding in this case
propertyValue = this.CreateObject(propertyValue, segmentInfo, false /*topLevel*/, out existingRelationship);
if (!existingRelationship)
{
this.Service.Provider.SetReference(resource, resourceProperty.Name, propertyValue);
}
changed = true;
}
else if (resourceProperty.Kind == ResourcePropertyKind.ResourceSetReference)
{
if (propertyValue == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName));
}
ArrayList resourceCollection = GetArrayList(propertyValue);
SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, true /* singleResult */);
foreach (object resourceObject in resourceCollection)
{
object resourceInstance = this.CreateObject(resourceObject, segmentInfo, false /*topLevel*/, out existingRelationship);
Debug.Assert(resourceInstance != null, "resourceInstance != null");
if (!existingRelationship)
{
this.Service.Provider.AddReferenceToCollection(resource, resourceProperty.Name, resourceInstance);
}
changed = true;
}
}
}
}
}
return changed;
}
#if ASTORIA_OPEN_OBJECT
///
/// Handle the open type property
///
/// parent resource to which the open property belongs to
/// name of the property
/// value of the property
private void HandleOpenTypeProperties(object parentResource, string propertyName, object propertyValue)
{
bool existingRelationship;
if (IsDeferredElement(propertyValue))
{
// Skip the deferred element
return;
}
// Check if its a collection or not
ArrayList arrayList = propertyValue as ArrayList;
if (arrayList == null)
{
SegmentInfo openPropertySegmentInfo = CreateSegment(null, propertyName, true /* singleResult */);
propertyValue = this.CreateObject(
propertyValue,
openPropertySegmentInfo,
false /*topLevel*/,
out existingRelationship);
// Resolve the type of the value
if (propertyValue == null || WebUtil.IsPrimitiveType(propertyValue.GetType()))
{
// For open properties, just set the value since we only support primitive type properties as
// open properties
SetOpenPropertyValue(parentResource, propertyName, propertyValue, this.Service.Provider);
}
else
{
ResourceType openPropertyResourceType = this.Service.Provider.GetResourceType(propertyValue.GetType());
if (openPropertyResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
{
this.Service.Provider.SetValue(parentResource, propertyName, propertyValue);
}
else
{
Debug.Assert(openPropertyResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "resource must be of entity type");
Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb);
if (!existingRelationship)
{
this.Service.Provider.SetReference(parentResource, propertyName, propertyValue);
}
}
}
}
else
{
Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb);
SegmentInfo openPropertySegmentInfo = CreateSegment(null, propertyName, false /* singleResult */);
foreach (object openPropertyValue in arrayList)
{
propertyValue = this.CreateObject(
openPropertyValue,
openPropertySegmentInfo,
false /*topLevel*/,
out existingRelationship);
if (propertyValue == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName));
}
if (!existingRelationship)
{
this.Service.Provider.AddReferenceToCollection(parentResource, propertyName, propertyValue);
}
}
}
}
#endif
///
/// Gets the type and uri specified in the metadata object in the given json object.
///
/// jsonObject which contains the metadata information
/// expected type that this segment of the uri is targeted to
/// whether the segment represents the top level object.
/// uri as specified in the metadata object. If its not specified, this is set to null
/// returns true if the metadata element was specified
/// typename and uri as specified in the metadata object
private ResourceType GetTypeAndUriFromMetadata(
Hashtable jsonObject,
ResourceType expectedType,
bool topLevel,
out string uri,
out bool metadataElementSpecified)
{
metadataElementSpecified = false;
// Get the metadata object
object metadataObject = jsonObject[XmlConstants.JsonMetadataString];
ResourceType targetType = expectedType;
bool typeNameSpecified = false;
uri = null;
if (metadataObject != null)
{
metadataElementSpecified = true;
Hashtable metadata = metadataObject as Hashtable;
if (metadata == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidMetadataContent);
}
// Get the type information from the metadata object. if the type name is not specified,
// then return the expectedType as the target type
object objectTypeName = metadata[XmlConstants.JsonTypeString];
if (objectTypeName != null)
{
string typeName = objectTypeName as string;
if (string.IsNullOrEmpty(typeName))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidTypeMetadata);
}
// Resolve resource type name
targetType = this.Service.Provider.TryResolveTypeName(typeName);
if (targetType == null || targetType.ResourceTypeKind == ResourceTypeKind.Primitive)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName));
}
if (expectedType != null && !expectedType.Type.IsAssignableFrom(targetType.Type))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeSpecified(typeName, expectedType.FullName));
}
typeNameSpecified = true;
}
uri = JsonDeserializer.ReadUri(metadata);
}
// Type information is optional for bind operations.
// Top level operations cannot be bind operations, since uri need to have $links
// for top level bind operations and that's a different code path.
// For bind operations, uri must be specified and nothing else should be specified.
bool bindOperation = !topLevel && uri != null && jsonObject.Count == 1;
// type name must be specified for POST or PUT/MERGE operations.
if (!typeNameSpecified)
{
if (!bindOperation)
{
if (expectedType == null)
{
// For open properties, you must specify the type information
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingTypeInformationForOpenTypeProperties);
}
else if (expectedType.HasDerivedTypes)
{
// For types that take part in inheritance, type information must be specified.
throw DataServiceException.CreateBadRequestError(Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance);
}
}
else
{
// If the type name is not specified, we should set the type name to null, since in case of inheritance,
// we don't want to guess the type information.
targetType = null;
}
}
return targetType;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MetadataCache.cs
- Number.cs
- Image.cs
- FilterFactory.cs
- DataGridViewColumnHeaderCell.cs
- autovalidator.cs
- EventSinkHelperWriter.cs
- ThreadInterruptedException.cs
- SqlCacheDependency.cs
- Message.cs
- QuaternionAnimationUsingKeyFrames.cs
- BamlLocalizableResource.cs
- ExtensionWindowHeader.cs
- HistoryEventArgs.cs
- LambdaCompiler.Generated.cs
- SqlUserDefinedAggregateAttribute.cs
- PublisherMembershipCondition.cs
- OdbcUtils.cs
- SqlNotificationRequest.cs
- PointValueSerializer.cs
- IListConverters.cs
- Globals.cs
- ListViewEditEventArgs.cs
- VectorCollectionValueSerializer.cs
- Thread.cs
- EnterpriseServicesHelper.cs
- BuildTopDownAttribute.cs
- SeekStoryboard.cs
- XamlClipboardData.cs
- WindowsRegion.cs
- DbProviderServices.cs
- ReflectEventDescriptor.cs
- invalidudtexception.cs
- Util.cs
- Calendar.cs
- AsyncResult.cs
- MatrixStack.cs
- AuthenticationManager.cs
- Shape.cs
- SerializationSectionGroup.cs
- ParsedRoute.cs
- TemplateContentLoader.cs
- MailSettingsSection.cs
- Int32Collection.cs
- CancellationToken.cs
- List.cs
- X509Certificate2.cs
- DeviceSpecific.cs
- DeviceFilterDictionary.cs
- CollectionDataContractAttribute.cs
- IOThreadScheduler.cs
- FileDetails.cs
- TextServicesManager.cs
- HtmlControl.cs
- AvtEvent.cs
- DrawingAttributeSerializer.cs
- BaseInfoTable.cs
- BulletedListDesigner.cs
- RepeatBehaviorConverter.cs
- DataGridBoolColumn.cs
- DirectoryNotFoundException.cs
- FixedSOMPageConstructor.cs
- StdValidatorsAndConverters.cs
- OpenTypeLayout.cs
- SuppressMessageAttribute.cs
- DataGridViewSelectedRowCollection.cs
- ViewGenerator.cs
- PowerModeChangedEventArgs.cs
- UpdateTracker.cs
- HttpException.cs
- TextFormatter.cs
- QilLiteral.cs
- WebPartCancelEventArgs.cs
- ObjectListComponentEditor.cs
- MsmqBindingMonitor.cs
- SessionEndedEventArgs.cs
- Win32Native.cs
- HitTestDrawingContextWalker.cs
- WebPartEditVerb.cs
- XmlPreloadedResolver.cs
- ValidationPropertyAttribute.cs
- XomlSerializationHelpers.cs
- EntityException.cs
- CompositeScriptReference.cs
- CellCreator.cs
- ClientSettingsProvider.cs
- DataTableTypeConverter.cs
- ZipIOLocalFileBlock.cs
- DataControlFieldCollection.cs
- Bitmap.cs
- ObjectPersistData.cs
- NullExtension.cs
- IsolatedStorageException.cs
- SqlClientMetaDataCollectionNames.cs
- IisTraceListener.cs
- WithParamAction.cs
- GrammarBuilderWildcard.cs
- WindowShowOrOpenTracker.cs
- MetadataCache.cs