/// <summary> /// <see cref="System.Dynamic.DynamicObject.TryInvokeMember(InvokeMemberBinder, object[], out object)"/> /// </summary> public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { Debug.Assert(binder != null); Debug.Assert(args != null); if (binder.IsVerb()) { // parse out the details of the invocation and have the derived class create a Task result = CreateVerbAsyncTask(binder.Name, binder.GetUnnamedArgs(args), binder.GetNamedArgs(args)); } else { if (args.Length != 1) { throw new InvalidOperationException("The segment escape sequence must have exactly 1 unnamed parameter"); } // this is for when we escape a url segment by passing it as an argument to a method invocation // example: proxy.segment1("escaped") // here we create two new dynamic objects, 1 for "segment1" which is the method name // and then we create one for the escaped segment passed as an argument - "escaped" in the example var tmp = CreateProxyNode(this, binder.Name); result = CreateProxyNode(tmp, args[0].ToString()); } return(true); }
/// <summary> /// <see cref="DynamicObject.TryInvokeMember(InvokeMemberBinder, object[], out object)"/> /// </summary> public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if (_verbs.Contains(binder.Name)) // the method name is one of our http verbs - invoke as such { var unnamedArgs = binder.GetUnnamedArgs(args); // filter our sentinal types out of the unnamed args to be passed on the request var requestArgs = unnamedArgs.Where(arg => !arg.IsOfType(_reservedTypes)); // these are the objects that can be passed as unnamed args that we use intenrally and do not pass to the request var cancelToken = unnamedArgs.OfType <CancellationToken>().DefaultIfEmpty(CancellationToken.None).First(); var serializationSettings = unnamedArgs.OfType <JsonSerializerSettings>().FirstOrNewInstance(); #if EXPERIMENTAL_GENERICS // dig the generic type argument out of the binder var returnType = binder.GetGenericTypeArguments().FirstOrDefault(); // evil exists within that method #else var returnType = unnamedArgs.OfType <Type>().FirstOrDefault(); #endif // if no return type argument provided there is no need for late bound method dispatch if (returnType == null) { // no return type argument so return result deserialized as dynamic // parse out the details of the invocation and have the derived class create a Task result = CreateVerbAsyncTask <dynamic>(binder.Name, requestArgs, binder.GetNamedArgs(args), cancelToken, serializationSettings); } else { // we got a type argument (like this if experimental: client.get<SomeType>(); or like this normally: client.get(typeof(SomeType)); ) // make and invoke the generic implementaiton of the CreateVerbAsyncTask method var methodInfo = this.GetType().GetTypeInfo().GetDeclaredMethod("CreateVerbAsyncTask"); var method = methodInfo.MakeGenericMethod(returnType); result = method.Invoke(this, new object[] { binder.Name, requestArgs, binder.GetNamedArgs(args), cancelToken, serializationSettings }); } } else // otherwise the method is yet another uri segment { if (args.Length != 1) { throw new InvalidOperationException("The segment escape sequence must have exactly 1 unnamed parameter"); } // this is for when we escape a url segment by passing it as an argument to a method invocation // example: proxy.segment1("escaped") // here we create two new dynamic objects, 1 for "segment1" which is the method name // and then we create one for the escaped segment passed as an argument - "escaped" in the example var tmp = CreateProxyNode(this, binder.Name); result = CreateProxyNode(tmp, args[0].ToString()); } return(true); }