1
//-----------------------------------------------------------------------
2 // <copyright file="Request.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth
.OpenId
.Provider
{
9 using System
.Collections
.Generic
;
12 using DotNetOpenAuth
.Messaging
;
13 using DotNetOpenAuth
.OpenId
.Messages
;
16 /// Implements the <see cref="IRequest"/> interface for all incoming
17 /// request messages to an OpenID Provider.
19 internal abstract class Request
: IRequest
{
21 /// The OpenIdProvider that received the incoming request.
23 private readonly OpenIdProvider provider
;
26 /// The incoming request message.
28 private readonly IDirectedProtocolMessage request
;
31 /// The incoming request message cast to its extensible form.
32 /// Or null if the message does not support extensions.
34 private readonly IProtocolMessageWithExtensions extensibleMessage
;
37 /// The list of extensions to add to the response message.
39 private List
<IOpenIdMessageExtension
> responseExtensions
= new List
<IOpenIdMessageExtension
>();
42 /// The last created user agent response, if one has been created
43 /// since the last message-altering change has been made to this object.
45 private UserAgentResponse cachedUserAgentResponse
;
48 /// Initializes a new instance of the <see cref="Request"/> class.
50 /// <param name="provider">The Provider.</param>
51 /// <param name="request">The incoming request message.</param>
52 protected Request(OpenIdProvider provider
, IDirectedProtocolMessage request
) {
53 ErrorUtilities
.VerifyArgumentNotNull(provider
, "provider");
54 ErrorUtilities
.VerifyArgumentNotNull(request
, "request");
56 this.provider
= provider
;
57 this.request
= request
;
58 this.extensibleMessage
= request
as IProtocolMessageWithExtensions
;
61 #region IRequest Members
64 /// Gets a value indicating whether the response is ready to be sent to the user agent.
68 /// This property returns false if there are properties that must be set on this
69 /// request instance before the response can be sent.
71 public abstract bool IsResponseReady { get; }
74 /// Gets the response to send to the user agent.
76 public UserAgentResponse Response
{
78 if (this.cachedUserAgentResponse
== null && this.IsResponseReady
) {
79 if (this.responseExtensions
.Count
> 0) {
80 var extensibleResponse
= this.ResponseMessage
as IProtocolMessageWithExtensions
;
81 ErrorUtilities
.VerifyOperation(extensibleResponse
!= null, MessagingStrings
.MessageNotExtensible
, this.ResponseMessage
.GetType().Name
);
82 foreach (var extension
in this.responseExtensions
) {
83 // It's possible that a prior call to this property
84 // has already added some/all of the extensions to the message.
85 // We don't have to worry about deleting old ones because
86 // this class provides no facility for removing extensions
87 // that are previously added.
88 if (!extensibleResponse
.Extensions
.Contains(extension
)) {
89 extensibleResponse
.Extensions
.Add(extension
);
94 this.cachedUserAgentResponse
= this.provider
.Channel
.PrepareResponse(this.ResponseMessage
);
97 return this.cachedUserAgentResponse
;
104 /// Gets the instance of the hosting <see cref="OpenIdProvider"/>.
106 protected OpenIdProvider Provider
{
107 get { return this.provider; }
111 /// Gets the original request message.
113 protected IDirectedProtocolMessage RequestMessage
{
114 get { return this.request; }
118 /// Gets the response message, once <see cref="IsResponseReady"/> is <c>true</c>.
120 protected abstract IProtocolMessage ResponseMessage { get; }
123 /// Gets the protocol version used in the request..
125 protected Protocol Protocol
{
126 get { return Protocol.Lookup(this.RequestMessage.Version); }
129 #region IRequest Methods
132 /// Adds an extension to the response to send to the relying party.
134 /// <param name="extension">The extension to add to the response message.</param>
135 public void AddResponseExtension(IOpenIdMessageExtension extension
) {
136 ErrorUtilities
.VerifyArgumentNotNull(extension
, "extension");
138 // Because the derived AuthenticationRequest class can swap out
139 // one response message for another (auth vs. no-auth), and because
140 // some response messages support extensions while others don't,
141 // we just add the extensions to a collection here and add them
142 // to the response on the way out.
143 this.responseExtensions
.Add(extension
);
144 this.ResetUserAgentResponse();
148 /// Gets an extension sent from the relying party.
150 /// <typeparam name="T">The type of the extension.</typeparam>
152 /// An instance of the extension initialized with values passed in with the request.
154 public T GetExtension
<T
>() where T
: IOpenIdMessageExtension
, new() {
155 if (this.extensibleMessage
!= null) {
156 return this.extensibleMessage
.Extensions
.OfType
<T
>().SingleOrDefault();
163 /// Gets an extension sent from the relying party.
165 /// <param name="extensionType">The type of the extension.</param>
167 /// An instance of the extension initialized with values passed in with the request.
169 public IOpenIdMessageExtension
GetExtension(Type extensionType
) {
170 ErrorUtilities
.VerifyArgumentNotNull(extensionType
, "extensionType");
171 if (this.extensibleMessage
!= null) {
172 return this.extensibleMessage
.Extensions
.OfType
<IOpenIdMessageExtension
>().Where(ext
=> extensionType
.IsInstanceOfType(ext
)).SingleOrDefault();
181 /// Resets any user agent response that may have been created already and cached.
183 protected void ResetUserAgentResponse() {
184 this.cachedUserAgentResponse
= null;