optional params

Mar 3, 2014 at 3:41 PM
I need to set optional params for a rpc-call.

is that possible?
Mar 3, 2014 at 3:59 PM
Edited Mar 3, 2014 at 4:02 PM
Hey raistlinthewiz,

Using the standard optional params worked for me. I solved a similar requirement like this:

Method Signature:
[JsonRpcMethod]
        private externalDataTypes.Result executeCommand(String targetId, String command, params object[] parameters)
Relevant JSON:
{"method":"executeCommand","params":["testDevice2","getVersionInfo",[<variable nr of params here>]],"id":1}
Easily adapted to all optional...
Mar 4, 2014 at 9:49 PM
I've tried
public Wallet.Responses.Getwork Getwork(params object[] parameters)
but didn't work.
Mar 4, 2014 at 10:08 PM
Okay my question was wrong, I want to use a single optional parameter.
        [JsonRpcMethod("getwork")]
        public Wallet.Responses.Getwork Getwork(string data = null)
I've tried above code. What I'm trying to implement is a json-rpc function that can accept a parameter called data which is optional.

How to achieve that?
Coordinator
Mar 5, 2014 at 2:37 AM
Can you post the two different JSON Requests that you want to be able to make?
Mar 5, 2014 at 7:44 AM
without 'data' parameter.
POST / HTTP/1.1
Authorization: Basic Y2RlY2tlcjphYmMxMjM=
Host: localhost:18332
Accept: */*
Accept-Encoding: deflate, gzip
Content-type: application/json
X-Mining-Extensions: longpoll midstate rollntime submitold
X-Mining-Hashrate: 583000000
Content-Length: 45
User-Agent: cgminer 2.8.1

{"method": "getwork", "params": [], "id":0}
with 'data' parameter
POST / HTTP/1.1
Authorization: Basic Y2RlY2tlcjphYmMxMjM=
Host: localhost:18332
Accept: */*
Accept-Encoding: deflate, gzip
Content-type: application/json
X-Mining-Extensions: longpoll midstate rollntime submitold
X-Mining-Hashrate: 661000000
Content-Length: 305
User-Agent: cgminer 2.8.1

{"method": "getwork", "params": [ "00000002b15704f4ecae05d077e54f6ec36da7f20189ef73b77603225ae56d2b00000000b052cbbdeed2489ccb13a526b77fadceef4caf7d3bb82a9eb0b69ebb90f9f5a7510c27fd1c0e8a37fa531338000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" ], "id":1}
Coordinator
Mar 5, 2014 at 3:00 PM
Edited Mar 5, 2014 at 3:07 PM
What you can do right now to support that is change your C# signature a little bit.
[JsonRpcMethod("getwork")]
        public Wallet.Responses.Getwork Getwork(string[] data){
                if(data!=null && data.Length == 1)
                {
                       return theRealGetWork(data[0]);
                }
                // If we get here, they didn't pass in the data param, or they passed in too many.
        }

// ALSO... you may have to change your RPC request to be similar to :
// empty: {"method":"getwork","params":[[]], "id":1}
// notEmpty: {"method":"getwork","params":[["string here"]],"id":1}
Let me know if any of that works for you.

I'll move all the version 2 development over to GitHub. If you want to follow it prior to it being finished, see: https://github.com/JaamConsulting
Mar 5, 2014 at 3:08 PM
Tried that but didn't work.

The client calls the methods without parameters;
{"method": "getwork", "params": [], "id":0}
and then jsonrpc.net returns this error;
{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params","data":"Expecting 1 parameters, and received 0"},"id":0}
My function;
        [JsonRpcMethod("getwork")]
        public Wallet.Responses.Getwork Getwork(string[] data)
        {
            if (data != null && data.Length == 1)
            {
            }
       }
Coordinator
Mar 5, 2014 at 3:09 PM
If it doesn't work for you like that. I can point you to the code where you can add support for true optional parameters.
Mar 5, 2014 at 3:13 PM
Nope didn't work, yes please I'd like fix this manually.
Mar 5, 2014 at 3:33 PM
Edited Mar 5, 2014 at 3:34 PM
Thanks for the link;

https://github.com/JaamConsulting/Jaam.RPC/

Maybe I can also commit some example rpc-over-http and rpc-over-sockets examples (based on my previous ones).
Coordinator
Mar 5, 2014 at 6:16 PM
Looks like you saw it before I edited the comment at the bottom. You would have to alter your request slightly. See my comment that starts with // ALSO

I'm at lunch now, I'll point you in the right direction for the code fix when I get back to a computer.
Coordinator
Mar 5, 2014 at 9:33 PM
https://jsonrpc2.codeplex.com/SourceControl/latest#AustinHarris.JsonRpc/Json-Rpc/Handler.cs

Handler.cs this code:
Instead of simply counting the number of params in the metadata, and comparing with the number of params passed in. You will need to check the metadata to see if any of the parameters are optional.
var metaDataParamCount = metadata.parameters.Count(x => x != null);
            
            var loopCt = (Rpc.Params as ICollection).Count;
            var paramCount = loopCt;
            if (paramCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount-1].ObjectType.Name.Contains(typeof(JsonRpcException).Name))
            {
                paramCount++;
                expectsRefException = true;
            }
            parameters = new object[paramCount];

            if (isJArray)
            {
                var jarr = ((Newtonsoft.Json.Linq.JArray)Rpc.Params);
                //var loopCt = jarr.Count;
                //var pCount = loopCt;
                //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException))
                //    pCount++;
                //parameters = new object[pCount];
                for (int i = 0; i < loopCt; i++)
                {
                    parameters[i] = CleanUpParameter(jarr[i], metadata.parameters[i]);
                }
            }
            else if (isJObject)
            {
                var jo = Rpc.Params as Newtonsoft.Json.Linq.JObject;
                //var loopCt = jo.Count;
                //var pCount = loopCt;
                //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException))
                //    pCount++;
                //parameters = new object[pCount];
                var asDict = jo as IDictionary<string, Newtonsoft.Json.Linq.JToken>;
                for (int i = 0; i < loopCt; i++)
                {
                    if (asDict.ContainsKey(metadata.parameters[i].Name) == false)
                    {
                        return new JsonResponse()
                        {
                            Error = ProcessException(Rpc,
                            new JsonRpcException(-32602,
                                "Invalid params",
                                string.Format("Named parameter '{0}' was not present.",
                                                metadata.parameters[i].Name)
                                ))
                                ,Id = Rpc.Id
                        };
                    }
                    parameters[i] = CleanUpParameter(jo[metadata.parameters[i].Name], metadata.parameters[i]);
                }
            }
            
            if (parameters.Length != metaDataParamCount)
            {
                return new JsonResponse()
                {
                    Error = ProcessException(Rpc,
                    new JsonRpcException(-32602,
                        "Invalid params",
                        string.Format("Expecting {0} parameters, and received {1}",
                                        metadata.parameters.Length,
                                        parameters.Length)
                        )),
                    Id = Rpc.Id
                };
            }
To properly do this you will likely have to capture additional metadata during service creation so that you can use that metadata in the above code.


Here is the code that creates the metadata when a service is registered.
https://jsonrpc2.codeplex.com/SourceControl/latest#AustinHarris.JsonRpc/Json-Rpc/Handler.cs

You will have to use some reflection on those parameters to determine if they are optional, and then add that optional flag to the metadata class.

This call is the one that associates metadata with a method.
handlerSession.MetaData.AddService(methodName, paras);
Feel free to add me on google Hangouts if you want to chat about it. austin.w.harris@gmail.com
Mar 5, 2014 at 9:56 PM
Hey there, your comments marked with ALSO part isn't applicable for me because the protocol i'm using is already well-defined (https://en.bitcoin.it/wiki/Getwork) and existing software uses it so. So basically I can't change how the clients uses the rpc-method.

Though i'll be trying the method you directed.
Coordinator
Mar 6, 2014 at 2:38 AM
ok. I'm going to pull a clone of the latest release over to github. I'll post the link for you when its up.
Coordinator
Mar 6, 2014 at 3:00 AM
A copy of the latest released code is at https://github.com/Astn/JSON-RPC.NET
Mar 6, 2014 at 8:19 AM
thanks i forked it, https://github.com/raistlinthewiz/JSON-RPC.NET

I guess I'll be implementing a common solution and PR it back to you.
Mar 6, 2014 at 11:25 AM
Hey Austin,
I've sent you a pull request over github ( https://github.com/Astn/JSON-RPC.NET/pull/1 ) that automatically handles optional parameters for arrays.

The code fixed my use-case and I'm sure it'll be pretty useful for other users too.

Hope you review the PR and merge it in and within the next release I can start using the nuget package instead of using a forked submodule with the fix (https://github.com/raistlinthewiz/JSON-RPC.NET)