Added strong-typed request token message to sample.
[dotnetoauth.git] / src / DotNetOAuth / Messaging / MessageSerializer.cs
blob1239dd0342117450561fa125c1634017893d3af7
1 //-----------------------------------------------------------------------
2 // <copyright file="MessageSerializer.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOAuth.Messaging {
8 using System;
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;
16 /// <summary>
17 /// Serializes/deserializes OAuth messages for/from transit.
18 /// </summary>
19 internal class MessageSerializer {
20 /// <summary>
21 /// The specific <see cref="IProtocolMessage"/>-derived type
22 /// that will be serialized and deserialized using this class.
23 /// </summary>
24 private readonly Type messageType;
26 /// <summary>
27 /// Initializes a new instance of the MessageSerializer class.
28 /// </summary>
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(
36 string.Format(
37 CultureInfo.CurrentCulture,
38 MessagingStrings.UnexpectedType,
39 typeof(IProtocolMessage).FullName,
40 messageType.FullName),
41 "messageType");
44 this.messageType = messageType;
47 /// <summary>
48 /// Creates or reuses a message serializer for a given message type.
49 /// </summary>
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);
60 /// <summary>
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.
62 /// </summary>
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);
73 return result;
76 /// <summary>
77 /// Reads name=value pairs into an OAuth message.
78 /// </summary>
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) {
83 if (fields == null) {
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();
96 return result;
99 /// <summary>
100 /// Instantiates a new message to deserialize data into.
101 /// </summary>
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]);
126 } else {
127 throw new InvalidOperationException("Unrecognized constructor signature on type " + this.messageType);
129 } else {
130 result = (IProtocolMessage)Activator.CreateInstance(this.messageType, true);
133 return result;