I'm saving a list of strings to my backend api but its malforming the string somehow. I have checked all possible things but I have had no sleep for 48 hours so I'm probably missing it.
It seems to replace _ with amp - not sure.
Correct string (also the string before persisting)
&_nc_cat=100&oh=2709db2b099e5eb5bb6eb19654de828a&oe=5E7FF7C5
The string after persisting
&_nc_cat=100&oh=2cda55a0255b0ef3afabe535412a43f8&oe=5E7FF7C5
The full orignal correct string is actually
https://scontent-lhr3-1.cdninstagram.com/s640x640/75448871_111514890143520_4913259559873269659_n.jpg?_nc_ht=scontent-lhr3-1.cdninstagram.com&_nc_cat=100&oh=2709db2b099e5eb5bb6eb19654de828a&oe=5E7FF7C5
Here is how I save to my api
var response = HttpFactory.PushItemToCache(new Dictionary<string, object>
{
{ "item", Url },
{ "username", Username },
{ "name", Name },
{ "picture", Picture },
{ "pictures", Pictures },
});
Http Methods:
public static IRestResponse PushItemToCache(Dictionary<string, object> data)
{
return HttpUtilities.Post("/api/cache", data);
}
Post method:
public static IRestResponse PerformResource(string resource, IDictionary<string, object> data = default, string method = "GET", bool checkToken = true)
{
var sw = Stopwatch.StartNew();
var request = new RestRequest(resource);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
if (data == null)
{
data = new Dictionary<string, object>();
}
data.Add("owner", Environment.UserName + Environment.MachineName);
if (method != "GET")
{
request.AddJsonBody(data);
}
else
{
foreach (var pair in data)
{
request.AddParameter(pair.Key, pair.Value);
}
}
IRestResponse response;
switch (method)
{
case "POST":
response = RestClient.Post(request);
break;
case "DELETE":
response = RestClient.Delete(request);
break;
case "PUT":
response = RestClient.Delete(request);
break;
case "PATCH":
response = RestClient.Patch(request);
break;
default:
response = RestClient.Get(request);
break;
}
if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.NotFound)
{
new ConsoleLogger().Error("Response for " + resource + " returned " + response.StatusDescription);
new ConsoleLogger().Error(response.Content);
new ConsoleLogger().Error(response.ErrorMessage);
}
if (sw.Elapsed.TotalSeconds >= 5)
{
new ConsoleLogger().Pink($"This request ({resource}) took {sw.Elapsed.TotalSeconds} seconds");
}
return response;
}
Looks like your string is url encoded, you can convert it back using HttpUtility.UrlDecode
working example here
Related
We are making a PUT call to the service layer to update an entity information
HttpClient.SendAsync method is throwing "A task was canceled" issue even though the API call is successfully made to the backend service layer. I could see the logs from service layer.
Initially I thought it could be related to timeout, so I increased the timeout from 10 seconds to 30 seconds, still the program is waiting for 30 seconds and gets timed out with the error "A task was canceled". But the api call was successfully completed in Service Layer within even 5 seconds
Please find below my code
protected override void Execute(CodeActivityContext context)
{
string uuid = UUID.Get(context);
Console.WriteLine(uuid + ": Http Api Call - STARTED");
string endPoint = EndPoint.Get(context);
string contentType = ContentType.Get(context);
string acceptFormat = AcceptFormat.Get(context);
HttpMethod httpMethod = HttpApiMethod.Get(context);
string clientCertificatePath = ClientCertificatePath.Get(context);
string clientCertificatePassword = ClientCertificatePassword.Get(context);
double httpTimeOut = HttpTimeout.Get(context);
Dictionary<string, string> requestHeaders = RequestHeaders.Get(context);
Dictionary<string, string> pathParams = PathParams.Get(context);
Dictionary<string, string> queryParams = QueryParams.Get(context);
string requestBody = RequestBody.Get(context);
WebRequestHandler webRequestHandler = new WebRequestHandler();
webRequestHandler.MaxConnectionsPerServer = 1;
if (clientCertificatePath != null && clientCertificatePath.Trim().Length > 0)
{
X509Certificate2 x509Certificate2 = null;
if (clientCertificatePassword != null && clientCertificatePassword.Trim().Length > 0)
{
x509Certificate2 = new X509Certificate2(clientCertificatePath.Trim(),
clientCertificatePassword.Trim());
}
else
{
x509Certificate2 = new X509Certificate2(clientCertificatePath.Trim());
}
webRequestHandler.ClientCertificates.Add(x509Certificate2);
}
HttpClient httpClient = new HttpClient(webRequestHandler)
{
Timeout = TimeSpan.FromMilliseconds(httpTimeOut)
};
if (acceptFormat != null)
{
httpClient.DefaultRequestHeaders.Add("Accept", acceptFormat);
}
HttpResponseMessage httpResponseMessage = InvokeApiSync(httpClient, endPoint,
httpMethod, contentType,
requestHeaders, pathParams,
queryParams, requestBody,
uuid
);
HttpResponseMessageObject.Set(context, httpResponseMessage);
ResponseBody.Set(context, httpResponseMessage.Content.ReadAsStringAsync().Result);
StatusCode.Set(context, (int)httpResponseMessage.StatusCode);
Console.WriteLine(uuid + ": Http Api Call - ENDED");
}
private HttpResponseMessage InvokeApiSync(HttpClient httpClient,
string endPoint,
HttpMethod httpMethod,
string contentType,
Dictionary<string, string> requestHeaders,
Dictionary<string, string> pathParams,
Dictionary<string, string> queryParams,
string requestBody,
string uuid)
{
if (pathParams != null)
{
ICollection<string> keys = pathParams.Keys;
if (keys.Count > 0)
{
foreach (string key in keys)
{
endPoint = endPoint.Replace(":" + key, pathParams[key]);
}
}
}
if (queryParams != null)
{
List<string> keys = new List<string>(queryParams.Keys);
if (keys.Count > 0)
{
endPoint = string.Concat(endPoint, "?", keys[0], "=", queryParams[keys[0]]);
for (int index = 1; index < keys.Count; index++)
{
endPoint = string.Concat(endPoint, "&", keys[index], "=", queryParams[keys[index]]);
}
}
}
try
{
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(httpMethod, endPoint);
if (requestHeaders != null)
{
foreach (string key in requestHeaders.Keys)
{
httpRequestMessage.Headers.Add(key, requestHeaders[key]);
}
}
if (httpMethod.Equals(HttpMethod.Put) || httpMethod.Equals(HttpMethod.Post))
{
StringContent reqContent = null;
if (requestBody != null)
{
reqContent = new StringContent(requestBody);
}
else
{
reqContent = new StringContent("");
}
reqContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
httpRequestMessage.Content = reqContent;
}
HttpResponseMessage httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;
return httpResponseMessage;
}
catch (Exception exception)
{
Console.WriteLine(uuid + " : HttpApi Error Has Occurred");
Console.WriteLine(uuid + " : " + exception.Message);
Console.WriteLine(uuid + " : " + exception.StackTrace);
throw exception;
}
}
Any help would be much appreciated. Thanks.!
I'm trying to change my Restsharp Client to work async instead of sync.
Each of my API-Calls referes to the GetAsync<T> method. When I try now to change the Client to call ExecuteAsync<T> instead of Execute i got this error:
Delegate 'Action, RestRequestAsyncHandle>' does not take 1 Arguments
I'm using RestSharp Version 106.6.10 currently.
Here is my GetAsyncMethod:
public async Task<T> GetAsync<T>(string url, Dictionary<string, object> keyValuePairs = null)
{
try
{
// Check token is expired
DateTime expires = DateTime.Parse(Account.Properties[".expires"]);
if (expires < DateTime.Now)
{
// Get new Token
await GetRefreshTokenAsync();
}
// Get AccessToken
string token = Account.Properties["access_token"];
if (string.IsNullOrEmpty(token))
throw new NullReferenceException("AccessToken is null or empty!");
// Create client
var client = new RestClient()
{
Timeout = 3000000
};
//Create Request
var request = new RestRequest(url, Method.GET);
request.RequestFormat = DataFormat.Json;
request.AddHeader("Authorization", "Bearer " + token);
// Add Parameter when necessary
if (keyValuePairs != null)
{
foreach (var pair in keyValuePairs)
{
request.AddParameter(pair.Key, pair.Value);
}
}
// Call
var result = default(T);
var asyncHandle = client.ExecuteAsync<T>(request, restResponse =>
{
// check respone
if (restResponse.ResponseStatus == ResponseStatus.Completed)
{
result = restResponse.Data;
}
//else
// throw new Exception("Call stopped with Status: " + response.StatusCode +
// " Description: " + response.StatusDescription);
});
return result;
}
catch (Exception ex)
{
Crashes.TrackError(ex);
return default(T);
}
}
Here one of the calling Methods:
public async Task<List<UcAudit>> GetAuditByHierarchyID(int hierarchyID)
{
string url = AuthSettings.ApiUrl + "/ApiMethod/" + hierarchyID;
List<UcAudit> auditList = await GetAsync<List<UcAudit>>(url);
return auditList;
}
When I Change the T in ExecuteAsync<T> in one of my classes the error is gone. How can I change the method to work async with <T>???
With the info from Lasse Vågsæther Karlsen I found the solution.
This is the start:
var asyncHandle = client.ExecuteAsync<T>(request, restResponse =>
{
// check respone
if (restResponse.ResponseStatus == ResponseStatus.Completed)
{
result = restResponse.Data;
}
//else
// throw new Exception("Call stopped with Status: " + response.StatusCode +
// " Description: " + response.StatusDescription);
});
Worked for me :
client.ExecuteAsync<T>(request, (response, asyncHandle )=>
{
//check respone
if (response.StatusCode == HttpStatusCode.OK)
{
result = response.Data;
}
else
throw new Exception("Call stopped with Status: " + response.StatusCode +
" Description: " + response.StatusDescription);
});
Thank you!
I am working on trying to connect to my GraphQL server my developers have setup from within Unity. I have found some scripts to help with this process, however, I am still not able to connect because i need to be logged into the system hosting graphql to be able to query externally, I cannot just use the endpoint url.
My developer has told me to do a POST request to mysystem/login and in the request body add {email: string, password: string}. I have tried a few different things and nothing is working. I have to log into the mysystem/login with email and password, then i will be able to connect to mygraphql endpoint from the code below.--i was assuming this portion would go where I have the //smt authentication notes. Any help on how to setup the post request and where it should be or how it should work would be much appreciated.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using SimpleJSON;
using UnityEngine;
using UnityEngine.Networking;
namespace graphQLClient
{
public class GraphQuery : MonoBehaviour
{
public static GraphQuery instance = null;
[Tooltip("The url of the node endpoint of the graphQL server being queried")]
public static string url;
public delegate void QueryComplete();
public static event QueryComplete onQueryComplete;
public enum Status { Neutral, Loading, Complete, Error };
public static Status queryStatus;
public static string queryReturn;
string authURL;
public static string LoginToken;
public class Query
{
public string query;
}
public void Awake()
{
if (instance == null)
{
instance = this;
}
else if (instance != this)
{
Destroy(gameObject);
}
DontDestroyOnLoad(gameObject);
StartCoroutine("PostLogin");
}
private void Start()
{
LoginToken = "";
}
public static Dictionary<string, string> variable = new Dictionary<string, string>();
public static Dictionary<string, string[]> array = new Dictionary<string, string[]>();
// Use this for initialization
// SMT Authentication to ELP
// SMT Needed for Authentication--- if (token != null) request.SetRequestHeader("Authorization", "Bearer " + token);
//In the request body: {email: string, password: string}
//You’ll either get a 401 with an empty response or 201 with {token: string, user: object}
IEnumerator PostLogin()
{
Debug.Log("Logging in...");
string authURL = "https://myapp.com/login";
string loginBody = "{\"email\":\"myemail.com\",\"password\":\"mypassowrd\"}";
var request = new UnityWebRequest(authURL, "POST");
byte[] bodyRaw = new System.Text.UTF8Encoding().GetBytes(loginBody);
request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log("Login error!");
foreach (KeyValuePair<string, string> entry in request.GetResponseHeaders())
{
Debug.Log(entry.Value + "=" + entry.Key);
}
Debug.Log(request.error);
}
else
{
Debug.Log("Login complete!");
//Debug.Log(request.downloadHandler.text);
LoginToken = request.downloadHandler.text;
Debug.Log(LoginToken);
}
}
public static WWW POST(string details)
{
//var request = new UnityWebRequest(url, "POST");
details = QuerySorter(details);
Query query = new Query();
string jsonData = "";
WWWForm form = new WWWForm();
query = new Query { query = details };
jsonData = JsonUtility.ToJson(query);
byte[] postData = Encoding.ASCII.GetBytes(jsonData);
Dictionary<string, string> postHeader = form.headers;
//postHeader["Authorization"] = "Bearer " + downloadHandler.Token;
if (postHeader.ContainsKey("Content-Type"))
//postHeader["Content-Type"] = "application/json";
postHeader.Add("Authorization", "Bearer " + LoginToken);
else
//postHeader.Add("Content-Type", "application/json");
postHeader.Add("Authorization", "Bearer " + LoginToken);
WWW www = new WWW(url, postData, postHeader);
instance.StartCoroutine(WaitForRequest(www));
queryStatus = Status.Loading;
return www;
}
static IEnumerator WaitForRequest(WWW data)
{
yield return data; // Wait until the download is done
if (data.error != null)
{
Debug.Log("There was an error sending request: " + data.error);
queryStatus = Status.Error;
}
else
{
queryReturn = data.text;
queryStatus = Status.Complete;
}
onQueryComplete();
}
public static string QuerySorter(string query)
{
string finalString;
string[] splitString;
string[] separators = { "$", "^" };
splitString = query.Split(separators, StringSplitOptions.RemoveEmptyEntries);
finalString = splitString[0];
for (int i = 1; i < splitString.Length; i++)
{
if (i % 2 == 0)
{
finalString += splitString[i];
}
else
{
if (!splitString[i].Contains("[]"))
{
finalString += variable[splitString[i]];
}
else
{
finalString += ArraySorter(splitString[i]);
}
}
}
return finalString;
}
public static string ArraySorter(string theArray)
{
string[] anArray;
string solution;
anArray = array[theArray];
solution = "[";
foreach (string a in anArray)
{
}
for (int i = 0; i < anArray.Length; i++)
{
solution += anArray[i].Trim(new Char[] { '"' });
if (i < anArray.Length - 1)
solution += ",";
}
solution += "]";
Debug.Log("This is solution " + solution);
return solution;
}
}
}
I am developing an app using instagram api to bring feed to my website. I have following code but when i try to access the access_token using the code provided by Instagram it's giving me `400 Bad request error. I would be much obliged if someone could help me to overcome this problem. Many Thanks
string code="";
public ActionResult Index()
{
if (!String.IsNullOrEmpty(Request["code"]))
{
code = Request["code"].ToString();
GetDataInstagramToken();
}
return View();
}
public ActionResult Instagram()
{
var client_id = ConfigurationManager.AppSettings["instagram.clientid"].ToString();
var redirect_uri = ConfigurationManager.AppSettings["instagram.redirecturi"].ToString();
string url = "https://api.instagram.com/oauth/authorize/?client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&response_type=code";
Response.Redirect(url);
return View();
}
public void GetDataInstagramToken()
{
var json = "";
var page = HttpContext.CurrentHandler as Page;
try
{
NameValueCollection parameters = new NameValueCollection();
parameters.Add("client_id", ConfigurationManager.AppSettings["instagram.clientid"].ToString());
parameters.Add("client_secret", ConfigurationManager.AppSettings["instagram.clientsecret"].ToString());
parameters.Add("grant_type", "authorization_code");
parameters.Add("redirect_uri", ConfigurationManager.AppSettings["instagram.redirecturi"].ToString());
parameters.Add("code", code);
WebClient client = new WebClient();
var result = client.UploadValues("https://api.instagram.com/oauth/access_token", "post", parameters);
var response = System.Text.Encoding.Default.GetString(result);
// deserializing nested JSON string to object
var jsResult = (JObject)JsonConvert.DeserializeObject(response);
string accessToken = (string)jsResult["access_token"];
int id = (int)jsResult["user"]["id"];
//This code register id and access token to get on client side
page.ClientScript.RegisterStartupScript(this.GetType(), "GetToken", "<script> var instagramaccessid=\"" + #"" + id + "" + "\"; var instagramaccesstoken=\"" + #"" + accessToken + "" + "\";</script>");
}
catch (Exception ex)
{
throw;
}
}
I am getting exception at
var result = client.UploadValues("https://api.instagram.com/oauth/access_token", "post", parameters);
In this line
client.UploadValues("https://api.instagram.com/oauth/access_token", "post", parameters);
You don't send any value to Instagram. If you check your parameter you can see your key but you cant see any value.
Try this:
public async void GetTokenFromCode()
{
var values = new Dictionary<string, string> {
{ "client_id","Your ChatId" },
{ "client_secret", "Your Client Secret" },
{ "grant_type", "authorization_code" },
{ "redirect_uri", "Your Redirect url"},
{ "code", "code" } };
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("https://api.instagram.com/oauth/access_token", content);
var responseString = await response.Content.ReadAsStringAsync();
}
I have been given the task to create a http post using basic auth.
I am developing in C# in an asp.net MVC application.
I have also been given this example.
{
POST /v2/token_endpoint HTTP/1.1
Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=
Accept: application/json
Content-Type: application/x-www-form-urlencoded
User-Agent: Java/1.6.0_33
Host: api.freeagent.com
Connection: close
Content-Length: 127
grant_type=authorization_code&code=12P3AsFZXwXjd7SLOE1dsaX8oCgix&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth
}
My question is how do i code this in C#?
If more information is need just ask, thanks in advance
edit: I have made some progress but I have not added the grant_type
public void AccessToken(string code)
{
string url = #"https://api.freeagent.com/v2/token_endpoint";
WebClient client = new WebClient();
string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(ApiKey + ":" + ApiSecret));
client.Headers[HttpRequestHeader.Authorization] = "Basic " + credentials;
client.Headers[HttpRequestHeader.Accept] = "application/json";
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
client.Headers[HttpRequestHeader.UserAgent] = "Java/1.6.0_33";
client.Headers[HttpRequestHeader.Host] = "api.freeagent.com";
client.Headers[HttpRequestHeader.Connection] = "close";
client.Headers["grant_type"] = "authorization_code";
var result = client.DownloadString(url);
}
So how do i add: grant_type=authorization_code&code=12P3AsFZXwXjd7SLOE1dsaX8oCgix&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth to the post?
You can find here two samples how to make basic auth request with WebRequest and WebClient classes:
http://grahamrhay.wordpress.com/2011/08/22/making-a-post-request-in-c-with-basic-authentication/
http://anishshenoy57.wordpress.com/2013/01/22/basic-http-authentication-using-c/
Basically basic auth it's just Base64(username:password), so it's easy to implement it.
UPDATE1
Here is a sample based on your method:
public void AccessToken(string code)
{
string url = #"https://api.freeagent.com/v2/token_endpoint";
WebClient client = new WebClient();
string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(ApiKey + ":" + ApiSecret));
client.Headers[HttpRequestHeader.Authorization] = "Basic " + credentials;
client.Headers[HttpRequestHeader.Accept] = "application/json";
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
client.Headers[HttpRequestHeader.UserAgent] = "Java/1.6.0_33";
client.Headers[HttpRequestHeader.Host] = "api.freeagent.com";
client.Headers[HttpRequestHeader.Connection] = "close";
client.Headers["grant_type"] = "authorization_code";
string data = string.Format(
"grant_type=authorization_code&code={0}&redirect_uri=http%3A%2F%2Flocalhost%3A8080",
code);
var result = client.UploadString(url, data);
}
The only different in calling method in WebClient. DownloadString will do GET request, but for POST you need to use UploadString method
I too have struggled with this, but I have now made it to the other side!
The one that held me up the most was that if you specify a redirect URL in the Auth Token request, you must also specify it in the Access Token request with the same URL, even though it's not used.
I started off with someones partial wrapper, and have evolved it almost beyond recognition. Hopefully this wrapper (complete with auth and access token code) will help others. I've only used it to create invoices and invoice items so far, and the other functions are untested, but it should get you your tokens and to the point where you can debug the requests.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Web.Script.Serialization;
namespace ClientZone.External
{
public class FreeAgent
{
public enum Methods
{
POST = 1,
PUT
}
public enum Status
{
Draft = 1,
Sent,
Cancelled
}
private string _subDomain;
private string _identifier;
private string _secret;
private string _redirectURI;
public static string AuthToken = "";
private static string _accessToken = "";
private static string _refreshToken = "";
private static DateTime _refreshTime;
public FreeAgent(string identifier, string secret, string subdomain, string redirectURI)
{
_subDomain = subdomain;
_identifier = identifier;
_secret = secret;
_redirectURI = redirectURI; // If this was specified in the Auth Token call, you must specify it here, and it must be the same
}
public bool GetAccessToken()
{
try
{
string url = #"https://api.freeagent.com/v2/token_endpoint";
WebClient client = new WebClient();
string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(_identifier + ":" + _secret));
client.Headers[HttpRequestHeader.Host] = "api.freeagent.com";
client.Headers[HttpRequestHeader.KeepAlive] = "true";
client.Headers[HttpRequestHeader.Accept] = "application/json";
client.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36";
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded;charset=UTF-8";
client.Headers[HttpRequestHeader.Authorization] = "Basic " + credentials;
System.Net.ServicePointManager.Expect100Continue = false;
client.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
client.Headers[HttpRequestHeader.AcceptLanguage] = "en-US,en;q=0.8";
var result = "";
if (!(_accessToken == "" && _refreshToken != ""))
{
string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}", AuthToken, _redirectURI);
result = client.UploadString(url, data);
}
else
{
// Marking the access token as blank and the refresh token as not blank
// is a sign we need to get a refresh token
string data = string.Format("grant_type=refresh_token&refresh_token={0}", _refreshToken);
result = client.UploadString(url, data);
}
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
var results_list = (IDictionary<string, object>)json_serializer.DeserializeObject(result);
_accessToken = results_list["access_token"].ToString();
int secondsUntilRefresh = Int32.Parse(results_list["expires_in"].ToString());
_refreshTime = DateTime.Now.AddSeconds(secondsUntilRefresh);
if (results_list.Any(x => x.Key == "refresh_token"))
{
_refreshToken = results_list["refresh_token"].ToString();
}
if (_accessToken == "" || _refreshToken == "" || _refreshTime == new DateTime())
{
return false;
}
}
catch
{
return false;
}
return true;
}
private HttpStatusCode SendWebRequest(Methods method, string URN, string request, out string ResponseData)
{
if (_accessToken == "")
{
// The access token has not been retrieved yet
GetAccessToken();
}
else
{
if (_refreshTime != new DateTime() && _refreshTime < DateTime.Now) {
// The token has expired and we need to refresh it
_accessToken = "";
GetAccessToken();
}
}
if (_accessToken != "")
{
try
{
WebClient client = new WebClient();
string url = "https://api.freeagentcentral.com/v2/" + URN;
client.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36";
client.Headers[HttpRequestHeader.Authorization] = "Bearer " + _accessToken;
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.Headers[HttpRequestHeader.Accept] = "application/json";
if (method == Methods.POST || method == Methods.PUT)
{
string data = request;
var result = client.UploadString(url, method.ToString(), data);
ResponseData = result;
return HttpStatusCode.Created;
}
else
{
var result = client.DownloadString(url);
ResponseData = result;
return HttpStatusCode.OK;
}
}
catch (WebException e)
{
if (e.GetType().Name == "WebException")
{
WebException we = (WebException)e;
HttpWebResponse response = (System.Net.HttpWebResponse)we.Response;
ResponseData = response.StatusDescription;
return response.StatusCode;
}
else
{
ResponseData = e.Message;
if (e.InnerException != null)
{
ResponseData = ResponseData + " - " + e.InnerException.ToString();
}
return HttpStatusCode.SeeOther;
}
}
}
else
{
ResponseData = "Access Token could not be retrieved";
return HttpStatusCode.SeeOther;
}
}
private int ExtractNewID(string resp, string URN)
{
if (resp != null && resp.Trim() != "")
{
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
var results_list = (IDictionary<string, object>)json_serializer.DeserializeObject(resp);
if (results_list.Any(x => x.Key == "invoice"))
{
var returnInvoice = (IDictionary<string, object>)results_list["invoice"];
if (returnInvoice["created_at"].ToString() != "")
{
string returnURL = returnInvoice["url"].ToString();
if (returnURL.Contains("http"))
{
return int.Parse(returnURL.Remove(0, ("https://api.freeagentcentral.com/v2/" + URN).Length + 1));
}
else
{
return int.Parse(returnURL.Remove(0, URN.Length + 2));
}
}
}
}
return -1;
}
public int CreateContact(string firstName, string lastName, string emailAddress, string street, string city, string state, string postcode, string country)
{
StringBuilder request = new StringBuilder();
request.Append("{\"contact\":{");
request.Append("\"first-name\":");
request.Append(firstName);
request.Append("\",");
request.Append("\"last-name\":");
request.Append(lastName);
request.Append("\",");
request.Append("\"email\":");
request.Append(emailAddress);
request.Append("\",");
request.Append("\"address1\":");
request.Append(street);
request.Append("\",");
request.Append("\"town\":");
request.Append(city);
request.Append("\",");
request.Append("\"region\":");
request.Append(state);
request.Append("\",");
request.Append("\"postcode\":");
request.Append(postcode);
request.Append("\",");
request.Append("\"country\":");
request.Append(country);
request.Append("\"");
request.Append("}");
string returnData = string.Empty;
HttpStatusCode responseCode = SendWebRequest(Methods.POST, "contacts", request.ToString(), out returnData);
if (responseCode == HttpStatusCode.OK || responseCode == HttpStatusCode.Created)
{
return ExtractNewID(returnData, "contacts");
}
else
{
return -1;
}
}
public int CreateInvoice(int contactID, DateTime invoiceDate, int terms, string reference, string comments, string currency = "GBP")
{
StringBuilder request = new StringBuilder();
request.Append("{\"invoice\":{");
request.Append("\"dated_on\": \"");
request.Append(invoiceDate.ToString("yyyy-MM-ddTHH:mm:00Z"));
request.Append("\",");
if (!string.IsNullOrEmpty(reference))
{
request.Append("\"reference\": \"");
request.Append(reference);
request.Append("\",");
}
if (!string.IsNullOrEmpty(comments))
{
request.Append("\"comments\": \"");
request.Append(comments);
request.Append("\",");
}
request.Append("\"payment_terms_in_days\": \"");
request.Append(terms);
request.Append("\",");
request.Append("\"contact\": \"");
request.Append(contactID);
request.Append("\",");
if (currency == "EUR")
{
request.Append("\"ec_status\": \"");
request.Append("EC Services");
request.Append("\",");
}
request.Append("\"currency\": \"");
request.Append(currency);
request.Append("\"");
request.Append("}}");
string returnData = string.Empty;
HttpStatusCode responseCode = SendWebRequest(Methods.POST, "invoices", request.ToString(), out returnData);
if (responseCode == HttpStatusCode.OK || responseCode == HttpStatusCode.Created)
{
return ExtractNewID(returnData, "invoices");
}
else
{
return -1;
}
}
public bool ChangeInvoiceStatus(int invoiceID, Status status)
{
string returnData = string.Empty;
HttpStatusCode resp = SendWebRequest(Methods.PUT, "invoices/" + invoiceID.ToString() + "/transitions/mark_as_" + status.ToString().ToLower(), string.Empty, out returnData);
return false;
}
public int CreateInvoiceItem(int invoiceID, string itemType, float price, int quantity, float taxRate, string description)
{
StringBuilder request = new StringBuilder();
request.Append("{\"invoice\":{");
request.Append("\"invoice_items\":[{");
request.Append("\"item_type\": \"");
request.Append(itemType);
request.Append("\",");
request.Append("\"price\": \"");
request.Append(price.ToString("0.00"));
request.Append("\",");
request.Append("\"quantity\": \"");
request.Append(quantity);
request.Append("\",");
request.Append("\"sales_tax_rate\": \"");
request.Append(taxRate.ToString("0.00"));
request.Append("\",");
request.Append("\"description\": \"");
request.Append(description);
request.Append("\"");
request.Append("}]");
request.Append("}");
request.Append("}");
string returnData = string.Empty;
HttpStatusCode responseCode = SendWebRequest(Methods.PUT, "invoices/" + invoiceID.ToString(), request.ToString(), out returnData);
if (responseCode == HttpStatusCode.OK || responseCode == HttpStatusCode.Created)
{
// Invoice items is an update call to an invoice, so we just get a 200 OK with no response body to extract an ID from
return 0;
}
else
{
return -1;
}
}
}
}
To use this in an MVC setup you need to detect in the Index whether the login is necessary or not. If it is, you tell FreeAgent to come back to another ActionResult (I've used Auth) to catch the redirect and store the code.
public ActionResult Index()
{
if (MyNamespace.External.FreeAgent.AuthToken == "")
{
return Redirect("https://api.freeagent.com/v2/approve_app?redirect_uri=" + Request.Url.Scheme + "://" + Request.Url.Authority + "/Invoice/Auth" + "&response_type=code&client_id=1234567890123456789012");
}
else
{
return View();
}
}
public ActionResult Auth()
{
if (Request.Params.Get("code").ToString() != "")
{
ClientZone.External.FreeAgent.AuthToken = Request.Params.Get("code").ToString();
}
return View("Index");
}
Then to use the functions all you need is
MyNameSpace.External.FreeAgent FA = new ClientZone.External.FreeAgent("abcdefghhijklmnopqrstu", "1234567890123456789012", "acme", "http://localhost:52404/Invoice/Auth");
int newID = FA.CreateInvoice(54321, InvoiceDate, 30, "", "", "GBP");
if (newID != -1)
{
FA.CreateInvoiceItem(newID, unit, rate, quantity, number, description);
}
There is some UK/EU specific coding in the CreateInvoice. I'm not sure how custom or standard this is, but I've left it in as it's easier to delete it than recreate it.