summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOAuth.Test/Messaging/ChannelTests.cs1
-rw-r--r--src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs2
-rw-r--r--src/DotNetOAuth.Test/Messaging/MessagingTestBase.cs54
-rw-r--r--src/DotNetOAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs13
-rw-r--r--src/DotNetOAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs4
-rw-r--r--src/DotNetOAuth.Test/Messaging/Reflection/MessagePartTests.cs95
-rw-r--r--src/DotNetOAuth.Test/Messaging/Reflection/ValueMappingTests.cs13
-rw-r--r--src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs3
-rw-r--r--src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs2
-rw-r--r--src/DotNetOAuth.Test/OAuthChannelTests.cs2
-rw-r--r--src/DotNetOAuth/Messaging/Bindings/ExpiredMessageException.cs3
-rw-r--r--src/DotNetOAuth/Messaging/Channel.cs33
-rw-r--r--src/DotNetOAuth/Messaging/HttpRequestInfo.cs6
-rw-r--r--src/DotNetOAuth/Messaging/MessagePartAttribute.cs25
-rw-r--r--src/DotNetOAuth/Messaging/MessageScheme.cs4
-rw-r--r--src/DotNetOAuth/Messaging/MessageSerializer.cs3
-rw-r--r--src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs2
-rw-r--r--src/DotNetOAuth/Messaging/MessagingStrings.resx2
-rw-r--r--src/DotNetOAuth/Messaging/Reflection/MessageDescription.cs59
-rw-r--r--src/DotNetOAuth/Messaging/Reflection/MessageDictionary.cs203
-rw-r--r--src/DotNetOAuth/Messaging/Reflection/MessagePart.cs187
-rw-r--r--src/DotNetOAuth/Messaging/Reflection/ValueMapping.cs15
-rw-r--r--src/DotNetOAuth/OAuthChannel.cs40
23 files changed, 532 insertions, 239 deletions
diff --git a/src/DotNetOAuth.Test/Messaging/ChannelTests.cs b/src/DotNetOAuth.Test/Messaging/ChannelTests.cs
index e8c4514..8aeaa5b 100644
--- a/src/DotNetOAuth.Test/Messaging/ChannelTests.cs
+++ b/src/DotNetOAuth.Test/Messaging/ChannelTests.cs
@@ -14,7 +14,6 @@ namespace DotNetOAuth.Test.Messaging {
using DotNetOAuth.Messaging.Bindings;
using DotNetOAuth.Test.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System.Xml;
[TestClass]
public class ChannelTests : MessagingTestBase {
diff --git a/src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs b/src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs
index a41753b..1d36b83 100644
--- a/src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs
+++ b/src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs
@@ -7,9 +7,9 @@
namespace DotNetOAuth.Test.Messaging {
using System;
using System.Collections.Generic;
+ using System.Xml;
using DotNetOAuth.Messaging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System.Xml;
/// <summary>
/// Tests for the <see cref="MessageSerializer"/> class.
diff --git a/src/DotNetOAuth.Test/Messaging/MessagingTestBase.cs b/src/DotNetOAuth.Test/Messaging/MessagingTestBase.cs
index 34cf1df..aa4f350 100644
--- a/src/DotNetOAuth.Test/Messaging/MessagingTestBase.cs
+++ b/src/DotNetOAuth.Test/Messaging/MessagingTestBase.cs
@@ -19,6 +19,30 @@ namespace DotNetOAuth.Test {
/// The base class that all messaging test classes inherit from.
/// </summary>
public class MessagingTestBase : TestBase {
+ internal enum FieldFill {
+ /// <summary>
+ /// An empty dictionary is returned.
+ /// </summary>
+ None,
+
+ /// <summary>
+ /// Only enough fields for the <see cref="TestMessageTypeProvider"/>
+ /// to identify the message are included.
+ /// </summary>
+ IdentifiableButNotAllRequired,
+
+ /// <summary>
+ /// All fields marked as required are included.
+ /// </summary>
+ AllRequired,
+
+ /// <summary>
+ /// All user-fillable fields in the message, leaving out those whose
+ /// values are to be set by channel binding elements.
+ /// </summary>
+ CompleteBeforeBindings,
+ }
+
internal Channel Channel { get; set; }
[TestInitialize]
@@ -85,30 +109,6 @@ namespace DotNetOAuth.Test {
return new TestChannel(typeProvider, bindingElements.ToArray());
}
- internal enum FieldFill {
- /// <summary>
- /// An empty dictionary is returned.
- /// </summary>
- None,
-
- /// <summary>
- /// Only enough fields for the <see cref="TestMessageTypeProvider"/>
- /// to identify the message are included.
- /// </summary>
- IdentifiableButNotAllRequired,
-
- /// <summary>
- /// All fields marked as required are included.
- /// </summary>
- AllRequired,
-
- /// <summary>
- /// All user-fillable fields in the message, leaving out those whose
- /// values are to be set by channel binding elements.
- /// </summary>
- CompleteBeforeBindings,
- }
-
internal static IDictionary<string, string> GetStandardTestFields(FieldFill fill) {
TestMessage expectedMessage = GetStandardTestMessage(fill);
@@ -152,8 +152,8 @@ namespace DotNetOAuth.Test {
internal void ParameterizedReceiveTest(string method) {
var fields = GetStandardTestFields(FieldFill.CompleteBeforeBindings);
- TestMessage expectedMessage = GetStandardTestMessage(FieldFill.CompleteBeforeBindings); ;
-
+ TestMessage expectedMessage = GetStandardTestMessage(FieldFill.CompleteBeforeBindings);
+
IProtocolMessage requestMessage = this.Channel.ReadFromRequest(CreateHttpRequestInfo(method, fields));
Assert.IsNotNull(requestMessage);
Assert.IsInstanceOfType(requestMessage, typeof(TestMessage));
@@ -164,7 +164,7 @@ namespace DotNetOAuth.Test {
}
internal void ParameterizedReceiveProtectedTest(DateTime? utcCreatedDate, bool invalidSignature) {
- TestMessage expectedMessage = GetStandardTestMessage(FieldFill.CompleteBeforeBindings); ;
+ TestMessage expectedMessage = GetStandardTestMessage(FieldFill.CompleteBeforeBindings);
var fields = GetStandardTestFields(FieldFill.CompleteBeforeBindings);
fields.Add("Signature", invalidSignature ? "badsig" : MockSigningBindingElement.MessageSignature);
fields.Add("Nonce", "someNonce");
diff --git a/src/DotNetOAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs b/src/DotNetOAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs
index 04c1df8..90c64dc 100644
--- a/src/DotNetOAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs
+++ b/src/DotNetOAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs
@@ -1,10 +1,13 @@
-namespace DotNetOAuth.Test.Messaging.Reflection {
+//-----------------------------------------------------------------------
+// <copyright file="MessageDescriptionTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Messaging.Reflection {
using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
using DotNetOAuth.Messaging.Reflection;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class MessageDescriptionTests : MessagingTestBase {
diff --git a/src/DotNetOAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs b/src/DotNetOAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs
index b1ae0b6..143e6b8 100644
--- a/src/DotNetOAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs
+++ b/src/DotNetOAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs
@@ -1,5 +1,5 @@
//-----------------------------------------------------------------------
-// <copyright file="MessageDictionaryTest.cs" company="Andrew Arnott">
+// <copyright file="MessageDictionaryTests.cs" company="Andrew Arnott">
// Copyright (c) Andrew Arnott. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
@@ -9,10 +9,10 @@ namespace DotNetOAuth.Test.Messaging.Reflection {
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+ using System.Xml;
using DotNetOAuth.Messaging;
using DotNetOAuth.Messaging.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System.Xml;
[TestClass]
public class MessageDictionaryTests : MessagingTestBase {
diff --git a/src/DotNetOAuth.Test/Messaging/Reflection/MessagePartTests.cs b/src/DotNetOAuth.Test/Messaging/Reflection/MessagePartTests.cs
index 0dba07b..90ccca4 100644
--- a/src/DotNetOAuth.Test/Messaging/Reflection/MessagePartTests.cs
+++ b/src/DotNetOAuth.Test/Messaging/Reflection/MessagePartTests.cs
@@ -1,61 +1,38 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using DotNetOAuth.Messaging.Reflection;
-using System.Reflection;
-using DotNetOAuth.Test.Mocks;
-using DotNetOAuth.Messaging;
+//-----------------------------------------------------------------------
+// <copyright file="MessagePartTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
namespace DotNetOAuth.Test.Messaging.Reflection {
- [TestClass]
- public class MessagePartTests :MessagingTestBase {
- class MessageWithNonNullableOptionalStruct : TestMessage {
- /// <summary>
- /// Optional structs like int must be nullable for Optional to make sense.
- /// </summary>
- [MessagePart(IsRequired = false)]
- internal int optionalInt = 0;
- }
- class MessageWithNonNullableRequiredStruct : TestMessage {
- /// <summary>
- /// This should work because a required field will always have a value so it
- /// need not be nullable.
- /// </summary>
- [MessagePart(IsRequired = true)]
- internal int optionalInt = 0;
- }
- class MessageWithNullableOptionalStruct : TestMessage {
- /// <summary>
- /// Optional structs like int must be nullable for Optional to make sense.
- /// </summary>
- [MessagePart(IsRequired = false)]
- internal int? optionalInt = 0;
- }
- class MessageWithNullableRequiredStruct : TestMessage {
- [MessagePart(IsRequired = true)]
- internal int? optionalInt = null;
- }
+ using System;
+ using System.Linq;
+ using System.Reflection;
+ using DotNetOAuth.Messaging;
+ using DotNetOAuth.Messaging.Reflection;
+ using DotNetOAuth.Test.Mocks;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ [TestClass]
+ public class MessagePartTests : MessagingTestBase {
[TestMethod, ExpectedException(typeof(ArgumentException))]
public void OptionalNonNullableStruct() {
- ParameterizedMessageTypeTest(typeof(MessageWithNonNullableOptionalStruct));
+ this.ParameterizedMessageTypeTest(typeof(MessageWithNonNullableOptionalStruct));
}
[TestMethod]
public void RequiredNonNullableStruct() {
- ParameterizedMessageTypeTest(typeof(MessageWithNonNullableRequiredStruct));
+ this.ParameterizedMessageTypeTest(typeof(MessageWithNonNullableRequiredStruct));
}
[TestMethod]
public void OptionalNullableStruct() {
- ParameterizedMessageTypeTest(typeof(MessageWithNullableOptionalStruct));
+ this.ParameterizedMessageTypeTest(typeof(MessageWithNullableOptionalStruct));
}
[TestMethod]
public void RequiredNullableStruct() {
- ParameterizedMessageTypeTest(typeof(MessageWithNullableRequiredStruct));
+ this.ParameterizedMessageTypeTest(typeof(MessageWithNullableRequiredStruct));
}
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
@@ -65,23 +42,23 @@ namespace DotNetOAuth.Test.Messaging.Reflection {
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullAttribute() {
- FieldInfo field = typeof(MessageWithNullableOptionalStruct).GetField("optionalInt", BindingFlags.NonPublic | BindingFlags.Instance);
+ PropertyInfo field = typeof(MessageWithNullableOptionalStruct).GetProperty("OptionalInt", BindingFlags.NonPublic | BindingFlags.Instance);
new MessagePart(field, null);
}
[TestMethod]
public void SetValue() {
var message = new MessageWithNonNullableRequiredStruct();
- MessagePart part = ParameterizedMessageTypeTest(message.GetType());
+ MessagePart part = this.ParameterizedMessageTypeTest(message.GetType());
part.SetValue(message, "5");
- Assert.AreEqual(5, message.optionalInt);
+ Assert.AreEqual(5, message.OptionalInt);
}
[TestMethod]
public void GetValue() {
var message = new MessageWithNonNullableRequiredStruct();
- message.optionalInt = 8;
- MessagePart part = ParameterizedMessageTypeTest(message.GetType());
+ message.OptionalInt = 8;
+ MessagePart part = this.ParameterizedMessageTypeTest(message.GetType());
Assert.AreEqual("8", part.GetValue(message));
}
@@ -92,9 +69,33 @@ namespace DotNetOAuth.Test.Messaging.Reflection {
}
private MessagePart ParameterizedMessageTypeTest(Type messageType) {
- FieldInfo field = messageType.GetField("optionalInt", BindingFlags.NonPublic | BindingFlags.Instance);
+ PropertyInfo field = messageType.GetProperty("OptionalInt", BindingFlags.NonPublic | BindingFlags.Instance);
MessagePartAttribute attribute = field.GetCustomAttributes(typeof(MessagePartAttribute), true).OfType<MessagePartAttribute>().Single();
return new MessagePart(field, attribute);
}
+
+ private class MessageWithNonNullableOptionalStruct : TestMessage {
+ // Optional structs like int must be nullable for Optional to make sense.
+ [MessagePart(IsRequired = false)]
+ internal int OptionalInt { get; set; }
+ }
+
+ private class MessageWithNonNullableRequiredStruct : TestMessage {
+ // This should work because a required field will always have a value so it
+ // need not be nullable.
+ [MessagePart(IsRequired = true)]
+ internal int OptionalInt { get; set; }
+ }
+
+ private class MessageWithNullableOptionalStruct : TestMessage {
+ // Optional structs like int must be nullable for Optional to make sense.
+ [MessagePart(IsRequired = false)]
+ internal int? OptionalInt { get; set; }
+ }
+
+ private class MessageWithNullableRequiredStruct : TestMessage {
+ [MessagePart(IsRequired = true)]
+ private int? OptionalInt { get; set; }
+ }
}
}
diff --git a/src/DotNetOAuth.Test/Messaging/Reflection/ValueMappingTests.cs b/src/DotNetOAuth.Test/Messaging/Reflection/ValueMappingTests.cs
index 9142a0c..5def394 100644
--- a/src/DotNetOAuth.Test/Messaging/Reflection/ValueMappingTests.cs
+++ b/src/DotNetOAuth.Test/Messaging/Reflection/ValueMappingTests.cs
@@ -1,10 +1,13 @@
-namespace DotNetOAuth.Test.Messaging.Reflection {
+//-----------------------------------------------------------------------
+// <copyright file="ValueMappingTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Messaging.Reflection {
using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
using DotNetOAuth.Messaging.Reflection;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class ValueMappingTests {
diff --git a/src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs b/src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs
index 6149902..2a52b2e 100644
--- a/src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs
+++ b/src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs
@@ -5,10 +5,9 @@
//-----------------------------------------------------------------------
namespace DotNetOAuth.Test.Mocks {
- using System.Runtime.Serialization;
using DotNetOAuth.Messaging;
- using DotNetOAuth.Messaging.Reflection;
using DotNetOAuth.Messaging.Bindings;
+ using DotNetOAuth.Messaging.Reflection;
internal class TestSignedDirectedMessage : TestDirectedMessage, ITamperResistantProtocolMessage {
internal TestSignedDirectedMessage() { }
diff --git a/src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs b/src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs
index 4eecb1f..33a2966 100644
--- a/src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs
+++ b/src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs
@@ -15,7 +15,7 @@ namespace DotNetOAuth.Test.Mocks {
private StringBuilder postEntity;
internal Func<HttpWebRequest, Response> Callback { get; set; }
-
+
internal Stream RequestEntityStream {
get {
if (this.postEntity == null) {
diff --git a/src/DotNetOAuth.Test/OAuthChannelTests.cs b/src/DotNetOAuth.Test/OAuthChannelTests.cs
index 8b7b24b..7677986 100644
--- a/src/DotNetOAuth.Test/OAuthChannelTests.cs
+++ b/src/DotNetOAuth.Test/OAuthChannelTests.cs
@@ -12,10 +12,10 @@ namespace DotNetOAuth.Test {
using System.Net;
using System.Text;
using System.Web;
+ using System.Xml;
using DotNetOAuth.Messaging;
using DotNetOAuth.Test.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System.Xml;
[TestClass]
public class OAuthChannelTests : TestBase {
diff --git a/src/DotNetOAuth/Messaging/Bindings/ExpiredMessageException.cs b/src/DotNetOAuth/Messaging/Bindings/ExpiredMessageException.cs
index df4c446..f983999 100644
--- a/src/DotNetOAuth/Messaging/Bindings/ExpiredMessageException.cs
+++ b/src/DotNetOAuth/Messaging/Bindings/ExpiredMessageException.cs
@@ -6,6 +6,7 @@
namespace DotNetOAuth.Messaging.Bindings {
using System;
+using System.Globalization;
/// <summary>
/// An exception thrown when a message is received that exceeds the maximum message age limit.
@@ -18,7 +19,7 @@ namespace DotNetOAuth.Messaging.Bindings {
/// <param name="utcExpirationDate">The date the message expired.</param>
/// <param name="faultedMessage">The expired message.</param>
public ExpiredMessageException(DateTime utcExpirationDate, IProtocolMessage faultedMessage)
- : base(string.Format(MessagingStrings.ExpiredMessage, utcExpirationDate.ToUniversalTime(), DateTime.UtcNow), faultedMessage) {
+ : base(string.Format(CultureInfo.CurrentCulture, MessagingStrings.ExpiredMessage, utcExpirationDate.ToUniversalTime(), DateTime.UtcNow), faultedMessage) {
}
/// <summary>
diff --git a/src/DotNetOAuth/Messaging/Channel.cs b/src/DotNetOAuth/Messaging/Channel.cs
index db6cc10..87c3bbe 100644
--- a/src/DotNetOAuth/Messaging/Channel.cs
+++ b/src/DotNetOAuth/Messaging/Channel.cs
@@ -16,7 +16,6 @@ namespace DotNetOAuth.Messaging {
using System.Text;
using System.Web;
using DotNetOAuth.Messaging.Reflection;
- using DotNetOAuth.Messaging.Bindings;
/// <summary>
/// Manages sending direct messages to a remote party and receiving responses.
@@ -334,7 +333,7 @@ namespace DotNetOAuth.Messaging {
}
WebHeaderCollection headers = new WebHeaderCollection();
- StringWriter bodyWriter = new StringWriter();
+ StringWriter bodyWriter = new StringWriter(CultureInfo.InvariantCulture);
StringBuilder hiddenFields = new StringBuilder();
foreach (var field in fields) {
hiddenFields.AppendFormat(
@@ -436,7 +435,7 @@ namespace DotNetOAuth.Messaging {
}
int countProtectionsOfThisKind = protectionElements.Count(element => (element.Protection & protectionKind) == protectionKind);
-
+
// Each protection binding element is backed by the presence of its dependent protection(s).
if (countProtectionsOfThisKind > 0 && !wasLastProtectionPresent) {
throw new ProtocolException(
@@ -485,6 +484,22 @@ namespace DotNetOAuth.Messaging {
}
/// <summary>
+ /// Verifies that all required message parts are initialized to values
+ /// prior to sending the message to a remote party.
+ /// </summary>
+ /// <param name="message">The message to verify.</param>
+ /// <exception cref="ProtocolException">
+ /// Thrown when any required message part does not have a value.
+ /// </exception>
+ private static void EnsureValidMessageParts(IProtocolMessage message) {
+ Debug.Assert(message != null, "message == null");
+
+ MessageDictionary dictionary = new MessageDictionary(message);
+ MessageDescription description = MessageDescription.Get(message.GetType());
+ description.EnsureRequiredMessagePartsArePresent(dictionary.Keys);
+ }
+
+ /// <summary>
/// Prepares a message for transmit by applying signatures, nonces, etc.
/// </summary>
/// <param name="message">The message to prepare for sending.</param>
@@ -530,16 +545,10 @@ namespace DotNetOAuth.Messaging {
throw new UnprotectedMessageException(message, appliedProtection);
}
- EnsureValidMessageParts(message);
+ // We do NOT verify that all required message parts are present here... the
+ // message deserializer did for us. It would be too late to do it here since
+ // they might look initialized by the time we have an IProtocolMessage instance.
message.EnsureValidMessage();
}
-
- private void EnsureValidMessageParts(IProtocolMessage message) {
- Debug.Assert(message != null, "message == null");
-
- MessageDictionary dictionary = new MessageDictionary(message);
- MessageDescription description = MessageDescription.Get(message.GetType());
- description.EnsureRequiredMessagePartsArePresent(dictionary.Keys);
- }
}
}
diff --git a/src/DotNetOAuth/Messaging/HttpRequestInfo.cs b/src/DotNetOAuth/Messaging/HttpRequestInfo.cs
index 9a583c0..65b5dcb 100644
--- a/src/DotNetOAuth/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOAuth/Messaging/HttpRequestInfo.cs
@@ -59,19 +59,19 @@ namespace DotNetOAuth.Messaging {
/// Gets or sets the verb in the request (i.e. GET, POST, etc.)
/// </summary>
internal string HttpMethod { get; set; }
-
+
/// <summary>
/// Gets or sets the entire URL of the request.
/// </summary>
internal Uri Url { get; set; }
-
+
/// <summary>
/// Gets the query part of the URL (The ? and everything after it).
/// </summary>
internal string Query {
get { return this.Url != null ? this.Url.Query : null; }
}
-
+
/// <summary>
/// Gets or sets the collection of headers that came in with the request.
/// </summary>
diff --git a/src/DotNetOAuth/Messaging/MessagePartAttribute.cs b/src/DotNetOAuth/Messaging/MessagePartAttribute.cs
index a8de784..ae88b61 100644
--- a/src/DotNetOAuth/Messaging/MessagePartAttribute.cs
+++ b/src/DotNetOAuth/Messaging/MessagePartAttribute.cs
@@ -9,24 +9,49 @@ namespace DotNetOAuth.Messaging {
using System.Net.Security;
using System.Reflection;
+ /// <summary>
+ /// Applied to fields and properties that form a key/value in a protocol message.
+ /// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
internal sealed class MessagePartAttribute : Attribute {
+ /// <summary>
+ /// The overridden name to use as the serialized name for the property.
+ /// </summary>
private string name;
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessagePartAttribute"/> class.
+ /// </summary>
internal MessagePartAttribute() {
}
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessagePartAttribute"/> class.
+ /// </summary>
+ /// <param name="name">
+ /// A special name to give the value of this member in the serialized message.
+ /// When null or empty, the name of the member will be used in the serialized message.
+ /// </param>
internal MessagePartAttribute(string name) {
this.Name = name;
}
+ /// <summary>
+ /// Gets or sets the name of the serialized form of this member in the message.
+ /// </summary>
public string Name {
get { return this.name; }
set { this.name = string.IsNullOrEmpty(value) ? null : value; }
}
+ /// <summary>
+ /// Gets or sets the level of protection required by this member in the serialized message.
+ /// </summary>
public ProtectionLevel RequiredProtection { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this member is a required part of the serialized message.
+ /// </summary>
public bool IsRequired { get; set; }
}
}
diff --git a/src/DotNetOAuth/Messaging/MessageScheme.cs b/src/DotNetOAuth/Messaging/MessageScheme.cs
index ee91740..2c0aec1 100644
--- a/src/DotNetOAuth/Messaging/MessageScheme.cs
+++ b/src/DotNetOAuth/Messaging/MessageScheme.cs
@@ -16,7 +16,7 @@ namespace DotNetOAuth.Messaging {
/// In the HTTP Authorization header as defined in OAuth HTTP Authorization Scheme (OAuth HTTP Authorization Scheme).
/// </summary>
AuthorizationHeaderRequest,
-
+
/// <summary>
/// As the HTTP POST request body with a content-type of application/x-www-form-urlencoded.
/// </summary>
@@ -26,7 +26,7 @@ namespace DotNetOAuth.Messaging {
/// Added to the URLs in the query part (as defined by [RFC3986] (Berners-Lee, T., “Uniform Resource Identifiers (URI): Generic Syntax,” .) section 3).
/// </summary>
GetRequest,
-
+
/// <summary>
/// Response parameters are sent by the Service Provider to return Tokens and other information to the Consumer in the HTTP response body. The parameter names and values are first encoded as per Parameter Encoding (Parameter Encoding), and concatenated with the ‘&amp;’ character (ASCII code 38) as defined in [RFC3986] (Berners-Lee, T., “Uniform Resource Identifiers (URI): Generic Syntax,” .) Section 2.1.
/// </summary>
diff --git a/src/DotNetOAuth/Messaging/MessageSerializer.cs b/src/DotNetOAuth/Messaging/MessageSerializer.cs
index 6edb0b6..800f691 100644
--- a/src/DotNetOAuth/Messaging/MessageSerializer.cs
+++ b/src/DotNetOAuth/Messaging/MessageSerializer.cs
@@ -64,6 +64,7 @@ namespace DotNetOAuth.Messaging {
/// </summary>
/// <param name="message">The message to be serialized.</param>
/// <returns>The dictionary of values to send for the message.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Parallel design with Deserialize method.")]
internal IDictionary<string, string> Serialize(IProtocolMessage message) {
if (message == null) {
throw new ArgumentNullException("message");
@@ -87,7 +88,7 @@ namespace DotNetOAuth.Messaging {
// Before we deserialize the message, make sure all the required parts are present.
MessageDescription.Get(this.messageType).EnsureRequiredMessagePartsArePresent(fields.Keys);
- IProtocolMessage result ;
+ IProtocolMessage result;
try {
result = (IProtocolMessage)Activator.CreateInstance(this.messageType, true);
} catch (MissingMethodException ex) {
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
index 9386f53..60e7c02 100644
--- a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
@@ -97,7 +97,7 @@ namespace DotNetOAuth.Messaging {
}
/// <summary>
- /// Looks up a localized string similar to Error occurred while sending a direct message or gettings the response..
+ /// Looks up a localized string similar to Error occurred while sending a direct message or getting the response..
/// </summary>
internal static string ErrorInRequestReplyMessage {
get {
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.resx b/src/DotNetOAuth/Messaging/MessagingStrings.resx
index bdbd212..b89ef4b 100644
--- a/src/DotNetOAuth/Messaging/MessagingStrings.resx
+++ b/src/DotNetOAuth/Messaging/MessagingStrings.resx
@@ -130,7 +130,7 @@
<value>The directed message's Recipient property must not be null.</value>
</data>
<data name="ErrorInRequestReplyMessage" xml:space="preserve">
- <value>Error occurred while sending a direct message or gettings the response.</value>
+ <value>Error occurred while sending a direct message or getting the response.</value>
</data>
<data name="ExceptionNotConstructedForTransit" xml:space="preserve">
<value>This exception was not constructed with a root request message that caused it.</value>
diff --git a/src/DotNetOAuth/Messaging/Reflection/MessageDescription.cs b/src/DotNetOAuth/Messaging/Reflection/MessageDescription.cs
index 9442f15..0f180c9 100644
--- a/src/DotNetOAuth/Messaging/Reflection/MessageDescription.cs
+++ b/src/DotNetOAuth/Messaging/Reflection/MessageDescription.cs
@@ -7,16 +7,36 @@
namespace DotNetOAuth.Messaging.Reflection {
using System;
using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Globalization;
using System.Linq;
using System.Reflection;
- using System.Globalization;
- using System.Diagnostics;
+ /// <summary>
+ /// A mapping between serialized key names and <see cref="MessagePart"/> instances describing
+ /// those key/values pairs.
+ /// </summary>
internal class MessageDescription {
- private static Dictionary<Type, MessageDescription> reflectedMessageTypes = new Dictionary<Type,MessageDescription>();
+ /// <summary>
+ /// A dictionary of reflected message types and the generated reflection information.
+ /// </summary>
+ private static Dictionary<Type, MessageDescription> reflectedMessageTypes = new Dictionary<Type, MessageDescription>();
+
+ /// <summary>
+ /// The type of message this instance was generated from.
+ /// </summary>
private Type messageType;
+
+ /// <summary>
+ /// A mapping between the serialized key names and their
+ /// describing <see cref="MessagePart"/> instances.
+ /// </summary>
private Dictionary<string, MessagePart> mapping;
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessageDescription"/> class.
+ /// </summary>
+ /// <param name="messageType">The type of message to reflect over.</param>
private MessageDescription(Type messageType) {
Debug.Assert(messageType != null, "messageType == null");
@@ -32,6 +52,20 @@ namespace DotNetOAuth.Messaging.Reflection {
this.ReflectMessageType();
}
+ /// <summary>
+ /// Gets the mapping between the serialized key names and their describing
+ /// <see cref="MessagePart"/> instances.
+ /// </summary>
+ internal IDictionary<string, MessagePart> Mapping {
+ get { return this.mapping; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="MessageDescription"/> instance prepared for the
+ /// given message type.
+ /// </summary>
+ /// <param name="messageType">A type that implements <see cref="IProtocolMessage"/>.</param>
+ /// <returns>A <see cref="MessageDescription"/> instance.</returns>
internal static MessageDescription Get(Type messageType) {
if (messageType == null) {
throw new ArgumentNullException("messageType");
@@ -49,10 +83,10 @@ namespace DotNetOAuth.Messaging.Reflection {
return result;
}
- internal IDictionary<string, MessagePart> Mapping {
- get { return this.mapping; }
- }
-
+ /// <summary>
+ /// Reflects over some <see cref="IProtocolMessage"/>-implementing type
+ /// and prepares to serialize/deserialize instances of that type.
+ /// </summary>
internal void ReflectMessageType() {
this.mapping = new Dictionary<string, MessagePart>();
@@ -75,16 +109,19 @@ namespace DotNetOAuth.Messaging.Reflection {
/// Verifies that a given set of keys include all the required parameters
/// for this message type or throws an exception.
/// </summary>
+ /// <param name="keys">The names of all parameters included in a message.</param>
/// <exception cref="ProtocolException">Thrown when required parts of a message are not in <paramref name="keys"/></exception>
internal void EnsureRequiredMessagePartsArePresent(IEnumerable<string> keys) {
var missingKeys = (from part in Mapping.Values
where part.IsRequired && !keys.Contains(part.Name)
select part.Name).ToArray();
if (missingKeys.Length > 0) {
- throw new ProtocolException(string.Format(CultureInfo.CurrentCulture,
- MessagingStrings.RequiredParametersMissing,
- this.messageType.FullName,
- string.Join(", ", missingKeys)));
+ throw new ProtocolException(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ MessagingStrings.RequiredParametersMissing,
+ this.messageType.FullName,
+ string.Join(", ", missingKeys)));
}
}
}
diff --git a/src/DotNetOAuth/Messaging/Reflection/MessageDictionary.cs b/src/DotNetOAuth/Messaging/Reflection/MessageDictionary.cs
index 196af54..3c233ce 100644
--- a/src/DotNetOAuth/Messaging/Reflection/MessageDictionary.cs
+++ b/src/DotNetOAuth/Messaging/Reflection/MessageDictionary.cs
@@ -16,10 +16,20 @@ namespace DotNetOAuth.Messaging.Reflection {
/// name/value pairs that have no properties associated with them.
/// </summary>
internal class MessageDictionary : IDictionary<string, string> {
+ /// <summary>
+ /// The <see cref="IProtocolMessage"/> instance manipulated by this dictionary.
+ /// </summary>
private IProtocolMessage message;
+ /// <summary>
+ /// The <see cref="MessageDescription"/> instance that describes the message type.
+ /// </summary>
private MessageDescription description;
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessageDictionary"/> class.
+ /// </summary>
+ /// <param name="message">The message instance whose values will be manipulated by this dictionary.</param>
internal MessageDictionary(IProtocolMessage message) {
if (message == null) {
throw new ArgumentNullException("message");
@@ -29,29 +39,29 @@ namespace DotNetOAuth.Messaging.Reflection {
this.description = MessageDescription.Get(message.GetType());
}
- #region IDictionary<string,string> Members
+ #region ICollection<KeyValuePair<string,string>> Properties
- public void Add(string key, string value) {
- if (value == null) {
- throw new ArgumentNullException("value");
- }
-
- MessagePart part;
- if (this.description.Mapping.TryGetValue(key, out part)) {
- if (part.IsNondefaultValueSet(this.message)) {
- throw new ArgumentException(MessagingStrings.KeyAlreadyExists);
- }
- part.SetValue(this.message, value);
- } else {
- this.message.ExtraData.Add(key, value);
- }
+ /// <summary>
+ /// Gets the number of explicitly set values in the message.
+ /// </summary>
+ public int Count {
+ get { return this.Keys.Count; }
}
- public bool ContainsKey(string key) {
- return this.message.ExtraData.ContainsKey(key) ||
- (this.description.Mapping.ContainsKey(key) && this.description.Mapping[key].GetValue(this.message) != null);
+ /// <summary>
+ /// Gets a value indicating whether this message is read only.
+ /// </summary>
+ bool ICollection<KeyValuePair<string, string>>.IsReadOnly {
+ get { return false; }
}
+ #endregion
+
+ #region IDictionary<string,string> Properties
+
+ /// <summary>
+ /// Gets all the keys that have values associated with them.
+ /// </summary>
public ICollection<string> Keys {
get {
List<string> keys = new List<string>(this.message.ExtraData.Count + this.description.Mapping.Count);
@@ -70,30 +80,9 @@ namespace DotNetOAuth.Messaging.Reflection {
}
}
- public bool Remove(string key) {
- if (this.message.ExtraData.Remove(key)) {
- return true;
- } else {
- MessagePart part;
- if (this.description.Mapping.TryGetValue(key, out part)) {
- if (part.GetValue(this.message) != null) {
- part.SetValue(this.message, null);
- return true;
- }
- }
- return false;
- }
- }
-
- public bool TryGetValue(string key, out string value) {
- MessagePart part;
- if (this.description.Mapping.TryGetValue(key, out part)) {
- value = part.GetValue(this.message);
- return true;
- }
- return this.message.ExtraData.TryGetValue(key, out value);
- }
-
+ /// <summary>
+ /// Gets all the values.
+ /// </summary>
public ICollection<string> Values {
get {
List<string> values = new List<string>(this.message.ExtraData.Count + this.description.Mapping.Count);
@@ -112,6 +101,16 @@ namespace DotNetOAuth.Messaging.Reflection {
}
}
+ /// <summary>
+ /// Gets or sets a value for some named value.
+ /// </summary>
+ /// <param name="key">The serialized form of a name for the value to read or write.</param>
+ /// <returns>The named value.</returns>
+ /// <remarks>
+ /// If the key matches a declared property or field on the message type,
+ /// that type member is set. Otherwise the key/value is stored in a
+ /// dictionary for extra (weakly typed) strings.
+ /// </remarks>
public string this[string key] {
get {
MessagePart part;
@@ -139,18 +138,106 @@ namespace DotNetOAuth.Messaging.Reflection {
#endregion
- #region ICollection<KeyValuePair<string,string>> Members
+ #region IDictionary<string,string> Methods
+
+ /// <summary>
+ /// Adds a named value to the message.
+ /// </summary>
+ /// <param name="key">The serialized form of the name whose value is being set.</param>
+ /// <param name="value">The serialized form of the value.</param>
+ /// <exception cref="ArgumentException">
+ /// Thrown if <paramref name="key"/> already has a set value in this message.
+ /// </exception>
+ /// <exception cref="ArgumentNullException">
+ /// Thrown if <paramref name="value"/> is null.
+ /// </exception>
+ public void Add(string key, string value) {
+ if (value == null) {
+ throw new ArgumentNullException("value");
+ }
+
+ MessagePart part;
+ if (this.description.Mapping.TryGetValue(key, out part)) {
+ if (part.IsNondefaultValueSet(this.message)) {
+ throw new ArgumentException(MessagingStrings.KeyAlreadyExists);
+ }
+ part.SetValue(this.message, value);
+ } else {
+ this.message.ExtraData.Add(key, value);
+ }
+ }
+
+ /// <summary>
+ /// Checks whether some named parameter has a value set in the message.
+ /// </summary>
+ /// <param name="key">The serialized form of the message part's name.</param>
+ /// <returns>True if the parameter by the given name has a set value. False otherwise.</returns>
+ public bool ContainsKey(string key) {
+ return this.message.ExtraData.ContainsKey(key) ||
+ (this.description.Mapping.ContainsKey(key) && this.description.Mapping[key].GetValue(this.message) != null);
+ }
+
+ /// <summary>
+ /// Removes a name and value from the message given its name.
+ /// </summary>
+ /// <param name="key">The serialized form of the name to remove.</param>
+ /// <returns>True if a message part by the given name was found and removed. False otherwise.</returns>
+ public bool Remove(string key) {
+ if (this.message.ExtraData.Remove(key)) {
+ return true;
+ } else {
+ MessagePart part;
+ if (this.description.Mapping.TryGetValue(key, out part)) {
+ if (part.GetValue(this.message) != null) {
+ part.SetValue(this.message, null);
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Gets some named value if the key has a value.
+ /// </summary>
+ /// <param name="key">The name (in serialized form) of the value being sought.</param>
+ /// <param name="value">The variable where the value will be set.</param>
+ /// <returns>True if the key was found and <paramref name="value"/> was set. False otherwise.</returns>
+ public bool TryGetValue(string key, out string value) {
+ MessagePart part;
+ if (this.description.Mapping.TryGetValue(key, out part)) {
+ value = part.GetValue(this.message);
+ return true;
+ }
+ return this.message.ExtraData.TryGetValue(key, out value);
+ }
+
+ #endregion
+
+ #region ICollection<KeyValuePair<string,string>> Methods
+ /// <summary>
+ /// Sets a named value in the message.
+ /// </summary>
+ /// <param name="item">The name-value pair to add. The name is the serialized form of the key.</param>
public void Add(KeyValuePair<string, string> item) {
this.Add(item.Key, item.Value);
}
+ /// <summary>
+ /// Removes all values in the message.
+ /// </summary>
public void Clear() {
foreach (string key in this.Keys) {
this.Remove(key);
}
}
+ /// <summary>
+ /// Checks whether a named value has been set on the message.
+ /// </summary>
+ /// <param name="item">The name/value pair.</param>
+ /// <returns>True if the key exists and has the given value. False otherwise.</returns>
public bool Contains(KeyValuePair<string, string> item) {
MessagePart part;
if (this.description.Mapping.TryGetValue(item.Key, out part)) {
@@ -160,20 +247,22 @@ namespace DotNetOAuth.Messaging.Reflection {
}
}
+ /// <summary>
+ /// Copies all the serializable data from the message to a key/value array.
+ /// </summary>
+ /// <param name="array">The array to copy to.</param>
+ /// <param name="arrayIndex">The index in the <paramref name="array"/> to begin copying to.</param>
void ICollection<KeyValuePair<string, string>>.CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) {
foreach (var pair in (IDictionary<string, string>)this) {
array[arrayIndex++] = pair;
}
}
- public int Count {
- get { return this.Keys.Count; }
- }
-
- bool ICollection<KeyValuePair<string, string>>.IsReadOnly {
- get { return false; }
- }
-
+ /// <summary>
+ /// Removes a named value from the message if it exists.
+ /// </summary>
+ /// <param name="item">The serialized form of the name and value to remove.</param>
+ /// <returns>True if the name/value was found and removed. False otherwise.</returns>
public bool Remove(KeyValuePair<string, string> item) {
// We use contains because that checks that the value is equal as well.
if (((ICollection<KeyValuePair<string, string>>)this).Contains(item)) {
@@ -187,8 +276,13 @@ namespace DotNetOAuth.Messaging.Reflection {
#region IEnumerable<KeyValuePair<string,string>> Members
+ /// <summary>
+ /// Gets an enumerator that generates KeyValuePair&lt;string, string&gt; instances
+ /// for all the key/value pairs that are set in the message.
+ /// </summary>
+ /// <returns>The enumerator that can generate the name/value pairs.</returns>
public IEnumerator<KeyValuePair<string, string>> GetEnumerator() {
- foreach (string key in Keys) {
+ foreach (string key in this.Keys) {
yield return new KeyValuePair<string, string>(key, this[key]);
}
}
@@ -197,6 +291,11 @@ namespace DotNetOAuth.Messaging.Reflection {
#region IEnumerable Members
+ /// <summary>
+ /// Gets an enumerator that generates KeyValuePair&lt;string, string&gt; instances
+ /// for all the key/value pairs that are set in the message.
+ /// </summary>
+ /// <returns>The enumerator that can generate the name/value pairs.</returns>
IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return ((IEnumerable<KeyValuePair<string, string>>)this).GetEnumerator();
}
diff --git a/src/DotNetOAuth/Messaging/Reflection/MessagePart.cs b/src/DotNetOAuth/Messaging/Reflection/MessagePart.cs
index 0cf7cd4..b79ad06 100644
--- a/src/DotNetOAuth/Messaging/Reflection/MessagePart.cs
+++ b/src/DotNetOAuth/Messaging/Reflection/MessagePart.cs
@@ -7,29 +7,64 @@
namespace DotNetOAuth.Messaging.Reflection {
using System;
using System.Collections.Generic;
+ using System.Globalization;
using System.Net.Security;
using System.Reflection;
using System.Xml;
- using System.Globalization;
+ /// <summary>
+ /// Describes an individual member of a message and assists in its serialization.
+ /// </summary>
internal class MessagePart {
+ /// <summary>
+ /// A map of converters that help serialize custom objects to string values and back again.
+ /// </summary>
private static readonly Dictionary<Type, ValueMapping> converters = new Dictionary<Type, ValueMapping>();
+ /// <summary>
+ /// The string-object conversion routines to use for this individual message part.
+ /// </summary>
private ValueMapping converter;
+ /// <summary>
+ /// The property that this message part is associated with, if aplicable.
+ /// </summary>
private PropertyInfo property;
+ /// <summary>
+ /// The field that this message part is associated with, if aplicable.
+ /// </summary>
private FieldInfo field;
+ /// <summary>
+ /// The type of the message part. (Not the type of the message itself).
+ /// </summary>
private Type memberDeclaredType;
+ /// <summary>
+ /// The default (uninitialized) value of the member inherent in its type.
+ /// </summary>
private object defaultMemberValue;
+ /// <summary>
+ /// Initializes static members of the <see cref="MessagePart"/> class.
+ /// </summary>
static MessagePart() {
Map<Uri>(uri => uri.AbsoluteUri, str => new Uri(str));
Map<DateTime>(dt => XmlConvert.ToString(dt, XmlDateTimeSerializationMode.Utc), str => XmlConvert.ToDateTime(str, XmlDateTimeSerializationMode.Utc));
}
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessagePart"/> class.
+ /// </summary>
+ /// <param name="member">
+ /// A property or field of an <see cref="IProtocolMessage"/> implementing type
+ /// that has a <see cref="MessagePartAttribute"/> attached to it.
+ /// </param>
+ /// <param name="attribute">
+ /// The attribute discovered on <paramref name="member"/> that describes the
+ /// serialization requirements of the message part.
+ /// </param>
internal MessagePart(MemberInfo member, MessagePartAttribute attribute) {
if (member == null) {
throw new ArgumentNullException("member");
@@ -38,11 +73,13 @@ namespace DotNetOAuth.Messaging.Reflection {
this.field = member as FieldInfo;
this.property = member as PropertyInfo;
if (this.field == null && this.property == null) {
- throw new ArgumentException(string.Format(
- CultureInfo.CurrentCulture,
- MessagingStrings.UnexpectedType,
- typeof(FieldInfo).Name + ", " + typeof(PropertyInfo).Name,
- member.GetType().Name), "member");
+ throw new ArgumentException(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ MessagingStrings.UnexpectedType,
+ typeof(FieldInfo).Name + ", " + typeof(PropertyInfo).Name,
+ member.GetType().Name),
+ "member");
}
if (attribute == null) {
@@ -53,32 +90,40 @@ namespace DotNetOAuth.Messaging.Reflection {
this.RequiredProtection = attribute.RequiredProtection;
this.IsRequired = attribute.IsRequired;
this.memberDeclaredType = (this.field != null) ? this.field.FieldType : this.property.PropertyType;
- this.defaultMemberValue = deriveDefaultValue(this.memberDeclaredType);
+ this.defaultMemberValue = DeriveDefaultValue(this.memberDeclaredType);
if (!converters.TryGetValue(this.memberDeclaredType, out this.converter)) {
this.converter = new ValueMapping(
obj => obj != null ? obj.ToString() : null,
- str => str != null ? Convert.ChangeType(str, memberDeclaredType) : null);
+ str => str != null ? Convert.ChangeType(str, this.memberDeclaredType, CultureInfo.InvariantCulture) : null);
}
// Validate a sane combination of settings
- ValidateSettings();
+ this.ValidateSettings();
}
+ /// <summary>
+ /// Gets or sets the name to use when serializing or deserializing this parameter in a message.
+ /// </summary>
internal string Name { get; set; }
+ /// <summary>
+ /// Gets or sets whether this message part must be signed.
+ /// </summary>
internal ProtectionLevel RequiredProtection { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this message part is required for the
+ /// containing message to be valid.
+ /// </summary>
internal bool IsRequired { get; set; }
- internal object ToValue(string value) {
- return this.converter.StringToValue(value);
- }
-
- internal string ToString(object value) {
- return this.converter.ValueToString(value);
- }
-
+ /// <summary>
+ /// Sets the member of a given message to some given value.
+ /// Used in deserialization.
+ /// </summary>
+ /// <param name="message">The message instance containing the member whose value should be set.</param>
+ /// <param name="value">The string representation of the value to set.</param>
internal void SetValue(IProtocolMessage message, string value) {
if (this.property != null) {
this.property.SetValue(message, this.ToValue(value), null);
@@ -87,19 +132,35 @@ namespace DotNetOAuth.Messaging.Reflection {
}
}
+ /// <summary>
+ /// Gets the value of a member of a given message.
+ /// Used in serialization.
+ /// </summary>
+ /// <param name="message">The message instance to read the value from.</param>
+ /// <returns>The string representation of the member's value.</returns>
internal string GetValue(IProtocolMessage message) {
return this.ToString(this.GetValueAsObject(message));
}
+ /// <summary>
+ /// Gets whether the value has been set to something other than its CLR type default value.
+ /// </summary>
+ /// <param name="message">The message instance to check the value on.</param>
+ /// <returns>True if the value is not the CLR default value.</returns>
internal bool IsNondefaultValueSet(IProtocolMessage message) {
if (this.memberDeclaredType.IsValueType) {
- return !GetValueAsObject(message).Equals(this.defaultMemberValue);
+ return !this.GetValueAsObject(message).Equals(this.defaultMemberValue);
} else {
- return this.defaultMemberValue != GetValueAsObject(message);
+ return this.defaultMemberValue != this.GetValueAsObject(message);
}
}
- private static object deriveDefaultValue(Type type) {
+ /// <summary>
+ /// Figures out the CLR default value for a given type.
+ /// </summary>
+ /// <param name="type">The type whose default value is being sought.</param>
+ /// <returns>Either null, or some default value like 0 or 0.0.</returns>
+ private static object DeriveDefaultValue(Type type) {
if (type.IsValueType) {
return Activator.CreateInstance(type);
} else {
@@ -107,32 +168,23 @@ namespace DotNetOAuth.Messaging.Reflection {
}
}
- private object GetValueAsObject(IProtocolMessage message) {
- if (this.property != null) {
- return this.property.GetValue(message, null);
- } else {
- return this.field.GetValue(message);
- }
- }
-
+ /// <summary>
+ /// Adds a pair of type conversion functions to the static converstion map.
+ /// </summary>
+ /// <typeparam name="T">The custom type to convert to and from strings.</typeparam>
+ /// <param name="toString">The function to convert the custom type to a string.</param>
+ /// <param name="toValue">The function to convert a string to the custom type.</param>
private static void Map<T>(Func<T, string> toString, Func<string, T> toValue) {
- converters.Add(
- typeof(T),
- new ValueMapping(
- obj => obj != null ? toString((T)obj) : null,
- str => str != null ? toValue(str) : default(T)));
- }
-
- private void ValidateSettings() {
- // An optional tag on a non-nullable value type is a contradiction.
- if (!this.IsRequired && IsNonNullableValueType(this.memberDeclaredType)) {
- MemberInfo member = (MemberInfo)this.field ?? this.property;
- throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
- "Invalid combination: {0} on message type {1} is a non-nullable value type but is marked as optional.",
- member.Name, member.DeclaringType));
- }
+ Func<object, string> safeToString = obj => obj != null ? toString((T)obj) : null;
+ Func<string, object> safeToT = str => str != null ? toValue(str) : default(T);
+ converters.Add(typeof(T), new ValueMapping(safeToString, safeToT));
}
+ /// <summary>
+ /// Checks whether a type is a nullable value type (i.e. int?)
+ /// </summary>
+ /// <param name="type">The type in question.</param>
+ /// <returns>True if this is a nullable value type.</returns>
private static bool IsNonNullableValueType(Type type) {
if (!type.IsValueType) {
return false;
@@ -144,5 +196,54 @@ namespace DotNetOAuth.Messaging.Reflection {
return true;
}
+
+ /// <summary>
+ /// Converts a string representation of the member's value to the appropriate type.
+ /// </summary>
+ /// <param name="value">The string representation of the member's value.</param>
+ /// <returns>An instance of the appropriate type for setting the member.</returns>
+ private object ToValue(string value) {
+ return this.converter.StringToValue(value);
+ }
+
+ /// <summary>
+ /// Converts the member's value to its string representation.
+ /// </summary>
+ /// <param name="value">The value of the member.</param>
+ /// <returns>The string representation of the member's value.</returns>
+ private string ToString(object value) {
+ return this.converter.ValueToString(value);
+ }
+
+ /// <summary>
+ /// Gets the value of the message part, without converting it to/from a string.
+ /// </summary>
+ /// <param name="message">The message instance to read from.</param>
+ /// <returns>The value of the member.</returns>
+ private object GetValueAsObject(IProtocolMessage message) {
+ if (this.property != null) {
+ return this.property.GetValue(message, null);
+ } else {
+ return this.field.GetValue(message);
+ }
+ }
+
+ /// <summary>
+ /// Validates that the message part and its attribute have agreeable settings.
+ /// </summary>
+ /// <exception cref="ArgumentException">
+ /// Thrown when a non-nullable value type is set as optional.
+ /// </exception>
+ private void ValidateSettings() {
+ if (!this.IsRequired && IsNonNullableValueType(this.memberDeclaredType)) {
+ MemberInfo member = (MemberInfo)this.field ?? this.property;
+ throw new ArgumentException(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Invalid combination: {0} on message type {1} is a non-nullable value type but is marked as optional.",
+ member.Name,
+ member.DeclaringType));
+ }
+ }
}
}
diff --git a/src/DotNetOAuth/Messaging/Reflection/ValueMapping.cs b/src/DotNetOAuth/Messaging/Reflection/ValueMapping.cs
index 2371b49..e2d869b 100644
--- a/src/DotNetOAuth/Messaging/Reflection/ValueMapping.cs
+++ b/src/DotNetOAuth/Messaging/Reflection/ValueMapping.cs
@@ -7,10 +7,25 @@
namespace DotNetOAuth.Messaging.Reflection {
using System;
+ /// <summary>
+ /// A pair of conversion functions to map some type to a string and back again.
+ /// </summary>
internal struct ValueMapping {
+ /// <summary>
+ /// The mapping function that converts some custom type to a string.
+ /// </summary>
internal Func<object, string> ValueToString;
+
+ /// <summary>
+ /// The mapping function that converts a string to some custom type.
+ /// </summary>
internal Func<string, object> StringToValue;
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ValueMapping"/> struct.
+ /// </summary>
+ /// <param name="toString">The mapping function that converts some custom type to a string.</param>
+ /// <param name="toValue">The mapping function that converts a string to some custom type.</param>
internal ValueMapping(Func<object, string> toString, Func<string, object> toValue) {
if (toString == null) {
throw new ArgumentNullException("toString");
diff --git a/src/DotNetOAuth/OAuthChannel.cs b/src/DotNetOAuth/OAuthChannel.cs
index 47f445f..bb8005e 100644
--- a/src/DotNetOAuth/OAuthChannel.cs
+++ b/src/DotNetOAuth/OAuthChannel.cs
@@ -135,13 +135,13 @@ namespace DotNetOAuth {
MessageScheme transmissionMethod = this.PreferredTransmissionScheme;
switch (transmissionMethod) {
case MessageScheme.AuthorizationHeaderRequest:
- httpRequest = this.InitializeRequestAsAuthHeader(request);
+ httpRequest = InitializeRequestAsAuthHeader(request);
break;
case MessageScheme.PostRequest:
httpRequest = this.InitializeRequestAsPost(request);
break;
case MessageScheme.GetRequest:
- httpRequest = this.InitializeRequestAsGet(request);
+ httpRequest = InitializeRequestAsGet(request);
break;
default:
throw new NotSupportedException();
@@ -192,7 +192,7 @@ namespace DotNetOAuth {
/// <remarks>
/// This method implements OAuth 1.0 section 5.2, item #1 (described in section 5.4).
/// </remarks>
- private HttpWebRequest InitializeRequestAsAuthHeader(IDirectedProtocolMessage requestMessage) {
+ private static HttpWebRequest InitializeRequestAsAuthHeader(IDirectedProtocolMessage requestMessage) {
var serializer = MessageSerializer.Get(requestMessage.GetType());
var fields = serializer.Serialize(requestMessage);
var protocol = Protocol.Lookup(requestMessage.ProtocolVersion);
@@ -218,44 +218,44 @@ namespace DotNetOAuth {
}
/// <summary>
- /// Prepares to send a request to the Service Provider as the payload of a POST request.
+ /// Prepares to send a request to the Service Provider as the query string in a GET request.
/// </summary>
/// <param name="requestMessage">The message to be transmitted to the ServiceProvider.</param>
/// <returns>The web request ready to send.</returns>
/// <remarks>
- /// This method implements OAuth 1.0 section 5.2, item #2.
+ /// This method implements OAuth 1.0 section 5.2, item #3.
/// </remarks>
- private HttpWebRequest InitializeRequestAsPost(IDirectedProtocolMessage requestMessage) {
+ private static HttpWebRequest InitializeRequestAsGet(IDirectedProtocolMessage requestMessage) {
var serializer = MessageSerializer.Get(requestMessage.GetType());
var fields = serializer.Serialize(requestMessage);
- HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(requestMessage.Recipient);
- httpRequest.Method = "POST";
- httpRequest.ContentType = "application/x-www-form-urlencoded";
- string requestBody = MessagingUtilities.CreateQueryString(fields);
- httpRequest.ContentLength = requestBody.Length;
- using (TextWriter writer = this.webRequestHandler.GetRequestStream(httpRequest)) {
- writer.Write(requestBody);
- }
+ UriBuilder builder = new UriBuilder(requestMessage.Recipient);
+ MessagingUtilities.AppendQueryArgs(builder, fields);
+ HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(builder.Uri);
return httpRequest;
}
/// <summary>
- /// Prepares to send a request to the Service Provider as the query string in a GET request.
+ /// Prepares to send a request to the Service Provider as the payload of a POST request.
/// </summary>
/// <param name="requestMessage">The message to be transmitted to the ServiceProvider.</param>
/// <returns>The web request ready to send.</returns>
/// <remarks>
- /// This method implements OAuth 1.0 section 5.2, item #3.
+ /// This method implements OAuth 1.0 section 5.2, item #2.
/// </remarks>
- private HttpWebRequest InitializeRequestAsGet(IDirectedProtocolMessage requestMessage) {
+ private HttpWebRequest InitializeRequestAsPost(IDirectedProtocolMessage requestMessage) {
var serializer = MessageSerializer.Get(requestMessage.GetType());
var fields = serializer.Serialize(requestMessage);
- UriBuilder builder = new UriBuilder(requestMessage.Recipient);
- MessagingUtilities.AppendQueryArgs(builder, fields);
- HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(builder.Uri);
+ HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(requestMessage.Recipient);
+ httpRequest.Method = "POST";
+ httpRequest.ContentType = "application/x-www-form-urlencoded";
+ string requestBody = MessagingUtilities.CreateQueryString(fields);
+ httpRequest.ContentLength = requestBody.Length;
+ using (TextWriter writer = this.webRequestHandler.GetRequestStream(httpRequest)) {
+ writer.Write(requestBody);
+ }
return httpRequest;
}