Has anyone had success using DotNetOpenAuth to access Yelp's v2 api using DotNetOpenAuth?
After digging through the examples and the source, this is what I came up with:
public class YelpConnector
{
private static readonly string YelpConsumerKey = ConfigurationManager.AppSettings["YelpConsumerKey"];
private static readonly string YelpConsumerSecret = ConfigurationManager.AppSettings["YelpConsumerSecret"];
private static readonly string YelpToken = ConfigurationManager.AppSettings["YelpToken"];
private static readonly string YelpTokenSecret = ConfigurationManager.AppSettings["YelpTokenSecret"];
private static readonly InMemoryTokenManager tokenManager = new InMemoryTokenManager(YelpConsumerKey, YelpConsumerSecret, YelpToken, YelpTokenSecret);
private static readonly Uri YelpURLBase = new Uri("http://api.yelp.com/v2/");
private static readonly ServiceProviderDescription YelpServiceDescription = new ServiceProviderDescription {
RequestTokenEndpoint = null,
UserAuthorizationEndpoint = null,
AccessTokenEndpoint = null,
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
};
private static dynamic SearchBase(string queryString)
{
if (string.IsNullOrEmpty(queryString))
throw new ArgumentNullException();
var searchEndpoint = new MessageReceivingEndpoint(new Uri(YelpURLBase, "search?" + queryString), HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
var consumer = new WebConsumer(YelpServiceDescription, tokenManager);
try
{
using (IncomingWebResponse response = consumer.PrepareAuthorizedRequestAndSend(searchEndpoint, YelpToken))
{
string rs = response.GetResponseReader().ReadToEnd();
dynamic js = SimpleJson.SimpleJson.DeserializeObject(rs);
return js;
}
}
catch (Exception e)
{
ErrorSignal.FromCurrentContext().Raise(e);
return null;
}
}
internal class InMemoryTokenManager : IConsumerTokenManager
{
private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
public InMemoryTokenManager(string consumerKey, string consumerSecret, string token, string secret)
{
if (String.IsNullOrEmpty(consumerKey))
{
throw new ArgumentNullException("consumerKey");
}
this.tokensAndSecrets[token] = secret;
this.ConsumerKey = consumerKey;
this.ConsumerSecret = consumerSecret;
}
public string ConsumerKey { get; private set; }
public string ConsumerSecret { get; private set; }
public string GetTokenSecret(string token)
{
return this.tokensAndSecrets[token];
}
public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response)
{
this.tokensAndSecrets[response.Token] = response.TokenSecret;
}
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret)
{
this.tokensAndSecrets.Remove(requestToken);
this.tokensAndSecrets[accessToken] = accessTokenSecret;
}
public TokenType GetTokenType(string token)
{
throw new NotImplementedException();
}
}
}
If I pass in the following QueryString limit=5&category_filter=movietheaters,bars,cafe,museums,danceclubs,parks&ll=37.78364455,-122.464104, I get an exception saying "Precondition failed.: value != null" and a stacktrace of:
at System.Diagnostics.Contracts.__ContractsRuntime.Requires[TException](Boolean condition, String message, String conditionText)
at DotNetOpenAuth.Messaging.MessagingUtilities.EscapeUriDataStringRfc3986(String value)
at DotNetOpenAuth.OAuth.ChannelElements.SigningBindingElementBase.ConstructSignatureBaseString(ITamperResistantOAuthMessage message, MessageDictionary messageDictionary)
at DotNetOpenAuth.OAuth.ChannelElements.HmacSha1SigningBindingElement.GetSignature(ITamperResistantOAuthMessage message)
at DotNetOpenAuth.OAuth.ChannelElements.SigningBindingElementBase.ProcessOutgoingMessage(IProtocolMessage message)
at DotNetOpenAuth.OAuth.ChannelElements.SigningBindingElementChain.ProcessOutgoingMessage(IProtocolMessage message)
at DotNetOpenAuth.Messaging.Channel.ProcessOutgoingMessage(IProtocolMessage message)
at DotNetOpenAuth.OAuth.ChannelElements.OAuthChannel.InitializeRequest(IDirectedProtocolMessage request)
at DotNetOpenAuth.OAuth.ConsumerBase.PrepareAuthorizedRequestAndSend(MessageReceivingEndpoint endpoint, String accessToken)
at MeetPpl.Helpers.SocialConnectors.YelpConnector.SearchBase(String queryString)
Any suggestions? Am I on the right trail?
I struggled with this issue for 1 whole day before giving up on dotnetopenauth. I found a very simple way to search yelp using the oauth library of http://www.twitterizer.net/ . Simply download the lite version of twitterizer and use my sample code below.
Download link is http://www.twitterizer.net/files/Twitterizer2lite-2.3.2.zip
public static string search()
{
string yelpSearchURL = "http://api.yelp.com/v2/search?term=food&location=San+Francisco";
string yelpConsumerKey = "your key";
string yelpConsumerSecret = "your secret";
string yelpRequestToken = "your token";
string yelpRequestTokenSecret = "your token secret";
Twitterizer.OAuthTokens ot = new Twitterizer.OAuthTokens();
ot.AccessToken = yelpRequestToken;
ot.AccessTokenSecret = yelpRequestTokenSecret;
ot.ConsumerKey = yelpConsumerKey;
ot.ConsumerSecret = yelpConsumerSecret;
string formattedUri = String.Format(CultureInfo.InvariantCulture,
yelpSearchURL, "");
Uri url = new Uri(formattedUri);
Twitterizer.WebRequestBuilder wb = new Twitterizer.WebRequestBuilder(url, Twitterizer.HTTPVerb.GET, ot);
System.Net.HttpWebResponse wr = wb.ExecuteRequest();
StreamReader sr = new StreamReader(wr.GetResponseStream());
return sr.ReadToEnd();
}
You can use RestSharp api: https://github.com/JustinBeckwith/YelpSharp in combination with OAuthBase: http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs.
In YelpSharp implementation change Yelp.cs class method makeRequest with this:
protected string makeRequest(string area, string id, Dictionary<string, string> parameters)
{
// build the url with parameters
var url = area;
if (!String.IsNullOrEmpty(id)) url += "/" + HttpUtility.UrlEncode(id);
if (parameters != null)
{
bool firstp = true;
string[] keys = parameters.Keys.ToArray();
foreach (string _key in keys)
{
if (firstp) url += "?";
else url += "&";
firstp = false;
//Double URL encode "&" to prevent restsharp from treating the second half of the string as a new parameter
parameters[_key] = parameters[_key].Replace("&", "%26");
parameters[_key] = parameters[_key].Replace("+", "%2B");
parameters[_key] = parameters[_key].Replace(" ", "%2B");
url += _key + "=" + parameters[_key]; //HttpUtility.UrlEncode(parameters[_key]);
}
}
var client = new RestClient(rootUri);
var request = new RestRequest(Method.GET);
OAuthBase oAuth = new OAuthBase();
string nonce = oAuth.GenerateNonce();
string timeStamp = oAuth.GenerateTimeStamp();
string normalizedUrl;
string normalizedRequestParameters;
string sig = oAuth.GenerateSignature(new Uri(string.Format("{0}/{1}", client.BaseUrl, url)),
options.ConsumerKey, options.ConsumerSecret,
options.AccessToken, options.AccessTokenSecret,
"GET", timeStamp, nonce, out normalizedUrl, out normalizedRequestParameters);
sig = HttpUtility.UrlEncode(sig);
request.Resource = string.Format(area);
if (parameters != null)
{
foreach (var p in parameters)
{
request.AddParameter(p.Key, p.Value);
}
}
request.AddParameter("oauth_consumer_key", options.ConsumerKey);
request.AddParameter("oauth_token", options.AccessToken);
request.AddParameter("oauth_nonce", nonce);
request.AddParameter("oauth_timestamp", timeStamp);
request.AddParameter("oauth_signature_method", "HMAC-SHA1");
request.AddParameter("oauth_version", "1.0");
request.AddParameter("oauth_signature", sig);
var response = client.Execute(request);
return response.Content;
}
Test like this:
public void testYelp()
{
string _term = "food";
string _location = "San Francisco";
var o = Credentials.GetOptions();
var y = new Yelp(o);
var searchOptions = new SearchOptions();
searchOptions.GeneralOptions = new GeneralOptions()
{
term = _term
};
searchOptions.LocationOptions = new LocationOptions()
{
location = _location
};
var results = y.Search(searchOptions);
}
Related
I have sucessfully generated classes from Swagger Definition (Openapi 3.0.3) using nSwag Studio, but I have no idea how to properly use this as a client.
Manually RestSharp code works fine, but I'd like to use autogenerated code to consume webservice methods and can't do it properly
This is working fine:
string clientId = "dev";
string clientSecret = #"pass";
var client = new RestClient("http://192.168.1.10/xyz/api/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("grant_type", "client_credentials");
var credentials = string.Format("{0}:{1}", clientId, clientSecret);
var headerValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
request.AddHeader("Authorization", $"Basic {headerValue}");
request.AddParameter($"application/x-www-form-urlencoded", $"grant_type=client_credentials&client_id={clientId}&client_secret{clientSecret}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request, Method.POST);
My try with autogenerated code. My apoligizes if its wrong, but can't find any example.
There's just few examples but looks like client is generated in a different way (client initialization with base url - but still no idea about basic authorization in this context)
Googling returns mostly "How to create server side" or add swagger to asp/mvc/webapi project.
string URL = #"http://192.168.1.10/xyz/api";
string clientId = "dev";
string clientSecret = #"pass";
IO.Swagger.Client.ApiClient client = new IO.Swagger.Client.ApiClient(URL);
IO.Swagger.Client.Configuration.DefaultApiClient = client; //<<this throws error
IO.Swagger.Client.Configuration.Username = clientId;
IO.Swagger.Client.Configuration.Password = clientSecret;
client.AddDefaultHeader("Authorization", "bearer TOKEN");
IO.Swagger.Api.AuthApi authApi = new IO.Swagger.Api.AuthApi(client);
Error in ApiClient class
public ApiClient(String basePath="/xyz/api")
{
BasePath = basePath;
RestClient = new RestClient(BasePath); //System.UriFormatException: 'Invalid URI: The format of the URI could not be determined.'
}
I have tried many string forms of url (class doesn't accept Uri explictly)
Configuration
using System;
using System.Reflection;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace IO.Swagger.Client
{
public class Configuration
{
public const string Version = "1.0.0";
public static ApiClient DefaultApiClient = new ApiClient();
public static String Username { get; set; }
public static String Password { get; set; }
public static Dictionary<String, String> ApiKey = new Dictionary<String, String>();
public static Dictionary<String, String> ApiKeyPrefix = new Dictionary<String, String>();
private static string _tempFolderPath = Path.GetTempPath();
public static String TempFolderPath
{
get { return _tempFolderPath; }
set
{
if (String.IsNullOrEmpty(value))
{
_tempFolderPath = value;
return;
}
// create the directory if it does not exist
if (!Directory.Exists(value))
Directory.CreateDirectory(value);
// check if the path contains directory separator at the end
if (value[value.Length - 1] == Path.DirectorySeparatorChar)
_tempFolderPath = value;
else
_tempFolderPath = value + Path.DirectorySeparatorChar;
}
}
private const string ISO8601_DATETIME_FORMAT = "o";
private static string _dateTimeFormat = ISO8601_DATETIME_FORMAT;
public static String DateTimeFormat
{
get
{
return _dateTimeFormat;
}
set
{
if (string.IsNullOrEmpty(value))
{
// Never allow a blank or null string, go back to the default
_dateTimeFormat = ISO8601_DATETIME_FORMAT;
return;
}
// Caution, no validation when you choose date time format other than ISO 8601
// Take a look at the above links
_dateTimeFormat = value;
}
}
public static String ToDebugReport()
{
String report = "C# SDK (IO.Swagger) Debug Report:\n";
report += " OS: " + Environment.OSVersion + "\n";
report += " .NET Framework Version: " + Assembly
.GetExecutingAssembly()
.GetReferencedAssemblies()
.Where(x => x.Name == "System.Core").First().Version.ToString() + "\n";
report += " Version of the API: 2.0.1\n";
report += " SDK Package Version: 1.0.0\n";
return report;
}
}
}
Client
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.IO;
using System.Web;
using System.Linq;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using RestSharp;
using RestSharp.Extensions;
namespace IO.Swagger.Client
{
public class ApiClient
{
private readonly Dictionary<String, String> _defaultHeaderMap = new Dictionary<String, String>();
public ApiClient(String basePath="/xyz/api")
{
BasePath = basePath;
RestClient = new RestClient(BasePath);
}
public string BasePath { get; set; }
public RestClient RestClient { get; set; }
public Dictionary<String, String> DefaultHeader
{
get { return _defaultHeaderMap; }
}
public Object CallApi(String path, RestSharp.Method method, Dictionary<String, String> queryParams, String postBody,
Dictionary<String, String> headerParams, Dictionary<String, String> formParams,
Dictionary<String, FileParameter> fileParams, String[] authSettings)
{
var request = new RestRequest(path, method);
UpdateParamsForAuth(queryParams, headerParams, authSettings);
// add default header, if any
foreach(var defaultHeader in _defaultHeaderMap)
request.AddHeader(defaultHeader.Key, defaultHeader.Value);
// add header parameter, if any
foreach(var param in headerParams)
request.AddHeader(param.Key, param.Value);
// add query parameter, if any
foreach(var param in queryParams)
request.AddParameter(param.Key, param.Value, ParameterType.GetOrPost);
// add form parameter, if any
foreach(var param in formParams)
request.AddParameter(param.Key, param.Value, ParameterType.GetOrPost);
// add file parameter, if any
foreach(var param in fileParams)
request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentType);
if (postBody != null) // http body (model) parameter
request.AddParameter("application/json", postBody, ParameterType.RequestBody);
return (Object)RestClient.Execute(request);
}
public void AddDefaultHeader(string key, string value)
{
_defaultHeaderMap.Add(key, value);
}
public string EscapeString(string str)
{
return RestSharp.Contrib.HttpUtility.UrlEncode(str);
}
public FileParameter ParameterToFile(string name, Stream stream)
{
if (stream is FileStream)
return FileParameter.Create(name, stream.ReadAsBytes(), Path.GetFileName(((FileStream)stream).Name));
else
return FileParameter.Create(name, stream.ReadAsBytes(), "no_file_name_provided");
}
public string ParameterToString(object obj)
{
if (obj is DateTime)
// Return a formatted date string - Can be customized with Configuration.DateTimeFormat
// Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o")
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
// For example: 2009-06-15T13:45:30.0000000
return ((DateTime)obj).ToString (Configuration.DateTimeFormat);
else if (obj is List<string>)
return String.Join(",", (obj as List<string>).ToArray());
else
return Convert.ToString (obj);
}
public object Deserialize(string content, Type type, IList<Parameter> headers=null)
{
if (type == typeof(Object)) // return an object
{
return content;
}
if (type == typeof(Stream))
{
var filePath = String.IsNullOrEmpty(Configuration.TempFolderPath)
? Path.GetTempPath()
: Configuration.TempFolderPath;
var fileName = filePath + Guid.NewGuid();
if (headers != null)
{
var regex = new Regex(#"Content-Disposition:.*filename=['""]?([^'""\s]+)['""]?$");
var match = regex.Match(headers.ToString());
if (match.Success)
fileName = filePath + match.Value.Replace("\"", "").Replace("'", "");
}
File.WriteAllText(fileName, content);
return new FileStream(fileName, FileMode.Open);
}
if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
{
return DateTime.Parse(content, null, System.Globalization.DateTimeStyles.RoundtripKind);
}
if (type == typeof(String) || type.Name.StartsWith("System.Nullable")) // return primitive type
{
return ConvertType(content, type);
}
// at this point, it must be a model (json)
try
{
return JsonConvert.DeserializeObject(content, type);
}
catch (IOException e)
{
throw new ApiException(500, e.Message);
}
}
public string Serialize(object obj)
{
try
{
return obj != null ? JsonConvert.SerializeObject(obj) : null;
}
catch (Exception e)
{
throw new ApiException(500, e.Message);
}
}
public string GetApiKeyWithPrefix (string apiKeyIdentifier)
{
var apiKeyValue = "";
Configuration.ApiKey.TryGetValue (apiKeyIdentifier, out apiKeyValue);
var apiKeyPrefix = "";
if (Configuration.ApiKeyPrefix.TryGetValue (apiKeyIdentifier, out apiKeyPrefix))
return apiKeyPrefix + " " + apiKeyValue;
else
return apiKeyValue;
}
public void UpdateParamsForAuth(Dictionary<String, String> queryParams, Dictionary<String, String> headerParams, string[] authSettings)
{
if (authSettings == null || authSettings.Length == 0)
return;
foreach (string auth in authSettings)
{
// determine which one to use
switch(auth)
{
case "BasicAuth":
headerParams["Authorization"] = "Basic " + Base64Encode(Configuration.Username + ":" + Configuration.Password);
break;
case "BearerAuth":
break;
default:
//TODO show warning about security definition not found
break;
}
}
}
public static string Base64Encode(string text)
{
var textByte = System.Text.Encoding.UTF8.GetBytes(text);
return System.Convert.ToBase64String(textByte);
}
public static Object ConvertType(Object fromObject, Type toObject) {
return Convert.ChangeType(fromObject, toObject);
}
}
}
AuthApi
using System;
using System.Collections.Generic;
using RestSharp;
using IO.Swagger.Client;
using IO.Swagger.Model;
namespace IO.Swagger.Api
{
public interface IAuthApi
{
InlineResponse200 OauthTokenPost (string grantType);
}
public class AuthApi : IAuthApi
{
public AuthApi(ApiClient apiClient = null)
{
if (apiClient == null) // use the default one in Configuration
this.ApiClient = Configuration.DefaultApiClient;
else
this.ApiClient = apiClient;
}
public AuthApi(String basePath)
{
this.ApiClient = new ApiClient(basePath);
}
public void SetBasePath(String basePath)
{
this.ApiClient.BasePath = basePath;
}
public String GetBasePath(String basePath)
{
return this.ApiClient.BasePath;
}
public ApiClient ApiClient {get; set;}
public InlineResponse200 OauthTokenPost (string grantType)
{
var path = "/oauth/token";
path = path.Replace("{format}", "json");
var queryParams = new Dictionary<String, String>();
var headerParams = new Dictionary<String, String>();
var formParams = new Dictionary<String, String>();
var fileParams = new Dictionary<String, FileParameter>();
String postBody = null;
if (grantType != null) formParams.Add("grant_type", ApiClient.ParameterToString(grantType)); // form parameter
// authentication setting, if any
String[] authSettings = new String[] { "BasicAuth" };
// make the HTTP request
IRestResponse response = (IRestResponse) ApiClient.CallApi(path, Method.POST, queryParams, postBody, headerParams, formParams, fileParams, authSettings);
if (((int)response.StatusCode) >= 400)
throw new ApiException ((int)response.StatusCode, "Error calling OauthTokenPost: " + response.Content, response.Content);
else if (((int)response.StatusCode) == 0)
throw new ApiException ((int)response.StatusCode, "Error calling OauthTokenPost: " + response.ErrorMessage, response.ErrorMessage);
return (InlineResponse200) ApiClient.Deserialize(response.Content, typeof(InlineResponse200), response.Headers);
}
}
}
I am under impression that your main problem is Uri formating. I would suggest finding the exact problem by doing
string URL = #"http://192.168.1.10/xyz/api";
Uri baseAddress = new Uri(URL);
string clientId = "dev";
string clientSecret = #"pass";
IO.Swagger.Client.ApiClient client = new IO.Swagger.Client.ApiClient(baseAddress.ToString());
IO.Swagger.Client.Configuration.DefaultApiClient = client; //<<this throws error
IO.Swagger.Client.Configuration.Username = clientId;
IO.Swagger.Client.Configuration.Password = clientSecret;
client.AddDefaultHeader("Authorization", "bearer TOKEN");
IO.Swagger.Api.AuthApi authApi = new IO.Swagger.Api.AuthApi(client);
I am trying to make code separate. Below class is tokenization/detokenization class to make data as token. but when i am calling this class i have pass all the parameters, This class calling as everywhere in solution. so i want to make as static. for example
Tokenization.Detokenize(reader["UserPhoneNumber"].ToString(), _appSettings.TokenGroup, _appSettings.TokenTemplatePhone, _appSettings.DetokenizeServiceURL, _appSettings.BearerTokenGeneratorURL, _appSettings.App_IDPayLoad, _appSettings.App_KeyPayLoad);
so i just want to pass as
Tokenization.Detokenize(reader["UserPhoneNumber"].ToString(), _appSettings.TokenGroup, _appSettings.TokenTemplatePhone)
basically i want to make separate the static block and tokenizae/detokenizae method. so it will look good. how i can do this?
public class Tokenization
{
private static AuthToken AuthToken = null;
private static void GetToken(string strBearTokenURL, string strAppid, string strAppkey)
{
RestClient tokenClinet = new RestClient(strBearTokenURL);
tokenClinet.AddDefaultHeader("App_ID", strAppid);
tokenClinet.AddDefaultHeader("App_Key", strAppkey);
tokenClinet.AddDefaultHeader("apiVersion", "2");
AuthToken = tokenClinet.Post<AuthToken>(new RestRequest()).Data;
}
private static bool IsTokenExpired(string strBearTokenURL, string strAppid, string strAppkey)
{
if (AuthToken == null) GetToken( strBearTokenURL, strAppid, strAppkey);
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds(AuthToken.expires_on).ToLocalTime();
return dtDateTime <= DateTime.Now;
}
public static RestClient RestClientWithAuth(string strBearTokenURL, string strAppid, string strAppkey)
{
try
{
RestClient clinet = new RestClient();
if (IsTokenExpired(strBearTokenURL, strAppid, strAppkey)) GetToken(strBearTokenURL, strAppid, strAppkey);
clinet.AddDefaultHeader("Authorization", "Bearer " + AuthToken.access_token);
return clinet;
}
catch (Exception ex)
{
throw ex;
}
}
public static string Tokenize(string tokenData, string tokenGroup, string tokenTemplate, string tokenizeServiceURL, string bearerTokenURL, string app_ID, string app_Key)
{
try
{
var request = new RestRequest(tokenizeServiceURL, Method.POST);
request.RequestFormat = DataFormat.Json;
List<TokenProfile> payLoad = new List<TokenProfile>();
payLoad.Add(new TokenProfile() { tokengroup = tokenGroup, data= tokenData, tokentemplate = tokenTemplate });
request.AddJsonBody(payLoad);
// execute the request
IRestResponse<List<TokenResponse>> response = RestClientWithAuth(bearerTokenURL, app_ID, app_Key).Execute<List<TokenResponse>>(request);
var responsestatus = response.ResponseStatus;
return response.Data.Select(t => t.token).FirstOrDefault();
}
catch(Exception ex)
{
throw ex;
}
}
public static string Detokenize(string deTokenData, string tokenGroup, string tokenTemplate, string detokenizeServiceURL, string bearerTokenURL, string app_ID, string app_KeyPay)
{
try
{
var request = new RestRequest(detokenizeServiceURL, Method.POST);
request.RequestFormat = DataFormat.Json;
List<DeTokenProfile> payLoad = new List<DeTokenProfile>();
payLoad.Add(new DeTokenProfile() { tokengroup = tokenGroup, token = deTokenData, tokentemplate = tokenTemplate });
request.AddJsonBody(payLoad);
IRestResponse<List<DeTokenResponse>> response = RestClientWithAuth(bearerTokenURL, app_ID, app_KeyPay).Execute<List<DeTokenResponse>>(request);
var responsestatus = response.ResponseStatus;
return response.Data.Select(t => t.data).FirstOrDefault();
}
catch(Exception ex)
{
throw ex;
}
}
}
Seems you would like to have some practical example of how Singleton design pattern can be implemented in practice. In your case if you want to implement, you may have to refactor your code base. Though its little costly at present but it will be good in a long run.
Note: Remember The main philosophy of Singleton design pattern is the instance of object will be created once in a lifetime. If you would like to know
more about this I suggest you to refer this doc and this
document
//Interface declaration
public interface ITokennization
{
object TokenizationClassMethod();
}
//Interface Inheritance/Implementation in class
public class TokenizationClass : ITokennization
{
private static TokenizationClass _singletonInstance;
private static readonly object padlock = new object();
//Default constructor
public TokenizationClass()
{
}
// SingleTon Design Pattern
public static TokenizationClass CheckSingleInstance()
{
if (_singletonInstance == null)
{
lock (padlock)
{
//Checks instance each time
if (_singletonInstance == null)
//creates new instance if no instances already created
_singletonInstance = new TokenizationClass();
}
}
return _singletonInstance;
}
// Class Method
public object TokenizationClassMethod()
{
throw new NotImplementedException();
}
}
Hope this would help
You should try this
(Important: I don't try this code)
public class Tokenization
{
private static Tokenization Instance = new Tokenization();
private AuthToken AuthToken = null;
private Tokenization(){}
private void GetToken(string strBearTokenURL, string strAppid, string strAppkey)
{
RestClient tokenClinet = new RestClient(strBearTokenURL);
tokenClinet.AddDefaultHeader("App_ID", strAppid);
tokenClinet.AddDefaultHeader("App_Key", strAppkey);
tokenClinet.AddDefaultHeader("apiVersion", "2");
AuthToken = tokenClinet.Post<AuthToken>(new RestRequest()).Data;
}
private bool IsTokenExpired(string strBearTokenURL, string strAppid, string strAppkey)
{
if (AuthToken == null) GetToken( strBearTokenURL, strAppid, strAppkey);
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds(AuthToken.expires_on).ToLocalTime();
return dtDateTime <= DateTime.Now;
}
public RestClient RestClientWithAuth(string strBearTokenURL, string strAppid, string strAppkey)
{
try
{
RestClient clinet = new RestClient();
if (IsTokenExpired(strBearTokenURL, strAppid, strAppkey)) GetToken(strBearTokenURL, strAppid, strAppkey);
clinet.AddDefaultHeader("Authorization", "Bearer " + AuthToken.access_token);
return clinet;
}
catch (Exception ex)
{
throw ex;
}
}
public string Tokenize(string tokenData, string tokenGroup, string tokenTemplate, string tokenizeServiceURL, string bearerTokenURL, string app_ID, string app_Key)
{
try
{
var request = new RestRequest(tokenizeServiceURL, Method.POST);
request.RequestFormat = DataFormat.Json;
List<TokenProfile> payLoad = new List<TokenProfile>();
payLoad.Add(new TokenProfile() { tokengroup = tokenGroup, data= tokenData, tokentemplate = tokenTemplate });
request.AddJsonBody(payLoad);
// execute the request
IRestResponse<List<TokenResponse>> response = RestClientWithAuth(bearerTokenURL, app_ID, app_Key).Execute<List<TokenResponse>>(request);
var responsestatus = response.ResponseStatus;
return response.Data.Select(t => t.token).FirstOrDefault();
}
catch(Exception ex)
{
throw ex;
}
}
public string Detokenize(string deTokenData, string tokenGroup, string tokenTemplate, string detokenizeServiceURL, string bearerTokenURL, string app_ID, string app_KeyPay)
{
try
{
var request = new RestRequest(detokenizeServiceURL, Method.POST);
request.RequestFormat = DataFormat.Json;
List<DeTokenProfile> payLoad = new List<DeTokenProfile>();
payLoad.Add(new DeTokenProfile() { tokengroup = tokenGroup, token = deTokenData, tokentemplate = tokenTemplate });
request.AddJsonBody(payLoad);
IRestResponse<List<DeTokenResponse>> response = RestClientWithAuth(bearerTokenURL, app_ID, app_KeyPay).Execute<List<DeTokenResponse>>(request);
var responsestatus = response.ResponseStatus;
return response.Data.Select(t => t.data).FirstOrDefault();
}
catch(Exception ex)
{
throw ex;
}
}
}
Use method:
Tokenization.Instance.Detokenize() same like
I am uploading files to a Gdrive follow this instructions. In the File objtect I just set the name, like this:
{
"name": "myObjectName"
}
The files are uploading without problem. Now I need to generate a shared link for each upload file, Do you know who is the request that I have to do?
Thanks,
With #Jacques-Guzel HeronĀ“s help, I completed the upload file process. I created a wrapper for Google Drive API v3. That is my code if any need to do something like that: (I am using C#):
public interface IGDriveApiV3Wrapper
{
string UploadFile(string filePath, string gDriveUploadDestinationFolderId = null);
bool SetFilePermissions(string fileId, GDriveFileRole gDriveRole, GDriveFileType gDriveType);
GDriveFile GetFileInfo(string fileId);
}
public class GDriveApiV3NativeWrapper : IGDriveApiV3Wrapper
{
private const string GDriveFilesApiResumablePath = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
private const string GDriveTokenApiPath = "https://oauth2.googleapis.com/token";
private static readonly HttpClient GDriveClient = new HttpClient { Timeout = Timeout.InfiniteTimeSpan };
private readonly List<KeyValuePair<string, string>> _getTokenRequestContent;
private static GDriveTokenInfo _gDriveTokenInfo;
private static readonly object UpdateGDriveTokenInfoLocker = new object();
public GDriveApiV3NativeWrapper(string gDriveApiClientId, string gDriveApiClientSecret, string gDriveApiRefreshToken)
{
_getTokenRequestContent = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", gDriveApiClientId),
new KeyValuePair<string, string>("client_secret", gDriveApiClientSecret),
new KeyValuePair<string, string>("refresh_token", gDriveApiRefreshToken),
new KeyValuePair<string, string>("grant_type", "refresh_token")
};
}
public string UploadFile(string filePath, string gDriveUploadDestinationFolderId = null)
{
if (string.IsNullOrEmpty(filePath))
throw new ArgumentException("Value cannot be null or empty.", nameof(filePath));
FileInfo fileInfo;
try
{
fileInfo = new FileInfo(filePath);
}
catch (Exception ex)
{
throw new ArgumentException("File not valid.", nameof(filePath), ex);
}
if (!fileInfo.Exists)
throw new ArgumentException("File not exists.", nameof(filePath));
using (var initiateResumableUploadSessionRequest = new HttpRequestMessage(HttpMethod.Post, GDriveFilesApiResumablePath))
{
UpdateGDriveTokenInfo();
initiateResumableUploadSessionRequest.Headers.Authorization = new AuthenticationHeaderValue(_gDriveTokenInfo.TokenType, _gDriveTokenInfo.AccessToken);
var jsonContent = new JObject(
new JProperty("name", fileInfo.Name));
if (!string.IsNullOrEmpty(gDriveUploadDestinationFolderId))
{
jsonContent.Add(new JProperty("parents", new JArray { gDriveUploadDestinationFolderId }));
}
initiateResumableUploadSessionRequest.Content = new StringContent(jsonContent.ToString(), Encoding.UTF8, "application/json");
var initiateResumableUploadSessionResponse = GDriveClient.SendAsync(initiateResumableUploadSessionRequest).Result;
if (initiateResumableUploadSessionResponse.StatusCode != HttpStatusCode.OK)
throw new ExternalException(initiateResumableUploadSessionResponse.ToString());
using (var uploadFileRequest = new HttpRequestMessage(HttpMethod.Put, initiateResumableUploadSessionResponse.Headers.Location))
{
uploadFileRequest.Content = new ByteArrayContent(File.ReadAllBytes(filePath));
HttpResponseMessage uploadFileResponse;
uploadFileResponse = GDriveClient.SendAsync(uploadFileRequest).Result;
if (uploadFileResponse.StatusCode != HttpStatusCode.OK && uploadFileResponse.StatusCode != HttpStatusCode.Created)
throw new ExternalException(uploadFileResponse.ReasonPhrase);
var uploadFileResponseBody = uploadFileResponse.Content.ReadAsStringAsync().Result;
JObject uploadFileResponseJson = JObject.Parse(uploadFileResponseBody);
return uploadFileResponseJson["id"].ToString();
}
}
}
public bool SetFilePermissions(string fileId, GDriveFileRole gDriveFileRole, GDriveFileType gDriveFileType)
{
if (string.IsNullOrEmpty(fileId))
throw new ArgumentException("Value cannot be null or empty.", nameof(fileId));
using (var setFilePermissionsRequest = new HttpRequestMessage(HttpMethod.Post, $"https://www.googleapis.com/drive/v3/files/{fileId}/permissions"))
{
UpdateGDriveTokenInfo();
setFilePermissionsRequest.Headers.Authorization = new AuthenticationHeaderValue(_gDriveTokenInfo.TokenType, _gDriveTokenInfo.AccessToken);
var jsonContent2 = new JObject(
new JProperty("role", gDriveFileRole.ToString().ToLower()),
new JProperty("type", gDriveFileType.ToString().ToLower()));
setFilePermissionsRequest.Content = new StringContent(jsonContent2.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage setFilePermissionsResponse = GDriveClient.SendAsync(setFilePermissionsRequest).Result;
if (setFilePermissionsResponse.StatusCode != HttpStatusCode.OK)
throw new ExternalException(setFilePermissionsResponse.ToString());
}
return true;
}
public GDriveFile GetFileInfo(string fileId)
{
using (var getFileInfoRequest = new HttpRequestMessage(HttpMethod.Get, $"https://www.googleapis.com/drive/v3/files/{fileId}?fields=name,webViewLink"))
{
UpdateGDriveTokenInfo();
getFileInfoRequest.Headers.Authorization = new AuthenticationHeaderValue(_gDriveTokenInfo.TokenType, _gDriveTokenInfo.AccessToken);
HttpResponseMessage getFileInfoResponse = GDriveClient.SendAsync(getFileInfoRequest).Result;
if (getFileInfoResponse.StatusCode != HttpStatusCode.OK)
throw new ExternalException(getFileInfoResponse.ToString());
var getFileInfoResponseBody = getFileInfoResponse.Content.ReadAsStringAsync().Result;
JObject getFileInfoResponseJson = JObject.Parse(getFileInfoResponseBody);
return new GDriveFile
{
Id = fileId,
Name = getFileInfoResponseJson["name"].ToString(),
WebViewLink = getFileInfoResponseJson["webViewLink"].ToString()
};
}
}
private void UpdateGDriveTokenInfo()
{
lock (UpdateGDriveTokenInfoLocker)
{
if (_gDriveTokenInfo != null && !_gDriveTokenInfo.IsExpired())
{
return;
}
using (var refreshTokenRequest = new HttpRequestMessage(HttpMethod.Post, GDriveTokenApiPath))
{
refreshTokenRequest.Content = new FormUrlEncodedContent(_getTokenRequestContent);
var getTokenRequestResponse = GDriveClient.SendAsync(refreshTokenRequest).Result;
var jsonResponse = JObject.Parse(getTokenRequestResponse.Content.ReadAsStringAsync().Result);
_gDriveTokenInfo = new GDriveTokenInfo((string)jsonResponse["access_token"], (int)jsonResponse["expires_in"], (string)jsonResponse["token_type"]);
}
}
}
public class GDriveFile
{
public string Id { get; set; }
public string Name { get; set; }
public string WebViewLink { get; set; }
}
public enum GDriveFileRole
{
Owner,
Organizer,
FileOrganizer,
Writer,
Commenter,
Reader
}
public enum GDriveFileType
{
User,
Group,
Domain,
Anyone
}
public class Program
{
private static IGDriveApiV3Wrapper _gDriveApiV3Wrapper;
private readonly string _gDriveUploadDestinationFolderId;
public Program(IGDriveApiV3Wrapper gDriveApiV3Wrapper, string gDriveUploadDestinationFolderId = null)
{
_gDriveApiV3Wrapper = gDriveApiV3Wrapper;
_gDriveUploadDestinationFolderId = gDriveUploadDestinationFolderId;
}
public string Upload(string filePath)
{
string fileId = _gDriveApiV3Wrapper.UploadFile(filePath, _gDriveUploadDestinationFolderId);
_gDriveApiV3Wrapper.SetFilePermissions(fileId, GDriveFileRole.Reader, GDriveFileType.Anyone);
GDriveFile gDriveFile = _gDriveApiV3Wrapper.GetFileInfo(fileId);
return gDriveFile.WebViewLink;
}
}
I'll assume that you are using Drive API v3. To set up permissions after uploading the file you have to use the method create. You can check the sharing documentation to know more about the different ways of creation of permissions and its different levels of access. After sharing the file, you can retrieve the link with the property webViewLink of the file. If you still have any doubts, please ask me for further clarification.
The Class GDrivenTokenInfo i don`t see its code
So I'm stuck at this point. I am trying to communicate with JanRain's "auth_info" service. In fact, to start, I'm just trying to get the "error" message/object/'.jsthingy' that you get when you surf to it directly in the browser:
https://rpxnow.com/api/v2/auth_info
but I want to get that back with a WCF call.
According to Fiddler, the content type of the information at that url is text/javascript. However, from what I can tell, WCF doesn't give me that option when calling it through WCF. I get two options: WebMessageFormat.Json, or WebMessageFormat.Xml.
I get the following error in Visual Studio:
InvalidOperationException was unhandled by User Code -
The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml', 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details.
WTF? So can WCF even do this? (I suspect a more manual solution ahead)
JanRain's online code examples are a little bit lacking in the C# examples.
Their documentation link on auth_info is here https://rpxnow.com/docs#auth_info
The address of their auth_info service is here:
https://rpxnow.com/api/v2/auth_info
[TestMethod]
public void CallJanRain()
{
var x = new JanRainProxy("https://rpxnow.com/api/v2");
x.GetAuthInfo("", ""); //the params are apiKey, and token. not passing either at the moment as I want to be able to know how to at least handle the error first. After all, the *browser* at least got it..
}
[ServiceContract]
public interface IJanRainContract
{
[OperationContract(Name="auth_info")]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Xml)]
JanRainAuthInfo GetAuthInfo(string apiKey, string token);
}
[DataContract]
public class JanRainAuthInfo
{
[DataMember(Name="identifier")]
public string Identifier { get; set; }
}
public class JanRainProxy: ClientBase<IJanRainContract>
{
public JanRainProxy(string url, WebHttpSecurityMode securityMode = WebHttpSecurityMode.Transport)
: base(ConstructEndpoint(url, securityMode))
{
}
//JanRainContract
public JanRainAuthInfo GetAuthInfo(string apiKey, string token)
{
return base.Channel.GetAuthInfo(apiKey, token);
}
// This method constructs a WebHttpBinding endpoint with all the appropriate
// settings for talking to our services.
private static ServiceEndpoint ConstructEndpoint(string serviceUri, WebHttpSecurityMode securityMode)
{
var contract = ContractDescription.GetContract(typeof(IJanRainContract));
var binding = new WebHttpBinding(securityMode);
//{
// MaxBufferPoolSize = 524288000,
// MaxReceivedMessageSize = 65536000
//};
var address = new EndpointAddress(serviceUri);
var endpoint = new ServiceEndpoint(
contract,
binding,
address);
var webHttpBehavior = new WebHttpBehavior()
{
DefaultBodyStyle = WebMessageBodyStyle.Wrapped,
DefaultOutgoingRequestFormat = WebMessageFormat.Json,
DefaultOutgoingResponseFormat = WebMessageFormat.Json,
AutomaticFormatSelectionEnabled = true,
FaultExceptionEnabled = true
};
endpoint.Behaviors.Add(webHttpBehavior);
return endpoint;
}
}
I'm figuring that perhaps I should leave the contenttype at json and tweak the behavior, or binding.
ok.. it looks like I needed to add a custom contentTypeMapper on my binding
after declaring my binding I added the following:
WebContentTypeMapper customMapper = new JsonContentTypeMapper();
binding.ContentTypeMapper = customMapper;
here's the custom Mapper:
public class JsonContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat
GetMessageFormatForContentType(string contentType)
{
if (contentType == "text/javascript")
{
return WebContentFormat.Raw;
}
else
{
return WebContentFormat.Json;
}
}
}
Kevin,
Here is a C# example on how to process the auth_info response that you might find helpful:
//C# Helper Class for Janrain Engage
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;
using System.Xml.XPath;
public class Rpx
{
private string apiKey;
private string baseUrl;
public Rpx(string apiKey, string baseUrl) {
while (baseUrl.EndsWith("/"))
baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
public string getApiKey() { return apiKey; }
public string getBaseUrl() { return baseUrl; }
public XmlElement AuthInfo(string token) {
Dictionary<string,string> query = new Dictionary<string,string>();
query.Add("token", token);
return ApiCall("auth_info", query);
}
public List<string> Mappings(string primaryKey) {
Dictionary<string,string> query = new Dictionary<string,string>();
query.Add("primaryKey", primaryKey);
XmlElement rsp = ApiCall("mappings", query);
XmlElement oids = (XmlElement)rsp.FirstChild;
List<string> result = new List<string>();
for (int i = 0; i < oids.ChildNodes.Count; i++) {
result.Add(oids.ChildNodes[i].InnerText);
}
return result;
}
public Dictionary<string,ArrayList> AllMappings() {
Dictionary<string,string> query = new Dictionary<string,string>();
XmlElement rsp = ApiCall("all_mappings", query);
Dictionary<string,ArrayList> result = new Dictionary<string,ArrayList>();
XPathNavigator nav = rsp.CreateNavigator();
XPathNodeIterator mappings = (XPathNodeIterator) nav.Evaluate("/rsp/mappings/mapping");
foreach (XPathNavigator m in mappings) {
string remote_key = GetContents("./primaryKey/text()", m);
XPathNodeIterator ident_nodes = (XPathNodeIterator) m.Evaluate("./identifiers/identifier");
ArrayList identifiers = new ArrayList();
foreach (XPathNavigator i in ident_nodes) {
identifiers.Add(i.ToString());
}
result.Add(remote_key, identifiers);
}
return result;
}
private string GetContents(string xpath_expr, XPathNavigator nav) {
XPathNodeIterator rk_nodes = (XPathNodeIterator) nav.Evaluate(xpath_expr);
while (rk_nodes.MoveNext()) {
return rk_nodes.Current.ToString();
}
return null;
}
public void Map(string identifier, string primaryKey) {
Dictionary<string,string> query = new Dictionary<string,string>();
query.Add("identifier", identifier);
query.Add("primaryKey", primaryKey);
ApiCall("map", query);
}
public void Unmap(string identifier, string primaryKey) {
Dictionary<string,string> query = new Dictionary<string,string>();
query.Add("identifier", identifier);
query.Add("primaryKey", primaryKey);
ApiCall("unmap", query);
}
private XmlElement ApiCall(string methodName, Dictionary<string,string> partialQuery) {
Dictionary<string,string> query = new Dictionary<string,string>(partialQuery);
query.Add("format", "xml");
query.Add("apiKey", apiKey);
StringBuilder sb = new StringBuilder();
foreach (KeyValuePair<string, string> e in query) {
if (sb.Length > 0) {
sb.Append('&');
}
sb.Append(System.Web.HttpUtility.UrlEncode(e.Key, Encoding.UTF8));
sb.Append('=');
sb.Append(HttpUtility.UrlEncode(e.Value, Encoding.UTF8));
}
string data = sb.ToString();
Uri url = new Uri(baseUrl + "/api/v2/" + methodName);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
// Write the request
StreamWriter stOut = new StreamWriter(request.GetRequestStream(),
Encoding.ASCII);
stOut.Write(data);
stOut.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream ();
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = false;
doc.Load(dataStream);
XmlElement resp = doc.DocumentElement;
if (resp == null || !resp.GetAttribute("stat").Equals("ok")) {
throw new Exception("Unexpected API error");
}
return resp;
}
public static void Main(string[] args) {
Rpx r = new Rpx(args[0], args[1]);
if (args[2].Equals("mappings")) {
Console.WriteLine("Mappings for " + args[3] + ":");
foreach(string s in r.Mappings(args[3])) {
Console.WriteLine(s);
}
}
if (args[2].Equals("all_mappings")) {
Console.WriteLine("All mappings:");
foreach (KeyValuePair<string, ArrayList> pair in r.AllMappings()) {
Console.WriteLine(pair.Key + ":");
foreach (string identifier in pair.Value) {
Console.WriteLine(" " + identifier);
}
}
}
if (args[2].Equals("map")) {
Console.WriteLine(args[3] + " mapped to " + args[4]);
r.Map(args[3], args[4]);
}
if (args[2].Equals("unmap")) {
Console.WriteLine(args[3] + " unmapped from " + args[4]);
r.Unmap(args[3], args[4]);
}
}
}
Code source: https://github.com/janrain/Janrain-Sample-Code/blob/master/c-sharp/csharp-helper-class.cs
would anyone have a working example of an amazon ITEMLOOKUP ?>
i have the following code but it does not seem to work:
string ISBN = "0393326381";
string ASIN = "";
if (!(string.IsNullOrEmpty(ISBN) && string.IsNullOrEmpty(ASIN)))
{
AWSECommerceServicePortTypeChannel service = new AWSECommerceServicePortTypeChannel();
ItemLookup lookup = new ItemLookup();
ItemLookupRequest request = new ItemLookupRequest();
lookup.AssociateTag = secretKey;
lookup.AWSAccessKeyId = accessKeyId;
if (string.IsNullOrEmpty(ASIN))
{
request.IdType = ItemLookupRequestIdType.ISBN;
request.ItemId = new string[] { ISBN.Replace("-", "") };
}
else
{
request.IdType = ItemLookupRequestIdType.ASIN;
request.ItemId = new string[] { ASIN };
}
request.ResponseGroup = new string[] { "OfferSummary" };
lookup.Request = new ItemLookupRequest[] { request };
response = service.ItemLookup(lookup);
if (response.Items.Length > 0 && response.Items[0].Item.Length > 0)
{
Item item = response.Items[0].Item[0];
if (item.MediumImage == null)
{
//bookImageHyperlink.Visible = false;
}
else
{
//bookImageHyperlink.ImageUrl = item.MediumImage.URL;
}
//bookImageHyperlink.NavigateUrl = item.DetailPageURL;
//bookTitleHyperlink.Text = item.ItemAttributes.Title;
//bookTitleHyperlink.NavigateUrl = item.DetailPageURL;
if (item.OfferSummary.LowestNewPrice == null)
{
if (item.OfferSummary.LowestUsedPrice == null)
{
//priceHyperlink.Visible = false;
}
else
{
//priceHyperlink.Text = string.Format("Buy used {0}", item.OfferSummary.LowestUsedPrice.FormattedPrice);
//priceHyperlink.NavigateUrl = item.DetailPageURL;
}
}
else
{
//priceHyperlink.Text = string.Format("Buy new {0}", item.OfferSummary.LowestNewPrice.FormattedPrice);
//priceHyperlink.NavigateUrl = item.DetailPageURL;
}
if (item.ItemAttributes.Author != null)
{
//authorLabel.Text = string.Format("By {0}", string.Join(", ", item.ItemAttributes.Author));
}
else
{
//authorLabel.Text = string.Format("By {0}", string.Join(", ", item.ItemAttributes.Creator.Select(c => c.Value).ToArray()));
}
/*
ItemLink link = item.ItemLinks.Where(i => i.Description.Contains("Wishlist")).FirstOrDefault();
if (link == null)
{
//wishListHyperlink.Visible = false;
}
else
{
//wishListHyperlink.NavigateUrl = link.URL;
}
* */
}
}
}
the problem is with this:
thisshould be defined differently but i do not know how AWSECommerceServicePortTypeChannel service = new AWSECommerceServicePortTypeChannel();
Say, that code looks awful familiar. You're missing the Endpoint signing piece from when they switched over to requiring that you add message signing. You need to add a behavior on your client. Here's the change to your code above:
if (!(string.IsNullOrEmpty(ISBN) && string.IsNullOrEmpty(ASIN)))
{
AWSECommerceServicePortTypeClient client = new AWSECommerceServicePortTypeClient();
client.ChannelFactory.Endpoint.Behaviors.Add(
new Amazon.AmazonSigningEndpointBehavior(
accessKeyId,
secretKey);
ItemLookup lookup = new ItemLookup();
ItemLookupRequest request = new ItemLookupRequest();
lookup.AssociateTag = accessKeyId;
lookup.AWSAccessKeyId = secretKey;
//... etc.
And here's the Endpoint (I can't take credit for this, I wish I could remember who should):
namespace Amazon
{
public class AmazonSigningEndpointBehavior : IEndpointBehavior {
private string accessKeyId = "";
private string secretKey = "";
public AmazonSigningEndpointBehavior(string accessKeyId, string secretKey) {
this.accessKeyId = accessKeyId;
this.secretKey = secretKey;
}
public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime) {
clientRuntime.MessageInspectors.Add(new AmazonSigningMessageInspector(accessKeyId, secretKey));
}
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher) { return; }
public void Validate(ServiceEndpoint serviceEndpoint) { return; }
public void AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection bindingParameters) { return; }
}
}
Oh. And you'll need the MessageInspector for that to work.
namespace Amazon
{
public class AmazonSigningMessageInspector : IClientMessageInspector {
private string accessKeyId = "";
private string secretKey = "";
public AmazonSigningMessageInspector(string accessKeyId, string secretKey) {
this.accessKeyId = accessKeyId;
this.secretKey = secretKey;
}
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
// prepare the data to sign
string operation = Regex.Match(request.Headers.Action, "[^/]+$").ToString();
DateTime now = DateTime.UtcNow;
string timestamp = now.ToString("yyyy-MM-ddTHH:mm:ssZ");
string signMe = operation + timestamp;
byte[] bytesToSign = Encoding.UTF8.GetBytes(signMe);
// sign the data
byte[] secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
HMAC hmacSha256 = new HMACSHA256(secretKeyBytes);
byte[] hashBytes = hmacSha256.ComputeHash(bytesToSign);
string signature = Convert.ToBase64String(hashBytes);
// add the signature information to the request headers
request.Headers.Add(new AmazonHeader("AWSAccessKeyId", accessKeyId));
request.Headers.Add(new AmazonHeader("Timestamp", timestamp));
request.Headers.Add(new AmazonHeader("Signature", signature));
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState) { }
}
}
And finally, the Header:
namespace Amazon
{
public class AmazonHeader : MessageHeader
{
private string name;
private string value;
public AmazonHeader(string name, string value)
{
this.name = name;
this.value = value;
}
public override string Name { get { return name; } }
public override string Namespace { get { return "http://security.amazonaws.com/doc/2007-01-01/"; } }
protected override void OnWriteHeaderContents(XmlDictionaryWriter xmlDictionaryWriter, MessageVersion messageVersion)
{
xmlDictionaryWriter.WriteString(value);
}
}
}
Yes, they made it complicated when they started requiring message signing...
A simple and easy library is available on nuget.
PM> Install-Package Nager.AmazonProductAdvertising
Example
var authentication = new AmazonAuthentication("accesskey", "secretkey");
var client = new AmazonProductAdvertisingClient(authentication, AmazonEndpoint.US);
var result = await client.GetItemsAsync("B00BYPW00I");
To perform a lookup for anything other then an ASIN, you need to specify the "SearchIndex" property. You can simply set it to "All".
var request = new ItemLookupRequest();
request.ItemId = new[] {upcCode};
request.IdType = ItemLookupRequestIdType.UPC;
request.IdTypeSpecified = true;
request.SearchIndex = "All";
Here is a link to the documentation: http://docs.amazonwebservices.com/AWSECommerceService/2011-08-01/DG/index.html?ItemLookup.html. Note the description of the SearchIndex parameter:
Constraint:If ItemIdis an ASIN, a search index cannot be specified in
the request. Required for non-ASIN ItemIds.
I actually built a little wrapper around it so it hands you back a handy object graph. I have the source up on BitBucket and a little more about it on the C# Amazon ItemLookup page.
C# Amazon ItemLookup
You can make calls like:
var item = client.LookupByAsin("B0037X9N5U");
double? price = item.GetLowestPrice();