Skip to content

Commit dea97b1

Browse files
committed
Version 4.0.0 (.NET 4.7.2)
N.B. This Version is NOT backward compatible. If you upgrade to this version then you must upgrade the Client Side code to implement the strict JSON-RPC specifications. JSON-RPC response structure fixed to implement strict specifications: https://www.jsonrpc.org/specification >> "data" property changed to "result" >> "error.code" changed to type integer >> "error.message" changed to type string >> "error.data" added as type dynamic API.Utility.GetUserAcceptLanguage() added API.Utility.EncodeBase64FromUTF8() added API.Utility.EncodeBase64FromByteArray() added
1 parent e22129a commit dea97b1

File tree

19 files changed

+178
-57
lines changed

19 files changed

+178
-57
lines changed

rls/API.Library.dll

2.5 KB
Binary file not shown.

rls/API.Library.pdb

2 KB
Binary file not shown.

src/API.Library/Entities/JSONRPC.cs

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -137,27 +137,27 @@ public void ProcessRequest(HttpContext context)
137137
this.Authenticate(ref context, ref JSONRPC_Request);
138138

139139
// Get results from the relevant method with the params
140-
dynamic result = GetResult(ref context, JSONRPC_Request);
140+
JSONRPC_Output result = GetResult(ref context, JSONRPC_Request);
141141
if (result == null)
142142
{
143143
JSONRPC_Error error = new JSONRPC_Error { code = -32603 };
144144
this.ParseError(ref context, JSONRPC_Request.id, error);
145145
}
146146
else if (result.error != null)
147147
{
148-
JSONRPC_Error error = new JSONRPC_Error { code = -32099, message = result.error };
148+
JSONRPC_Error error = new JSONRPC_Error { code = -32099, data = result.error };
149149
this.ParseError(ref context, JSONRPC_Request.id, error);
150150
}
151151
else
152152
{
153-
// Check if the request.data is already a JSON type casted as: new JRaw(data);
153+
// Check if the result.data is already a JSON type casted as: new JRaw(data);
154154
var jsonRaw = result.data as JRaw;
155155
if (jsonRaw != null)
156156
{
157157
JSONRPC_API_ResponseDataJRaw output = new JSONRPC_API_ResponseDataJRaw
158158
{
159159
jsonrpc = JSONRPC_Request.jsonrpc,
160-
data = jsonRaw,
160+
result = jsonRaw,
161161
id = JSONRPC_Request.id
162162
};
163163
// Output the JSON-RPC repsonse with JRaw data
@@ -168,7 +168,7 @@ public void ProcessRequest(HttpContext context)
168168
JSONRPC_API_ResponseData output = new JSONRPC_API_ResponseData
169169
{
170170
jsonrpc = JSONRPC_Request.jsonrpc,
171-
data = result.data,
171+
result = result.data,
172172
id = JSONRPC_Request.id
173173
};
174174
// Output the JSON-RPC repsonse
@@ -181,8 +181,7 @@ public void ProcessRequest(HttpContext context)
181181

182182
/// <summary>
183183
/// Parse the API error
184-
/// From -32000 to -32098 reserved for implementation-defined errors.
185-
/// -32099 reserved for application errors
184+
/// From -32000 to -32099 reserved for implementation-defined errors.
186185
/// </summary>
187186
///
188187
/// <param name="response"></param>
@@ -191,37 +190,40 @@ public void ProcessRequest(HttpContext context)
191190
private void ParseError(ref HttpContext context, object id, JSONRPC_Error error)
192191
{
193192
if (error.message == null)
194-
switch (error.code.ToString())
193+
switch (error.code)
195194
{
196195
// Custom codes and messages
197-
case "-32000":
196+
case -32000:
198197
error.message = "Invalid version";
199198
break;
200-
case "-32002":
199+
case -32002:
201200
error.message = "Invalid authentication";
202201
break;
202+
case -32099:
203+
error.message = "Application error";
204+
break;
203205

204206
// Standard codes and messages
205-
case "-32700":
207+
case -32700:
206208
error.message = "Parse error";
207209
break;
208-
case "-32600":
210+
case -32600:
209211
error.message = "Invalid request";
210212
break;
211-
case "-32601":
213+
case -32601:
212214
error.message = "Method not found";
213215
break;
214-
case "-32602":
216+
case -32602:
215217
error.message = "Invalid params";
216218
break;
217-
case "-32603":
219+
case -32603:
218220
default:
219-
error.code = "-32603";
221+
error.code = -32603;
220222
error.message = "Internal error";
221223
break;
222224
}
223225

224-
Log.Instance.Info("IP: " + Utility.IpAddress + ", Error Code: " + error.code + ", Error Message: " + error.message);
226+
Log.Instance.Info("IP: " + Utility.IpAddress + ", Error Code: " + error.code.ToString() + ", Error Message: " + error.message.ToString() + ", Error Data: " + (error.data == null ? "" : error.data.ToString()));
225227
object output = new JSONRPC_ResponseError { jsonrpc = JSONRPC_Version, error = error, id = id };
226228
context.Response.Write(Utility.JsonSerialize_IgnoreLoopingReference(output));
227229
context.Response.End();
@@ -747,12 +749,17 @@ internal class JSONRPC_Error
747749
/// <summary>
748750
/// JSON-RPC error code
749751
/// </summary>
750-
public object code;
752+
public int code;
751753

752754
/// <summary>
753755
/// JSON-RPC error message
754756
/// </summary>
755-
public object message;
757+
public string message;
758+
759+
/// <summary>
760+
/// JSON-RPC error data
761+
/// </summary>
762+
public dynamic data;
756763

757764
#endregion
758765
}
@@ -828,9 +835,9 @@ internal class JSONRPC_API_ResponseData
828835
public object jsonrpc { get; set; }
829836

830837
/// <summary>
831-
/// JSON-RPC data as object
838+
/// JSON-RPC result as object
832839
/// </summary>
833-
public object data { get; set; }
840+
public object result { get; set; }
834841

835842
/// <summary>
836843
/// JSON-RPC id
@@ -852,9 +859,9 @@ internal class JSONRPC_API_ResponseDataJRaw
852859
public object jsonrpc { get; set; }
853860

854861
/// <summary>
855-
/// JSON-RPC data as raw json
862+
/// JSON-RPC result as raw json
856863
/// </summary>
857-
public JRaw data { get; set; }
864+
public JRaw result { get; set; }
858865

859866
/// <summary>
860867
/// JSON-RPC id

src/API.Library/Entities/ReCAPTCHA.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
using System.Net;
2-
using Newtonsoft.Json;
3-
using Newtonsoft.Json.Linq;
1+
using Newtonsoft.Json.Linq;
42
using System;
53
using System.Configuration;
4+
using System.Net;
65

76
namespace API
87
{
@@ -87,10 +86,10 @@ public static bool Validate(string encodedResponse)
8786
catch (Exception e)
8887
{
8988
Log.Instance.Fatal(e);
90-
throw;
89+
return false;
9190
}
9291
}
9392

9493
#endregion
9594
}
96-
}
95+
}

src/API.Library/Entities/Utility.cs

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using log4net;
22
using Newtonsoft.Json;
33
using System;
4+
using System.Collections.Generic;
45
using System.Collections.Specialized;
56
using System.Configuration;
7+
using System.Globalization;
68
using System.IO;
79
using System.IO.Compression;
810
using System.Linq;
@@ -203,7 +205,69 @@ public static string GetCustomConfig(string key)
203205
}
204206

205207
/// <summary>
206-
/// Decode a base64 data into a UTF8 string
208+
/// Encode a byte array into a base64 string
209+
/// N.B. UFT8 in C# includes UTF16 too
210+
/// </summary>
211+
/// <param name="data"></param>
212+
/// <returns></returns>
213+
public static string EncodeBase64FromByteArray(byte[] byteArray, string mimeType = null)
214+
{
215+
try
216+
{
217+
if (byteArray == null)
218+
{
219+
return null;
220+
}
221+
222+
if (String.IsNullOrEmpty(mimeType))
223+
{
224+
return System.Convert.ToBase64String(byteArray);
225+
}
226+
else
227+
{
228+
return "data:" + mimeType + ";base64," + System.Convert.ToBase64String(byteArray);
229+
}
230+
}
231+
catch (Exception)
232+
{
233+
//Do not trow nor log. Instead, return null if data cannot be decoded
234+
return null;
235+
}
236+
}
237+
238+
/// <summary>
239+
/// Encode a string into a base64 string
240+
/// N.B. UFT8 in C# includes UTF16 too
241+
/// </summary>
242+
/// <param name="data"></param>
243+
/// <returns></returns>
244+
public static string EncodeBase64FromUTF8(string data, string mimeType = null)
245+
{
246+
try
247+
{
248+
if (String.IsNullOrEmpty(data))
249+
{
250+
return null;
251+
}
252+
253+
if (String.IsNullOrEmpty(mimeType))
254+
{
255+
return System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(data));
256+
}
257+
else
258+
{
259+
return "data:" + mimeType + ";base64," + System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(data));
260+
}
261+
}
262+
catch (Exception)
263+
{
264+
//Do not trow nor log. Instead, return null if data cannot be decoded
265+
return null;
266+
}
267+
}
268+
269+
/// <summary>
270+
/// Decode a base64 string into a UTF8 string
207271
/// N.B. UFT8 in C# includes UTF16 too
208272
/// </summary>
209273
/// <param name="data"></param>
@@ -217,10 +281,10 @@ public static string DecodeBase64ToUTF8(string data)
217281
return null;
218282
}
219283

220-
if (data.ToLower().Contains("base64,"))
284+
if (data.ToLower().Contains(";base64,"))
221285
{
222286
// i.e. data:*/*;base64,cdsckdslfkdsfos
223-
data = data.Split(new[] { "base64," }, StringSplitOptions.None)[1];
287+
data = data.Split(new[] { ";base64," }, StringSplitOptions.None)[1];
224288
}
225289

226290
return Encoding.UTF8.GetString(Convert.FromBase64String(data));
@@ -283,6 +347,47 @@ public static string GZipDecompress(string inputBase64)
283347
return Encoding.UTF8.GetString(msOutput.ToArray());
284348
}
285349
}
350+
351+
/// <summary>
352+
/// Get the User's enviornment language from the http request Accept Languages
353+
/// C# code reverse engineered from JS https://github.com/opentable/accept-language-parser/
354+
/// </summary>
355+
/// <returns></returns>
356+
public static string GetUserAcceptLanguage()
357+
{
358+
List<string> acceptLanguages = HttpContext.Current.Request.UserLanguages.ToList<string>();
359+
List<dynamic> outLanguages = new List<dynamic>();
360+
361+
if (acceptLanguages.Count() == 0)
362+
{
363+
acceptLanguages.Add(CultureInfo.CurrentCulture.Name);
364+
}
365+
acceptLanguages.Add(CultureInfo.CurrentCulture.Name);
366+
foreach (string al in acceptLanguages)
367+
{
368+
369+
string[] bits = al.Split(';');
370+
string[] ietf = bits[0].Split('-');
371+
bool hasScript = ietf.Length == 3;
372+
string q = "1.0";
373+
374+
if (bits.Count() > 1)
375+
{
376+
string[] innerBits = bits[1].Split('=');
377+
q = innerBits.Count() > 1 ? innerBits[1] : "1.0";
378+
}
379+
380+
outLanguages.Add(new
381+
{
382+
code = ietf[0],
383+
script = hasScript && ietf.Count() > 1 ? ietf[1] : null,
384+
region = hasScript && ietf.Count() > 2 ? ietf[2] : (ietf.Count() > 1 ? ietf[1] : null),
385+
quality = Convert.ToDouble(q)
386+
});
387+
}
388+
389+
return outLanguages.OrderByDescending(x => x.quality).FirstOrDefault().code;
390+
}
286391
#endregion
287392
}
288393
}

src/API.Library/Entities/eMail/eMail.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public class eMail : MailMessage
6868
/// Send an Email
6969
/// </summary>
7070
/// <returns></returns>
71-
public void Send()
71+
public bool Send()
7272
{
7373
Log.Instance.Info("Email Enabled: " + API_EMAIL_ENABLED);
7474
Log.Instance.Info("Email NoReply: " + API_EMAIL_MAIL_NOREPLY);
@@ -82,7 +82,7 @@ public void Send()
8282

8383
if (!API_EMAIL_ENABLED)
8484
{
85-
return;
85+
return false;
8686
}
8787

8888
try
@@ -119,11 +119,12 @@ public void Send()
119119
smtpClient.Send(this);
120120

121121
Log.Instance.Info("eMail sent");
122+
return true;
122123
}
123124
catch (Exception e)
124125
{
125126
Log.Instance.Fatal(e);
126-
throw;
127+
return false;
127128
}
128129
}
129130

@@ -185,4 +186,4 @@ public eMail_KeyValuePair()
185186
}
186187
}
187188

188-
}
189+
}

src/API.Library/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("3.0.6.0")]
36-
[assembly: AssemblyFileVersion("3.0.6.0")]
35+
[assembly: AssemblyVersion("4.0.0.0")]
36+
[assembly: AssemblyFileVersion("4.0.0.0")]
3737

3838
// Configure log4net using the Web.config file by default
3939
[assembly: log4net.Config.XmlConfigurator(Watch = true)]

test/API.Test/API.Test.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@
7171
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
7272
</PropertyGroup>
7373
<ItemGroup>
74-
<Reference Include="API.Library, Version=3.0.6.0, Culture=neutral, processorArchitecture=MSIL">
74+
<Reference Include="API.Library, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
7575
<SpecificVersion>False</SpecificVersion>
76-
<HintPath>..\packages\API.Library.3.0.6\API.Library.dll</HintPath>
76+
<HintPath>..\packages\API.Library.4.0.0\API.Library.dll</HintPath>
7777
</Reference>
7878
<Reference Include="Enyim.Caching, Version=2.16.0.0, Culture=neutral, PublicKeyToken=cec98615db04012e, processorArchitecture=MSIL">
7979
<HintPath>..\packages\EnyimMemcached.2.16.0\lib\net35\Enyim.Caching.dll</HintPath>

test/API.Test/Entities/Sample/ADO.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using System;
1+
using API;
2+
using System;
23
using System.Collections.Generic;
3-
using API;
44

55
namespace Sample
66
{

0 commit comments

Comments
 (0)