diff --git a/Samples/Serialization/Program.cs b/Samples/Serialization/Program.cs index f978e85..21e626d 100644 --- a/Samples/Serialization/Program.cs +++ b/Samples/Serialization/Program.cs @@ -55,7 +55,7 @@ class ImageProcessingAPI Bgr[,] image = null; try { image = imgUrl.GetBytes().DecodeAsColorImage(); } - catch { throw new Exception("The specified url does not point to a valid image."); } + catch(Exception ex) { throw new Exception("The specified url does not point to a valid image."); } image.Apply(c => swapChannels(c, order), inPlace: true); return image; @@ -66,24 +66,26 @@ unsafe Bgr swapChannels(Bgr c, int[] order) var uC = (byte*)Unsafe.AsPointer(ref c); var swapC = new Bgr(uC[order[0]], uC[order[1]], uC[order[2]]); return swapC; - } + } } class Program { - //if access denied execute: "netsh http delete urlacl url=http://+:8001/" + //if access denied execute: "cmd" //open Index.html to run the client static void Main(string[] args) { + Directory.SetCurrentDirectory(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)); + RPCSettings.MaxMessageSize = 1 * 1024 * 1024; //1MiB RPCSettings.AddConverter(new JpgBase64Converter()); //generate js code - File.WriteAllText($"../Site/{nameof(ImageProcessingAPI)}.js", RPCJs.GenerateCallerWithDoc()); + File.WriteAllText($"../../Site/{nameof(ImageProcessingAPI)}.js", RPCJs.GenerateCallerWithDoc()); //start server and bind its local and remote API var cts = new CancellationTokenSource(); - Server.ListenAsync("http://localhost:8001/", cts.Token, (c, ws) => c.Bind(new ImageProcessingAPI())).Wait(0); + Server.ListenAsync("http://localhost:8001/", cts.Token, (c, ws) => c.Bind(new ImageProcessingAPI())).Wait(); Console.Write("Running: '{0}'. Press [Enter] to exit.", nameof(ServerClientJsSerialization)); Console.ReadLine(); diff --git a/Samples/Serialization/Serialization.csproj b/Samples/Serialization/Serialization.csproj index f52989c..0d7a196 100644 --- a/Samples/Serialization/Serialization.csproj +++ b/Samples/Serialization/Serialization.csproj @@ -10,6 +10,14 @@ Exe + + + AnyCPU + + + + AnyCPU + diff --git a/Source/WebSocketRPC.Base/Invokers/LocalInvoker.cs b/Source/WebSocketRPC.Base/Invokers/LocalInvoker.cs index dad67e5..a2db95a 100644 --- a/Source/WebSocketRPC.Base/Invokers/LocalInvoker.cs +++ b/Source/WebSocketRPC.Base/Invokers/LocalInvoker.cs @@ -59,7 +59,7 @@ static void verifyType(MethodInfo[] methodList) { //check constraints if (typeof(TObj).IsInterface) - throw new Exception("The specified type must be a object type."); + throw new Exception("The specified type must be a class."); var overloadedMethodNames = methodList.GroupBy(x => x.Name) .DefaultIfEmpty() @@ -71,20 +71,31 @@ static void verifyType(MethodInfo[] methodList) var propertyList = typeof(TObj).GetProperties(BindingFlags.Public | BindingFlags.Instance); if (propertyList.Any()) - throw new NotSupportedException("The interface must not declare any properties: " + String.Join(", ", propertyList.Select(x => x.Name)) + "."); + throw new NotSupportedException("The class must not declare any properties: " + String.Join(", ", propertyList.Select(x => x.Name)) + "."); } public async Task InvokeAsync(TObj obj, Request clientMessage) { - var (result, error) = await invokeAsync(obj, clientMessage.FunctionName, clientMessage.Arguments); + JToken result = null; + Exception error = null; + + try + { + result = await invokeAsync(obj, clientMessage.FunctionName, clientMessage.Arguments); + } + catch (Exception ex) + { + while (ex.InnerException != null) ex = ex.InnerException; + error = ex; + } return new Response { FunctionName = clientMessage.FunctionName, ReturnValue = result, Error = error?.Message }; } - async Task<(JToken Result, Exception Error)> invokeAsync(TObj obj, string functionName, JToken[] args) + async Task invokeAsync(TObj obj, string functionName, JToken[] args) { if (!methods.ContainsKey(functionName)) - throw new ArgumentException(functionName + ": The object does not contain the provided method name: " + functionName + "."); + throw new ArgumentException(functionName + ": The object does not contain the provided method name: " + functionName + "."); var methodParams = methods[functionName].GetParameters(); if (methodParams.Length != args.Length) @@ -94,30 +105,23 @@ public async Task InvokeAsync(TObj obj, Request clientMessage) for (int i = 0; i < methodParams.Length; i++) argObjs[i] = args[i].ToObject(methodParams[i].ParameterType, RPCSettings.Serializer); - try + + var hasResult = methods[functionName].ReturnType != typeof(void) && + methods[functionName].ReturnType != typeof(Task); + + JToken result = null; + if (hasResult) { - var hasResult = methods[functionName].ReturnType != typeof(void) && - methods[functionName].ReturnType != typeof(Task); - - JToken result = null; - if (hasResult) - { - var returnVal = await invokeWithResultAsync(methods[functionName], obj, argObjs); - result = (returnVal != null) ? JToken.FromObject(returnVal, RPCSettings.Serializer) : null; - } - else - { - await invokeAsync(methods[functionName], obj, argObjs); - result = JToken.FromObject(true); - } - - return (result, null); + var returnVal = await invokeWithResultAsync(methods[functionName], obj, argObjs); + result = (returnVal != null) ? JToken.FromObject(returnVal, RPCSettings.Serializer) : null; } - catch (Exception ex) + else { - while (ex.InnerException != null) ex = ex.InnerException; - return (null, ex); + await invokeAsync(methods[functionName], obj, argObjs); + result = JToken.FromObject(true); } + + return result; } async Task invokeAsync(MethodInfo method, TObj obj, object[] args) diff --git a/Source/WebsocketRPC.Standalone/ClientServer/Server.cs b/Source/WebsocketRPC.Standalone/ClientServer/Server.cs index 0819a06..f8d4f80 100644 --- a/Source/WebsocketRPC.Standalone/ClientServer/Server.cs +++ b/Source/WebsocketRPC.Standalone/ClientServer/Server.cs @@ -24,7 +24,6 @@ #endregion using System; -using System.Collections.Generic; using System.Net; using System.Net.WebSockets; using System.Threading; @@ -45,6 +44,23 @@ public static class Server /// Action executed when connection is created. /// Server task. public static async Task ListenAsync(string httpListenerPrefix, CancellationToken token, Action onConnect) + { + await ListenAsync(httpListenerPrefix, token, onConnect, (rq, rp) => + { + rp.StatusCode = (int)HttpStatusCode.BadRequest; + }); + } + + /// + /// Creates and starts a new instance of the http / websocket server. + /// All HTTP requests will have the 'BadRequest' response. + /// + /// The http/https URI listening prefix. + /// Cancellation token. + /// Action executed when connection is created. + /// Action executed on HTTP request. + /// Server task. + public static async Task ListenAsync(string httpListenerPrefix, CancellationToken token, Action onConnect, Action onHttpRequest) { var listener = new HttpListener(); listener.Prefixes.Add(httpListenerPrefix); @@ -60,7 +76,7 @@ public static async Task ListenAsync(string httpListenerPrefix, CancellationToke } else { - listenerContext.Response.StatusCode = 400; + onHttpRequest(listenerContext.Request, listenerContext.Response); listenerContext.Response.Close(); } diff --git a/WebsocketRPC.sln b/WebsocketRPC.sln index 1d6c3bc..61fb2a4 100644 --- a/WebsocketRPC.sln +++ b/WebsocketRPC.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.16 +VisualStudioVersion = 15.0.27004.2005 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{3CE373E0-6D9A-48C4-808D-510E6FB69D5C}" EndProject @@ -10,29 +10,29 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{E550 Samples\README.md = Samples\README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsocketRPC.Standalone", "Source\WebsocketRPC.Standalone\WebsocketRPC.Standalone.csproj", "{AB4A5DDF-1F91-4AF8-9E9C-242832576C5E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebsocketRPC.Standalone", "Source\WebsocketRPC.Standalone\WebsocketRPC.Standalone.csproj", "{AB4A5DDF-1F91-4AF8-9E9C-242832576C5E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebSocketRPC.Js", "Source\WebSocketRPC.JS\WebSocketRPC.Js.csproj", "{965791BF-8F77-4A69-97E2-8B6B66CF9863}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSocketRPC.Js", "Source\WebSocketRPC.JS\WebSocketRPC.Js.csproj", "{965791BF-8F77-4A69-97E2-8B6B66CF9863}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ServerClientSample", "ServerClientSample", "{E4A64C0A-0127-42AD-A439-2063A145F536}" ProjectSection(SolutionItems) = preProject Samples\ServerClientSample\Run.bat = Samples\ServerClientSample\Run.bat EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerClientJs", "Samples\ClientJs\ServerClientJs.csproj", "{C0449FA5-C667-4B5C-878A-04773903B130}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerClientJs", "Samples\ClientJs\ServerClientJs.csproj", "{C0449FA5-C667-4B5C-878A-04773903B130}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Samples\ServerClientSample\Client\Client.csproj", "{E0DBB446-3B2B-4BC2-871F-925AB60917E3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Samples\ServerClientSample\Client\Client.csproj", "{E0DBB446-3B2B-4BC2-871F-925AB60917E3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Samples\ServerClientSample\Server\Server.csproj", "{841054C8-559B-4E6F-8DCD-44C2D3DA2F0B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Samples\ServerClientSample\Server\Server.csproj", "{841054C8-559B-4E6F-8DCD-44C2D3DA2F0B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{26CCD24E-8415-4FD5-8AB3-17433A265B08}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.exe = .nuget\NuGet.exe EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultiService", "Samples\MultiService\MultiService.csproj", "{2B69F62E-991C-4E4B-B1FF-2A5906415764}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiService", "Samples\MultiService\MultiService.csproj", "{2B69F62E-991C-4E4B-B1FF-2A5906415764}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serialization", "Samples\Serialization\Serialization.csproj", "{9F82F6DD-238B-4F65-A95C-55F2BA20F1B0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serialization", "Samples\Serialization\Serialization.csproj", "{9F82F6DD-238B-4F65-A95C-55F2BA20F1B0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6B3680DB-211E-492C-BC67-46FF1F00A730}" ProjectSection(SolutionItems) = preProject @@ -55,9 +55,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{CBCEF1A5 EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "WebSocketRPC.Base", "Source\WebSocketRPC.Base\WebSocketRPC.Base.shproj", "{EAEBAA06-D5BB-4106-8694-C022832175D6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebSocketRPC.AspCore", "Source\WebSocketRPC.AspCore\WebSocketRPC.AspCore.csproj", "{CE4BAD88-2358-4B3D-8A34-90A74C73E521}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSocketRPC.AspCore", "Source\WebSocketRPC.AspCore\WebSocketRPC.AspCore.csproj", "{CE4BAD88-2358-4B3D-8A34-90A74C73E521}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspRpc", "Samples\AspRpc\AspRpc.csproj", "{CFC334A5-2B52-42A0-87AE-4B3F84B09530}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspRpc", "Samples\AspRpc\AspRpc.csproj", "{CFC334A5-2B52-42A0-87AE-4B3F84B09530}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution