1
//-----------------------------------------------------------------------
2 // <copyright file="MessageSerializer.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 namespace DotNetOAuth
.Messaging
{
9 using System
.Collections
.Generic
;
10 using System
.Diagnostics
;
11 using System
.Globalization
;
12 using System
.Reflection
;
13 using DotNetOAuth
.ChannelElements
;
14 using DotNetOAuth
.Messaging
.Reflection
;
17 /// Serializes/deserializes OAuth messages for/from transit.
19 internal class MessageSerializer
{
21 /// The specific <see cref="IProtocolMessage"/>-derived type
22 /// that will be serialized and deserialized using this class.
24 private readonly Type messageType
;
27 /// Initializes a new instance of the MessageSerializer class.
29 /// <param name="messageType">The specific <see cref="IProtocolMessage"/>-derived type
30 /// that will be serialized and deserialized using this class.</param>
31 private MessageSerializer(Type messageType
) {
32 Debug
.Assert(messageType
!= null, "messageType == null");
34 if (!typeof(IProtocolMessage
).IsAssignableFrom(messageType
)) {
35 throw new ArgumentException(
37 CultureInfo
.CurrentCulture
,
38 MessagingStrings
.UnexpectedType
,
39 typeof(IProtocolMessage
).FullName
,
40 messageType
.FullName
),
44 this.messageType
= messageType
;
48 /// Creates or reuses a message serializer for a given message type.
50 /// <param name="messageType">The type of message that will be serialized/deserialized.</param>
51 /// <returns>A message serializer for the given message type.</returns>
52 internal static MessageSerializer
Get(Type messageType
) {
53 if (messageType
== null) {
54 throw new ArgumentNullException("messageType");
57 return new MessageSerializer(messageType
);
61 /// Reads the data from a message instance and returns a series of name=value pairs for the fields that must be included in the message.
63 /// <param name="message">The message to be serialized.</param>
64 /// <returns>The dictionary of values to send for the message.</returns>
65 [System
.Diagnostics
.CodeAnalysis
.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification
= "Parallel design with Deserialize method.")]
66 internal IDictionary
<string, string> Serialize(IProtocolMessage message
) {
67 if (message
== null) {
68 throw new ArgumentNullException("message");
71 var result
= new Reflection
.MessageDictionary(message
);
77 /// Reads name=value pairs into an OAuth message.
79 /// <param name="fields">The name=value pairs that were read in from the transport.</param>
80 /// <param name="recipient">The recipient of the message.</param>
81 /// <returns>The instantiated and initialized <see cref="IProtocolMessage"/> instance.</returns>
82 internal IProtocolMessage
Deserialize(IDictionary
<string, string> fields
, MessageReceivingEndpoint recipient
) {
84 throw new ArgumentNullException("fields");
87 // Before we deserialize the message, make sure all the required parts are present.
88 MessageDescription
.Get(this.messageType
).EnsureRequiredMessagePartsArePresent(fields
.Keys
);
90 IProtocolMessage result
= this.CreateMessage(recipient
);
91 foreach (var pair
in fields
) {
92 IDictionary
<string, string> dictionary
= new MessageDictionary(result
);
93 dictionary
[pair
.Key
] = pair
.Value
;
95 result
.EnsureValidMessage();
100 /// Instantiates a new message to deserialize data into.
102 /// <param name="recipient">The recipient this message is directed to, if any.</param>
103 /// <returns>The newly created message object.</returns>
104 private IProtocolMessage
CreateMessage(MessageReceivingEndpoint recipient
) {
105 IProtocolMessage result
;
106 BindingFlags bindingFlags
= BindingFlags
.Public
| BindingFlags
.NonPublic
| BindingFlags
.Instance
;
107 if (typeof(IOAuthDirectedMessage
).IsAssignableFrom(this.messageType
)) {
108 // Some OAuth messages take just the recipient, while others take the whole endpoint
109 ConstructorInfo ctor
;
110 if ((ctor
= this.messageType
.GetConstructor(bindingFlags
, null, new Type
[] { typeof(Uri) }
, null)) != null) {
111 if (recipient
== null) {
112 // We need a recipient to deserialize directed messages.
113 throw new ArgumentNullException("recipient");
116 result
= (IProtocolMessage
)ctor
.Invoke(new object[] { recipient.Location }
);
117 } else if ((ctor
= this.messageType
.GetConstructor(bindingFlags
, null, new Type
[] { typeof(MessageReceivingEndpoint) }
, null)) != null) {
118 if (recipient
== null) {
119 // We need a recipient to deserialize directed messages.
120 throw new ArgumentNullException("recipient");
123 result
= (IProtocolMessage
)ctor
.Invoke(new object[] { recipient }
);
124 } else if ((ctor
= this.messageType
.GetConstructor(bindingFlags
, null, new Type
[0], null)) != null) {
125 result
= (IProtocolMessage
)ctor
.Invoke(new object[0]);
127 throw new InvalidOperationException("Unrecognized constructor signature on type " + this.messageType
);
130 result
= (IProtocolMessage
)Activator
.CreateInstance(this.messageType
, true);