Skip to content

Instantly share code, notes, and snippets.

@atifaziz
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atifaziz/9371972 to your computer and use it in GitHub Desktop.
Save atifaziz/9371972 to your computer and use it in GitHub Desktop.
Demo of enabling optional parameters support in Jayrock
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using Jayrock;
using Jayrock.JsonRpc;
using Jayrock.Services;
static class Program
{
static void Main()
{
JsonRpcDispatcherFactory.Current = service => new JsonRpcDispatcher(service);
var dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(new MyService());
Console.WriteLine(dispatcher.Process(@"{ id: 1, method: getwork }"));
Console.WriteLine(dispatcher.Process(@"{ id: 1, method: getwork, params: [] }"));
Console.WriteLine(dispatcher.Process(@"{ id: 2, method: getwork, params: {} }"));
Console.WriteLine(dispatcher.Process(@"{ id: 2, method: getwork, params: [bar] }"));
Console.WriteLine(dispatcher.Process(@"{ id: 2, method: getwork, params: { data: bar } }"));
}
}
class MyService : JsonRpcService
{
[JsonRpcMethod("getwork", Idempotent = true), JsonRpcOptionalParametersSupport]
public object Getwork(string data = "foo") { return data; }
}
interface IJsonRpcRequestLifetimeNotice
{
void OnStart(IDictionary request);
void OnEnd(IDictionary request, IDictionary response);
}
sealed class JsonRpcDispatcher : Jayrock.JsonRpc.JsonRpcDispatcher
{
public JsonRpcDispatcher(IService service) : base(service) {}
public override IDictionary Invoke(IDictionary request)
{
var notice = Service as IJsonRpcRequestLifetimeNotice;
if (notice != null) notice.OnStart(request);
var response = base.Invoke(request);
if (notice != null) notice.OnEnd(request, response);
return response;
}
}
interface IJsonRpcRequestProperty { IDictionary Request { get; } }
class JsonRpcService : Jayrock.JsonRpc.JsonRpcService,
IJsonRpcRequestLifetimeNotice,
IJsonRpcRequestProperty
{
IDictionary _request;
IDictionary IJsonRpcRequestProperty.Request { get { return _request; } }
void IJsonRpcRequestLifetimeNotice.OnStart(IDictionary request) { _request = request; }
void IJsonRpcRequestLifetimeNotice.OnEnd(IDictionary request, IDictionary response) { _request = null; }
}
[AttributeUsage(AttributeTargets.Method)]
sealed class JsonRpcOptionalParametersSupportAttribute : Attribute,
IMethodModifier,
IAttributeAttachment
{
MethodInfo _method;
void IAttributeAttachment.SetAttachment(ICustomAttributeProvider obj) { _method = (MethodInfo)obj; }
void IMethodModifier.Modify(MethodBuilder builder)
{
builder.Handler = new MethodImpl(_method.GetParameters(), builder.Handler);
}
sealed class MethodImpl : IMethodImpl
{
readonly IMethodImpl _impl;
readonly ParameterInfo[] _parameters;
public MethodImpl(ParameterInfo[] parameters, IMethodImpl impl)
{
_impl = impl;
_parameters = parameters;
}
object[] DefaultOptionalParameters(IService service, object[] args)
{
var parameters = _parameters;
var missingCount = parameters.Length - args.Length;
if (missingCount > 0)
{
var defaults = parameters.Skip(args.Length)
.Take(missingCount)
.TakeWhile(p => p.IsOptional)
.Select(p => p.GetDefaultValue())
.ToArray();
if (!defaults.Any())
return args;
args = args.Concat(defaults).ToArray();
}
IJsonRpcRequestProperty rp;
IDictionary request;
IDictionary paramz;
if ((rp = service as IJsonRpcRequestProperty) != null
&& (request = rp.Request) != null
&& ((paramz = request["params"] as IDictionary) != null))
{
var defaults =
from p in service.GetClass()
.GetMethodByName(request["method"].ToString())
.GetParameters()
.Zip(parameters, (rem, loc) => new
{
Remote = rem,
Local = loc
})
where p.Local.IsOptional && !paramz.Contains(p.Remote.Name)
select new
{
p.Local.Position,
DefaultValue = p.Local.GetDefaultValue()
};
foreach (var e in defaults)
args[e.Position] = e.DefaultValue;
}
return args;
}
public object Invoke(IService service, object[] args)
{
return _impl.Invoke(service, DefaultOptionalParameters(service, args));
}
public IAsyncResult BeginInvoke(IService service, object[] args, AsyncCallback callback, object asyncState)
{
return _impl.BeginInvoke(service, DefaultOptionalParameters(service, args), callback, asyncState);
}
public object EndInvoke(IService service, IAsyncResult asyncResult)
{
return _impl.EndInvoke(service, asyncResult);
}
public bool IsAsynchronous { get { return _impl.IsAsynchronous; } }
}
}
static class ParameterInfoExtensions
{
public static object GetDefaultValue(this ParameterInfo param)
{
return ParameterAttributes.HasDefault == (param.Attributes & ParameterAttributes.HasDefault)
? param.DefaultValue
: param.ParameterType.IsValueType
? Activator.CreateInstance(param.ParameterType)
: null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment