summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--samples/Consumer/App_Code/Constants.cs40
-rw-r--r--samples/Consumer/App_Code/InMemoryTokenManager.cs71
-rw-r--r--samples/Consumer/App_Code/Logging.cs20
-rw-r--r--samples/Consumer/App_Code/TracePageAppender.cs11
-rw-r--r--samples/Consumer/Default.aspx10
-rw-r--r--samples/Consumer/Global.asax32
-rw-r--r--samples/Consumer/GoogleAddressBook.aspx45
-rw-r--r--samples/Consumer/GoogleAddressBook.aspx.cs70
-rw-r--r--samples/Consumer/MasterPage.master23
-rw-r--r--samples/Consumer/Settings.StyleCop1
-rw-r--r--samples/Consumer/TracePage.aspx18
-rw-r--r--samples/Consumer/TracePage.aspx.cs21
-rw-r--r--samples/Consumer/Web.config138
-rw-r--r--samples/ConsumerWpf/App.config28
-rw-r--r--samples/ConsumerWpf/App.xaml8
-rw-r--r--samples/ConsumerWpf/App.xaml.cs14
-rw-r--r--samples/ConsumerWpf/Constants.cs48
-rw-r--r--samples/ConsumerWpf/ConsumerWpf.csproj112
-rw-r--r--samples/ConsumerWpf/InMemoryTokenManager.cs71
-rw-r--r--samples/ConsumerWpf/MainWindow.xaml40
-rw-r--r--samples/ConsumerWpf/MainWindow.xaml.cs69
-rw-r--r--samples/ConsumerWpf/Properties/AssemblyInfo.cs46
-rw-r--r--samples/ConsumerWpf/Properties/Resources.Designer.cs63
-rw-r--r--samples/ConsumerWpf/Properties/Resources.resx117
-rw-r--r--samples/ConsumerWpf/Properties/Settings.Designer.cs26
-rw-r--r--samples/ConsumerWpf/Properties/Settings.settings7
-rw-r--r--samples/Settings.StyleCop39
-rw-r--r--src/DotNetOAuth.sln36
28 files changed, 1224 insertions, 0 deletions
diff --git a/samples/Consumer/App_Code/Constants.cs b/samples/Consumer/App_Code/Constants.cs
new file mode 100644
index 0000000..ecf76a8
--- /dev/null
+++ b/samples/Consumer/App_Code/Constants.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using DotNetOAuth;
+using DotNetOAuth.ChannelElements;
+using DotNetOAuth.Messaging;
+
+/// <summary>
+/// Service Provider definitions.
+/// </summary>
+public static class Constants {
+ /// <summary>
+ /// The Consumer to use for accessing Google data APIs.
+ /// </summary>
+ public static readonly ServiceProviderDescription GoogleDescription = new ServiceProviderDescription {
+ RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethod.AuthorizationHeaderRequest),
+ UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthAuthorizeToken", HttpDeliveryMethod.AuthorizationHeaderRequest),
+ AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetAccessToken", HttpDeliveryMethod.AuthorizationHeaderRequest),
+ TamperProtectionElements = new ITamperProtectionChannelBindingElement[] {
+ new HmacSha1SigningBindingElement(),
+ },
+ };
+
+ /// <summary>
+ /// Values of the "scope" parameter that indicates what data streams the Consumer
+ /// wants access to.
+ /// </summary>
+ public static class GoogleScopes {
+ /// <summary>
+ /// Access to the Gmail address book.
+ /// </summary>
+ public const string Contacts = "http://www.google.com/m8/feeds/";
+
+ /// <summary>
+ /// The URI to get contacts once authorization is granted.
+ /// </summary>
+ public static readonly MessageReceivingEndpoint GetContacts = new MessageReceivingEndpoint("http://www.google.com/m8/feeds/contacts/default/full/", HttpDeliveryMethod.GetRequest);
+ }
+}
diff --git a/samples/Consumer/App_Code/InMemoryTokenManager.cs b/samples/Consumer/App_Code/InMemoryTokenManager.cs
new file mode 100644
index 0000000..dc80da1
--- /dev/null
+++ b/samples/Consumer/App_Code/InMemoryTokenManager.cs
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------
+// <copyright file="InMemoryTokenManager.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using DotNetOAuth.ChannelElements;
+
+public class InMemoryTokenManager : ITokenManager {
+ private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
+
+ public InMemoryTokenManager(string consumerKey, string consumerSecret) {
+ this.ConsumerKey = consumerKey;
+ this.ConsumerSecret = consumerSecret;
+ }
+
+ public string ConsumerKey { get; private set; }
+
+ public string ConsumerSecret { get; private set; }
+
+ #region ITokenManager Members
+
+ public string GetConsumerSecret(string consumerKey) {
+ if (consumerKey == this.ConsumerKey) {
+ return this.ConsumerSecret;
+ } else {
+ throw new ArgumentException("Unrecognized consumer key.", "consumerKey");
+ }
+ }
+
+ public string GetTokenSecret(string token) {
+ return this.tokensAndSecrets[token];
+ }
+
+ public void StoreNewRequestToken(string consumerKey, string requestToken, string requestTokenSecret, IDictionary<string, string> parameters) {
+ this.tokensAndSecrets[requestToken] = requestTokenSecret;
+ }
+
+ /// <summary>
+ /// Checks whether a given request token has already been authorized
+ /// by some user for use by the Consumer that requested it.
+ /// </summary>
+ /// <param name="requestToken">The Consumer's request token.</param>
+ /// <returns>
+ /// True if the request token has already been fully authorized by the user
+ /// who owns the relevant protected resources. False if the token has not yet
+ /// been authorized, has expired or does not exist.
+ /// </returns>
+ public bool IsRequestTokenAuthorized(string requestToken) {
+ throw new NotImplementedException();
+ }
+
+ public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
+ this.tokensAndSecrets.Remove(requestToken);
+ this.tokensAndSecrets[accessToken] = accessTokenSecret;
+ }
+
+ /// <summary>
+ /// Classifies a token as a request token or an access token.
+ /// </summary>
+ /// <param name="token">The token to classify.</param>
+ /// <returns>Request or Access token, or invalid if the token is not recognized.</returns>
+ public TokenType GetTokenType(string token) {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+}
diff --git a/samples/Consumer/App_Code/Logging.cs b/samples/Consumer/App_Code/Logging.cs
new file mode 100644
index 0000000..cba9b4e
--- /dev/null
+++ b/samples/Consumer/App_Code/Logging.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web;
+
+/// <summary>
+/// Logging tools for this sample.
+/// </summary>
+public static class Logging {
+ /// <summary>
+ /// An application memory cache of recent log messages.
+ /// </summary>
+ public static StringBuilder LogMessages = new StringBuilder();
+
+ /// <summary>
+ /// The logger for this sample to use.
+ /// </summary>
+ public static log4net.ILog Logger = log4net.LogManager.GetLogger("DotNetOAuth.ConsumerSample");
+}
diff --git a/samples/Consumer/App_Code/TracePageAppender.cs b/samples/Consumer/App_Code/TracePageAppender.cs
new file mode 100644
index 0000000..b3b539a
--- /dev/null
+++ b/samples/Consumer/App_Code/TracePageAppender.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Web;
+
+public class TracePageAppender : log4net.Appender.AppenderSkeleton {
+ protected override void Append(log4net.Core.LoggingEvent loggingEvent) {
+ StringWriter sw = new StringWriter(Logging.LogMessages);
+ Layout.Format(sw, loggingEvent);
+ }
+}
diff --git a/samples/Consumer/Default.aspx b/samples/Consumer/Default.aspx
new file mode 100644
index 0000000..ac9ebec
--- /dev/null
+++ b/samples/Consumer/Default.aspx
@@ -0,0 +1,10 @@
+<%@ Page Title="DotNetOAuth Consumer samples" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" %>
+
+<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server">
+ <p>OAuth allows this web site to access your private data with your authorization,
+ but without you having to give up your password. </p>
+ <p>Select a demo:</p>
+ <ul>
+ <li><a href="GoogleAddressBook.aspx">Download your Gmail address book</a></li>
+ </ul>
+</asp:Content>
diff --git a/samples/Consumer/Global.asax b/samples/Consumer/Global.asax
new file mode 100644
index 0000000..d622f9c
--- /dev/null
+++ b/samples/Consumer/Global.asax
@@ -0,0 +1,32 @@
+<%@ Application Language="C#" %>
+
+<script RunAt="server">
+ void Application_Start(object sender, EventArgs e) {
+ log4net.Config.XmlConfigurator.Configure();
+ Logging.Logger.Info("Sample starting...");
+ }
+
+ void Application_End(object sender, EventArgs e) {
+ Logging.Logger.Info("Sample shutting down...");
+ // this would be automatic, but in partial trust scenarios it is not.
+ log4net.LogManager.Shutdown();
+ }
+
+ void Application_Error(object sender, EventArgs e) {
+ // Code that runs when an unhandled error occurs
+
+ }
+
+ void Session_Start(object sender, EventArgs e) {
+ // Code that runs when a new session is started
+
+ }
+
+ void Session_End(object sender, EventArgs e) {
+ // Code that runs when a session ends.
+ // Note: The Session_End event is raised only when the sessionstate mode
+ // is set to InProc in the Web.config file. If session mode is set to StateServer
+ // or SQLServer, the event is not raised.
+
+ }
+</script>
diff --git a/samples/Consumer/GoogleAddressBook.aspx b/samples/Consumer/GoogleAddressBook.aspx
new file mode 100644
index 0000000..2f0f6d1
--- /dev/null
+++ b/samples/Consumer/GoogleAddressBook.aspx
@@ -0,0 +1,45 @@
+<%@ Page Title="Gmail address book demo" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
+ CodeFile="GoogleAddressBook.aspx.cs" Inherits="GoogleAddressBook" %>
+
+<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server">
+ <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
+ <asp:View runat="server" ID="Authorize">
+ <table>
+ <tr>
+ <td>
+ Google Consumer Key
+ </td>
+ <td>
+ <asp:TextBox ID="consumerKeyBox" runat="server" Columns="35"></asp:TextBox>
+ <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
+ ControlToValidate="consumerKeyBox" Display="Dynamic"
+ ErrorMessage="RequiredFieldValidator">*</asp:RequiredFieldValidator>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Google Consumer Secret
+ </td>
+ <td>
+ <asp:TextBox ID="consumerSecretBox" runat="server" Columns="35"></asp:TextBox>
+ <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server"
+ ControlToValidate="consumerSecretBox" Display="Dynamic">*</asp:RequiredFieldValidator>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ &nbsp;</td>
+ <td>
+ Don&#39;t have a Google Consumer Key?&nbsp;
+ <a href="https://www.google.com/accounts/ManageDomains">Get one</a>.</td>
+ </tr>
+ </table>
+ <asp:Button ID="authorizeButton" runat="server" Text="Download your Gmail Address Book"
+ OnClick="authorizeButton_Click" />
+ </asp:View>
+ <asp:View runat="server" ID="Results">
+ <p>Now displaying the first 25 records from your address book:</p>
+ <asp:PlaceHolder runat="server" ID="resultsPlaceholder" />
+ </asp:View>
+ </asp:MultiView>
+</asp:Content>
diff --git a/samples/Consumer/GoogleAddressBook.aspx.cs b/samples/Consumer/GoogleAddressBook.aspx.cs
new file mode 100644
index 0000000..5197b66
--- /dev/null
+++ b/samples/Consumer/GoogleAddressBook.aspx.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Xml.Linq;
+using DotNetOAuth;
+using DotNetOAuth.ChannelElements;
+using DotNetOAuth.Messaging;
+
+/// <summary>
+/// A page to demonstrate downloading a Gmail address book using OAuth.
+/// </summary>
+public partial class GoogleAddressBook : System.Web.UI.Page {
+ protected void Page_Load(object sender, EventArgs e) {
+ if (!IsPostBack) {
+ if (Session["TokenManager"] != null) {
+ InMemoryTokenManager tokenManager = (InMemoryTokenManager)Session["TokenManager"];
+ Consumer google = new Consumer(Constants.GoogleDescription, tokenManager) {
+ ConsumerKey = tokenManager.ConsumerKey,
+ ConsumerSecret = tokenManager.ConsumerSecret,
+ };
+
+ var accessTokenMessage = google.ProcessUserAuthorization();
+ if (accessTokenMessage != null) {
+ // User has approved access
+ MultiView1.ActiveViewIndex = 1;
+ resultsPlaceholder.Controls.Add(new Label { Text = accessTokenMessage.AccessToken });
+
+ Response contactsResponse = google.SendAuthorizedRequest(Constants.GoogleScopes.GetContacts, accessTokenMessage.AccessToken);
+ XDocument contactsDocument = XDocument.Parse(contactsResponse.Body);
+ var contacts = from entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom"))
+ select new {
+ Name = entry.Element(XName.Get("title", "http://www.w3.org/2005/Atom")).Value,
+ Email = entry.Element(XName.Get("email", "http://schemas.google.com/g/2005")).Attribute("address").Value,
+ };
+ StringBuilder tableBuilder = new StringBuilder();
+ tableBuilder.Append("<table><tr><td>Name</td><td>Email</td></tr>");
+ foreach (var contact in contacts) {
+ tableBuilder.AppendFormat(
+ "<tr><td>{0}</td><td>{1}</td></tr>",
+ HttpUtility.HtmlEncode(contact.Name),
+ HttpUtility.HtmlEncode(contact.Email));
+ }
+ tableBuilder.Append("</table>");
+ resultsPlaceholder.Controls.Add(new Literal { Text = tableBuilder.ToString() });
+ }
+ }
+ }
+ }
+
+ protected void authorizeButton_Click(object sender, EventArgs e) {
+ if (!Page.IsValid) {
+ return;
+ }
+
+ InMemoryTokenManager tokenManager = new InMemoryTokenManager(consumerKeyBox.Text, consumerSecretBox.Text);
+ Session["TokenManager"] = tokenManager;
+ Consumer google = new Consumer(Constants.GoogleDescription, tokenManager);
+ google.ConsumerKey = consumerKeyBox.Text;
+ google.ConsumerSecret = consumerSecretBox.Text;
+
+ var extraParameters = new Dictionary<string, string> {
+ { "scope", Constants.GoogleScopes.Contacts },
+ };
+ google.RequestUserAuthorization(new Uri(Request.Url, Request.RawUrl), extraParameters, null).Send();
+ }
+}
diff --git a/samples/Consumer/MasterPage.master b/samples/Consumer/MasterPage.master
new file mode 100644
index 0000000..08d139d
--- /dev/null
+++ b/samples/Consumer/MasterPage.master
@@ -0,0 +1,23 @@
+<%@ Master Language="C#" %>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<script runat="server">
+
+</script>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head runat="server">
+ <title>DotNetOAuth Consumer sample</title>
+ <asp:ContentPlaceHolder ID="head" runat="server"/>
+</head>
+<body>
+ <form id="form1" runat="server">
+ <h1>DotNetOAuth Consumer ASP.NET WebForms sample</h1>
+ <div>
+ <asp:ContentPlaceHolder ID="Body" runat="server">
+ </asp:ContentPlaceHolder>
+ </div>
+ </form>
+</body>
+</html>
diff --git a/samples/Consumer/Settings.StyleCop b/samples/Consumer/Settings.StyleCop
new file mode 100644
index 0000000..7f55ce6
--- /dev/null
+++ b/samples/Consumer/Settings.StyleCop
@@ -0,0 +1 @@
+<StyleCopSettings Version="4.3" /> \ No newline at end of file
diff --git a/samples/Consumer/TracePage.aspx b/samples/Consumer/TracePage.aspx
new file mode 100644
index 0000000..960e6ed
--- /dev/null
+++ b/samples/Consumer/TracePage.aspx
@@ -0,0 +1,18 @@
+<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TracePage.aspx.cs" Inherits="TracePage" %>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head runat="server">
+ <title></title>
+</head>
+<body>
+ <form id="form1" runat="server">
+ <p align="right">
+ <asp:Button runat="server" Text="Clear log" ID="clearLogButton" OnClick="clearLogButton_Click" />
+ </p>
+ <pre>
+ <asp:PlaceHolder runat="server" ID="placeHolder1" />
+ </pre>
+ </form>
+</body>
+</html>
diff --git a/samples/Consumer/TracePage.aspx.cs b/samples/Consumer/TracePage.aspx.cs
new file mode 100644
index 0000000..47e217b
--- /dev/null
+++ b/samples/Consumer/TracePage.aspx.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Web;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+
+/// <summary>
+/// A page to display recent log messages.
+/// </summary>
+public partial class TracePage : System.Web.UI.Page {
+ protected void Page_Load(object sender, EventArgs e) {
+ placeHolder1.Controls.Add(new Label { Text = Logging.LogMessages.ToString() });
+ }
+
+ protected void clearLogButton_Click(object sender, EventArgs e) {
+ Logging.LogMessages.Length = 0;
+
+ // clear the page immediately, and allow for F5 without a Postback warning.
+ Response.Redirect(Request.Url.AbsoluteUri);
+ }
+}
diff --git a/samples/Consumer/Web.config b/samples/Consumer/Web.config
new file mode 100644
index 0000000..763a4bd
--- /dev/null
+++ b/samples/Consumer/Web.config
@@ -0,0 +1,138 @@
+<?xml version="1.0"?>
+<!--
+ Note: As an alternative to hand editing this file you can use the
+ web admin tool to configure settings for your application. Use
+ the Website->Asp.Net Configuration option in Visual Studio.
+ A full list of settings and comments can be found in
+ machine.config.comments usually located in
+ \Windows\Microsoft.Net\Framework\v2.x\Config
+-->
+<configuration>
+ <configSections>
+ <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler" requirePermission="false" />
+ <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+ <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+ <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+ <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+ <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
+ <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+ <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+ <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+ </sectionGroup>
+ </sectionGroup>
+ </sectionGroup>
+ </configSections>
+ <appSettings/>
+ <connectionStrings/>
+ <system.web>
+ <!--
+ Set compilation debug="true" to insert debugging
+ symbols into the compiled page. Because this
+ affects performance, set this value to true only
+ during development.
+ -->
+ <compilation debug="true">
+ <assemblies>
+ <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
+ <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
+ <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
+ </assemblies>
+ </compilation>
+ <!--
+ The <authentication> section enables configuration
+ of the security authentication mode used by
+ ASP.NET to identify an incoming user.
+ -->
+ <authentication mode="Windows"/>
+ <!--
+ The <customErrors> section enables configuration
+ of what to do if/when an unhandled error occurs
+ during the execution of a request. Specifically,
+ it enables developers to configure html error pages
+ to be displayed in place of a error stack trace.
+
+ <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
+ <error statusCode="403" redirect="NoAccess.htm" />
+ <error statusCode="404" redirect="FileNotFound.htm" />
+ </customErrors>
+ -->
+ <pages>
+ <controls>
+ <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ </controls>
+ </pages>
+ <httpHandlers>
+ <remove verb="*" path="*.asmx"/>
+ <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
+ </httpHandlers>
+ <httpModules>
+ <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ </httpModules>
+ </system.web>
+ <system.codedom>
+ <compilers>
+ <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+ <providerOption name="CompilerVersion" value="v3.5"/>
+ <providerOption name="WarnAsError" value="false"/>
+ </compiler>
+ <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+ <providerOption name="CompilerVersion" value="v3.5"/>
+ <providerOption name="OptionInfer" value="true"/>
+ <providerOption name="WarnAsError" value="false"/>
+ </compiler>
+ </compilers>
+ </system.codedom>
+ <!--
+ The system.webServer section is required for running ASP.NET AJAX under Internet
+ Information Services 7.0. It is not necessary for previous version of IIS.
+ -->
+ <system.webServer>
+ <validation validateIntegratedModeConfiguration="false"/>
+ <modules>
+ <remove name="ScriptModule"/>
+ <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ </modules>
+ <handlers>
+ <remove name="WebServiceHandlerFactory-Integrated"/>
+ <remove name="ScriptHandlerFactory"/>
+ <remove name="ScriptHandlerFactoryAppServices"/>
+ <remove name="ScriptResource"/>
+ <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+ </handlers>
+ </system.webServer>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
+ <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
+ <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+ <log4net>
+ <appender name="TracePageAppender" type="TracePageAppender, __code">
+ <layout type="log4net.Layout.PatternLayout">
+ <conversionPattern value="%date (GMT%date{%z}) [%thread] %-5level %logger - %message%newline" />
+ </layout>
+ </appender>
+ <!-- Setup the root category, add the appenders and set the default level -->
+ <root>
+ <level value="INFO" />
+ <!--<appender-ref ref="RollingFileAppender" />-->
+ <appender-ref ref="TracePageAppender" />
+ </root>
+ <!-- Specify the level for some specific categories -->
+ <logger name="DotNetOAuth">
+ <level value="ALL" />
+ </logger>
+ </log4net>
+</configuration>
diff --git a/samples/ConsumerWpf/App.config b/samples/ConsumerWpf/App.config
new file mode 100644
index 0000000..d8bc983
--- /dev/null
+++ b/samples/ConsumerWpf/App.config
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler" requirePermission="false" />
+ </configSections>
+ <log4net>
+ <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
+ <file value="Testing.log" />
+ <appendToFile value="true" />
+ <rollingStyle value="Size" />
+ <maxSizeRollBackups value="10" />
+ <maximumFileSize value="1024KB" />
+ <staticLogFileName value="true" />
+ <layout type="log4net.Layout.PatternLayout">
+ <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
+ </layout>
+ </appender>
+ <!-- Setup the root category, add the appenders and set the default level -->
+ <root>
+ <level value="INFO" />
+ <appender-ref ref="RollingFileAppender" />
+ </root>
+ <!-- Specify the level for some specific categories -->
+ <logger name="DotNetOAuth">
+ <level value="ALL" />
+ </logger>
+ </log4net>
+</configuration> \ No newline at end of file
diff --git a/samples/ConsumerWpf/App.xaml b/samples/ConsumerWpf/App.xaml
new file mode 100644
index 0000000..030c7ea
--- /dev/null
+++ b/samples/ConsumerWpf/App.xaml
@@ -0,0 +1,8 @@
+<Application x:Class="ConsumerWpf.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ StartupUri="MainWindow.xaml">
+ <Application.Resources>
+
+ </Application.Resources>
+</Application>
diff --git a/samples/ConsumerWpf/App.xaml.cs b/samples/ConsumerWpf/App.xaml.cs
new file mode 100644
index 0000000..075d6f6
--- /dev/null
+++ b/samples/ConsumerWpf/App.xaml.cs
@@ -0,0 +1,14 @@
+namespace ConsumerWpf {
+ using System;
+ using System.Collections.Generic;
+ using System.Configuration;
+ using System.Data;
+ using System.Linq;
+ using System.Windows;
+
+ /// <summary>
+ /// Interaction logic for App.xaml
+ /// </summary>
+ public partial class App : Application {
+ }
+}
diff --git a/samples/ConsumerWpf/Constants.cs b/samples/ConsumerWpf/Constants.cs
new file mode 100644
index 0000000..ecb3fec
--- /dev/null
+++ b/samples/ConsumerWpf/Constants.cs
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------
+// <copyright file="Constants.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Samples.ConsumerWpf {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using DotNetOAuth;
+ using DotNetOAuth.ChannelElements;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// Service Provider definitions.
+ /// </summary>
+ public static class Constants {
+ /// <summary>
+ /// The Consumer to use for accessing Google data APIs.
+ /// </summary>
+ public static readonly ServiceProviderDescription GoogleDescription = new ServiceProviderDescription {
+ RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethod.AuthorizationHeaderRequest),
+ UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthAuthorizeToken", HttpDeliveryMethod.AuthorizationHeaderRequest),
+ AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetAccessToken", HttpDeliveryMethod.AuthorizationHeaderRequest),
+ TamperProtectionElements = new ITamperProtectionChannelBindingElement[] {
+ new HmacSha1SigningBindingElement(),
+ },
+ };
+
+ /// <summary>
+ /// Values of the "scope" parameter that indicates what data streams the Consumer
+ /// wants access to.
+ /// </summary>
+ public static class GoogleScopes {
+ /// <summary>
+ /// Access to the Gmail address book.
+ /// </summary>
+ public const string Contacts = "http://www.google.com/m8/feeds/";
+
+ /// <summary>
+ /// The URI to get contacts once authorization is granted.
+ /// </summary>
+ public static readonly MessageReceivingEndpoint GetContacts = new MessageReceivingEndpoint("http://www.google.com/m8/feeds/contacts/default/full/", HttpDeliveryMethod.GetRequest);
+ }
+ }
+} \ No newline at end of file
diff --git a/samples/ConsumerWpf/ConsumerWpf.csproj b/samples/ConsumerWpf/ConsumerWpf.csproj
new file mode 100644
index 0000000..389894f
--- /dev/null
+++ b/samples/ConsumerWpf/ConsumerWpf.csproj
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6EC36418-DBC5-4AD1-A402-413604AA7A08}</ProjectGuid>
+ <OutputType>WinExe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>DotNetOAuth.Samples.ConsumerWpf</RootNamespace>
+ <AssemblyName>ConsumerWpf</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </ApplicationDefinition>
+ <Page Include="MainWindow.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="MainWindow.xaml.cs">
+ <DependentUpon>MainWindow.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Constants.cs" />
+ <Compile Include="InMemoryTokenManager.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="App.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <AppDesigner Include="Properties\" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\src\DotNetOAuth\DotNetOAuth.csproj">
+ <Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project>
+ <Name>DotNetOAuth</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/samples/ConsumerWpf/InMemoryTokenManager.cs b/samples/ConsumerWpf/InMemoryTokenManager.cs
new file mode 100644
index 0000000..4f61ba4
--- /dev/null
+++ b/samples/ConsumerWpf/InMemoryTokenManager.cs
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------
+// <copyright file="InMemoryTokenManager.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Samples.ConsumerWpf {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using DotNetOAuth.ChannelElements;
+
+ internal class InMemoryTokenManager : ITokenManager {
+ private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
+
+ internal InMemoryTokenManager() {
+ }
+
+ internal string ConsumerKey { get; set; }
+
+ internal string ConsumerSecret { get; set; }
+
+ #region ITokenManager Members
+
+ public string GetConsumerSecret(string consumerKey) {
+ if (consumerKey == this.ConsumerKey) {
+ return this.ConsumerSecret;
+ } else {
+ throw new ArgumentException("Unrecognized consumer key.", "consumerKey");
+ }
+ }
+
+ public string GetTokenSecret(string token) {
+ return this.tokensAndSecrets[token];
+ }
+
+ public void StoreNewRequestToken(string consumerKey, string requestToken, string requestTokenSecret, IDictionary<string, string> parameters) {
+ this.tokensAndSecrets[requestToken] = requestTokenSecret;
+ }
+
+ /// <summary>
+ /// Checks whether a given request token has already been authorized
+ /// by some user for use by the Consumer that requested it.
+ /// </summary>
+ /// <param name="requestToken">The Consumer's request token.</param>
+ /// <returns>
+ /// True if the request token has already been fully authorized by the user
+ /// who owns the relevant protected resources. False if the token has not yet
+ /// been authorized, has expired or does not exist.
+ /// </returns>
+ public bool IsRequestTokenAuthorized(string requestToken) {
+ throw new NotImplementedException();
+ }
+
+ public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
+ this.tokensAndSecrets.Remove(requestToken);
+ this.tokensAndSecrets[accessToken] = accessTokenSecret;
+ }
+
+ /// <summary>
+ /// Classifies a token as a request token or an access token.
+ /// </summary>
+ /// <param name="token">The token to classify.</param>
+ /// <returns>Request or Access token, or invalid if the token is not recognized.</returns>
+ public TokenType GetTokenType(string token) {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/samples/ConsumerWpf/MainWindow.xaml b/samples/ConsumerWpf/MainWindow.xaml
new file mode 100644
index 0000000..1c8fa84
--- /dev/null
+++ b/samples/ConsumerWpf/MainWindow.xaml
@@ -0,0 +1,40 @@
+<Window x:Class="DotNetOAuth.Samples.ConsumerWpf.MainWindow"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ Title="DotNetOAuth Consumer (sample)" Height="248" Width="429">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition />
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="Auto" />
+ <RowDefinition />
+ </Grid.RowDefinitions>
+ <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="3">
+ <Button Name="beginAuthorizationButton" Click="beginAuthorizationButton_Click">Start authorize</Button>
+ <Button Name="completeAuthorizationButton" Margin="5,0,0,0" Click="completeAuthorizationButton_Click">Complete authorization</Button>
+ </StackPanel>
+ <Label>Consumer Key</Label>
+ <TextBox Grid.Column="1" Name="consumerKeyBox"/>
+ <Label Grid.Row="1">Consumer Secret</Label>
+ <TextBox Grid.Row="1" Grid.Column="1" Name="consumerSecretBox"/>
+ <Label Grid.Row="2" Grid.Column="1">
+ <TextBlock>
+ Don't have a Google Consumer Key?
+ <Hyperlink NavigateUri="https://www.google.com/accounts/ManageDomains">
+ <TextBlock>Get one!</TextBlock>
+ </Hyperlink>
+ </TextBlock>
+ </Label>
+ <Grid Grid.ColumnSpan="2" Grid.Row="4" Name="contactsGrid">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="Auto" />
+ </Grid.ColumnDefinitions>
+ </Grid>
+ </Grid>
+</Window>
diff --git a/samples/ConsumerWpf/MainWindow.xaml.cs b/samples/ConsumerWpf/MainWindow.xaml.cs
new file mode 100644
index 0000000..30b7cb5
--- /dev/null
+++ b/samples/ConsumerWpf/MainWindow.xaml.cs
@@ -0,0 +1,69 @@
+namespace DotNetOAuth.Samples.ConsumerWpf {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Windows;
+ using System.Windows.Controls;
+ using System.Windows.Data;
+ using System.Windows.Documents;
+ using System.Windows.Input;
+ using System.Windows.Media;
+ using System.Windows.Media.Imaging;
+ using System.Windows.Navigation;
+ using System.Windows.Shapes;
+ using System.Xml.Linq;
+ using DotNetOAuth;
+ using DotNetOAuth.ChannelElements;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// Interaction logic for MainWindow.xaml
+ /// </summary>
+ public partial class MainWindow : Window {
+ private InMemoryTokenManager tokenManager = new InMemoryTokenManager();
+ private Consumer google;
+ private string requestToken;
+
+ public MainWindow() {
+ InitializeComponent();
+
+ this.google = new Consumer(Constants.GoogleDescription, this.tokenManager);
+ }
+
+ private void beginAuthorizationButton_Click(object sender, RoutedEventArgs e) {
+ this.tokenManager.ConsumerKey = consumerKeyBox.Text;
+ this.tokenManager.ConsumerSecret = consumerSecretBox.Text;
+ this.google.ConsumerKey = consumerKeyBox.Text;
+ this.google.ConsumerSecret = consumerSecretBox.Text;
+
+ var extraParameters = new Dictionary<string, string> {
+ { "scope", Constants.GoogleScopes.Contacts },
+ };
+ Uri browserAuthorizationLocation = this.google.RequestUserAuthorization(extraParameters, null, out this.requestToken);
+ System.Diagnostics.Process.Start(browserAuthorizationLocation.AbsoluteUri);
+ }
+
+ private void completeAuthorizationButton_Click(object sender, RoutedEventArgs e) {
+ var grantedAccess = this.google.ProcessUserAuthorization(this.requestToken);
+ Response contactsResponse = this.google.SendAuthorizedRequest(Constants.GoogleScopes.GetContacts, grantedAccess.AccessToken);
+ XDocument contactsDocument = XDocument.Parse(contactsResponse.Body);
+ var contacts = from entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom"))
+ select new {
+ Name = entry.Element(XName.Get("title", "http://www.w3.org/2005/Atom")).Value,
+ Email = entry.Element(XName.Get("email", "http://schemas.google.com/g/2005")).Attribute("address").Value,
+ };
+ contactsGrid.Children.Clear();
+ foreach (var contact in contacts) {
+ contactsGrid.RowDefinitions.Add(new RowDefinition());
+ TextBlock name = new TextBlock { Text = contact.Name };
+ TextBlock email = new TextBlock { Text = contact.Email };
+ Grid.SetRow(name, contactsGrid.RowDefinitions.Count - 1);
+ Grid.SetRow(email, contactsGrid.RowDefinitions.Count - 1);
+ Grid.SetColumn(email, 1);
+ contactsGrid.Children.Add(name);
+ contactsGrid.Children.Add(email);
+ }
+ }
+ }
+}
diff --git a/samples/ConsumerWpf/Properties/AssemblyInfo.cs b/samples/ConsumerWpf/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d54cc97
--- /dev/null
+++ b/samples/ConsumerWpf/Properties/AssemblyInfo.cs
@@ -0,0 +1,46 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ConsumerWpf")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ConsumerWpf")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// In order to begin building localizable applications, set
+// <UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
+// inside a <PropertyGroup>. For example, if you are using US english
+// in your source files, set the <UICulture> to en-US. Then uncomment
+// the NeutralResourceLanguage attribute below. Update the "en-US" in
+// the line below to match the UICulture setting in the project file.
+
+////[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/samples/ConsumerWpf/Properties/Resources.Designer.cs b/samples/ConsumerWpf/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..3ca3b89
--- /dev/null
+++ b/samples/ConsumerWpf/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.3053
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace DotNetOAuth.Samples.ConsumerWpf.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DotNetOAuth.Samples.ConsumerWpf.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/samples/ConsumerWpf/Properties/Resources.resx b/samples/ConsumerWpf/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/samples/ConsumerWpf/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/samples/ConsumerWpf/Properties/Settings.Designer.cs b/samples/ConsumerWpf/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..c884743
--- /dev/null
+++ b/samples/ConsumerWpf/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.3053
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace DotNetOAuth.Samples.ConsumerWpf.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/samples/ConsumerWpf/Properties/Settings.settings b/samples/ConsumerWpf/Properties/Settings.settings
new file mode 100644
index 0000000..8f2fd95
--- /dev/null
+++ b/samples/ConsumerWpf/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ No newline at end of file
diff --git a/samples/Settings.StyleCop b/samples/Settings.StyleCop
new file mode 100644
index 0000000..882783c
--- /dev/null
+++ b/samples/Settings.StyleCop
@@ -0,0 +1,39 @@
+<StyleCopSettings Version="4.3">
+ <Analyzers>
+ <Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.DocumentationRules">
+ <Rules>
+ <Rule Name="FileMustHaveHeader">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementsMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ <Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.MaintainabilityRules">
+ <Rules>
+ <Rule Name="FieldsMustBePrivate">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ <Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.NamingRules">
+ <Rules>
+ <Rule Name="ElementMustBeginWithUpperCaseLetter">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ </Analyzers>
+</StyleCopSettings> \ No newline at end of file
diff --git a/src/DotNetOAuth.sln b/src/DotNetOAuth.sln
index 7b9ad5d..f3961cf 100644
--- a/src/DotNetOAuth.sln
+++ b/src/DotNetOAuth.sln
@@ -16,6 +16,32 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specs", "Specs", "{CD57219F
..\doc\specs\OAuth Core 1.0.htm = ..\doc\specs\OAuth Core 1.0.htm
EndProjectSection
EndProject
+Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Consumer", "..\samples\Consumer", "{F9076F04-17AF-4205-93A2-1D3BEBFCDAEB}"
+ ProjectSection(WebsiteProperties) = preProject
+ TargetFramework = "3.5"
+ ProjectReferences = "{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}|DotNetOAuth.dll;"
+ Debug.AspNetCompiler.VirtualPath = "/Consumer"
+ Debug.AspNetCompiler.PhysicalPath = "..\samples\Consumer\"
+ Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\Consumer\"
+ Debug.AspNetCompiler.Updateable = "true"
+ Debug.AspNetCompiler.ForceOverwrite = "true"
+ Debug.AspNetCompiler.FixedNames = "false"
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.VirtualPath = "/Consumer"
+ Release.AspNetCompiler.PhysicalPath = "..\samples\Consumer\"
+ Release.AspNetCompiler.TargetPath = "PrecompiledWeb\Consumer\"
+ Release.AspNetCompiler.Updateable = "true"
+ Release.AspNetCompiler.ForceOverwrite = "true"
+ Release.AspNetCompiler.FixedNames = "false"
+ Release.AspNetCompiler.Debug = "False"
+ VWDPort = "16323"
+ DefaultWebSiteLanguage = "Visual C#"
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{B4C6F647-C046-4B54-BE12-7701C4119EE7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerWpf", "..\samples\ConsumerWpf\ConsumerWpf.csproj", "{6EC36418-DBC5-4AD1-A402-413604AA7A08}"
+EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = DotNetOAuth.vsmdi
@@ -33,11 +59,21 @@ Global
{4376ECC9-C346-4A99-B13C-FA93C0FBD2C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4376ECC9-C346-4A99-B13C-FA93C0FBD2C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4376ECC9-C346-4A99-B13C-FA93C0FBD2C9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F9076F04-17AF-4205-93A2-1D3BEBFCDAEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F9076F04-17AF-4205-93A2-1D3BEBFCDAEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F9076F04-17AF-4205-93A2-1D3BEBFCDAEB}.Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {F9076F04-17AF-4205-93A2-1D3BEBFCDAEB}.Release|Any CPU.Build.0 = Debug|Any CPU
+ {6EC36418-DBC5-4AD1-A402-413604AA7A08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6EC36418-DBC5-4AD1-A402-413604AA7A08}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6EC36418-DBC5-4AD1-A402-413604AA7A08}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6EC36418-DBC5-4AD1-A402-413604AA7A08}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CD57219F-24F4-4136-8741-6063D0D7A031} = {20B5E173-C3C4-49F8-BD25-E69044075B4D}
+ {F9076F04-17AF-4205-93A2-1D3BEBFCDAEB} = {B4C6F647-C046-4B54-BE12-7701C4119EE7}
+ {6EC36418-DBC5-4AD1-A402-413604AA7A08} = {B4C6F647-C046-4B54-BE12-7701C4119EE7}
EndGlobalSection
EndGlobal