diff --git a/src/Microsoft.OData.Core/ODataPreferenceHeader.cs b/src/Microsoft.OData.Core/ODataPreferenceHeader.cs index 5e8bd02db9..42c05f007e 100644 --- a/src/Microsoft.OData.Core/ODataPreferenceHeader.cs +++ b/src/Microsoft.OData.Core/ODataPreferenceHeader.cs @@ -46,6 +46,21 @@ public sealed class ODataPreferenceHeader /// private const string WaitPreferenceTokenName = "wait"; + /// + /// The odata.continue-on-error preference token. + /// + private const string ODataContinueOnErrorPreferenceToken = "odata.continue-on-error"; + + /// + /// The odata.maxpagesize=# preference token. + /// + private const string ODataMaxPageSizePreferenceToken = "odata.maxpagesize"; + + /// + /// The odata.track-changes preference token. + /// + private const string ODataTrackChangesPreferenceToken = "odata.track-changes"; + /// /// The Prefer header name. /// @@ -61,6 +76,11 @@ public sealed class ODataPreferenceHeader /// private static readonly KeyValuePair[] EmptyParameters = new KeyValuePair[0]; + /// + /// The odata.continue-on-error preference. + /// + private static readonly HttpHeaderValueElement ContinueOnErrorPreference = new HttpHeaderValueElement(ODataContinueOnErrorPreferenceToken, null, EmptyParameters); + /// /// The return=minimal preference. /// @@ -76,6 +96,11 @@ public sealed class ODataPreferenceHeader /// private static readonly HttpHeaderValueElement RespondAsyncPreference = new HttpHeaderValueElement(RespondAsyncPreferenceToken, null, EmptyParameters); + /// + /// The odata.track-changes preference. + /// + private static readonly HttpHeaderValueElement TrackChangesPreference = new HttpHeaderValueElement(ODataTrackChangesPreferenceToken, null, EmptyParameters); + /// /// The message to set the preference header to and to get the preference header from. /// @@ -288,6 +313,98 @@ private HttpHeaderValue Preferences get { return this.preferences ?? (this.preferences = this.ParsePreferences()); } } + /// + /// Property to get and set the "odata.continue-on-error" preference to the "Prefer" header on the underlying IODataRequestMessage or + /// the "Preference-Applied" header on the underlying IODataResponseMessage. + /// Setting true sets the "odata.continue-on-error" preference. + /// Setting false clears the "odata.continue-on-error" preference. + /// Returns true of the "odata.continue-on-error" preference is on the header. Otherwise returns false if the "odata.continue-on-error" is not on the header. + /// + public bool ContinueOnError + { + get + { + return this.Get(ODataContinueOnErrorPreferenceToken) != null; + } + + set + { + if (value) + { + this.Set(ContinueOnErrorPreference); + } + else + { + this.Clear(ODataContinueOnErrorPreferenceToken); + } + } + } + + /// + /// Property to get and set the "odata.maxpagesize" preference to the "Prefer" header on the underlying IODataRequestMessage or + /// the "Preference-Applied" header on the underlying IODataResponseMessage. + /// Setting N sets the "odata.maxpagesize=N" preference. + /// Setting null clears the "odata.maxpagesize" preference. + /// Returns N if the "odata.maxpagesize=N" preference is on the header. + /// Returning null indicates that "odata.maxpagesize" is not on the header. + /// + public int? MaxPageSize + { + get + { + var maxPageSizeHttpHeaderValueElement = this.Get(ODataMaxPageSizePreferenceToken); + + // Should check maxPageSizeHttpHeaderValueElement.Value != null. + // Should do int.TryParse. + // If either of the above fail, should throw an ODataException for parsing, not a System.Exception (such as FormatException, etc.). + if (maxPageSizeHttpHeaderValueElement != null) + { + return int.Parse(maxPageSizeHttpHeaderValueElement.Value, CultureInfo.InvariantCulture); + } + + return null; + } + + set + { + if (value.HasValue) + { + this.Set(new HttpHeaderValueElement(ODataMaxPageSizePreferenceToken, string.Format(CultureInfo.InvariantCulture, "{0}", value.Value), EmptyParameters)); + } + else + { + this.Clear(ODataMaxPageSizePreferenceToken); + } + } + } + + /// + /// Property to get and set the "odata.track-changes" preference to the "Prefer" header on the underlying IODataRequestMessage or + /// the "Preference-Applied" header on the underlying IODataResponseMessage. + /// Setting true sets the "odata.track-changes" preference. + /// Setting false clears the "odata.track-changes" preference. + /// Returns true of the "odata.track-changes" preference is on the header. Otherwise returns false if the "odata.track-changes" is not on the header. + /// + public bool TrackChanges + { + get + { + return this.Get(ODataTrackChangesPreferenceToken) != null; + } + + set + { + if (value) + { + this.Set(TrackChangesPreference); + } + else + { + this.Clear(ODataTrackChangesPreferenceToken); + } + } + } + /// /// Adds quotes around the given text value. /// diff --git a/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs b/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs index e1b726c129..995eb99838 100644 --- a/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs +++ b/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs @@ -30,6 +30,9 @@ public class ODataPreferenceHeaderTests private const string RespondAyncPreference = "respond-async"; private const string RespondAsyncAndWaitPreference = "respond-async,wait=10"; private const string WaitPreference = "wait=10"; + private const string MaxPageSizePreference = "odata.maxpagesize"; + private const string TrackChangesPreference = "odata.track-changes"; + private const string ContinueOnErrorPreference = "odata.continue-on-error"; [TestInitialize] public void TestInit() @@ -250,5 +253,64 @@ public void ReturnWaitOfBadIntergerFormatShouldThrow() Action test = () => wait = this.preferHeader.Wait; test.ShouldThrow().WithMessage("Input string was not in a correct format."); } + + [TestMethod] + public void SetContinueOnErrorToTrueShouldAppendHeader() + { + this.preferHeader.ContinueOnError = true; + this.preferHeader.ContinueOnError.Should().BeTrue(); + this.requestMessage.GetHeader(PreferHeaderName).Should().Be(ContinueOnErrorPreference); + } + + [TestMethod] + public void SetContinueOnErrorToFalseShouldClearHeader() + { + this.preferHeader.ContinueOnError = false; + this.preferHeader.ContinueOnError.Should().BeFalse(); + this.requestMessage.GetHeader(PreferHeaderName).Should().BeNull(); + } + + [TestMethod] + public void SetMaxPageSizeShouldAppendHeader() + { + const int MaxPageSize = 10; + this.preferHeader.MaxPageSize = MaxPageSize; + this.preferHeader.MaxPageSize.Should().Be(MaxPageSize); + this.requestMessage.GetHeader(PreferHeaderName).Should().Be(string.Format("{0}={1}", MaxPageSizePreference, MaxPageSize)); + } + + [TestMethod] + public void SetMaxPageSizeToNullShouldClearHeader() + { + this.preferHeader.MaxPageSize = null; + this.preferHeader.MaxPageSize.Should().Be(null); + this.requestMessage.GetHeader(PreferHeaderName).Should().BeNull(); + } + + [TestMethod] + public void ReturnMaxPageSizeOfBadIntergerFormatShouldThrow() + { + this.requestMessage.SetHeader(PreferHeaderName, string.Format("{0}=abc", MaxPageSizePreference)); + this.preferHeader = new ODataPreferenceHeader(this.requestMessage); + int? maxPageSize; + Action test = () => maxPageSize = this.preferHeader.MaxPageSize; + test.ShouldThrow().WithMessage("Input string was not in a correct format."); + } + + [TestMethod] + public void SetTrackChangesToTrueShouldAppendHeader() + { + this.preferHeader.TrackChanges = true; + this.preferHeader.TrackChanges.Should().BeTrue(); + this.requestMessage.GetHeader(PreferHeaderName).Should().Be(TrackChangesPreference); + } + + [TestMethod] + public void SetTrackChangesToFalseShouldClearHeader() + { + this.preferHeader.TrackChanges = false; + this.preferHeader.TrackChanges.Should().BeFalse(); + this.requestMessage.GetHeader(PreferHeaderName).Should().BeNull(); + } } }