Last active
August 29, 2015 13:57
-
-
Save atifaziz/9371972 to your computer and use it in GitHub Desktop.
Demo of enabling optional parameters support in Jayrock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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