public void CtorMessageAndInner() { Exception inner = new Exception ("inner"); var ex = new DataServiceException ("message", inner); Assert.AreEqual ("message", ex.Message); Assert.AreEqual (inner, ex.InnerException); }
public void CtorStatusAndErrorMessageLanguageException() { Exception inner = new Exception ("inner"); var ex = new DataServiceException (404, "error", "message", "language", inner); Assert.AreEqual ("message", ex.Message); Assert.AreEqual (404, ex.StatusCode); Assert.AreEqual ("language", ex.MessageLanguage); Assert.AreEqual (inner, ex.InnerException); }
/// <summary> /// Converts the given value to the expected type as per XML serializer rules. /// Make sure these rules are in sync with PlainXmlSerializer. /// </summary> /// <param name="value">value to the converted</param> /// <param name="propertyName">name of the property whose value is getting converted</param> /// <param name="typeToBeConverted">clr type to which the value needs to be converted to</param> /// <returns>object which is in sync with the properties type</returns> internal static object ConvertValuesForXml(object value, string propertyName, Type typeToBeConverted) { Debug.Assert(WebUtil.IsPrimitiveType(typeToBeConverted), "WebUtil.IsPrimitiveType(typeToBeConverted)"); Debug.Assert(value == null || value is string, "This method should be used only for converting string to a primitve value."); string stringValue = value as string; if (stringValue != null) { try { value = WebConvert.StringToPrimitive(stringValue, typeToBeConverted); } catch (FormatException e) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ErrorInConvertingPropertyValue(propertyName, typeToBeConverted), e); } } return(value); }
/// <summary> /// Override the HandleException method to throw 400 Bad Request /// exception to the client side. /// </summary> /// <param name="args">The HandleException argument</param> protected override void HandleException(HandleExceptionArgs args) { // Check if the InnerException is null if (args.Exception.InnerException != null) { // Convert the InnerException to DataServiceException DataServiceException ex = args.Exception.InnerException as DataServiceException; // Check if the InnerException is in type of // DataServiceException and the StatusCode is // 400(Bad Request) if (ex != null && ex.StatusCode == 400) { // Return the DataServiceException to the client args.Exception = ex; } } base.HandleException(args); }
protected void setModelStateErrors(DataServiceException ex) { if (ex.DataServiceExceptionData != null && !String.IsNullOrWhiteSpace(ex.DataServiceExceptionData.GeneralMessage)) { ModelState.AddModelError("ErrorGeneralMessage", ex.DataServiceExceptionData.GeneralMessage); errorGeneralMessage = ex.DataServiceExceptionData.GeneralMessage; } if (ex.DataServiceExceptionData != null && ex.DataServiceExceptionData.Messages != null) { foreach (string name in ex.DataServiceExceptionData.Messages.Keys) { IList <string> list = ex.DataServiceExceptionData.Messages[name]; foreach (string msg in list) { ModelState.AddModelError(name, msg); } } } }
/// <summary> /// Sets a resource reference to resource referenced by a URL. /// </summary> /// <param name="entityResource">The entity resource to set the resource reference on.</param> /// <param name="navigationProperty">The navigation property for which to set the reference to null.</param> /// <param name="url">The URL which points to the resource to set as the value of the navigation property.</param> private void SetResourceReferenceToUrl(object entityResource, ResourceProperty navigationProperty, string url) { Debug.Assert(entityResource != null, "entityResource != null"); Debug.Assert(navigationProperty != null, "navigationProperty != null"); // Update the object count when you are performing a bind operation. this.CheckAndIncrementObjectCount(); // Get the referenced resource. Uri referencedUri = RequestUriProcessor.GetAbsoluteUriFromReference(url, this.Service.OperationContext); RequestDescription requestDescription = RequestUriProcessor.ProcessRequestUri(referencedUri, this.Service, true /*internalQuery*/); // ATOM deserializer checks that the url doesn't point to a collection. If it does it will ignore the link. if (this.IsAtomRequest && !requestDescription.IsSingleResult) { if (navigationProperty != null && navigationProperty.Kind == ResourcePropertyKind.ResourceReference) { throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.BadRequest_LinkHrefMustReferToSingleResource(navigationProperty.Name)); } return; } // Get the resource object referencedResource = this.Service.GetResource(requestDescription, requestDescription.SegmentInfos.Count - 1, null); if (navigationProperty.Kind == ResourcePropertyKind.ResourceReference) { this.Updatable.SetReference(entityResource, navigationProperty.Name, referencedResource); } else { Debug.Assert(navigationProperty.Kind == ResourcePropertyKind.ResourceSetReference, "Only navigation properties are allowed in this method."); // If we are to set the resource to a collection property it must not be null (so check for nulls), otherwise do allow nulls for backward compatibility. WebUtil.CheckResourceExists(referencedResource != null, requestDescription.LastSegmentInfo.Identifier); this.Updatable.AddReferenceToCollection(entityResource, navigationProperty.Name, referencedResource); } }
/// <summary>Applies a property from the reader to the specified resource.</summary> /// <param name='reader'>XmlReader to read from.</param> /// <param name='propertyName'>Name of property to set on the specified resource.</param> /// <param name='resourceType'>Type of resource.</param> /// <param name='resource'>Resource to set value on.</param> private void ApplyProperty(XmlReader reader, string propertyName, ResourceType resourceType, object resource) { Debug.Assert(reader != null, "reader != null"); Debug.Assert(propertyName != null, "propertyName != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(resource != null, "resource != null"); ResourceProperty property = resourceType.TryResolvePropertyName(propertyName); bool ignoreValue = false; if (property == null) { if (resourceType.IsOpenType == false) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(propertyName, resourceType.FullName)); } } else { if (this.Update && property.IsOfKind(ResourcePropertyKind.Key)) { ignoreValue = true; } } object propertyValue = this.ReadPropertyWithType(reader, propertyName, property); if (!ignoreValue) { if (property == null) { Deserializer.SetOpenPropertyValue(resource, propertyName, propertyValue, this.Service); } else { Deserializer.SetPropertyValue(property, resource, propertyValue, this.ContentFormat, this.Service); } } }
internal void SetValue(object instance, object propertyValue, ResourceProperty resourceProperty) { MethodInfo setMethod = this.GetPropertyInfo(resourceProperty).GetSetMethod(); if (setMethod == null) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.BadRequest_PropertyValueCannotBeSet(resourceProperty.Name)); } try { setMethod.Invoke(instance, new object[] { propertyValue }); } catch (TargetInvocationException exception) { ErrorHandler.HandleTargetInvocationException(exception); throw; } catch (ArgumentException exception2) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.BadRequest_ErrorInSettingPropertyValue(resourceProperty.Name), exception2); } }
/// <summary>Reads the number from the reader.</summary> /// <returns>reads the clr number object</returns> private object ReadNumber() { char ch = this.ReadNextCharacter(); StringBuilder sb = new StringBuilder(); sb.Append(ch); while (true) { ch = this.PeekNextSignificantCharacter(); if (Char.IsDigit(ch) || (ch == '.') || (ch == 'E') || (ch == 'e') || (ch == '-') || (ch == '+')) { this.ReadNextCharacter(); sb.Append(ch); } else { break; } } string s = sb.ToString(); Double doubleValue; int intValue; // We will first try and convert this int32. If this succeeds, great. Otherwise, we will try // and convert this into a double. if (Int32.TryParse(s, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out intValue)) { return(intValue); } else if (Double.TryParse(s, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out doubleValue)) { return(doubleValue); } throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent); }
protected sealed override object Deserialize(System.Data.Services.SegmentInfo segmentInfo) { object obj2; try { obj2 = this.Read(segmentInfo); } catch (XmlException exception) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.DataServiceException_GeneralError, exception); } catch (ODataContentTypeException exception2) { throw new DataServiceException(0x19f, null, System.Data.Services.Strings.DataServiceException_UnsupportedMediaType, null, exception2); } catch (ODataException exception3) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.DataServiceException_GeneralError, exception3); } return(obj2); }
public void When_DataServiceException_is_serialized_all_public_instance_data_is_saved() { // Arrange const int expectedStatusCode = 705; const string expectedErrorCode = "A47"; const string expectedMessage = "Server error."; const string expectedMessageLang = "en"; var sut = new DataServiceException( expectedStatusCode, expectedErrorCode, expectedMessage, expectedMessageLang, innerException: null); // Act var ds = SerializeAndDeserializeDataServiceException(sut); // Assert Assert.AreNotSame(sut, ds); Assert.AreEqual(sut.GetType(), ds.GetType()); Assert.AreEqual(expectedMessage, ds.Message); Assert.AreEqual(expectedStatusCode, ds.StatusCode); Assert.AreEqual(expectedErrorCode, ds.ErrorCode); Assert.AreEqual(expectedMessageLang, ds.MessageLanguage); }
private void ExecutionCompletionEventHandler(IAsyncResult ar) { Exception dataServiceException; lock (this.syncObject) { this.timer.Stop(); this.isExecutionCompleted = true; if (!this.isExceedsMaxExecutionTime) { dataServiceException = PSCommand.CheckPowershellForException(this.cmdletInfo.CmdletName, this.commandType, this.powerShell); } else { object[] cmdletName = new object[1]; cmdletName[0] = this.cmdletInfo.CmdletName; dataServiceException = new DataServiceException(0x193, ExceptionHelpers.GetDataServiceExceptionMessage(HttpStatusCode.Forbidden, Resources.CmdletExecutionQuotaExceeded, cmdletName)); TraceHelper.Current.CommandExecutionTimeExceeded(this.cmdletInfo.CmdletName, this.runspace.Borrower.Name, DataServiceController.Current.Configuration.PowerShell.Quotas.MaxExecutionTime, 0); DataServiceController.Current.PerfCounters.SystemQuotaViolationsPerSec.Increment(); DataServiceController.Current.QuotaSystem.SystemQuotaViolation.Increment(); } if (this.output != null && dataServiceException == null) { foreach (PSObject pSObject in this.output) { if (pSObject == null) { continue; } DSResource dSResource = SerializerBase.SerializeEntity(pSObject, this.entityType); this.dataStore.Add(dSResource); } } this.dataStore.Completed(dataServiceException); this.powerShell.Trace(); } this.Dispose(); }
internal object HandlePutRequest() { object requestValue = null; object entityResource = null; ResourceSetWrapper entityContainer = null; string str; Encoding encoding; HttpProcessUtility.ReadContentType(this.Service.OperationContext.Host.RequestContentType, out str, out encoding); System.Data.Services.RequestDescription requestDescription = this.RequestDescription; if (((requestDescription.TargetKind == RequestTargetKind.MediaResource) || (requestDescription.TargetKind == RequestTargetKind.OpenPropertyValue)) || (requestDescription.TargetKind == RequestTargetKind.PrimitiveValue)) { requestValue = this.Deserialize(requestDescription.LastSegmentInfo); } else if (requestDescription.LinkUri) { Uri referencedUri = (Uri)this.Deserialize(null); object targetResourceToBind = this.GetTargetResourceToBind(referencedUri, true); entityResource = HandleBindOperation(requestDescription, targetResourceToBind, this.Service, this.Tracker); entityContainer = requestDescription.LastSegmentInfo.TargetContainer; } else { requestValue = this.ReadEntity(); if (((requestValue == null) && requestDescription.LastSegmentInfo.HasKeyValues) && (requestDescription.TargetSource == RequestTargetSource.EntitySet)) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.BadRequest_CannotSetTopLevelResourceToNull(requestDescription.ResultUri.AbsoluteUri)); } } if (!requestDescription.LinkUri && IsQueryRequired(requestDescription, requestValue)) { object resourceToBeModified = GetResourceToModify(requestDescription, this.Service, false, out entityResource, out entityContainer, true); this.Tracker.TrackAction(entityResource, entityContainer, UpdateOperations.Change); ModifyResource(requestDescription, resourceToBeModified, requestValue, this.Service); } return(entityResource ?? requestValue); }
/// <summary> /// Converts the given text into an arrayList /// </summary> /// <returns>returns the arraylist containing the list of objects</returns> private ArrayList ReadArray() { ArrayList array = new ArrayList(); // Consume the '[' this.ReadNextCharacter(); while (true) { char ch = this.PeekNextSignificantCharacter(); if (ch == '\0') { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent); } if (ch == ']') { this.ReadNextCharacter(); return(array); } if (array.Count != 0) { if (ch != ',') { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingArrayMemberSeperator); } else { this.ReadNextCharacter(); } } object item = this.ReadValue(); array.Add(item); } }
protected void setModelStateErrors(DataServiceException ex) { if (ex.DataServiceExceptionData != null && !String.IsNullOrWhiteSpace(ex.DataServiceExceptionData.GeneralMessage)) { ModelState.AddModelError("ErrorGeneralMessage", ex.DataServiceExceptionData.GeneralMessage); errorGeneralMessage = ex.DataServiceExceptionData.GeneralMessage; } if (ex.DataServiceExceptionData != null && ex.DataServiceExceptionData.Messages != null) { foreach (string name in ex.DataServiceExceptionData.Messages.Keys) { IList <string> list = ex.DataServiceExceptionData.Messages[name]; foreach (string msg in list) { ModelState.AddModelError(name, msg); } } } if (ex.DataServiceExceptionData != null && ex.DataServiceExceptionData.IndexMessages != null) { foreach (int index in ex.DataServiceExceptionData.IndexMessages.Keys) { Dictionary <string, List <string> > d = ex.DataServiceExceptionData.IndexMessages[index]; foreach (string name in d.Keys) { IList <string> list = d[name]; foreach (string msg in list) { ModelState.AddModelError(String.Format("{0}[{1}]", name, index), msg); } } } } }
public void ProcessException(HandleExceptionArgs args) { this.plainException = args.Exception; DataServiceException dse = args.Exception as DataServiceException; if (dse != null) { if (dse.StatusCode == (int)HttpStatusCode.NotModified) { // 304 is not a failure, we let the server handle it. return; } } if (AllowServerToSerializeException.Value) { this.ResponseStatusCode = args.ResponseStatusCode; this.ResponseContentType = args.ResponseContentType; } else { // set the right status code and content type this.ResponseStatusCode = args.ResponseStatusCode; this.ResponseContentType = "text/plain"; // write the error message in the payload StreamWriter writer = new StreamWriter(this.responseStream); writer.WriteLine("TestServiceHost.ProcessException special pre-writing handling:"); writer.Write(args.Exception.Message); writer.Flush(); // Re-throw the exception. This makes things consistent for tests, // which except an exception from HttpWebRequest.StatusCode <> 200 as well. throw new WebException("WebException from TestServiceHost.ProcessException", args.Exception); } }
/// <summary> /// Reads the given payload and return the top level object. /// </summary> /// <param name="segmentInfo">Info about the object being created.</param> /// <returns>Instance of the object created.</returns> protected override sealed object Deserialize(SegmentInfo segmentInfo) { try { return(this.Read(segmentInfo)); } catch (System.Xml.XmlException exception) { throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.DataServiceException_GeneralError, exception); } catch (ODataContentTypeException exception) { throw new DataServiceException( 415, null, Microsoft.OData.Service.Strings.DataServiceException_UnsupportedMediaType, null, exception); } catch (ODataException exception) { throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.DataServiceException_GeneralError, exception); } }
/// <summary> /// Applies an entry which is the content of a navigation property to the specified entity resource. /// </summary> /// <param name="navigationProperty">The navigation property for which the feed was specified.</param> /// <param name="targetResourceSet">The resource set of the target of the navigation property.</param> /// <param name="entityResource">The entity resource to apply the value to.</param> /// <param name="entry">The entry to apply. This can be null if the null value should be applied.</param> /// <remarks>Note that the targetResourceSet will be filled for non-ATOM formats, but it will be null for ATOM.</remarks> private void ApplyEntryInNavigationProperty( ResourceProperty navigationProperty, ResourceSetWrapper targetResourceSet, object entityResource, ODataEntry entry) { Debug.Assert( navigationProperty != null && navigationProperty.TypeKind == ResourceTypeKind.EntityType, "navigationProperty != null && navigationProperty.TypeKind == ResourceTypeKind.EntityType"); Debug.Assert( navigationProperty.Kind == ResourcePropertyKind.ResourceReference, "ODataLib reader should never report an entry for a collection navigation property."); Debug.Assert(targetResourceSet != null, "targetResourceSet != null"); Debug.Assert(entityResource != null, "entityResource != null"); // Deep insert is not allowed in updates, unless it's JSON and the deep insert is a null value. if ((this.IsAtomRequest || entry != null) && this.Update) { throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.BadRequest_DeepUpdateNotSupported); } if (entry == null) { this.SetResourceReferenceToNull(entityResource, navigationProperty); } else { Debug.Assert(targetResourceSet != null, "targetResourceSet != null"); SegmentInfo propertySegmentInfo = CreateSegment(navigationProperty, navigationProperty.Name, targetResourceSet, true /* singleResult */); Debug.Assert(propertySegmentInfo.TargetKind != RequestTargetKind.OpenProperty, "Open navigation properties are not supported on OpenTypes."); object childEntityResource = this.CreateNestedEntityAndApplyProperties(propertySegmentInfo, entry); this.Updatable.SetReference(entityResource, navigationProperty.Name, childEntityResource); } }
private void CreateEntityResource(System.Data.Services.SegmentInfo segmentInfo, ODataEntry entry, ODataEntryAnnotation entryAnnotation, bool topLevel) { object obj2; base.CheckAndIncrementObjectCount(); ResourceType entryResourceType = this.GetEntryResourceType(entry, segmentInfo.TargetResourceType); base.UpdateAndCheckRequestResponseDSV(entryResourceType, topLevel); if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segmentInfo.Identifier)); } if (base.Update) { obj2 = base.GetObjectFromSegmentInfo(entryResourceType, segmentInfo, true, true, base.Service.OperationContext.Host.HttpVerb == HttpVerbs.PUT); } else { DataServiceConfiguration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend); obj2 = base.Updatable.CreateResource(segmentInfo.TargetContainer.Name, entryResourceType.FullName); } entryAnnotation.EntityResource = obj2; entryAnnotation.EntityResourceType = entryResourceType; }
/// <summary> /// Read the link media type and validate for non open property types /// </summary> /// <param name="mediaType">media type as specified on the link element.</param> /// <param name="property">property which the link represents.</param> /// <returns>returns the type parameters specified in the media link.</returns> private static string ValidateTypeParameterForNonOpenTypeProperties(string mediaType, ResourceProperty property) { string typeParameterValue = null; if (!String.IsNullOrEmpty(mediaType)) { string mime; Encoding encoding; KeyValuePair <string, string>[] contentTypeParameters = HttpProcessUtility.ReadContentType(mediaType, out mime, out encoding); if (mime != XmlConstants.MimeApplicationAtom) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MimeTypeMustBeApplicationAtom(mime, XmlConstants.MimeApplicationAtom)); } // If the type parameter is specified, make sure its correct. We do the validation for known properties here // and for open-properties, the validation is done if the link is expanded. Otherwise, there is no good way of // doing the validation. typeParameterValue = HttpProcessUtility.GetParameterValue(contentTypeParameters, XmlConstants.AtomTypeAttributeName); if (!String.IsNullOrEmpty(typeParameterValue) && property != null) { if (property.Kind == ResourcePropertyKind.ResourceReference) { if (typeParameterValue != XmlConstants.AtomEntryElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomEntryElementName)); } } else if (typeParameterValue != XmlConstants.AtomFeedElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomFeedElementName)); } } } return(typeParameterValue); }
/// <summary> /// Returns collection item type name or null if the provided type name is not a collection. /// </summary> /// <param name="typeName">Collection type name read from payload.</param> /// <param name="isNested">Whether it is a nested (recursive) call.</param> /// <returns>Collection element type name or null if not a collection.</returns> /// <remarks> /// The following rules are used for collection type names: /// - it has to start with "Collection(" and end with ")" - trailing and leading whitespaces make the type not to be recognized as collection. /// - there is to be no characters (including whitespaces) between "Collection" and "(" - otherwise it won't be recognized as collection /// - collection item type name has to be a non-empty string - i.e. "Collection()" won't be recognized as collection /// - nested collection - e.g. "Collection(Collection(Edm.Int32))" - are not supported - we will throw /// Note the following are examples of valid type names which are not collection: /// - "Collection()" /// - " Collection(Edm.Int32)" /// - "Collection (Edm.Int32)" /// - "Collection(" /// If the type name is not recognized as a collection it will be eventually passed to type resolver if it is not a known primitive type. /// </remarks> internal static string GetCollectionItemTypeName(string typeName, bool isNested) { // to be recognized as a collection wireTypeName must not be null, has to start with "Collection(" and end with ")" and must not be "Collection()" if (typeName != null && typeName.StartsWith(XmlConstants.CollectionTypeQualifier + "(", StringComparison.Ordinal) && typeName[typeName.Length - 1] == ')' && typeName.Length != (XmlConstants.CollectionTypeQualifier + "()").Length) { if (isNested) { #if ODATA_CLIENT throw Error.InvalidOperation(Strings.ClientType_CollectionOfCollectionNotSupported); #else throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CollectionOfCollectionNotSupported); #endif } string innerTypeName = typeName.Substring((XmlConstants.CollectionTypeQualifier + "(").Length, typeName.Length - (XmlConstants.CollectionTypeQualifier + "()").Length); // Check if it is not a nested collection and throw if it is GetCollectionItemTypeName(innerTypeName, true); return(innerTypeName); } return(null); }
/// <summary> /// Reads the input request payload and returns the WCF DS value representation of it. /// </summary> /// <param name="segmentInfo">Info about the request to read. For entity reference requests this is null.</param> /// <returns>The WCF DS representation of the value read. For entity reference link this is the Uri of the link.</returns> protected override object Read(SegmentInfo segmentInfo) { Debug.Assert(segmentInfo == null, "segmentInfo == null"); Debug.Assert(this.RequestDescription.LinkUri, "The EntityReferenceLinkDeserializer only supports $ref payloads."); ODataEntityReferenceLink entityReferenceLink = this.MessageReader.ReadEntityReferenceLink(); Debug.Assert(entityReferenceLink != null, "ReadEntityReferenceLink should never return null."); Uri entityReferenceUri = entityReferenceLink.Url; Debug.Assert(entityReferenceUri != null, "The Url of the entity reference link should never be null."); AssertReaderFormatIsExpected(this.MessageReader, ODataFormat.Json); // We must fail on empty URI string entityReferenceUriAsString = UriUtil.UriToString(entityReferenceUri); if (string.IsNullOrEmpty(entityReferenceUriAsString)) { throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.BadRequest_MissingUriForLinkOperation); } // Resolve the URI against the service return(RequestUriProcessor.GetAbsoluteUriFromReference(entityReferenceUri, this.Service.OperationContext.AbsoluteServiceUri)); }
/// <summary> /// Converts the given value to the expected type as per json reader rules /// Make sure these rules are in sync with jsonwriter. /// </summary> /// <param name="value">value to the converted</param> /// <param name="propertyName">name of the property whose value is getting converted</param> /// <param name="typeToBeConverted">clr type to which the value needs to be converted to</param> /// <param name="provider">underlying data service provider.</param> /// <returns>object which is in sync with the properties type</returns> internal static object ConvertValues(object value, string propertyName, Type typeToBeConverted, DataServiceProviderWrapper provider) { 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 (propertyType != typeof(Int32) && !provider.IsV1Provider) { // In V1, whenever we encountered a conversion which was unsafe, we would just return and most likely, it // would fail when the provider tried and set the value to the property since the type won't match. // Ideally, we should have thrown here, instead of allowing it to pass to the provider. // Now in V2, with provider becoming public, and another configuration option available (EnableTypeConversion), // it seems wrong to pass the value to the provider without doing the conversion when the EnableTypeConversion is set to true // But since we can't break the behaviour for V1 providers, we will be doing this only for custom V2 providers. throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ErrorInConvertingNumericValues(propertyName)); } } else if (value is Double) { Double doubleValue = (Double)value; if (propertyType == typeof(Single)) { return(Convert.ToSingle(doubleValue)); } else if (propertyType != typeof(Double) && !provider.IsV1Provider) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_ErrorInConvertingNumericValues(propertyName)); } } } 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); }
public PagedMessage GetPage(DataMessage dataMessage) { int sequenceId = (int)dataMessage.headers[DataMessage.SequenceIdHeader]; Sequence sequence = GetSequence(sequenceId); if (sequence != null) return GetPagedMessage(dataMessage, sequence); else { DataServiceException dse = new DataServiceException(string.Format("Sequence {0} in destination {1} was not found", sequenceId, dataMessage.destination)); throw dse; } }
/// <summary> /// Converts the given value into the right type /// </summary> /// <returns>returns the clr object instance which </returns> public object ReadValue() { this.RecurseEnter(); object value = null; bool allowNull = false; char ch = this.PeekNextSignificantCharacter(); if (ch == '[') { value = this.ReadArray(); } else if (ch == '{') { value = this.ReadObject(); } else if ((ch == '\'') || (ch == '"')) { bool hasLeadingSlash; string s = this.ReadString(out hasLeadingSlash); value = s; // may be overwritten with a DateTime if ends up being a date/time // Atlas format for date/time if (hasLeadingSlash) { Match match = DateTimeFormat.Match(s); if (match.Success) { string ticksStr = match.Groups["ticks"].Value; long ticks; if (long.TryParse(ticksStr, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out ticks)) { // The javascript ticks start from 1/1/1970 but FX DateTime ticks start from 1/1/0001 DateTime dateTime = new DateTime(ticks * 10000 + JsonWriter.DatetimeMinTimeTicks, DateTimeKind.Utc); value = dateTime; } } } } else if (Char.IsDigit(ch) || (ch == '-') || (ch == '.')) { value = this.ReadNumber(); } else if ((ch == 't') || (ch == 'f')) { value = this.ReadBoolean(); } else if (ch == 'n') { this.ReadNull(); allowNull = true; } if ((value == null) && (allowNull == false)) { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent); } this.RecurseLeave(); // if there is junk data at the end of the stream ex. {...}junk // then an exception will be thrown. if (this.recursionDepth == 0) { // at the end of the stream if (this.PeekNextSignificantCharacter() != '\0') { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent); } } return(value); }
/// <summary> /// Read the string value from the reader /// </summary> /// <param name="hasLeadingSlash">out parameter indicating whether the string has a leading slash or not</param> /// <returns>returns the string value read from the reader</returns> private string ReadString(out bool hasLeadingSlash) { char endQuoteCharacter = this.ReadNextCharacter(); char ch = this.ReadNextCharacter(); hasLeadingSlash = (ch == '\\') ? true : false; StringBuilder sb = new StringBuilder(); while (true) { if (ch == '\\') { ch = this.ReadNextCharacter(); // From 4627, section 2.5: Strings, here's the list of characters that we should be escaping if (ch == 'u') { string unicodeSequence = this.GetCharacters(4); Debug.Assert(unicodeSequence != null, "unicodeSequence != null"); ch = (char)Int32.Parse(unicodeSequence, NumberStyles.HexNumber, CultureInfo.InvariantCulture); sb.Append(ch); } else if (ch == 'b') { sb.Append('\b'); } else if (ch == 'f') { sb.Append('\f'); } else if (ch == 'n') { sb.Append('\n'); } else if (ch == 'r') { sb.Append('\r'); } else if (ch == 't') { sb.Append('\t'); } else if (ch == '\\' || ch == '\"' || ch == '/' || ch == '\'') { sb.Append(ch); } else { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidJsonUnrecognizedEscapeSequence); } } else if (ch == endQuoteCharacter) { return(sb.ToString()); } else { sb.Append(ch); } ch = this.ReadNextCharacter(); } }
/// <summary> /// Create the object given the list of the properties. One of the properties will be __metadata property /// which will contain type information /// </summary> /// <param name="jsonObject">list of the properties and values specified in the payload</param> /// <param name="segmentInfo">info about the object being created</param> /// <param name="topLevel">true if the current object is a top level one, otherwise false</param> /// <param name="existingRelationship">does this resource already binded to its parent</param> /// <returns>instance of the object created</returns> private object CreateObject(object jsonObject, SegmentInfo segmentInfo, bool topLevel, out bool existingRelationship) { this.RecurseEnter(); existingRelationship = true; bool existingResource = true; object resource = null; ResourceType resourceType; JsonReader.JsonObjectRecords jsonObjectRecord; if (topLevel) { // Every top level json content must be JsonObjectRecords - primitive, complex or entity jsonObjectRecord = jsonObject as JsonReader.JsonObjectRecords; if (jsonObjectRecord == null) { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity); } object nonEntityResource; if (HandleTopLevelNonEntityProperty(jsonObjectRecord, segmentInfo, out nonEntityResource)) { // if the segment refers to primitive type, then return the value if (segmentInfo.TargetKind == RequestTargetKind.Primitive || nonEntityResource == null || (segmentInfo.TargetKind == RequestTargetKind.OpenProperty && WebUtil.IsPrimitiveType(nonEntityResource.GetType()))) { return(nonEntityResource); } jsonObject = nonEntityResource; } } else if ( jsonObject == null || (segmentInfo.TargetKind == RequestTargetKind.OpenProperty && WebUtil.IsPrimitiveType(jsonObject.GetType())) || 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 JsonObjectRecords, since we don't allow multiple inserts // at the top level jsonObjectRecord = jsonObject as JsonReader.JsonObjectRecords; if (jsonObjectRecord == null) { throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity); } ResourceType targetResourceType = null; if (segmentInfo.TargetKind != RequestTargetKind.OpenProperty) { targetResourceType = segmentInfo.TargetResourceType; 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( jsonObjectRecord.Entries, targetResourceType, topLevel, out uri, out metadataElementSpecified); Debug.Assert((resourceType != null && resourceType.ResourceTypeKind != ResourceTypeKind.Primitive) || uri != null, "Either uri or resource type must be specified"); if ((uri != null || resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) && segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { // Open navigation properties are not supported on OpenTypes. throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segmentInfo.Identifier)); } 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 && jsonObjectRecord.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 = GetObjectFromSegmentInfo( resourceType, segmentInfo, true /*checkETag*/, true /*checkForNull*/, this.Service.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.PUT /*replaceResource*/); } else { // case of binding at the first level. existingRelationship = false; return(this.GetTargetResourceToBind(uri, false /*checkNull*/)); } } 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 && jsonObjectRecord.Count == 1) { this.RecurseLeave(); return(this.GetTargetResourceToBind(uri, false /*checkNull*/)); } } } } Debug.Assert(resourceType != null, "resourceType != null"); if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType) { Debug.Assert(resource == null, "resource == null"); resource = this.Updatable.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 DataServiceConfiguration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend); resource = this.Updatable.CreateResource(segmentInfo.TargetContainer.Name, resourceType.FullName); // If resourceType is FF mapped with KeepInContent=false and the response format is Atom, we need to raise the response DSV version // Note that we only need to do this for POST since PUT responds with 204 and DSV=1.0 // // Errr, mismatching request and response formats don't meet the bar at this point, commenting out the fix... // //// this.UpdateAndCheckEpmRequestResponseDSV(resourceType, topLevel); this.Tracker.TrackAction(resource, segmentInfo.TargetContainer, UpdateOperations.Add); } else { Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.OpenProperty, "segmentInfo.TargetKind == RequestTargetKind.OpenProperty"); // Open navigation properties are not supported on OpenTypes. throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segmentInfo.Identifier)); } existingResource = false; } bool changed = this.PopulateProperties(jsonObjectRecord, resource, segmentInfo.TargetContainer, 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.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.PUT; if (changed && existingResource && segmentInfo.TargetContainer != null) { this.Tracker.TrackAction(resource, segmentInfo.TargetContainer, UpdateOperations.Change); } this.RecurseLeave(); return(resource); }
/// <summary> /// Populate the properties of the given resource /// </summary> /// <param name="jsonObject">JsonObjectRecords containing property name and values</param> /// <param name="resource">instance of the resource whose properties needs to be populated</param> /// <param name="parentResourceSet">resource set where <paramref name="resource"/> belongs to</param> /// <param name="parentResourceType">resource type whose properties needs to be populated</param> /// <returns>true if any properties were set; false otherwise.</returns> private bool PopulateProperties(JsonReader.JsonObjectRecords jsonObject, object resource, ResourceSetWrapper parentResourceSet, 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; List <ResourceProperty> navProperties = new List <ResourceProperty>(); List <object> navPropertyValues = new List <object>(); #region Handle Non-Nav Properties foreach (string propertyName in jsonObject.OrderedKeys) { // 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 (resourceProperty == null && parentResourceType.IsOpenType == false) { 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.Entries[propertyName]; bool existingRelationship; // If its a open property if (resourceProperty == null) { this.HandleOpenTypeProperties(resource, propertyName, propertyValue); changed = true; } else if (resourceProperty.TypeKind == ResourceTypeKind.ComplexType) { SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, null, true /* singleResult */); segmentInfo.TargetKind = RequestTargetKind.ComplexObject; propertyValue = this.CreateObject(propertyValue, segmentInfo, false /*topLevel*/, out existingRelationship); SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service); 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); } changed = true; } else { Debug.Assert(ResourceTypeKind.EntityType == resourceProperty.TypeKind, "only expecting nav properties"); if (IsDeferredElement(propertyValue)) { // Skip the deferred element continue; } else { navProperties.Add(resourceProperty); navPropertyValues.Add(propertyValue); } } } #endregion Non-Navigation Properties #region Handle Navigation Properties Debug.Assert(navProperties.Count == navPropertyValues.Count, "nav properties and nav property values count must be the same"); // The reason why we need to do this is so that we can gaurantee that the nav properties are getting set at the end. // This is nice, since we already do this in the atom deserializer. Hence its consistent. Second, we wanted to // give a gaurantee that when FK and nav properties are specified in the payload, nav properties always win. for (int i = 0; i < navProperties.Count; i++) { this.HandleNavigationProperty(parentResourceSet, parentResourceType, resource, navProperties[i], navPropertyValues[i]); changed = true; } #endregion Handle Navigation Properties return(changed); }
/// <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 an exception for a parse error.</summary> /// <param name="message">Message text.</param> /// <returns>A new Exception.</returns> private static Exception ParseError(string message) { return(DataServiceException.CreateSyntaxError(message)); }
public SequencedMessage GetPageItems(DataMessage dataMessage) { int sequenceId = (int)dataMessage.headers[DataMessage.SequenceIdHeader]; Sequence sequence = GetSequence(sequenceId); if (sequence != null) { IList DSids = dataMessage.headers["DSids"] as IList; //ArrayList items = new ArrayList(DSids.Count); SequencedMessage sequencedMessage = new SequencedMessage(); object[] items = new object[DSids.Count]; lock (_objLock) { for (int i = 0; i < DSids.Count; i++) { Identity identity = new Identity(DSids[i] as IDictionary); ItemWrapper itemWrapper = GetItem(identity); //items.Add(item); items[i] = itemWrapper.Instance; } sequencedMessage.destination = dataMessage.destination; sequencedMessage.sequenceId = sequence.Id; sequencedMessage.sequenceSize = sequence.Size; sequencedMessage.sequenceProxies = null; sequencedMessage.body = items; } return sequencedMessage; } else { DataServiceException dse = new DataServiceException(string.Format("Sequence {0} in destination {1} was not found", sequenceId, dataMessage.destination)); throw dse; } }
/// <summary> /// Generates a comparison expression which can handle NULL values for any type. /// NULL is always treated as the smallest possible value. /// So for example for strings NULL is smaller than any non-NULL string. /// For now only GreaterThan and LessThan operators are supported by this method. /// </summary> /// <param name="left">Left hand side expression</param> /// <param name="right">Right hand side expression</param> /// <param name="operatorKind">gt or lt operator token</param> /// <returns>Resulting comparison expression (has a Boolean value)</returns> private Expression GenerateNullAwareComparison(Expression left, Expression right, BinaryOperatorKind operatorKind) { Debug.Assert( operatorKind == BinaryOperatorKind.GreaterThan || operatorKind == BinaryOperatorKind.LessThan, "Only GreaterThan or LessThan operators are supported by the GenerateNullAwateComparison method for now."); if (WebUtil.TypeAllowsNull(left.Type)) { if (!WebUtil.TypeAllowsNull(right.Type)) { right = Expression.Convert(right, typeof(Nullable <>).MakeGenericType(right.Type)); } } else if (WebUtil.TypeAllowsNull(right.Type)) { left = Expression.Convert(left, typeof(Nullable <>).MakeGenericType(left.Type)); } else { // Can't perform NULL aware comparison on this type. Just let the normal // comparison deal with it. Since the type doesn't allow NULL one should // never appear, so normal comparison is just fine. return(this.GenerateComparisonExpression(left, right, operatorKind)); } switch (operatorKind) { case BinaryOperatorKind.GreaterThan: // (left != null) && ((right == null) || Compare(left, right) > 0) if (left == ExpressionUtils.NullLiteral) { return(Expression.Constant(false, typeof(bool))); } else if (right == ExpressionUtils.NullLiteral) { return(ExpressionGenerator.GenerateNotEqual(left, Expression.Constant(null, left.Type))); } else { return(ExpressionGenerator.GenerateLogicalAnd( ExpressionGenerator.GenerateNotEqual(left, Expression.Constant(null, left.Type)), ExpressionGenerator.GenerateLogicalOr( ExpressionGenerator.GenerateEqual(right, Expression.Constant(null, right.Type)), this.GenerateComparisonExpression(left, right, operatorKind)))); } case BinaryOperatorKind.LessThan: // (right != null) && ((left == null) || Compare(left, right) < 0) if (right == ExpressionUtils.NullLiteral) { return(Expression.Constant(false, typeof(bool))); } else if (left == ExpressionUtils.NullLiteral) { return(ExpressionGenerator.GenerateNotEqual(right, Expression.Constant(null, right.Type))); } else { return(ExpressionGenerator.GenerateLogicalAnd( ExpressionGenerator.GenerateNotEqual(right, Expression.Constant(null, left.Type)), ExpressionGenerator.GenerateLogicalOr( ExpressionGenerator.GenerateEqual(left, Expression.Constant(null, right.Type)), this.GenerateComparisonExpression(left, right, operatorKind)))); } default: // For now only < and > are supported as we use this only from $skiptoken string message = ServiceStrings.RequestQueryParser_NullOperatorUnsupported(operatorKind); throw DataServiceException.CreateSyntaxError(message); } }
public void CtorStatusAndMessage() { var ex = new DataServiceException (404, "message"); Assert.AreEqual (404, ex.StatusCode); Assert.AreEqual ("message", ex.Message); }
public void UpdateProviderPropertyTest() { IDataService service = this.serviceFactory.CreateService <CustomUpdateProvider2Service>(); ODataProtocolVersion[] versions = new[] { ODataProtocolVersion.V4 }; bool[] boolValues = new[] { true, false }; List <string> failureCombinations = new List <string>(); foreach (var version in versions) { foreach (var hasReflectionOrEFProviderQueryBehavior in boolValues) { foreach (var implementsIUpdatable in boolValues) { foreach (var implementsIDSUP in boolValues) { foreach (var implementsIDSUP2 in boolValues) { service.Configuration.DataServiceBehavior.MaxProtocolVersion = version; CustomUpdateProvider2Service.ImplementsIUpdatable = implementsIUpdatable; CustomUpdateProvider2Service.ImplementsIDSUP = implementsIDSUP; CustomUpdateProvider2Service.ImplementsIDSUP2 = implementsIDSUP2; CustomUpdateProvider2Service.IUpdatableGetCount = 0; CustomUpdateProvider2Service.IDataServiceUpdateProviderGetCount = 0; CustomUpdateProvider2Service.IDataServiceUpdateProvider2GetCount = 0; ((DataServiceSimulator)service).Provider = CreateProviderWrapper(service.Configuration, hasReflectionOrEFProviderQueryBehavior); UpdatableWrapper updatable = new UpdatableWrapper(service); try { var instance = updatable.GetType().GetProperty("UpdateProvider", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(updatable, null); Assert.IsNotNull(instance, "UpdatableWrapper should throw if UpdateProvider fails to get the interface."); Assert.AreEqual(1, CustomUpdateProvider2Service.IDataServiceUpdateProvider2GetCount); // None of this code is actually hit, we need to investigate this. if (!CustomUpdateProvider2Service.ImplementsIDSUP2) { if (hasReflectionOrEFProviderQueryBehavior) { Assert.AreEqual(1, CustomUpdateProvider2Service.IUpdatableGetCount); } else { Assert.AreEqual(0, CustomUpdateProvider2Service.IUpdatableGetCount); } if (!CustomUpdateProvider2Service.ImplementsIUpdatable) { Assert.AreEqual(1, CustomUpdateProvider2Service.IDataServiceUpdateProviderGetCount); } else { if (hasReflectionOrEFProviderQueryBehavior) { Assert.AreEqual(0, CustomUpdateProvider2Service.IDataServiceUpdateProviderGetCount); } else { Assert.AreEqual(1, CustomUpdateProvider2Service.IDataServiceUpdateProviderGetCount); } } } else { Assert.AreEqual(0, CustomUpdateProvider2Service.IUpdatableGetCount); Assert.AreEqual(0, CustomUpdateProvider2Service.IDataServiceUpdateProviderGetCount); } } catch (TargetInvocationException tie) { string errorCaseVariation = string.Format("Version:{0}, hasReflectionOrEFProviderQueryBehavior:{1}, implementsIUpdatable:{2}, implementsIDSUP:{3}, implementsIDSUP2:{4}", version, hasReflectionOrEFProviderQueryBehavior, implementsIUpdatable, implementsIDSUP, implementsIDSUP2); failureCombinations.Add(errorCaseVariation); DataServiceException e = (DataServiceException)tie.InnerException; Assert.AreEqual(501, e.StatusCode); if (hasReflectionOrEFProviderQueryBehavior) { Assert.AreEqual("The data source must implement IUpdatable, IDataServiceUpdateProvider or IDataServiceUpdateProvider2 to support updates.", e.Message); } else { Assert.AreEqual("The data source must implement IDataServiceUpdateProvider or IDataServiceUpdateProvider2 to support updates.", e.Message); } } } } } } } }
public void CtorMessage() { var ex = new DataServiceException ("message"); Assert.AreEqual ("message", ex.Message); Assert.IsNull (ex.InnerException); }
/// <summary> /// Reads the input request payload and returns the WCF DS value representation of it. /// </summary> /// <param name="segmentInfo">Info about the request to read.</param> /// <returns>The WCF DS representation of the value read.</returns> protected override object Read(SegmentInfo segmentInfo) { Debug.Assert(segmentInfo != null, "segmentInfo != null"); Debug.Assert( segmentInfo.TargetKind == RequestTargetKind.Primitive || segmentInfo.TargetKind == RequestTargetKind.ComplexObject || segmentInfo.TargetKind == RequestTargetKind.Collection || segmentInfo.TargetKind == RequestTargetKind.OpenProperty, "The PropertyDeserializer only supports Primitive, ComplexObject, Collection or OpenProperty target kinds."); ResourceProperty resourceProperty; ResourceType propertyResourceType; IEdmTypeReference propertyTypeReference; if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { resourceProperty = null; propertyResourceType = null; propertyTypeReference = null; } else { resourceProperty = segmentInfo.ProjectedProperty; propertyResourceType = resourceProperty.ResourceType; propertyTypeReference = this.GetTypeReference(propertyResourceType, resourceProperty.CustomAnnotations.ToList()); // WCF DS server allows null values for primitive properties. For non top-level properties, custom annotations are added // to ensure ODataLib does not perform any validation. The provider can choose to throw in which case, the response code will be 500. The // same applies to top-level primitive properties. So, we ensure the type reference carries the correct value for the nullability facet. if (resourceProperty.Kind == ResourcePropertyKind.Primitive && MetadataProviderUtils.ShouldDisablePrimitivePropertyNullValidation(resourceProperty, (IEdmPrimitiveTypeReference)propertyTypeReference)) { propertyTypeReference = this.GetSchemaType(propertyResourceType).ToTypeReference(true); } // WCF DS server allows null values for complex properties. For non top-level properties, custom annotations are added // to ensure ODataLib does not perform any validation. The provider can choose to throw in which case, the response code will be 500. The // same applies to top-level complex properties. So, we ensure the type reference carries the correct value for the nullability facet. if (resourceProperty.Kind == ResourcePropertyKind.ComplexType && this.Service.Provider.HasReflectionOrEFProviderQueryBehavior && !propertyTypeReference.IsNullable) { propertyTypeReference = this.GetSchemaType(propertyResourceType).ToTypeReference(true); } } ODataProperty property = this.MessageReader.ReadProperty(propertyTypeReference); Debug.Assert(property != null, "property != null"); #pragma warning disable 618 AssertReaderFormatIsExpected(this.MessageReader, ODataFormat.Atom, ODataFormat.Json); #pragma warning restore 618 // On V4, it seems this checking logic is useless. Will remove it after fully understanding. // PlainXmlDeserializer - PUT to a property with m:null='true' doesn't verify the name of the property matches // // PUT to open property with XML payload ignores the name of the property in the payload. // For backward compat reasons we must not fail if the property name doesn't match and the value is null or it's an open property (in XML case). // // V2 Server reads JSON complex values without property wrapper, ODataLib will report these as ODataProperty with empty name, so for those // we need to not compare the property name. // // For Json light, we do not validate the property name since in requests we do not parse the metadata URI and thus // will always report 'value'. if (!this.IsAtomRequest && !this.IsJsonLightRequest && string.CompareOrdinal(segmentInfo.Identifier, property.Name) != 0) { throw DataServiceException.CreateBadRequestError( Microsoft.OData.Service.Strings.PlainXml_IncorrectElementName(segmentInfo.Identifier, property.Name)); } object propertyValue = property.Value; object convertedValue = this.ConvertValue(propertyValue, ref propertyResourceType); if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { // Set the target resource type for open properties so we can reason over the property type later. // The target resource type of an open property segment is determined when converting the payload value above. Debug.Assert(segmentInfo.TargetResourceType == null, "segmentInfo.TargetResourceType == null"); segmentInfo.TargetResourceType = propertyResourceType; } else { Debug.Assert(segmentInfo.TargetResourceType.FullName == propertyResourceType.FullName, "segmentInfo.TargetResourceType == propertyResourceType"); } return(convertedValue); }