/// <summary> /// Gets the type and uri specified in the metadata object in the given json object. /// </summary> /// <param name="jsonObjectTable">jsonObject which contains the metadata information</param> /// <param name="expectedType">expected type that this segment of the uri is targeted to</param> /// <param name="topLevel">whether the segment represents the top level object.</param> /// <param name="uri">uri as specified in the metadata object. If its not specified, this is set to null</param> /// <param name="metadataElementSpecified">returns true if the metadata element was specified</param> /// <returns>typename and uri as specified in the metadata object</returns> private ResourceType GetTypeAndUriFromMetadata( Dictionary <String, Object> jsonObjectTable, ResourceType expectedType, bool topLevel, out string uri, out bool metadataElementSpecified) { metadataElementSpecified = false; // Get the metadata object object metadataObject; ResourceType targetType = expectedType; bool typeNameSpecified = false; uri = null; if (jsonObjectTable.TryGetValue(XmlConstants.JsonMetadataString, out metadataObject)) { metadataElementSpecified = true; JsonReader.JsonObjectRecords metadata = metadataObject as JsonReader.JsonObjectRecords; 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; if (metadata.Entries.TryGetValue(XmlConstants.JsonTypeString, out objectTypeName)) { string typeName = objectTypeName as string; if (string.IsNullOrEmpty(typeName)) { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidTypeMetadata); } // Resolve resource type name targetType = this.Service.Provider.TryResolveResourceType(typeName); if (targetType == null || targetType.ResourceTypeKind == ResourceTypeKind.Primitive) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName)); } if (expectedType != null && !expectedType.IsAssignableFrom(targetType)) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeSpecified(typeName, expectedType.FullName)); } typeNameSpecified = true; } uri = JsonDeserializer.ReadUri(metadata.Entries); } // 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 && jsonObjectTable.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 (this.Service.Provider.HasDerivedTypes(expectedType)) { // 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); }
/// <summary> /// Creates a new <see cref="Deserializer"/> for the specified stream. /// </summary> /// <param name="description">description about the request uri.</param> /// <param name="dataService">Data service for which the deserializer will act.</param> /// <param name="update">indicates whether this is a update operation or not</param> /// <param name="tracker">Tracker to use for modifications.</param> /// <returns>A new instance of <see cref="Deserializer"/>.</returns> internal static Deserializer CreateDeserializer(RequestDescription description, IDataService dataService, bool update, UpdateTracker tracker) { string mimeType; System.Text.Encoding encoding; DataServiceHostWrapper host = dataService.OperationContext.Host; HttpProcessUtility.ReadContentType(host.RequestContentType, out mimeType, out encoding); ContentFormat requestFormat = WebUtil.SelectRequestFormat(mimeType, description); Stream requestStream = host.RequestStream; Debug.Assert(requestStream != null, "requestStream != null"); Debug.Assert(tracker != null, "Change tracker must always be created."); Deserializer deserializer = null; Debug.Assert( (!update /*POST*/ && dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.POST) || (update /*PUT,MERGE*/ && (dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.MERGE || dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.PUT)), "For PUT and MERGE, update must be true; for POST, update must be false"); switch (requestFormat) { case ContentFormat.Json: deserializer = new JsonDeserializer( requestStream, encoding, update, dataService, tracker); break; case ContentFormat.Atom: SyndicationFormatterFactory factory = new Atom10FormatterFactory(); deserializer = new SyndicationDeserializer( requestStream, // stream encoding, // encoding dataService, // dataService update, factory, tracker); // factory break; case ContentFormat.PlainXml: deserializer = new PlainXmlDeserializer( requestStream, encoding, dataService, update, tracker); break; default: throw new DataServiceException(415, Strings.BadRequest_UnsupportedRequestContentType(host.RequestContentType)); } Debug.Assert(deserializer != null, "deserializer != null"); return deserializer; }