This commit is contained in:
@@ -53,6 +53,9 @@
|
|||||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||||
<HintPath>..\libs\QuickBooks\Interop.QBFC15.dll</HintPath>
|
<HintPath>..\libs\QuickBooks\Interop.QBFC15.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
@@ -99,6 +102,7 @@
|
|||||||
<DependentUpon>Resources.resx</DependentUpon>
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<None Include="packages.config" />
|
||||||
<None Include="Properties\Settings.settings">
|
<None Include="Properties\Settings.settings">
|
||||||
<Generator>SettingsSingleFileGenerator</Generator>
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
|||||||
1
AyaNovaQBI/auth.Designer.cs
generated
1
AyaNovaQBI/auth.Designer.cs
generated
@@ -110,6 +110,7 @@
|
|||||||
this.btnLogin.TabIndex = 9;
|
this.btnLogin.TabIndex = 9;
|
||||||
this.btnLogin.Text = "Login";
|
this.btnLogin.Text = "Login";
|
||||||
this.btnLogin.UseVisualStyleBackColor = true;
|
this.btnLogin.UseVisualStyleBackColor = true;
|
||||||
|
this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
|
||||||
//
|
//
|
||||||
// btnCancel
|
// btnCancel
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -19,12 +19,84 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
private void auth_Load(object sender, EventArgs e)
|
private void auth_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
edServerUrl.Text = util.SERVER_URL;
|
edServerUrl.Text = Properties.Settings.Default.serverurl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnTest_Click(object sender, EventArgs e)
|
private async void btnTest_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!ValidateAndCleanServerAddress()) return;
|
||||||
|
btnLogin.Enabled = btnTest.Enabled = false;
|
||||||
|
var result = await util.InitAndConfirmAddressAsync(edServerUrl.Text);
|
||||||
|
btnLogin.Enabled = btnTest.Enabled = true;
|
||||||
|
if (result == "OK")
|
||||||
|
{
|
||||||
|
MessageBox.Show("Server URL is GOOD!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show("Server could not be reached at that URL\n" + result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void btnLogin_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (!ValidateAndCleanServerAddress()) return;
|
||||||
|
btnLogin.Enabled = btnTest.Enabled = false;
|
||||||
|
// if (!util.Initialized)
|
||||||
|
//{
|
||||||
|
var result = await util.InitAndConfirmAddressAsync(edServerUrl.Text);
|
||||||
|
if (result != "OK")
|
||||||
|
{
|
||||||
|
MessageBox.Show("Server could not be reached at that URL\n" + result);
|
||||||
|
btnLogin.Enabled = btnTest.Enabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
var res = await util.AuthenticateAsync(edUserName.Text, edPassword.Text);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
MessageBox.Show("AyaNova 8 SuperUser account login failed");
|
||||||
|
btnLogin.Enabled = btnTest.Enabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
btnLogin.Enabled = btnTest.Enabled = true;
|
||||||
|
|
||||||
|
this.DialogResult = DialogResult.OK;
|
||||||
|
this.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateAndCleanServerAddress()
|
||||||
|
{
|
||||||
|
var serverUrl = edServerUrl.Text;
|
||||||
|
Uri u;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
u = new Uri(serverUrl);
|
||||||
|
var scheme = u.Scheme;
|
||||||
|
var host = u.Host;
|
||||||
|
var port = u.Port;
|
||||||
|
|
||||||
|
edServerUrl.Text = scheme + "://" + host + ":" + port + "/" + util.API_BASE_ROUTE;
|
||||||
|
|
||||||
|
//client url for notification default links, help links etc
|
||||||
|
if ((scheme == "https" && port == 443) || (scheme == "http" && port == 80))
|
||||||
|
util.GuessClientUrl = scheme + "://" + host + "/";
|
||||||
|
else
|
||||||
|
util.GuessClientUrl = scheme + "://" + host + ":" + port + "/";
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Server address not valid\n" + ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ok, it's some kind of url, now format it for api access
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
AyaNovaQBI/packages.config
Normal file
4
AyaNovaQBI/packages.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
|
||||||
|
</packages>
|
||||||
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/.signature.p7s
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/.signature.p7s
vendored
Normal file
Binary file not shown.
20
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/LICENSE.md
vendored
Normal file
20
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/LICENSE.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2007 James Newton-King
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/Newtonsoft.Json.13.0.1.nupkg
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/Newtonsoft.Json.13.0.1.nupkg
vendored
Normal file
Binary file not shown.
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net20/Newtonsoft.Json.dll
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net20/Newtonsoft.Json.dll
vendored
Normal file
Binary file not shown.
10335
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net20/Newtonsoft.Json.xml
vendored
Normal file
10335
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net20/Newtonsoft.Json.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net35/Newtonsoft.Json.dll
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net35/Newtonsoft.Json.dll
vendored
Normal file
Binary file not shown.
9483
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net35/Newtonsoft.Json.xml
vendored
Normal file
9483
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net35/Newtonsoft.Json.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net40/Newtonsoft.Json.dll
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net40/Newtonsoft.Json.dll
vendored
Normal file
Binary file not shown.
9683
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net40/Newtonsoft.Json.xml
vendored
Normal file
9683
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net40/Newtonsoft.Json.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net45/Newtonsoft.Json.dll
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net45/Newtonsoft.Json.dll
vendored
Normal file
Binary file not shown.
11305
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net45/Newtonsoft.Json.xml
vendored
Normal file
11305
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/net45/Newtonsoft.Json.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.0/Newtonsoft.Json.dll
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.0/Newtonsoft.Json.dll
vendored
Normal file
Binary file not shown.
10993
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.0/Newtonsoft.Json.xml
vendored
Normal file
10993
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.0/Newtonsoft.Json.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.3/Newtonsoft.Json.dll
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.3/Newtonsoft.Json.dll
vendored
Normal file
Binary file not shown.
11115
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.3/Newtonsoft.Json.xml
vendored
Normal file
11115
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.3/Newtonsoft.Json.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard2.0/Newtonsoft.Json.dll
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard2.0/Newtonsoft.Json.dll
vendored
Normal file
Binary file not shown.
11280
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard2.0/Newtonsoft.Json.xml
vendored
Normal file
11280
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/lib/netstandard2.0/Newtonsoft.Json.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/packageIcon.png
vendored
Normal file
BIN
AyaNovaQBI/packages/Newtonsoft.Json.13.0.1/packageIcon.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@@ -6,19 +6,346 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace AyaNovaQBI
|
namespace AyaNovaQBI
|
||||||
{
|
{
|
||||||
internal class util
|
internal class util
|
||||||
{
|
{
|
||||||
|
#region API stuff
|
||||||
public const string TEST_ROUTE = "notify/hello";
|
public const string TEST_ROUTE = "notify/hello";
|
||||||
public const string API_BASE_ROUTE = "api/v8/";
|
public const string API_BASE_ROUTE = "api/v8/";
|
||||||
private const int MAX_TRIES = 3;//max times to retry an api call before giving up
|
private const int MAX_TRIES = 3;//max times to retry an api call before giving up
|
||||||
private const int API_RETRY_DELAY = 3000;//pause in ms before retrying api call
|
private const int API_RETRY_DELAY = 3000;//pause in ms before retrying api call
|
||||||
public static int HTTPCLIENT_TIMEOUT_SECONDS = 100;//changed by the setting in ops anyway, just a in-case sensible default here
|
public static int HTTPCLIENT_TIMEOUT_SECONDS = 100;//changed by the setting in ops anyway, just a in-case sensible default here
|
||||||
public static HttpClient client = null;
|
public static HttpClient client = null;
|
||||||
internal static string SERVER_URL { get; set; } = Properties.Settings.Default.serverurl;
|
//url once known to be good
|
||||||
|
internal static string ApiBaseUrl { get; set; }
|
||||||
|
//auth processes url for api and this is the best guess as to the client url to use for notification / help links etc
|
||||||
|
internal static string GuessClientUrl { get; set; }
|
||||||
|
|
||||||
|
internal static string JWT { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void InitClient()
|
||||||
|
{
|
||||||
|
if (client != null)
|
||||||
|
{
|
||||||
|
client.Dispose();
|
||||||
|
client = null;
|
||||||
|
}
|
||||||
|
client = new HttpClient();
|
||||||
|
client.Timeout = TimeSpan.FromSeconds(HTTPCLIENT_TIMEOUT_SECONDS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Only a return value of "OK" is ok
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serverUrl"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> InitAndConfirmAddressAsync(string serverUrl)
|
||||||
|
{
|
||||||
|
ApiBaseUrl = serverUrl;
|
||||||
|
InitClient();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// TimeSpan tsDefault = client.Timeout;
|
||||||
|
// client.Timeout = new TimeSpan(0, 0, 20);
|
||||||
|
HttpResponseMessage response = await client.GetAsync(serverUrl + TEST_ROUTE);
|
||||||
|
// client.Timeout = tsDefault;
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
return "OK";
|
||||||
|
else
|
||||||
|
return "Failed: " + response.StatusCode.ToString();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
while (ex.InnerException != null)
|
||||||
|
ex = ex.InnerException;
|
||||||
|
return "Failed exception: \r\n" + ex.Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async static Task<bool> AuthenticateAsync(string login, string password = null)
|
||||||
|
{
|
||||||
|
InitClient();
|
||||||
|
|
||||||
|
if (password == null)
|
||||||
|
password = login;
|
||||||
|
|
||||||
|
dynamic creds = new JObject();
|
||||||
|
creds.login = login;
|
||||||
|
creds.password = password;
|
||||||
|
|
||||||
|
ApiResponse a = await PostAsync("auth", creds.ToString());
|
||||||
|
|
||||||
|
if (a.HttpResponse.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
JWT = a.ObjectResponse["data"]["token"].Value<string>();
|
||||||
|
//Must be *the* SuperUser to continue:
|
||||||
|
a = await GetAsync("user/amsu");
|
||||||
|
var IsSuperUser = a.ObjectResponse["data"].Value<bool>();
|
||||||
|
if (!IsSuperUser)
|
||||||
|
{
|
||||||
|
JWT = string.Empty;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async static Task<ApiResponse> GetAsync(string route)
|
||||||
|
{
|
||||||
|
Exception FirstException = null;
|
||||||
|
|
||||||
|
for (int x = 0; x < MAX_TRIES; x++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await TryGetAsync(route);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (FirstException == null)
|
||||||
|
FirstException = ex;
|
||||||
|
}
|
||||||
|
await Task.Delay(API_RETRY_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
//no luck re-throw the exception
|
||||||
|
throw new Exception("API call failed after " + MAX_TRIES.ToString() + " attempts", FirstException);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async static Task<ApiResponse> TryGetAsync(string route)
|
||||||
|
{
|
||||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Get, ApiBaseUrl + route);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(JWT))
|
||||||
|
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JWT);
|
||||||
|
|
||||||
|
HttpResponseMessage response = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = await client.SendAsync(requestMessage);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
var Err = ex.Message;
|
||||||
|
var InnerErr = "";
|
||||||
|
if (ex.InnerException != null)
|
||||||
|
InnerErr = ex.InnerException.Message;
|
||||||
|
throw new Exception("GET error, route: " + route + "\r\nError:" + Err + "\r\nInner error:" + InnerErr + "\r\nStack:" + ex.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var responseAsString = await response.Content.ReadAsStringAsync();
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new Exception("GET error, code: " + (int)response.StatusCode + ", route: " + route + "\r\n" + responseAsString + "\r\n" + response.ReasonPhrase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return new ApiResponse() { HttpResponse = response, ObjectResponse = Parse(responseAsString) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async static Task<ApiResponse> PostAsync(string route, dynamic d)
|
||||||
|
{
|
||||||
|
Exception FirstException = null;
|
||||||
|
|
||||||
|
for (int x = 0; x < MAX_TRIES; x++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await TryPostAsync(route, d.ToString(Newtonsoft.Json.Formatting.None));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (FirstException == null)
|
||||||
|
FirstException = ex;
|
||||||
|
}
|
||||||
|
await Task.Delay(API_RETRY_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
//no luck re-throw the exception
|
||||||
|
throw new Exception("API call failed after " + MAX_TRIES.ToString() + " attempts", FirstException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async static Task<ApiResponse> PostAsync(string route, string s = null)
|
||||||
|
{
|
||||||
|
Exception FirstException = null;
|
||||||
|
|
||||||
|
for (int x = 0; x < MAX_TRIES; x++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await TryPostAsync(route, s);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (FirstException == null)
|
||||||
|
FirstException = ex;
|
||||||
|
}
|
||||||
|
await Task.Delay(API_RETRY_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
//no luck re-throw the exception
|
||||||
|
throw new Exception("API call failed after " + MAX_TRIES.ToString() + " attempts", FirstException);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async static Task<ApiResponse> TryPostAsync(string route, string postJson = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Post, ApiBaseUrl + route);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(JWT))
|
||||||
|
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JWT);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(postJson))
|
||||||
|
requestMessage.Content = new StringContent(postJson, System.Text.Encoding.UTF8, "application/json");
|
||||||
|
HttpResponseMessage response = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = await client.SendAsync(requestMessage);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
var Err = ex.Message;
|
||||||
|
var InnerErr = "";
|
||||||
|
if (ex.InnerException != null)
|
||||||
|
InnerErr = ex.InnerException.Message;
|
||||||
|
throw new Exception("POST error, route: " + route + "\r\nError:" + Err + "\r\nInner error:" + InnerErr + "\r\nStack:" + ex.StackTrace + "\r\nPOSTED OBJECT:\r\n" + postJson);
|
||||||
|
}
|
||||||
|
var responseAsString = await response.Content.ReadAsStringAsync();
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(postJson))
|
||||||
|
postJson = "n/a";
|
||||||
|
throw new Exception("POST error, code: " + (int)response.StatusCode + ", route: " + route + "\r\n" + responseAsString + "\r\n" + response.ReasonPhrase + "\r\nPOSTED OBJECT:\r\n" + postJson);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return new ApiResponse() { HttpResponse = response, ObjectResponse = Parse(responseAsString) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async static Task<ApiResponse> PutAsync(string route, dynamic d)
|
||||||
|
{
|
||||||
|
Exception FirstException = null;
|
||||||
|
|
||||||
|
for (int x = 0; x < MAX_TRIES; x++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await TryPutAsync(route, d.ToString(Newtonsoft.Json.Formatting.None));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (FirstException == null)
|
||||||
|
FirstException = ex;
|
||||||
|
}
|
||||||
|
await Task.Delay(API_RETRY_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
//no luck re-throw the exception
|
||||||
|
throw new Exception("API call failed after " + MAX_TRIES.ToString() + " attempts", FirstException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async static Task<ApiResponse> PutAsync(string route)
|
||||||
|
{
|
||||||
|
Exception FirstException = null;
|
||||||
|
|
||||||
|
for (int x = 0; x < MAX_TRIES; x++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await TryPutAsync(route);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (FirstException == null)
|
||||||
|
FirstException = ex;
|
||||||
|
}
|
||||||
|
await Task.Delay(API_RETRY_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
//no luck re-throw the exception
|
||||||
|
throw new Exception("API call failed after " + MAX_TRIES.ToString() + " attempts", FirstException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async static Task<ApiResponse> TryPutAsync(string route, string putJson = null)
|
||||||
|
{
|
||||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Put, ApiBaseUrl + route);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(JWT))
|
||||||
|
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JWT);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(putJson))
|
||||||
|
requestMessage.Content = new StringContent(putJson, System.Text.Encoding.UTF8, "application/json");
|
||||||
|
HttpResponseMessage response = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = await client.SendAsync(requestMessage);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
var Err = ex.Message;
|
||||||
|
var InnerErr = "";
|
||||||
|
if (ex.InnerException != null)
|
||||||
|
InnerErr = ex.InnerException.Message;
|
||||||
|
throw new Exception("PUT error, route: " + route + "\r\nError:" + Err + "\r\nInner error:" + InnerErr + "\r\nStack:" + ex.StackTrace + "\r\nPOSTED OBJECT:\r\n" + putJson);
|
||||||
|
}
|
||||||
|
var responseAsString = await response.Content.ReadAsStringAsync();
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(putJson))
|
||||||
|
putJson = "n/a";
|
||||||
|
throw new Exception("PUT error, code: " + (int)response.StatusCode + ", route: " + route + "\r\n" + responseAsString + "\r\n" + response.ReasonPhrase + "\r\nPUT OBJECT:\r\n" + putJson);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return new ApiResponse() { HttpResponse = response, ObjectResponse = Parse(responseAsString) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class ApiResponse
|
||||||
|
{
|
||||||
|
public HttpResponseMessage HttpResponse { get; set; }
|
||||||
|
public JObject ObjectResponse { get; set; }
|
||||||
|
public string CompactResponse
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ObjectResponse.ToString(Newtonsoft.Json.Formatting.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region QB STUFF
|
||||||
public static List<InvoiceableItem> GetInvoiceableItems()
|
public static List<InvoiceableItem> GetInvoiceableItems()
|
||||||
{
|
{
|
||||||
var random = new Random();
|
var random = new Random();
|
||||||
@@ -66,7 +393,7 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user