Index: binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs
===================================================================
--- binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 394)
+++ binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs	(revision 402)
@@ -1,6 +1,7 @@
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.Net;
-using AllocsFixes.JSON;
+using Utf8Json;
 
 namespace Webserver.WebAPI {
@@ -9,20 +10,28 @@
 
 		public sealed override void HandleRequest (RequestContext _context) {
-			JsonNode jsonBody = null;
+			IDictionary<string, object> inputJson = null;
+			byte[] jsonInputData = null;
+			
+			if (_context.Request.HasEntityBody) {
+				Stream requestInputStream = _context.Request.InputStream;
+				
+				jsonInputData = new byte[_context.Request.ContentLength64];
+				requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64);
+				
+				try {
+					jsonDeserializeSampler.Begin ();
+					inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (jsonInputData);
+					
+					// Log.Out ("JSON body:");
+					// foreach ((string key, object value) in inputJson) {
+					// 	Log.Out ($" - {key} = {value} ({value.GetType ()})");
+					// }
+					
+					jsonDeserializeSampler.End ();
+				} catch (Exception e) {
+					jsonDeserializeSampler.End ();
 
-			if (_context.Request.HasEntityBody) {
-				string body = new StreamReader (_context.Request.InputStream).ReadToEnd ();
-
-				if (!string.IsNullOrEmpty (body)) {
-					try {
-						jsonDeserializeSampler.Begin ();
-						jsonBody = Parser.Parse (body);
-						jsonDeserializeSampler.End ();
-					} catch (Exception e) {
-						jsonDeserializeSampler.End ();
-
-						SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
-						return;
-					}
+					SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
+					return;
 				}
 			}
@@ -31,6 +40,6 @@
 				switch (_context.Request.HttpMethod) {
 					case "GET":
-						if (jsonBody != null) {
-							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "GET_WITH_BODY");
+						if (inputJson != null) {
+							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY");
 							return;
 						}
@@ -40,36 +49,36 @@
 					case "POST":
 						if (!string.IsNullOrEmpty (_context.RequestPath)) {
-							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "POST_WITH_ID");
+							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID");
 							return;
 						}
 
-						if (jsonBody == null) {
-							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
+						if (inputJson == null) {
+							SendErrorResult (_context, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
 							return;
 						}
 
-						HandleRestPost (_context, jsonBody);
+						HandleRestPost (_context, inputJson, jsonInputData);
 						return;
 					case "PUT":
 						if (string.IsNullOrEmpty (_context.RequestPath)) {
-							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "PUT_WITHOUT_ID");
+							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID");
 							return;
 						}
 
-						if (jsonBody == null) {
-							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
+						if (inputJson == null) {
+							SendErrorResult (_context, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
 							return;
 						}
 
-						HandleRestPut (_context, jsonBody);
+						HandleRestPut (_context, inputJson, jsonInputData);
 						return;
 					case "DELETE":
 						if (string.IsNullOrEmpty (_context.RequestPath)) {
-							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "DELETE_WITHOUT_ID");
+							SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID");
 							return;
 						}
 
-						if (jsonBody != null) {
-							SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
+						if (inputJson != null) {
+							SendErrorResult (_context, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
 							return;
 						}
@@ -78,50 +87,50 @@
 						return;
 					default:
-						SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
+						SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
 						return;
 				}
 			} catch (Exception e) {
-				SendEnvelopedResult (_context, null, HttpStatusCode.InternalServerError, jsonBody, "ERROR_PROCESSING", e);
+				SendErrorResult (_context, HttpStatusCode.InternalServerError, jsonInputData, "ERROR_PROCESSING", e);
 			}
 		}
 
-		private static readonly JsonArray emptyData = new JsonArray ();
-
-		protected void SendEnvelopedResult (RequestContext _context, JsonNode _resultData, HttpStatusCode _statusCode = HttpStatusCode.OK,
-			JsonNode _jsonInputBody = null, string _errorCode = null, Exception _exception = null) {
-			JsonObject meta = new JsonObject ();
-
-			meta.Add ("serverTime", new JsonString (DateTime.Now.ToString ("o")));
-			if (!string.IsNullOrEmpty (_errorCode)) {
-				meta.Add ("requestMethod", new JsonString (_context.Request.HttpMethod));
-				meta.Add ("requestSubpath", new JsonString (_context.RequestPath));
-				meta.Add ("requestBody", new JsonString (_jsonInputBody?.ToString () ?? "-empty-"));
-				meta.Add ("errorCode", new JsonString (_errorCode));
-				if (_exception != null) {
-					meta.Add ("exceptionMessage", new JsonString (_exception.Message));
-					meta.Add ("exceptionTrace", new JsonString (_exception.StackTrace));
-				}
-			}
-
-			JsonObject envelope = new JsonObject ();
-			envelope.Add ("meta", meta);
-			envelope.Add ("data", _resultData ?? emptyData);
-
-			WebUtils.WriteJson (_context.Response, envelope, _statusCode);
+		protected void SendErrorResult (RequestContext _context, HttpStatusCode _statusCode, byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
+			PrepareEnvelopedResult (out JsonWriter writer);
+			writer.WriteRaw (JsonEmptyData);
+			SendEnvelopedResult (_context, ref writer, _statusCode, _jsonInputData, _errorCode, _exception);
 		}
 
-		protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out int _value) {
+		static AbsRestApi () {
+			JsonWriter writer = new JsonWriter ();
+			writer.WriteBeginArray ();
+			writer.WriteEndArray ();
+			JsonEmptyData = writer.ToUtf8ByteArray ();
+		}
+
+		protected static readonly byte[] JsonEmptyData;
+		
+		protected void PrepareEnvelopedResult (out JsonWriter _writer) {
+			WebUtils.PrepareEnvelopedResult (out _writer);
+		}
+
+		protected void SendEnvelopedResult (RequestContext _context, ref JsonWriter _writer, HttpStatusCode _statusCode = HttpStatusCode.OK,
+			byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
+			
+			WebUtils.SendEnvelopedResult (_context, ref _writer, _statusCode, _jsonInputData, _errorCode, _exception);
+		}
+
+		protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out int _value) {
 			_value = default;
 			
-			if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
+			if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
 				return false;
 			}
 
-			if (!(fieldNode is JsonValue valueField)) {
+			if (fieldNode is not double value) {
 				return false;
 			}
 
 			try {
-				_value = valueField.AsInt;
+				_value = (int)value;
 				return true;
 			} catch (Exception) {
@@ -130,17 +139,17 @@
 		}
 
-		protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out double _value) {
+		protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out double _value) {
 			_value = default;
 			
-			if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
+			if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
 				return false;
 			}
 
-			if (!(fieldNode is JsonValue valueField)) {
+			if (fieldNode is not double value) {
 				return false;
 			}
 
 			try {
-				_value = valueField.AsDouble;
+				_value = value;
 				return true;
 			} catch (Exception) {
@@ -149,17 +158,17 @@
 		}
 
-		protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out string _value) {
+		protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out string _value) {
 			_value = default;
 			
-			if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
+			if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
 				return false;
 			}
 
-			if (!(fieldNode is JsonValue valueField)) {
+			if (fieldNode is not string value) {
 				return false;
 			}
 
 			try {
-				_value = valueField.AsString;
+				_value = value;
 				return true;
 			} catch (Exception) {
@@ -168,11 +177,19 @@
 		}
 
-		protected abstract void HandleRestGet (RequestContext _context);
+		protected virtual void HandleRestGet (RequestContext _context) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
+		}
 
-		protected abstract void HandleRestPost (RequestContext _context, JsonNode _jsonBody);
+		protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
+		}
 
-		protected abstract void HandleRestPut (RequestContext _context, JsonNode _jsonBody);
+		protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
+		}
 
-		protected abstract void HandleRestDelete (RequestContext _context);
+		protected virtual void HandleRestDelete (RequestContext _context) {
+			SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
+		}
 	}
 }
