From: gu.martinm@gmail.com Date: Sat, 1 Mar 2014 00:15:30 +0000 (+0100) Subject: Remote Agents Mono Implementation: JSONRPC4NET implementation (kind of) X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=6a3a3d458a6640a6401855872e1e39f0a85953bc;p=CSharpForFun%2F.git Remote Agents Mono Implementation: JSONRPC4NET implementation (kind of) --- diff --git a/Mono/RemoteAgents/GTKLinux/GTKLinux.csproj b/Mono/RemoteAgents/GTKLinux/GTKLinux.csproj index 6926b21..feea786 100644 --- a/Mono/RemoteAgents/GTKLinux/GTKLinux.csproj +++ b/Mono/RemoteAgents/GTKLinux/GTKLinux.csproj @@ -54,16 +54,19 @@ through JSON API. False + + ..\..\jsonrpc4net\jsonrpc4net\bin\Debug\jsonrpc4net.dll + + + ..\..\..\..\..\..\..\usr\mymono\custom\log4net-1.2.13\cli\1.0\log4net.dll + - ..\..\..\..\..\..\..\..\usr\mymono\lib\mono\4.5\System.Net.Http.dll + ..\..\..\..\..\..\..\usr\mymono\lib\mono\4.5\System.Net.Http.dll monodevelop True - - ..\..\..\..\..\..\..\usr\mymono\custom\log4net-1.2.13\cli\1.0\log4net.dll - @@ -75,7 +78,6 @@ through JSON API. - Program.cs diff --git a/Mono/RemoteAgents/GTKLinux/MainWindow.cs b/Mono/RemoteAgents/GTKLinux/MainWindow.cs index 44acec5..6e5498c 100644 --- a/Mono/RemoteAgents/GTKLinux/MainWindow.cs +++ b/Mono/RemoteAgents/GTKLinux/MainWindow.cs @@ -1,6 +1,5 @@ using System; using Gtk; -using System.Net.Http; using System.Threading.Tasks; using Example.RemoteAgents.GTKLinux.View; using log4net; @@ -9,15 +8,14 @@ namespace Example.RemoteAgents.GTKLinux { public partial class MainWindow: Gtk.Window { - ViewImpl view; + private readonly ViewImpl _view; private static readonly ILog logger = LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public MainWindow () : base (Gtk.WindowType.Toplevel) { - view = new ViewImpl(); + _view = new ViewImpl(); Build (); - this.RetrieveRemoteDateButton.Clicked += this.ButtonClicked; this.ButtonGetDate.Clicked += this.ButtonGetDateClicked; } @@ -27,18 +25,10 @@ namespace Example.RemoteAgents.GTKLinux a.RetVal = true; } - async private void ButtonClicked(object sender, EventArgs a) - { - using (HttpClient client = new HttpClient ()) { - Task resultGET = client.GetStringAsync ("http://gumartinm.name"); - this.RemoteDate.Buffer.Text = await resultGET; - } - } - async private void ButtonGetDateClicked(object sender, EventArgs a) { try { - string currentDate = await view.GetCurrentDateAsync(); + string currentDate = await _view.GetCurrentDateAsync(); if (currentDate != null) { this.RemoteDate.Buffer.Text = currentDate; diff --git a/Mono/RemoteAgents/GTKLinux/Model/CallRemoteProcedure.cs b/Mono/RemoteAgents/GTKLinux/Model/CallRemoteProcedure.cs deleted file mode 100644 index f444c0d..0000000 --- a/Mono/RemoteAgents/GTKLinux/Model/CallRemoteProcedure.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Reflection; -using System.Runtime.Remoting.Lifetime; -using System.Runtime.Remoting.Messaging; -using System.Security.Cryptography.X509Certificates; -using System.Threading.Tasks; -using Gtk; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; -using System.Threading; -using log4net; - -namespace Example.RemoteAgents.GTKLinux.Model -{ - public class CallRemoteProcedure - { - private static readonly ILog logger = LogManager.GetLogger( - System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - async public Task PostRemoteServiceAsync(string uri, string method) - { - POSTResult postResult = await this.PostAsync(uri, method, CancellationToken.None); - - return postResult.result; - } - - async private Task> PostAsync(string uri, string method, CancellationToken cancellation) - { - var postData = new POST(); - postData.id = "2114567586433855105"; - postData.jsonrpc = "2.0"; - postData.method = method; - var jsonSettings = new JsonSerializerSettings{ - Error = delegate(object sender, ErrorEventArgs args) - { - logger.Error(args.ErrorContext.Error.Message); - args.ErrorContext.Handled = true; - } - }; - - string data = JsonConvert.SerializeObject(postData, jsonSettings); - - // see: http://stackoverflow.com/questions/1329739/nested-using-statements-in-c-sharp - // see: http://stackoverflow.com/questions/5895879/when-do-we-need-to-call-dispose-in-dot-net-c - //TODO: Am I really sure I have to call the Dispose method of HttpContent content. In this case shouldn't it be stupid? - // for HttpResponseMessage response I am sure I have to do it but I am not for HttpContent content. - using (HttpContent content = new StringContent(data, System.Text.Encoding.UTF8, "application/json-rpc")) - using (HttpResponseMessage response = await this.PostAsync(uri, content, cancellation)) - { - POSTResult postResult = new POSTResult(); - - if (response.StatusCode == HttpStatusCode.OK) { - byte[] responseBytes = await response.Content.ReadAsByteArrayAsync(); - string responseString = System.Text.Encoding.UTF8.GetString(responseBytes); - - postResult = JsonConvert.DeserializeObject>(responseString, jsonSettings); - } - - return postResult; - } - } - - /// - /// Send a POST request to the specified Uri as an asynchronous operation. - /// - /// The Uri the request is sent to. - /// The HTTP request content sent to the server. - /// Cancellation token. - /// When some error. - /// System.Threading.Tasks.Task]]>.The task object representing the asynchronous operation. - async private Task PostAsync(string uri, HttpContent content, CancellationToken cancellation) - { - using (HttpClient client = new HttpClient{ Timeout = TimeSpan.FromSeconds(5)}) - { - return await client.PostAsync(uri, content, cancellation); - } - } - - private class POST - { - public string id { get; set; } - public string jsonrpc { get; set; } - public string method { get; set; } - } - - - private class POSTResult - { - public string id { get; set; } - public string jsonrpc { get; set; } - public TResult result { get; set; } - } - - // TODO: When error I receive from JSONRPC: {"jsonrpc":"2.0","id":"null","error":{"code":-32600,"message":"Invalid Request"}} - private class Error - { - public int code { get; set; } - public string message { get; set; } - } - - private class ERRORResult - { - public string jsonrpc { get; set; } - public string id { get; set; } - public Error error { get; set; } - } - } -} - diff --git a/Mono/RemoteAgents/GTKLinux/View/View.cs b/Mono/RemoteAgents/GTKLinux/View/View.cs index 93660f2..e423c2d 100644 --- a/Mono/RemoteAgents/GTKLinux/View/View.cs +++ b/Mono/RemoteAgents/GTKLinux/View/View.cs @@ -7,11 +7,11 @@ namespace Example.RemoteAgents.GTKLinux.View { public class ViewImpl { - private static readonly ViewModelImpl vm = new ViewModelImpl(); + private readonly ViewModelImpl _vm = new ViewModelImpl(); async public Task GetCurrentDateAsync() { - return await vm.GetCurrentDateAsync(); + return await _vm.GetCurrentDateAsync(); } } } diff --git a/Mono/RemoteAgents/GTKLinux/ViewModel/ViewModel.cs b/Mono/RemoteAgents/GTKLinux/ViewModel/ViewModel.cs index e21730c..704fe6b 100644 --- a/Mono/RemoteAgents/GTKLinux/ViewModel/ViewModel.cs +++ b/Mono/RemoteAgents/GTKLinux/ViewModel/ViewModel.cs @@ -1,17 +1,18 @@ using System; using System.Threading.Tasks; -using Example.RemoteAgents.GTKLinux.Model; +using GumartinM.JsonRPC4Mono; +using System.ComponentModel; namespace Example.RemoteAgents.GTKLinux.ViewModel { public class ViewModelImpl { - private static readonly string uri = "http://gumartinm.name/spring-mainapp/CurrentDateService.json"; - private readonly CallRemoteProcedure remoteProcedure = new CallRemoteProcedure(); + private static readonly string uri = "http://127.0.0.1:8080/spring-mainapp/CurrentDateService.json"; + private readonly JsonRpcHttpAsyncClient _remoteClient = new JsonRpcHttpAsyncClient(); async public Task GetCurrentDateAsync() { - return await remoteProcedure.PostRemoteServiceAsync(uri, "getCurrentDate"); + return await _remoteClient.PostRemoteServiceAsync(uri, "getCurrentDate"); } } } diff --git a/Mono/jsonrpc4net/jsonrpc4net.sln b/Mono/jsonrpc4net/jsonrpc4net.sln new file mode 100644 index 0000000..41c9388 --- /dev/null +++ b/Mono/jsonrpc4net/jsonrpc4net.sln @@ -0,0 +1,21 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "jsonrpc4net", "jsonrpc4net\jsonrpc4net.csproj", "{0C624E8F-9C80-457F-A7D1-39FA29E23F79}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0C624E8F-9C80-457F-A7D1-39FA29E23F79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C624E8F-9C80-457F-A7D1-39FA29E23F79}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C624E8F-9C80-457F-A7D1-39FA29E23F79}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C624E8F-9C80-457F-A7D1-39FA29E23F79}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = jsonrpc4net\jsonrpc4net.csproj + description = jsonrpc4net library implementation (just for fun) + EndGlobalSection +EndGlobal diff --git a/Mono/jsonrpc4net/jsonrpc4net/ExceptionResolver.cs b/Mono/jsonrpc4net/jsonrpc4net/ExceptionResolver.cs new file mode 100644 index 0000000..81b8d81 --- /dev/null +++ b/Mono/jsonrpc4net/jsonrpc4net/ExceptionResolver.cs @@ -0,0 +1,66 @@ +using System; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; + +namespace GumartinM.JsonRPC4Mono +{ + public class ExceptionResolver + { + /// + /// Resolves the exception. + /// + /// The exception. + /// Error token. + public Exception ResolveException(JToken errorToken) + { + JObject errorData = (JObject) errorToken; + IDictionary errorTokens = errorData; + + if (!errorTokens.ContainsKey("data")) + { + return CreateJsonRpcClientException(errorToken); + } + + JToken dataToken = errorToken["data"]; + JObject data = (JObject) dataToken; + errorTokens = data; + + if (!errorTokens.ContainsKey("exceptionTypeName")) + { + return CreateJsonRpcClientException(errorToken); + } + + string exceptionTypeName = data["exceptionTypeName"].Value(); + string message = data.Value("message"); + + Exception endException = CreateException(exceptionTypeName, message); + + return endException; + } + + /// + /// Creates the json rpc client exception. + /// + /// The json rpc client exception. + /// Error token. + private JsonRpcClientException CreateJsonRpcClientException(JToken errorToken) + { + return new JsonRpcClientException( + errorToken.Value("code") ?? 0, + errorToken.Value("message"), + errorToken.SelectToken("data")); + } + + /// + /// Creates the exception. + /// + /// The exception. + /// Exception type name. + /// Message. + private Exception CreateException(string exceptionTypeName, string message) + { + return new Exception("Remote exception: " + exceptionTypeName + "Message: " + message); + } + } +} + diff --git a/Mono/jsonrpc4net/jsonrpc4net/JsonRpcClientException.cs b/Mono/jsonrpc4net/jsonrpc4net/JsonRpcClientException.cs new file mode 100644 index 0000000..31b7985 --- /dev/null +++ b/Mono/jsonrpc4net/jsonrpc4net/JsonRpcClientException.cs @@ -0,0 +1,58 @@ +using System; +using System.Runtime.Serialization; +using Newtonsoft.Json.Linq; + +namespace GumartinM.JsonRPC4Mono +{ + public class JsonRpcClientException : System.Exception, ISerializable + { + /// + /// The _code. + /// + private readonly int _code; + + /// + /// The _data. + /// + private readonly JToken _data; + + /// + /// Initializes a new instance of the class. + /// + /// Code. + /// Message. + /// Data. + public JsonRpcClientException(int code, String message, JToken data) : base(message) + { + _code = code; + _data = data; + } + + /// + /// Initializes a new instance of the class. + /// + /// Info. + /// Context. + protected JsonRpcClientException(SerializationInfo info, StreamingContext context) + { + // TODO + } + + /// + /// Gets the code. + /// + /// The code. + public int getCode() { + return _code; + } + + /// + /// Gets the data. + /// + /// The data. + public JToken getData() { + return _data; + } + } +} + diff --git a/Mono/jsonrpc4net/jsonrpc4net/JsonRpcHttpAsyncClient.cs b/Mono/jsonrpc4net/jsonrpc4net/JsonRpcHttpAsyncClient.cs new file mode 100644 index 0000000..a2ad1dc --- /dev/null +++ b/Mono/jsonrpc4net/jsonrpc4net/JsonRpcHttpAsyncClient.cs @@ -0,0 +1,154 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using System.Threading; +using log4net; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System.Net; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; + +namespace GumartinM.JsonRPC4Mono +{ + public class JsonRpcHttpAsyncClient + { + private long _nextId; + + /// + /// The logger. + /// + private static readonly ILog logger = LogManager.GetLogger( + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// The _json settings. + /// + private readonly JsonSerializerSettings _jsonSettings = + new JsonSerializerSettings{ + Error = delegate(object sender, ErrorEventArgs args) + { + logger.Error(args.ErrorContext.Error.Message); + args.ErrorContext.Handled = true; + } + }; + + /// + /// The _exception resolver. + /// + private readonly ExceptionResolver _exceptionResolver = new ExceptionResolver(); + + + + /// + /// Posts the remote service async. + /// + /// The remote service async. + /// URI. + /// Method. + /// The 1st type parameter. + async public Task PostRemoteServiceAsync(string uri, string method) + { + POSTResult postResult = await this.PostAsync(uri, method, CancellationToken.None); + + return postResult.result; + } + + /// + /// Posts the async. + /// + /// The async. + /// URI. + /// Method. + /// Cancellation. + /// The 1st type parameter. + async private Task> PostAsync(string uri, string method, CancellationToken cancellation) + { + var postData = new POST(); + postData.id = Interlocked.Increment(ref _nextId).ToString(); + postData.jsonrpc = "2.0"; + postData.method = method; + + string data = JsonConvert.SerializeObject(postData, _jsonSettings); + + // see: http://stackoverflow.com/questions/1329739/nested-using-statements-in-c-sharp + // see: http://stackoverflow.com/questions/5895879/when-do-we-need-to-call-dispose-in-dot-net-c + //TODO: Am I really sure I have to call the Dispose method of HttpContent content? In this case, shouldn't it be stupid? + // For HttpResponseMessage response I am sure I have to do it but I am not for HttpContent content. + using (HttpContent content = new StringContent(data, System.Text.Encoding.UTF8, "application/json-rpc")) + using (HttpResponseMessage response = await this.PostAsync(uri, content, cancellation)) + { + + if (response.StatusCode == HttpStatusCode.OK) { + byte[] jsonBytes = await response.Content.ReadAsByteArrayAsync(); + + return this.ReadResponse(jsonBytes); + } + + throw new Exception("Unexpected response code: " + response.StatusCode); + } + } + + /// + /// Reads the response. + /// + /// The response. + /// Json bytes. + /// The 1st type parameter. + private POSTResult ReadResponse(byte[] jsonBytes) + { + POSTResult postResult = new POSTResult(); + + string json = System.Text.Encoding.UTF8.GetString(jsonBytes); + + JObject jsonObjects = JObject.Parse(json); + IDictionary jsonTokens = jsonObjects; + + + if (jsonTokens.ContainsKey("error")) + { + throw _exceptionResolver.ResolveException(jsonObjects["error"]); + } + + if (jsonTokens.ContainsKey("result")) + { + postResult = JsonConvert.DeserializeObject>(json, _jsonSettings); + } + + return postResult; + } + + /// + /// Send a POST request to the specified Uri as an asynchronous operation. + /// + /// The Uri the request is sent to. + /// The HTTP request content sent to the server. + /// Cancellation token. + /// When some error. + /// System.Threading.Tasks.Task]]>.The task object representing the asynchronous operation. + async private Task PostAsync(string uri, HttpContent content, CancellationToken cancellation) + { + using (HttpClient client = new HttpClient{ Timeout = TimeSpan.FromSeconds(5)}) + { + // TODO: cancellation + return await client.PostAsync(uri, content, cancellation); + } + } + + private class POST + { + public string id { get; set; } + public string jsonrpc { get; set; } + public string method { get; set; } + } + + + private class POSTResult + { + public string id { get; set; } + public string jsonrpc { get; set; } + public TResult result { get; set; } + } + } +} + diff --git a/Mono/jsonrpc4net/jsonrpc4net/Properties/AssemblyInfo.cs b/Mono/jsonrpc4net/jsonrpc4net/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c842ef8 --- /dev/null +++ b/Mono/jsonrpc4net/jsonrpc4net/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle("jsonrpc4net")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("gustavo")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/Mono/jsonrpc4net/jsonrpc4net/jsonrpc4net.csproj b/Mono/jsonrpc4net/jsonrpc4net/jsonrpc4net.csproj new file mode 100644 index 0000000..1de2357 --- /dev/null +++ b/Mono/jsonrpc4net/jsonrpc4net/jsonrpc4net.csproj @@ -0,0 +1,53 @@ + + + + Debug + AnyCPU + 12.0.0 + 2.0 + {0C624E8F-9C80-457F-A7D1-39FA29E23F79} + Library + GumartinM.JsonRPC4Mono + jsonrpc4net + v4.5 + Dirty implementation of JSON RPC. Just trying to learn how +to use C#. + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + ..\..\..\..\..\..\..\usr\mymono\lib\mono\4.5\System.Net.Http.dll + + + ..\..\..\..\..\..\..\usr\mymono\custom\log4net-1.2.13\cli\1.0\log4net.dll + + + monodevelop + + + + + + + + + + \ No newline at end of file