summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2013-01-23 07:49:02 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2013-01-23 07:49:02 -0800
commitf04d5ca8396bdb0d09b0fea4e22d4e96c4fa8ad2 (patch)
tree93b2b354a85a6705914d8e12ecfce159a24bb563
parent22df10e81fe404fb3f7beb47a2e50a96b79ca78b (diff)
downloadDotNetOpenAuth-f04d5ca8396bdb0d09b0fea4e22d4e96c4fa8ad2.zip
DotNetOpenAuth-f04d5ca8396bdb0d09b0fea4e22d4e96c4fa8ad2.tar.gz
DotNetOpenAuth-f04d5ca8396bdb0d09b0fea4e22d4e96c4fa8ad2.tar.bz2
ApplicationBlock builds.
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj7
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs75
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs118
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/Util.cs176
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs17
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/packages.config4
-rw-r--r--samples/OpenIdProviderMvc/Controllers/OpenIdController.cs52
-rw-r--r--samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj7
-rw-r--r--samples/OpenIdProviderMvc/packages.config4
-rw-r--r--src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj1
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/Channel.cs27
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/IMessageWithBinaryData.cs2
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs23
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs6
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs2
-rw-r--r--src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs5
-rw-r--r--src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs4
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/Provider/IHostProcessedRequest.cs2
-rw-r--r--src/packages/repositories.config2
19 files changed, 230 insertions, 304 deletions
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
index 81160f2..9f37931 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
+++ b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
@@ -33,6 +33,7 @@
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\src\</SolutionDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -73,6 +74,8 @@
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Web" />
@@ -168,6 +171,10 @@
<Name>DotNetOpenAuth.OpenId</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " />
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
</Project> \ No newline at end of file
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs
index 1bdb04d..50c385e 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs
@@ -4,7 +4,8 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.ApplicationBlock {
+namespace DotNetOpenAuth.ApplicationBlock
+{
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -12,9 +13,13 @@ namespace DotNetOpenAuth.ApplicationBlock {
using System.IO;
using System.Linq;
using System.Net;
+ using System.Net.Http;
+ using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
+ using System.Threading;
+ using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using DotNetOpenAuth.Messaging;
@@ -24,7 +29,8 @@ namespace DotNetOpenAuth.ApplicationBlock {
/// <summary>
/// A consumer capable of communicating with Google Data APIs.
/// </summary>
- public static class GoogleConsumer {
+ public static class GoogleConsumer
+ {
/// <summary>
/// The Consumer to use for accessing Google data APIs.
/// </summary>
@@ -66,7 +72,8 @@ namespace DotNetOpenAuth.ApplicationBlock {
/// The many specific authorization scopes Google offers.
/// </summary>
[Flags]
- public enum Applications : long {
+ public enum Applications : long
+ {
/// <summary>
/// The Gmail address book.
/// </summary>
@@ -172,7 +179,7 @@ namespace DotNetOpenAuth.ApplicationBlock {
/// </summary>
/// <param name="consumer">The Google consumer previously constructed using <see cref="CreateWebConsumer"/> or <see cref="CreateDesktopConsumer"/>.</param>
/// <param name="requestedAccessScope">The requested access scope.</param>
- public static void RequestAuthorization(WebConsumer consumer, Applications requestedAccessScope) {
+ public static async Task RequestAuthorizationAsync(WebConsumer consumer, Applications requestedAccessScope, CancellationToken cancellationToken = default(CancellationToken)) {
if (consumer == null) {
throw new ArgumentNullException("consumer");
}
@@ -181,8 +188,9 @@ namespace DotNetOpenAuth.ApplicationBlock {
{ "scope", GetScopeUri(requestedAccessScope) },
};
Uri callback = Util.GetCallbackUrlFromContext();
- var request = consumer.PrepareRequestUserAuthorization(callback, extraParameters, null);
- consumer.Channel.Send(request);
+ var request = await consumer.PrepareRequestUserAuthorizationAsync(callback, extraParameters, null, cancellationToken);
+ var redirectingResponse = await consumer.Channel.PrepareResponseAsync(request, cancellationToken);
+ redirectingResponse.Send();
}
/// <summary>
@@ -191,8 +199,8 @@ namespace DotNetOpenAuth.ApplicationBlock {
/// <param name="consumer">The Google consumer previously constructed using <see cref="CreateWebConsumer"/> or <see cref="CreateDesktopConsumer"/>.</param>
/// <param name="requestedAccessScope">The requested access scope.</param>
/// <param name="requestToken">The unauthorized request token assigned by Google.</param>
- /// <returns>The request token</returns>
- public static Uri RequestAuthorization(DesktopConsumer consumer, Applications requestedAccessScope, out string requestToken) {
+ /// <returns>The URI to redirect to and the request token.</returns>
+ public static Task<Tuple<Uri, string>> RequestAuthorization(DesktopConsumer consumer, Applications requestedAccessScope, CancellationToken cancellationToken = default(CancellationToken)) {
if (consumer == null) {
throw new ArgumentNullException("consumer");
}
@@ -201,7 +209,7 @@ namespace DotNetOpenAuth.ApplicationBlock {
{ "scope", GetScopeUri(requestedAccessScope) },
};
- return consumer.RequestUserAuthorization(extraParameters, null, out requestToken);
+ return consumer.RequestUserAuthorizationAsync(extraParameters, null, cancellationToken);
}
/// <summary>
@@ -212,7 +220,7 @@ namespace DotNetOpenAuth.ApplicationBlock {
/// <param name="maxResults">The maximum number of entries to return. If you want to receive all of the contacts, rather than only the default maximum, you can specify a very large number here.</param>
/// <param name="startIndex">The 1-based index of the first result to be retrieved (for paging).</param>
/// <returns>An XML document returned by Google.</returns>
- public static XDocument GetContacts(ConsumerBase consumer, string accessToken, int maxResults/* = 25*/, int startIndex/* = 1*/) {
+ public static async Task<XDocument> GetContactsAsync(ConsumerBase consumer, string accessToken, int maxResults = 25, int startIndex = 1, CancellationToken cancellationToken = default(CancellationToken)) {
if (consumer == null) {
throw new ArgumentNullException("consumer");
}
@@ -221,19 +229,22 @@ namespace DotNetOpenAuth.ApplicationBlock {
{ "start-index", startIndex.ToString(CultureInfo.InvariantCulture) },
{ "max-results", maxResults.ToString(CultureInfo.InvariantCulture) },
};
- var request = consumer.PrepareAuthorizedRequest(GetContactsEndpoint, accessToken, extraData);
+ var request = await consumer.PrepareAuthorizedRequestAsync(GetContactsEndpoint, accessToken, extraData, cancellationToken);
// Enable gzip compression. Google only compresses the response for recognized user agent headers. - Mike Lim
- request.AutomaticDecompression = DecompressionMethods.GZip;
- request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16";
-
- var response = consumer.Channel.WebRequestHandler.GetResponse(request);
- string body = response.GetResponseReader().ReadToEnd();
- XDocument result = XDocument.Parse(body);
- return result;
+ var handler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip };
+ request.Headers.UserAgent.Add(ProductInfoHeaderValue.Parse("Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16"));
+
+ using (var httpClient = consumer.Channel.HostFactories.CreateHttpClient(handler)) {
+ using (var response = await httpClient.SendAsync(request, cancellationToken)) {
+ string body = await response.Content.ReadAsStringAsync();
+ XDocument result = XDocument.Parse(body);
+ return result;
+ }
+ }
}
- public static void PostBlogEntry(ConsumerBase consumer, string accessToken, string blogUrl, string title, XElement body) {
+ public static async Task PostBlogEntryAsync(ConsumerBase consumer, string accessToken, string blogUrl, string title, XElement body, CancellationToken cancellationToken) {
string feedUrl;
var getBlogHome = WebRequest.Create(blogUrl);
using (var blogHomeResponse = getBlogHome.GetResponse()) {
@@ -258,20 +269,20 @@ namespace DotNetOpenAuth.ApplicationBlock {
XmlWriter xw = XmlWriter.Create(ms, xws);
entry.WriteTo(xw);
xw.Flush();
-
- WebRequest request = consumer.PrepareAuthorizedRequest(new MessageReceivingEndpoint(feedUrl, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), accessToken);
- request.ContentType = "application/atom+xml";
- request.Method = "POST";
- request.ContentLength = ms.Length;
ms.Seek(0, SeekOrigin.Begin);
- using (Stream requestStream = request.GetRequestStream()) {
- ms.CopyTo(requestStream);
- }
- using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
- if (response.StatusCode == HttpStatusCode.Created) {
- // Success
- } else {
- // Error!
+
+ var request = await consumer.PrepareAuthorizedRequestAsync(new MessageReceivingEndpoint(feedUrl, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), accessToken, cancellationToken);
+ request.Content = new StreamContent(ms);
+ request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/atom+xml");
+ request.Method = HttpMethod.Post;
+ using (var httpClient = consumer.Channel.HostFactories.CreateHttpClient()) {
+ using (var response = await httpClient.SendAsync(request, cancellationToken)) {
+ if (response.StatusCode == HttpStatusCode.Created) {
+ // Success
+ } else {
+ // Error!
+ response.EnsureSuccessStatusCode(); // throw some meaningful exception.
+ }
}
}
}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs
index 013e66b..9cbedb6 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs
@@ -11,11 +11,16 @@ namespace DotNetOpenAuth.ApplicationBlock {
using System.Globalization;
using System.IO;
using System.Net;
+ using System.Net.Http;
+ using System.Net.Http.Headers;
+ using System.Threading;
+ using System.Threading.Tasks;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
@@ -125,50 +130,78 @@ namespace DotNetOpenAuth.ApplicationBlock {
}
}
- public static XDocument GetUpdates(ConsumerBase twitter, string accessToken) {
- IncomingWebResponse response = twitter.PrepareAuthorizedRequestAndSend(GetFriendTimelineStatusEndpoint, accessToken);
- return XDocument.Load(XmlReader.Create(response.GetResponseReader()));
+ public static async Task<XDocument> GetUpdatesAsync(
+ ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ var request = await twitter.PrepareAuthorizedRequestAsync(GetFriendTimelineStatusEndpoint, accessToken, cancellationToken);
+ using (var httpClient = twitter.Channel.HostFactories.CreateHttpClient()) {
+ using (var response = await httpClient.SendAsync(request)) {
+ using (var stream = await response.Content.ReadAsStreamAsync()) {
+ return XDocument.Load(XmlReader.Create(stream));
+ }
+ }
+ }
}
- public static XDocument GetFavorites(ConsumerBase twitter, string accessToken) {
- IncomingWebResponse response = twitter.PrepareAuthorizedRequestAndSend(GetFavoritesEndpoint, accessToken);
- return XDocument.Load(XmlReader.Create(response.GetResponseReader()));
+ public static async Task<XDocument> GetFavorites(ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ var request = await twitter.PrepareAuthorizedRequestAsync(GetFavoritesEndpoint, accessToken, cancellationToken);
+ using (var httpClient = twitter.Channel.HostFactories.CreateHttpClient()) {
+ using (HttpResponseMessage response = await httpClient.SendAsync(request)) {
+ return XDocument.Parse(await response.Content.ReadAsStringAsync());
+ }
+ }
}
- public static XDocument UpdateProfileBackgroundImage(ConsumerBase twitter, string accessToken, string image, bool tile) {
- var parts = new[] {
- MultipartPostPart.CreateFormFilePart("image", image, "image/" + Path.GetExtension(image).Substring(1).ToLowerInvariant()),
- MultipartPostPart.CreateFormPart("tile", tile.ToString().ToLowerInvariant()),
+ public static async Task<XDocument> UpdateProfileBackgroundImageAsync(ConsumerBase twitter, string accessToken, string image, bool tile, CancellationToken cancellationToken) {
+ var imageAttachment = new StreamContent(File.OpenRead(image));
+ imageAttachment.Headers.ContentType = new MediaTypeHeaderValue("image/" + Path.GetExtension(image).Substring(1).ToLowerInvariant());
+ var parts = new List<MultipartContentMember> {
+ new MultipartContentMember(imageAttachment , "image"),
+ new MultipartContentMember(new StringContent(tile.ToString().ToLowerInvariant()) , "tile"),
};
- HttpWebRequest request = twitter.PrepareAuthorizedRequest(UpdateProfileBackgroundImageEndpoint, accessToken, parts);
- request.ServicePoint.Expect100Continue = false;
- IncomingWebResponse response = twitter.Channel.WebRequestHandler.GetResponse(request);
- string responseString = response.GetResponseReader().ReadToEnd();
- return XDocument.Parse(responseString);
+ HttpRequestMessage request = await twitter.PrepareAuthorizedRequestAsync(UpdateProfileBackgroundImageEndpoint, accessToken, parts, cancellationToken);
+ request.Headers.ExpectContinue = false;
+ using (var httpClient = twitter.Channel.HostFactories.CreateHttpClient()) {
+ using (HttpResponseMessage response = await httpClient.SendAsync(request)) {
+ string responseString = await response.Content.ReadAsStringAsync();
+ return XDocument.Parse(responseString);
+ }
+ }
}
- public static XDocument UpdateProfileImage(ConsumerBase twitter, string accessToken, string pathToImage) {
+ public static Task<XDocument> UpdateProfileImageAsync(ConsumerBase twitter, string accessToken, string pathToImage, CancellationToken cancellationToken = default(CancellationToken)) {
string contentType = "image/" + Path.GetExtension(pathToImage).Substring(1).ToLowerInvariant();
- return UpdateProfileImage(twitter, accessToken, File.OpenRead(pathToImage), contentType);
+ return UpdateProfileImageAsync(twitter, accessToken, File.OpenRead(pathToImage), contentType, cancellationToken);
}
- public static XDocument UpdateProfileImage(ConsumerBase twitter, string accessToken, Stream image, string contentType) {
- var parts = new[] {
- MultipartPostPart.CreateFormFilePart("image", "twitterPhoto", contentType, image),
+ public static async Task<XDocument> UpdateProfileImageAsync(ConsumerBase twitter, string accessToken, Stream image, string contentType, CancellationToken cancellationToken = default(CancellationToken)) {
+ var imageAttachment = new StreamContent(image);
+ imageAttachment.Headers.ContentType = new MediaTypeHeaderValue(contentType);
+ var parts = new List<MultipartContentMember> {
+ new MultipartContentMember(imageAttachment,"image", "twitterPhoto"),
};
- HttpWebRequest request = twitter.PrepareAuthorizedRequest(UpdateProfileImageEndpoint, accessToken, parts);
- IncomingWebResponse response = twitter.Channel.WebRequestHandler.GetResponse(request);
- string responseString = response.GetResponseReader().ReadToEnd();
- return XDocument.Parse(responseString);
+
+ HttpRequestMessage request = await twitter.PrepareAuthorizedRequestAsync(UpdateProfileImageEndpoint, accessToken, parts, cancellationToken);
+ using (var httpClient = twitter.Channel.HostFactories.CreateHttpClient()) {
+ using (HttpResponseMessage response = await httpClient.SendAsync(request)) {
+ string responseString = await response.Content.ReadAsStringAsync();
+ return XDocument.Parse(responseString);
+ }
+ }
}
- public static XDocument VerifyCredentials(ConsumerBase twitter, string accessToken) {
- IncomingWebResponse response = twitter.PrepareAuthorizedRequestAndSend(VerifyCredentialsEndpoint, accessToken);
- return XDocument.Load(XmlReader.Create(response.GetResponseReader()));
+ public static async Task<XDocument> VerifyCredentialsAsync(ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ var request = await twitter.PrepareAuthorizedRequestAsync(VerifyCredentialsEndpoint, accessToken, cancellationToken);
+ using (var httpClient = twitter.Channel.HostFactories.CreateHttpClient()) {
+ using (var response = await httpClient.SendAsync(request)) {
+ using (var stream = await response.Content.ReadAsStreamAsync()) {
+ return XDocument.Load(XmlReader.Create(stream));
+ }
+ }
+ }
}
- public static string GetUsername(ConsumerBase twitter, string accessToken) {
- XDocument xml = VerifyCredentials(twitter, accessToken);
+ public static async Task<string> GetUsername(ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ XDocument xml = await VerifyCredentialsAsync(twitter, accessToken, cancellationToken);
XPathNavigator nav = xml.CreateNavigator();
return nav.SelectSingleNode("/user/screen_name").Value;
}
@@ -183,42 +216,37 @@ namespace DotNetOpenAuth.ApplicationBlock {
/// <c>return StartSignInWithTwitter().<see cref="MessagingUtilities.AsActionResult">AsActionResult()</see></c>
/// to actually perform the redirect.
/// </remarks>
- public static OutgoingWebResponse StartSignInWithTwitter(bool forceNewLogin) {
+ public static async Task<HttpResponseMessage> StartSignInWithTwitterAsync(bool forceNewLogin, CancellationToken cancellationToken) {
var redirectParameters = new Dictionary<string, string>();
if (forceNewLogin) {
redirectParameters["force_login"] = "true";
}
Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_");
- var request = TwitterSignIn.PrepareRequestUserAuthorization(callback, null, redirectParameters);
- return TwitterSignIn.Channel.PrepareResponse(request);
+ var request = await TwitterSignIn.PrepareRequestUserAuthorizationAsync(callback, null, redirectParameters, cancellationToken);
+ return await TwitterSignIn.Channel.PrepareResponseAsync(request, cancellationToken);
}
/// <summary>
/// Checks the incoming web request to see if it carries a Twitter authentication response,
/// and provides the user's Twitter screen name and unique id if available.
/// </summary>
- /// <param name="screenName">The user's Twitter screen name.</param>
- /// <param name="userId">The user's Twitter unique user ID.</param>
/// <returns>
- /// A value indicating whether Twitter authentication was successful;
- /// otherwise <c>false</c> to indicate that no Twitter response was present.
+ /// A tuple with the screen name and Twitter unique user ID if successful; otherwise <c>null</c>.
/// </returns>
- public static bool TryFinishSignInWithTwitter(out string screenName, out int userId) {
- screenName = null;
- userId = 0;
- var response = TwitterSignIn.ProcessUserAuthorization();
+ public static async Task<Tuple<string, int>> TryFinishSignInWithTwitterAsync(CancellationToken cancellationToken = default(CancellationToken)) {
+ var response = await TwitterSignIn.ProcessUserAuthorizationAsync(cancellationToken: cancellationToken);
if (response == null) {
- return false;
+ return null;
}
- screenName = response.ExtraData["screen_name"];
- userId = int.Parse(response.ExtraData["user_id"]);
+ string screenName = response.ExtraData["screen_name"];
+ int userId = int.Parse(response.ExtraData["user_id"]);
// If we were going to make this LOOK like OpenID even though it isn't,
// this seems like a reasonable, secure claimed id to allow the user to assume.
- OpenId.Identifier fake_claimed_id = string.Format(CultureInfo.InvariantCulture, "http://twitter.com/{0}#{1}", screenName, userId);
+ ////OpenId.Identifier fake_claimed_id = string.Format(CultureInfo.InvariantCulture, "http://twitter.com/{0}#{1}", screenName, userId);
- return true;
+ return Tuple.Create(screenName, userId);
}
}
}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
index 0bec372..3e0795a 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
@@ -13,33 +13,6 @@
internal static readonly Random NonCryptoRandomDataGenerator = new Random();
/// <summary>
- /// Sets the channel's outgoing HTTP requests to use default network credentials.
- /// </summary>
- /// <param name="channel">The channel to modify.</param>
- public static void UseDefaultNetworkCredentialsOnOutgoingHttpRequests(this Channel channel)
- {
- Debug.Assert(!(channel.WebRequestHandler is WrappingWebRequestHandler), "Wrapping an already wrapped web request handler. This is legal, but highly suspect of a bug as you don't want to wrap the same channel repeatedly to apply the same effect.");
- AddOutgoingHttpRequestTransform(channel, http => http.Credentials = CredentialCache.DefaultNetworkCredentials);
- }
-
- /// <summary>
- /// Adds some action to any outgoing HTTP request on this channel.
- /// </summary>
- /// <param name="channel">The channel's whose outgoing HTTP requests should be modified.</param>
- /// <param name="action">The action to perform on outgoing HTTP requests.</param>
- internal static void AddOutgoingHttpRequestTransform(this Channel channel, Action<HttpWebRequest> action) {
- if (channel == null) {
- throw new ArgumentNullException("channel");
- }
-
- if (action == null) {
- throw new ArgumentNullException("action");
- }
-
- channel.WebRequestHandler = new WrappingWebRequestHandler(channel.WebRequestHandler, action);
- }
-
- /// <summary>
/// Enumerates through the individual set bits in a flag enum.
/// </summary>
/// <param name="flags">The flags enum value.</param>
@@ -106,154 +79,5 @@
return totalCopiedBytes;
}
-
- /// <summary>
- /// Wraps some instance of a web request handler in order to perform some extra operation on all
- /// outgoing HTTP requests.
- /// </summary>
- private class WrappingWebRequestHandler : IDirectWebRequestHandler
- {
- /// <summary>
- /// The handler being wrapped.
- /// </summary>
- private readonly IDirectWebRequestHandler wrappedHandler;
-
- /// <summary>
- /// The action to perform on outgoing HTTP requests.
- /// </summary>
- private readonly Action<HttpWebRequest> action;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="WrappingWebRequestHandler"/> class.
- /// </summary>
- /// <param name="wrappedHandler">The HTTP handler to wrap.</param>
- /// <param name="action">The action to perform on outgoing HTTP requests.</param>
- internal WrappingWebRequestHandler(IDirectWebRequestHandler wrappedHandler, Action<HttpWebRequest> action)
- {
- if (wrappedHandler == null) {
- throw new ArgumentNullException("wrappedHandler");
- }
-
- if (action == null) {
- throw new ArgumentNullException("action");
- }
-
- this.wrappedHandler = wrappedHandler;
- this.action = action;
- }
-
- #region Implementation of IDirectWebRequestHandler
-
- /// <summary>
- /// Determines whether this instance can support the specified options.
- /// </summary>
- /// <param name="options">The set of options that might be given in a subsequent web request.</param>
- /// <returns>
- /// <c>true</c> if this instance can support the specified options; otherwise, <c>false</c>.
- /// </returns>
- public bool CanSupport(DirectWebRequestOptions options)
- {
- return this.wrappedHandler.CanSupport(options);
- }
-
- /// <summary>
- /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
- /// </summary>
- /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
- /// <returns>
- /// The stream the caller should write out the entity data to.
- /// </returns>
- /// <exception cref="ProtocolException">Thrown for any network error.</exception>
- /// <remarks>
- /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
- /// and any other appropriate properties <i>before</i> calling this method.
- /// Callers <i>must</i> close and dispose of the request stream when they are done
- /// writing to it to avoid taking up the connection too long and causing long waits on
- /// subsequent requests.</para>
- /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
- /// <see cref="ProtocolException"/> to abstract away the transport and provide
- /// a single exception type for hosts to catch.</para>
- /// </remarks>
- public Stream GetRequestStream(HttpWebRequest request)
- {
- this.action(request);
- return this.wrappedHandler.GetRequestStream(request);
- }
-
- /// <summary>
- /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
- /// </summary>
- /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
- /// <param name="options">The options to apply to this web request.</param>
- /// <returns>
- /// The stream the caller should write out the entity data to.
- /// </returns>
- /// <exception cref="ProtocolException">Thrown for any network error.</exception>
- /// <remarks>
- /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
- /// and any other appropriate properties <i>before</i> calling this method.
- /// Callers <i>must</i> close and dispose of the request stream when they are done
- /// writing to it to avoid taking up the connection too long and causing long waits on
- /// subsequent requests.</para>
- /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
- /// <see cref="ProtocolException"/> to abstract away the transport and provide
- /// a single exception type for hosts to catch.</para>
- /// </remarks>
- public Stream GetRequestStream(HttpWebRequest request, DirectWebRequestOptions options)
- {
- this.action(request);
- return this.wrappedHandler.GetRequestStream(request, options);
- }
-
- /// <summary>
- /// Processes an <see cref="HttpWebRequest"/> and converts the
- /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
- /// </summary>
- /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
- /// <returns>An instance of <see cref="IncomingWebResponse"/> describing the response.</returns>
- /// <exception cref="ProtocolException">Thrown for any network error.</exception>
- /// <remarks>
- /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
- /// <see cref="ProtocolException"/> to abstract away the transport and provide
- /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, should be Closed before throwing.</para>
- /// </remarks>
- public IncomingWebResponse GetResponse(HttpWebRequest request)
- {
- // If the request has an entity, the action would have already been processed in GetRequestStream.
- if (request.Method == "GET")
- {
- this.action(request);
- }
-
- return this.wrappedHandler.GetResponse(request);
- }
-
- /// <summary>
- /// Processes an <see cref="HttpWebRequest"/> and converts the
- /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
- /// </summary>
- /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
- /// <param name="options">The options to apply to this web request.</param>
- /// <returns>An instance of <see cref="IncomingWebResponse"/> describing the response.</returns>
- /// <exception cref="ProtocolException">Thrown for any network error.</exception>
- /// <remarks>
- /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
- /// <see cref="ProtocolException"/> to abstract away the transport and provide
- /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, should be Closed before throwing.</para>
- /// </remarks>
- public IncomingWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options)
- {
- // If the request has an entity, the action would have already been processed in GetRequestStream.
- if (request.Method == "GET") {
- this.action(request);
- }
-
- return this.wrappedHandler.GetResponse(request, options);
- }
-
- #endregion
- }
}
}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs
index bbeb861..cedcbf7 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs
@@ -4,18 +4,22 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.ApplicationBlock {
+namespace DotNetOpenAuth.ApplicationBlock
+{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
- public static class YammerConsumer {
+ public static class YammerConsumer
+ {
/// <summary>
/// The Consumer to use for accessing Google data APIs.
/// </summary>
@@ -31,16 +35,15 @@ namespace DotNetOpenAuth.ApplicationBlock {
return new DesktopConsumer(ServiceDescription, tokenManager);
}
- public static Uri PrepareRequestAuthorization(DesktopConsumer consumer, out string requestToken) {
+ public static Task<Tuple<Uri, string>> PrepareRequestAuthorizationAsync(DesktopConsumer consumer, CancellationToken cancellationToken = default(CancellationToken)) {
if (consumer == null) {
throw new ArgumentNullException("consumer");
}
- Uri authorizationUrl = consumer.RequestUserAuthorization(null, null, out requestToken);
- return authorizationUrl;
+ return consumer.RequestUserAuthorizationAsync(null, null, cancellationToken);
}
- public static AuthorizedTokenResponse CompleteAuthorization(DesktopConsumer consumer, string requestToken, string userCode) {
+ public static async Task<AuthorizedTokenResponse> CompleteAuthorizationAsync(DesktopConsumer consumer, string requestToken, string userCode, CancellationToken cancellationToken = default(CancellationToken)) {
// Because Yammer has a proprietary callback_token parameter, and it's passed
// with the message that specifically bans extra arguments being passed, we have
// to cheat by adding the data to the URL itself here.
@@ -54,7 +57,7 @@ namespace DotNetOpenAuth.ApplicationBlock {
// To use a custom service description we also must create a new WebConsumer.
var customConsumer = new DesktopConsumer(customServiceDescription, consumer.TokenManager);
- var response = customConsumer.ProcessUserAuthorization(requestToken, userCode);
+ var response = await customConsumer.ProcessUserAuthorizationAsync(requestToken, userCode, cancellationToken);
return response;
}
}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/packages.config b/samples/DotNetOpenAuth.ApplicationBlock/packages.config
new file mode 100644
index 0000000..d8ffcb7
--- /dev/null
+++ b/samples/DotNetOpenAuth.ApplicationBlock/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs
index bd6de1b..7828b5c 100644
--- a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs
+++ b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs
@@ -3,6 +3,7 @@ namespace OpenIdProviderMvc.Controllers {
using System.Collections.Generic;
using System.Linq;
using System.Net;
+ using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
@@ -29,12 +30,13 @@ namespace OpenIdProviderMvc.Controllers {
public IFormsAuthentication FormsAuth { get; private set; }
[ValidateInput(false)]
- public ActionResult Provider() {
- IRequest request = OpenIdProvider.GetRequest();
+ public async Task<ActionResult> Provider() {
+ IRequest request = await OpenIdProvider.GetRequestAsync(this.Request, this.Response.ClientDisconnectedToken);
if (request != null) {
// Some requests are automatically handled by DotNetOpenAuth. If this is one, go ahead and let it go.
if (request.IsResponseReady) {
- return OpenIdProvider.PrepareResponse(request).AsActionResult();
+ var response = await OpenIdProvider.PrepareResponseAsync(request, this.Response.ClientDisconnectedToken);
+ return response.AsActionResult();
}
// This is apparently one that the host (the web site itself) has to respond to.
@@ -51,28 +53,28 @@ namespace OpenIdProviderMvc.Controllers {
}
}
- return this.ProcessAuthRequest();
+ return await this.ProcessAuthRequest();
} else {
// No OpenID request was recognized. This may be a user that stumbled on the OP Endpoint.
return this.View();
}
}
- public ActionResult ProcessAuthRequest() {
+ public async Task<ActionResult> ProcessAuthRequest() {
if (ProviderEndpoint.PendingRequest == null) {
return this.RedirectToAction("Index", "Home");
}
// Try responding immediately if possible.
- ActionResult response;
- if (this.AutoRespondIfPossible(out response)) {
+ ActionResult response = await this.AutoRespondIfPossibleAsync();
+ if (response != null) {
return response;
}
// We can't respond immediately with a positive result. But if we still have to respond immediately...
if (ProviderEndpoint.PendingRequest.Immediate) {
// We can't stop to prompt the user -- we must just return a negative response.
- return this.SendAssertion();
+ return await this.SendAssertion();
}
return this.RedirectToAction("AskUser");
@@ -83,15 +85,15 @@ namespace OpenIdProviderMvc.Controllers {
/// </summary>
/// <returns>The response for the user agent.</returns>
[Authorize]
- public ActionResult AskUser() {
+ public async Task<ActionResult> AskUser() {
if (ProviderEndpoint.PendingRequest == null) {
// Oops... precious little we can confirm without a pending OpenID request.
return this.RedirectToAction("Index", "Home");
}
// The user MAY have just logged in. Try again to respond automatically to the RP if appropriate.
- ActionResult response;
- if (this.AutoRespondIfPossible(out response)) {
+ ActionResult response = await this.AutoRespondIfPossibleAsync();
+ if (response != null) {
return response;
}
@@ -106,10 +108,9 @@ namespace OpenIdProviderMvc.Controllers {
}
[HttpPost, Authorize, ValidateAntiForgeryToken]
- public ActionResult AskUserResponse(bool confirmed) {
+ public async Task<ActionResult> AskUserResponse(bool confirmed) {
if (!ProviderEndpoint.PendingAuthenticationRequest.IsDirectedIdentity &&
- !this.UserControlsIdentifier(ProviderEndpoint.PendingAuthenticationRequest))
- {
+ !this.UserControlsIdentifier(ProviderEndpoint.PendingAuthenticationRequest)) {
// The user shouldn't have gotten this far without controlling the identifier we'd send an assertion for.
return new HttpStatusCodeResult((int)HttpStatusCode.BadRequest);
}
@@ -122,14 +123,14 @@ namespace OpenIdProviderMvc.Controllers {
throw new InvalidOperationException("There's no pending authentication request!");
}
- return this.SendAssertion();
+ return await this.SendAssertion();
}
/// <summary>
/// Sends a positive or a negative assertion, based on how the pending request is currently marked.
/// </summary>
/// <returns>An MVC redirect result.</returns>
- public ActionResult SendAssertion() {
+ public async Task<ActionResult> SendAssertion() {
var pendingRequest = ProviderEndpoint.PendingRequest;
var authReq = pendingRequest as IAuthenticationRequest;
var anonReq = pendingRequest as IAnonymousRequest;
@@ -188,17 +189,17 @@ namespace OpenIdProviderMvc.Controllers {
}
}
- return OpenIdProvider.PrepareResponse(pendingRequest).AsActionResult();
+ var response = await OpenIdProvider.PrepareResponseAsync(pendingRequest, this.Response.ClientDisconnectedToken);
+ return response.AsActionResult();
}
/// <summary>
/// Attempts to formulate an automatic response to the RP if the user's profile allows it.
/// </summary>
- /// <param name="response">Receives the ActionResult for the caller to return, or <c>null</c> if no automatic response can be made.</param>
- /// <returns>A value indicating whether an automatic response is possible.</returns>
- private bool AutoRespondIfPossible(out ActionResult response) {
+ /// <returns>The ActionResult for the caller to return, or <c>null</c> if no automatic response can be made.</returns>
+ private async Task<ActionResult> AutoRespondIfPossibleAsync() {
// If the odds are good we can respond to this one immediately (without prompting the user)...
- if (ProviderEndpoint.PendingRequest.IsReturnUrlDiscoverable(OpenIdProvider.Channel.WebRequestHandler) == RelyingPartyDiscoveryResult.Success
+ if (await ProviderEndpoint.PendingRequest.IsReturnUrlDiscoverableAsync(OpenIdProvider.Channel.HostFactories, this.Response.ClientDisconnectedToken) == RelyingPartyDiscoveryResult.Success
&& User.Identity.IsAuthenticated
&& this.HasUserAuthorizedAutoLogin(ProviderEndpoint.PendingRequest)) {
// Is this is an identity authentication request? (as opposed to an anonymous request)...
@@ -207,21 +208,18 @@ namespace OpenIdProviderMvc.Controllers {
if (ProviderEndpoint.PendingAuthenticationRequest.IsDirectedIdentity
|| this.UserControlsIdentifier(ProviderEndpoint.PendingAuthenticationRequest)) {
ProviderEndpoint.PendingAuthenticationRequest.IsAuthenticated = true;
- response = this.SendAssertion();
- return true;
+ return await this.SendAssertion();
}
}
// If this is an anonymous request, we can respond to that too.
if (ProviderEndpoint.PendingAnonymousRequest != null) {
ProviderEndpoint.PendingAnonymousRequest.IsApproved = true;
- response = this.SendAssertion();
- return true;
+ return await this.SendAssertion();
}
}
- response = null;
- return false;
+ return null;
}
/// <summary>
diff --git a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj
index 45686cd..4c57961 100644
--- a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj
+++ b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj
@@ -9,6 +9,7 @@
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\src\</SolutionDir>
</PropertyGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -49,6 +50,8 @@
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Drawing" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.ComponentModel.DataAnnotations">
@@ -143,6 +146,9 @@
<Name>DotNetOpenAuth.ApplicationBlock</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Content Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
@@ -172,4 +178,5 @@
</VisualStudio>
</ProjectExtensions>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " />
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
</Project> \ No newline at end of file
diff --git a/samples/OpenIdProviderMvc/packages.config b/samples/OpenIdProviderMvc/packages.config
new file mode 100644
index 0000000..d8ffcb7
--- /dev/null
+++ b/samples/OpenIdProviderMvc/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
index ccba40f..353ecca 100644
--- a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
+++ b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
@@ -29,6 +29,7 @@
<Compile Include="Messaging\Bindings\ICryptoKeyStore.cs" />
<Compile Include="Messaging\Bindings\MemoryCryptoKeyStore.cs" />
<Compile Include="Messaging\BinaryDataBagFormatter.cs" />
+ <Compile Include="Messaging\MultipartContentMember.cs" />
<Compile Include="Messaging\DataBagFormatterBase.cs" />
<Compile Include="Messaging\HmacAlgorithms.cs" />
<Compile Include="Messaging\HttpRequestHeaders.cs" />
diff --git a/src/DotNetOpenAuth.Core/Messaging/Channel.cs b/src/DotNetOpenAuth.Core/Messaging/Channel.cs
index 7eadecd..36c91c7 100644
--- a/src/DotNetOpenAuth.Core/Messaging/Channel.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/Channel.cs
@@ -554,6 +554,28 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Adds just the binary data part of a message to a multipart form content object.
+ /// </summary>
+ /// <param name="requestMessageWithBinaryData">The request message with binary data.</param>
+ /// <returns>The initialized HttpContent.</returns>
+ protected static MultipartFormDataContent InitializeMultipartFormDataContent(IMessageWithBinaryData requestMessageWithBinaryData) {
+ Requires.NotNull(requestMessageWithBinaryData, "requestMessageWithBinaryData");
+
+ var content = new MultipartFormDataContent();
+ foreach (var part in requestMessageWithBinaryData.BinaryData) {
+ if (string.IsNullOrEmpty(part.Name)) {
+ content.Add(part.Content);
+ } else if (string.IsNullOrEmpty(part.FileName)) {
+ content.Add(part.Content, part.Name);
+ } else {
+ content.Add(part.Content, part.Name, part.FileName);
+ }
+ }
+
+ return content;
+ }
+
+ /// <summary>
/// Checks whether a given HTTP method is expected to include an entity body in its request.
/// </summary>
/// <param name="httpMethod">The HTTP method.</param>
@@ -1041,10 +1063,7 @@ namespace DotNetOpenAuth.Messaging {
var requestMessageWithBinaryData = requestMessage as IMessageWithBinaryData;
if (requestMessageWithBinaryData != null && requestMessageWithBinaryData.SendAsMultipart) {
- var content = new MultipartFormDataContent();
- foreach (var part in requestMessageWithBinaryData.BinaryData) {
- content.Add(part.Value, part.Key);
- }
+ var content = InitializeMultipartFormDataContent(requestMessageWithBinaryData);
// When sending multi-part, all data gets send as multi-part -- even the non-binary data.
foreach (var field in fields) {
diff --git a/src/DotNetOpenAuth.Core/Messaging/IMessageWithBinaryData.cs b/src/DotNetOpenAuth.Core/Messaging/IMessageWithBinaryData.cs
index bcf4d8d..84a7760 100644
--- a/src/DotNetOpenAuth.Core/Messaging/IMessageWithBinaryData.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/IMessageWithBinaryData.cs
@@ -20,7 +20,7 @@ namespace DotNetOpenAuth.Messaging {
/// Gets the parts of the message that carry binary data.
/// </summary>
/// <value>A list of parts. Never null.</value>
- IDictionary<string, HttpContent> BinaryData { get; }
+ IList<MultipartContentMember> BinaryData { get; }
/// <summary>
/// Gets a value indicating whether this message should be sent as multi-part POST.
diff --git a/src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs b/src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs
new file mode 100644
index 0000000..2aa33ae
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs
@@ -0,0 +1,23 @@
+namespace DotNetOpenAuth.Messaging {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net.Http;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ public struct MultipartContentMember {
+ public MultipartContentMember(HttpContent content, string name = null, string fileName = null)
+ : this() {
+ this.Content = content;
+ this.Name = name;
+ this.FileName = fileName;
+ }
+
+ public HttpContent Content { get; set; }
+
+ public string Name { get; set; }
+
+ public string FileName { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
index b34d4f8..80a1381 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
@@ -148,15 +148,13 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="accessToken">The access token that permits access to the protected resource.</param>
/// <param name="binaryData">Extra parameters to include in the message. Must not be null, but may be empty.</param>
/// <returns>The initialized WebRequest object.</returns>
- public Task<HttpRequestMessage> PrepareAuthorizedRequestAsync(MessageReceivingEndpoint endpoint, string accessToken, IDictionary<string, HttpContent> binaryData, CancellationToken cancellationToken = default(CancellationToken)) {
+ public Task<HttpRequestMessage> PrepareAuthorizedRequestAsync(MessageReceivingEndpoint endpoint, string accessToken, IEnumerable<MultipartContentMember> binaryData, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNull(endpoint, "endpoint");
Requires.NotNullOrEmpty(accessToken, "accessToken");
Requires.NotNull(binaryData, "binaryData");
AccessProtectedResourceRequest message = this.CreateAuthorizingMessage(endpoint, accessToken);
- foreach (var part in binaryData) {
- message.BinaryData.Add(part);
- }
+ message.BinaryData.AddRange(binaryData);
return this.OAuthChannel.InitializeRequestAsync(message, cancellationToken);
}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs
index 4627d23..cd16c7e 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs
@@ -38,7 +38,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
/// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
/// <param name="requestToken">The request token that must be exchanged for an access token after the user has provided authorization.</param>
- /// <returns>The URL to open a browser window to allow the user to provide authorization.</returns>
+ /// <returns>The URL to open a browser window to allow the user to provide authorization and the request token.</returns>
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Two results")]
public async Task<Tuple<Uri, string>> RequestUserAuthorizationAsync(IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) {
var message = await this.PrepareRequestUserAuthorizationAsync(null, requestParameters, redirectParameters, cancellationToken);
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs
index f3c5897..e5dd258 100644
--- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs
+++ b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthChannel.cs
@@ -309,11 +309,8 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
if (requestMessageWithBinaryData != null && requestMessageWithBinaryData.SendAsMultipart) {
// Include the binary data in the multipart entity, and any standard text extra message data.
// The standard declared message parts are included in the authorization header.
- var content = new MultipartFormDataContent();
+ var content = InitializeMultipartFormDataContent(requestMessageWithBinaryData);
httpRequest.Content = content;
- foreach (var contentPart in requestMessageWithBinaryData.BinaryData) {
- content.Add(contentPart.Value, contentPart.Key);
- }
foreach (var extraData in requestMessage.ExtraData) {
content.Add(new StringContent(extraData.Value), extraData.Key);
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs
index 77b1733..9b698b9 100644
--- a/src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs
+++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs
@@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// <summary>
/// A store for the binary data that is carried in the message.
/// </summary>
- private Dictionary<string, HttpContent> binaryData = new Dictionary<string, HttpContent>();
+ private List<MultipartContentMember> binaryData = new List<MultipartContentMember>();
/// <summary>
/// Initializes a new instance of the <see cref="AccessProtectedResourceRequest"/> class.
@@ -58,7 +58,7 @@ namespace DotNetOpenAuth.OAuth.Messages {
/// Gets the parts of the message that carry binary data.
/// </summary>
/// <value>A list of parts. Never null.</value>
- public IDictionary<string, HttpContent> BinaryData {
+ public IList<MultipartContentMember> BinaryData {
get { return this.binaryData; }
}
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Provider/IHostProcessedRequest.cs b/src/DotNetOpenAuth.OpenId/OpenId/Provider/IHostProcessedRequest.cs
index 8f7767b..0e40f0f 100644
--- a/src/DotNetOpenAuth.OpenId/OpenId/Provider/IHostProcessedRequest.cs
+++ b/src/DotNetOpenAuth.OpenId/OpenId/Provider/IHostProcessedRequest.cs
@@ -56,6 +56,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <para>Return URL verification is only attempted if this method is called.</para>
/// <para>See OpenID Authentication 2.0 spec section 9.2.1.</para>
/// </remarks>
- Task<RelyingPartyDiscoveryResult> IsReturnUrlDiscoverableAsync(IHostFactories hostFactories, CancellationToken cancellationToken);
+ Task<RelyingPartyDiscoveryResult> IsReturnUrlDiscoverableAsync(IHostFactories hostFactories = null, CancellationToken cancellationToken = default(CancellationToken));
}
}
diff --git a/src/packages/repositories.config b/src/packages/repositories.config
index 1f57a14..6bb73e0 100644
--- a/src/packages/repositories.config
+++ b/src/packages/repositories.config
@@ -3,6 +3,7 @@
<repository path="..\..\projecttemplates\MvcRelyingParty\packages.config" />
<repository path="..\..\projecttemplates\RelyingPartyLogic\packages.config" />
<repository path="..\..\projecttemplates\WebFormsRelyingParty\packages.config" />
+ <repository path="..\..\samples\DotNetOpenAuth.ApplicationBlock\packages.config" />
<repository path="..\..\samples\OAuthAuthorizationServer\packages.config" />
<repository path="..\..\samples\OAuthClient\packages.config" />
<repository path="..\..\samples\OAuthConsumer\packages.config" />
@@ -10,6 +11,7 @@
<repository path="..\..\samples\OAuthResourceServer\packages.config" />
<repository path="..\..\samples\OAuthServiceProvider\packages.config" />
<repository path="..\..\samples\OpenIdOfflineProvider\packages.config" />
+ <repository path="..\..\samples\OpenIdProviderMvc\packages.config" />
<repository path="..\..\samples\OpenIdProviderWebForms\packages.config" />
<repository path="..\..\samples\OpenIdRelyingPartyMvc\packages.config" />
<repository path="..\..\samples\OpenIdRelyingPartyWebForms\packages.config" />