예제 #1
0
        public void GetMatchingMethod_ListParam_Match_Snake_Case(string parameterNameCase)
        {
            DefaultRequestMatcher matcher = this.GetMatcher();

            IEnumerable <KeyValuePair <string, RpcParameterType> > parameters = new[]
            {
                new KeyValuePair <string, RpcParameterType>(parameterNameCase, RpcParameterType.String)
            };

            string        methodName       = nameof(MethodMatcherController.SnakeCaseParams);
            var           requestSignature = RpcRequestSignature.Create(methodName, parameters);
            RpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);


            Assert.NotNull(methodInfo);
            MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !;

            Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo);
            Assert.Single(methodInfo.Parameters);

            Assert.False(methodInfo.Parameters[0].IsOptional);
            Assert.Equal(typeof(string), methodInfo.Parameters[0].RawType);
            Assert.Equal(RpcParameterType.String, methodInfo.Parameters[0].Type);
            Assert.True(RpcUtil.NamesMatch(methodInfo.Parameters[0].Name, parameterNameCase));
        }
예제 #2
0
        private HttpApiClient GetClient(RpcMethodInfo toCall)
        {
            HttpClient httpClient = new HttpClient(Build(), false);

            httpClient.Timeout     = config.TimeOut;
            httpClient.BaseAddress = new System.Uri(config.urlProvider.GetEndpoint(toCall));
            return(new HttpApiClient(httpClient, serializer));
        }
예제 #3
0
        public async Task <object> Invoke(RpcMethodInfo toCall, object[] param)
        {
            if (param == null)
            {
                param = new object[0];
            }
            //This format is recognized by the default implementation of the server.
            //The base url for the request is expected to be set on the HttpClient
            string requestUri     = CreateIdString(toCall);
            var    theHttpRequest = new HttpRequestMessage(HttpMethod.Post, requestUri);

            var outstream = new System.IO.MemoryStream();

            var theSerializer = serializer;

            switch (param.Length)
            {
            case 0:
                break;

            case 1:
                theSerializer.ToStream(outstream, param[0]);
                break;

            default:
                theSerializer.ToStream(outstream, param);
                break;
            }

            outstream.Position     = 0;
            theHttpRequest.Content = new StreamContent(outstream);

            theHttpRequest.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(theSerializer.ProduceMimeType);

            var response = await httpClient.SendAsync(theHttpRequest);

            if (response.IsSuccessStatusCode)
            {
                if (toCall.ReturnType == typeof(void) | toCall.ReturnType == typeof(Task))
                {
                    return(null);
                }
                var ret = theSerializer.FromStream(await response.Content.ReadAsStreamAsync(), toCall.ReturnType);

                return(ret);
            }
            else if ((int)response.StatusCode >= 500)
            {
                var remoteExceptionInfo = theSerializer.FromStream(await response.Content.ReadAsStreamAsync(), typeof(RemoteExceptionInfo));
                throw new WebRpcCallFailedException((RemoteExceptionInfo)remoteExceptionInfo);
            }
            else
            {
                throw new HttpRequestException($"{response.StatusCode} {response.Content.ReadAsStringAsync().Result}");
            }
        }
예제 #4
0
        public ResponseCodeGen(RpcMethodInfo hRpcInfo, int iProtocolCounter)
        {
            Name    = string.Format("Response{0}", hRpcInfo.Method.Name);
            RpcInfo = hRpcInfo;

            string sReturnProperty  = hRpcInfo.Method.ReturnType != typeof(void) ? string.Format("public {0} Data;", hRpcInfo.Method.ReturnType.AsKeyword()) : string.Empty;
            string sEncodeParam     = hRpcInfo.Method.ReturnType != typeof(void) ? string.Format("{0} hData", hRpcInfo.Method.ReturnType.AsKeyword()) : string.Empty;
            string sWriteCalls      = hRpcInfo.Method.ReturnType != typeof(void) ? "m_hWriter.Write(hData);" : string.Empty;
            string sLoadCalls       = hRpcInfo.Method.ReturnType != typeof(void) ? string.Format("Data = hReader.Read{0}();", hRpcInfo.Method.ReturnType.Name) : string.Empty;

            string sResult = string.Format(@"
                using System;
                using System.Collections.Generic;
                using System.IO;
                using Netbase.Shared;

                namespace {0}
                {{
                    [NetbasePacket({1})]
                    public class {2} : Packet
                    {{
                        {3}

                        public {4}() : base({1}, {5})
                        {{

                        }}

                        public void Encode({6})
                        {{
                            this.BeginEncode();
                            {7}
                            this.EndEncode();
                        }}

                        public override void LoadData(BinaryReader hReader)
                        {{
                            base.LoadData(hReader);
                            {8}
                        }}
                    }}
                }}",
                RpcInfo.Service.Pair.Client.Namespace,
                iProtocolCounter,
                Name,
                sReturnProperty,
                Name,
                1024,
                sEncodeParam,
                sWriteCalls,
                sLoadCalls);

            Code = sResult;
        }
예제 #5
0
        public RequestActionCodeGen(IRequestActionBuilder hBuilder, RpcMethodInfo hRpc)
        {
            Name    = string.Format("Request{0}Action", hRpc.Method.Name);
            RpcInfo = hRpc;

            string sResult = string.Format(@"
                using System;
                using System.Reflection;
                using Netbase.Shared;
                {0}

                namespace {1}
                {{
                    //{10}
                    public class {2} : {3}, IAction
                    {{
                        private const string      m_sMethodName = ""{4}"";
                        private static MethodInfo m_hMethod;
                        {5}

                        public {2}() : base()
                        {{
                            {6}
                        }}

                        public void Execute(IService hService, ISession hContext)
                        {{
                            if(m_hMethod == null)
                                m_hMethod = hService.GetType().GetMethod(m_sMethodName);

                            {7}

                            {8}

                            {9}
                        }}
                    }}
                }}
                ",
                hBuilder.UsingNamespace(RpcInfo.Service),            //0 - using ProjName.Service;
                RpcInfo.Service.Namespace,                           //1
                Name,                                                //2
                RpcInfo.Request.Name,                                //3
                hBuilder.MethodToCall(RpcInfo),                                 //4
                hBuilder.ResponseDeclaration(RpcInfo.Response),      //5 - private ResponseSomeThing m_hResponse
                hBuilder.ResponseAllocation(RpcInfo.Response),       //6 - m_hResponse = new ResponseSomeThing();
                hBuilder.ResponseCallIdSet,                          //7 - m_hResponse.CallId = this.CallId;
                hBuilder.MethodCall(RpcInfo),
                hBuilder.ResponseSend,                               //8 - hContext.Send(m_hResponse);
                "Generated With: " + hBuilder.GetType().Name
                );

            Code = sResult;
        }
        public string MethodCall(RpcMethodInfo hRpc)
        {
            string sMethodCall = string.Format("m_hMethod.Invoke(hService, new object[] {{ hContext, {0} }})", hRpc.Method.GetParametersString(false));

            if (hRpc.Method.ReturnType == typeof(void))
            {
                sMethodCall = string.Format("{0}; m_hResponse.Encode();", sMethodCall);
            }
            else
            {
                sMethodCall = string.Format("m_hResponse.Encode(({0}){1});", hRpc.Method.ReturnType.AsKeyword(), sMethodCall);
            }

            return sMethodCall;
        }
예제 #7
0
        /// <summary>
        /// Invokes the method with the specified parameters, returns the result of the method
        /// </summary>
        /// <exception cref="RpcInvalidParametersException">Thrown when conversion of parameters fails or when invoking the method is not compatible with the parameters</exception>
        /// <param name="parameters">List of parameters to invoke the method with</param>
        /// <returns>The result of the invoked method</returns>
        private async Task <object> InvokeAsync(RpcMethodInfo methodInfo, RpcPath path)
        {
            object obj = null;

            if (this.serviceProvider != null)
            {
                //Use service provider (if exists) to create instance
                var objectFactory = ActivatorUtilities.CreateFactory(methodInfo.Method.DeclaringType, new Type[0]);
                obj = objectFactory(this.serviceProvider, null);
            }
            if (obj == null)
            {
                //Use reflection to create instance if service provider failed or is null
                obj = Activator.CreateInstance(methodInfo.Method.DeclaringType);
            }
            try
            {
                object returnObj = methodInfo.Method.Invoke(obj, methodInfo.ConvertedParameters);

                returnObj = await DefaultRpcInvoker.HandleAsyncResponses(returnObj);

                return(returnObj);
            }
            catch (TargetInvocationException ex)
            {
                var routeInfo = new RpcRouteInfo(methodInfo, path, this.serviceProvider);

                //Controller error handling
                RpcErrorFilterAttribute errorFilter = methodInfo.Method.DeclaringType.GetTypeInfo().GetCustomAttribute <RpcErrorFilterAttribute>();
                if (errorFilter != null)
                {
                    OnExceptionResult result = errorFilter.OnException(routeInfo, ex.InnerException);
                    if (!result.ThrowException)
                    {
                        return(result.ResponseObject);
                    }
                    if (result.ResponseObject is Exception rEx)
                    {
                        throw rEx;
                    }
                }
                throw new RpcUnknownException("Exception occurred from target method execution.", ex);
            }
            catch (Exception ex)
            {
                throw new RpcInvalidParametersException("Exception from attempting to invoke method. Possibly invalid parameters for method.", ex);
            }
        }
예제 #8
0
        public void GetMatchingMethod_SimpleMulitParam_DictMatch()
        {
            DefaultRequestMatcher matcher = this.GetMatcher();

            var parameters = new Dictionary <string, RpcParameterType>
            {
                { "a", RpcParameterType.Number },
                { "b", RpcParameterType.Boolean },
                { "c", RpcParameterType.String },
                { "d", RpcParameterType.Object },
                { "e", RpcParameterType.Null }
            };
            string        methodName       = nameof(MethodMatcherController.SimpleMulitParam);
            var           requestSignature = RpcRequestSignature.Create(methodName, parameters);
            RpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);


            Assert.NotNull(methodInfo);
            MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !;

            Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo);
            Assert.Equal(5, methodInfo.Parameters.Length);

            Assert.False(methodInfo.Parameters[0].IsOptional);
            Assert.Equal(typeof(int), methodInfo.Parameters[0].RawType);
            Assert.Equal(RpcParameterType.Number, methodInfo.Parameters[0].Type);
            Assert.Equal("a", methodInfo.Parameters[0].Name);

            Assert.False(methodInfo.Parameters[1].IsOptional);
            Assert.Equal(typeof(bool), methodInfo.Parameters[1].RawType);
            Assert.Equal(RpcParameterType.Boolean, methodInfo.Parameters[1].Type);
            Assert.Equal("b", methodInfo.Parameters[1].Name);

            Assert.False(methodInfo.Parameters[2].IsOptional);
            Assert.Equal(typeof(string), methodInfo.Parameters[2].RawType);
            Assert.Equal(RpcParameterType.String, methodInfo.Parameters[2].Type);
            Assert.Equal("c", methodInfo.Parameters[2].Name);

            Assert.False(methodInfo.Parameters[3].IsOptional);
            Assert.Equal(typeof(object), methodInfo.Parameters[3].RawType);
            Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[3].Type);
            Assert.Equal("d", methodInfo.Parameters[3].Name);

            Assert.True(methodInfo.Parameters[4].IsOptional);
            Assert.Equal(typeof(int?), methodInfo.Parameters[4].RawType);
            Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[4].Type);
            Assert.Equal("e", methodInfo.Parameters[4].Name);
        }
예제 #9
0
        public void GetMatchingMethod_GuidParameter_Match()
        {
            string methodName = nameof(MethodMatcherController.GuidTypeMethod);

            DefaultRequestMatcher matcher  = this.GetMatcher();
            var           requestSignature = RpcRequestSignature.Create(methodName, new[] { RpcParameterType.String });
            RpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);


            Assert.NotNull(methodInfo);
            MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !;

            Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo);
            Assert.Single(methodInfo.Parameters);
            Assert.False(methodInfo.Parameters[0].IsOptional);
            Assert.Equal(typeof(Guid), methodInfo.Parameters[0].RawType);
            Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[0].Type);
            Assert.Equal("guid", methodInfo.Parameters[0].Name);
        }
예제 #10
0
        public string GetEndpoint(RpcMethodInfo invokeInfo)
        {
            if (TypeReg.ContainsKey(invokeInfo.MasterType))
            {
                return(TypeReg[invokeInfo.MasterType][0]);
            }
            if (AssemblyReg.ContainsKey(invokeInfo.MasterType.Assembly))
            {
                return(AssemblyReg[invokeInfo.MasterType.Assembly][0]);
            }

            if (Next == null)
            {
                throw new UrlNotConfiguredException(invokeInfo);
            }
            else
            {
                return(Next.GetEndpoint(invokeInfo));
            }
        }
예제 #11
0
        public void GetMatchingMethod_ListParam_Match()
        {
            DefaultRequestMatcher matcher = this.GetMatcher();

            RpcParameterType[] parameters  = new[] { RpcParameterType.Object };
            string             methodName  = nameof(MethodMatcherController.List);
            var           requestSignature = RpcRequestSignature.Create(methodName, parameters);
            RpcMethodInfo methodInfo       = matcher.GetMatchingMethod(requestSignature);


            Assert.NotNull(methodInfo);
            MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !;

            Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo);
            Assert.Single(methodInfo.Parameters);

            Assert.False(methodInfo.Parameters[0].IsOptional);
            Assert.Equal(typeof(List <string>), methodInfo.Parameters[0].RawType);
            Assert.Equal(RpcParameterType.Object, methodInfo.Parameters[0].Type);
            Assert.Equal("values", methodInfo.Parameters[0].Name);
        }
예제 #12
0
        public ResponseActionCodeGen(IResponseActionBuilder hBuilder, RpcMethodInfo hRpc)
        {
            Name    = string.Format("Response{0}Action", hRpc.Method.Name);
            RpcInfo = hRpc;

            string sResult = string.Format(@"
                using System;
                using System.Reflection;
                using Netbase.Shared;
                {0}

                namespace {1}
                {{
                    //{7}
                    public class {2} : {3}, IAction
                    {{
                        private const string      m_sMethodName = ""On{5}"";
                        private static MethodInfo m_hMethod;

                        public void Execute(IService hService, ISession hContext)
                        {{
                            if(m_hMethod == null)
                                {6}

                            {4}
                        }}
                    }}
                }}
                ",
                hBuilder.UsingNamespace(RpcInfo.Service),
                hBuilder.Namespace(RpcInfo),
                Name,
                RpcInfo.Response.Name,
                hBuilder.MethodInvoke,
                RpcInfo.Method.Name,
                hBuilder.MethodInit,
                "Generated With: " + hBuilder.GetType().Name);

            Code = sResult;
        }
예제 #13
0
        public void GetMatchingMethod_CulturallyInvariantComparison()
        {
            DefaultRequestMatcher matcher = this.GetMatcher();

            RpcParameterType[] parameters = Array.Empty <RpcParameterType>();
            string             methodName = nameof(MethodMatcherController.IsLunchTime);
            // Use lowercase version of method name when making request.
            var methodNameLower  = methodName.ToLowerInvariant();
            var requestSignature = RpcRequestSignature.Create(methodNameLower, parameters);
            var previousCulture  = System.Globalization.CultureInfo.CurrentCulture;

            // Switch to a culture that would result in lowercasing 'I' to
            // U+0131, if not done with invariant culture.
            System.Globalization.CultureInfo.CurrentCulture = new System.Globalization.CultureInfo("az");
            RpcMethodInfo methodInfo = matcher.GetMatchingMethod(requestSignature);

            Assert.NotNull(methodInfo);
            MethodInfo expectedMethodInfo = typeof(MethodMatcherController).GetMethod(methodName) !;

            Assert.Equal(expectedMethodInfo, methodInfo.MethodInfo);
            System.Globalization.CultureInfo.CurrentCulture = previousCulture;
        }
예제 #14
0
        private DefaultRpcInvoker GetInvoker(MethodInfo?methodInfo, RpcPath?path = null)

        {
            var         logger         = new Mock <ILogger <DefaultRpcInvoker> >(MockBehavior.Loose);
            var         options        = new Mock <IOptions <RpcServerConfiguration> >(MockBehavior.Strict);
            var         matcher        = new Mock <IRpcRequestMatcher>(MockBehavior.Strict);
            var         accessor       = new Mock <IRpcContextAccessor>(MockBehavior.Strict);
            IRpcContext requestContext = this.GetRouteContext(path);

            accessor
            .SetupGet(a => a.Value)
            .Returns(requestContext);
            Moq.Language.Flow.ISetup <IRpcRequestMatcher, RpcMethodInfo> matcherSetup = matcher
                                                                                        .Setup(m => m.GetMatchingMethod(It.IsAny <RpcRequestSignature>()));
            if (methodInfo != null)
            {
                //TODO better way of getting this for unit tests?
                RpcMethodInfo method = DefaultRequestMatcher.BuildMethodInfo(methodInfo);
                matcherSetup.Returns(method);
            }
            else
            {
                matcherSetup.Throws(new RpcException(RpcErrorCode.MethodNotFound, "Method not found"));
            }
            var config = new RpcServerConfiguration();

            config.ShowServerExceptions = true;
            options
            .SetupGet(o => o.Value)
            .Returns(config);
            var authHandler = new Mock <IRpcAuthorizationHandler>(MockBehavior.Strict);

            authHandler
            .Setup(h => h.IsAuthorizedAsync(It.IsAny <MethodInfo>()))
            .Returns(Task.FromResult(true));

            return(new DefaultRpcInvoker(logger.Object, options.Object, matcher.Object, accessor.Object, authHandler.Object));
        }
예제 #15
0
        private void WriteServerCallbackMethod(RpcMethodInfo hTransportCodeGen, StringBuilder hSb)
        {
            string sResult = string.Format(@"
            public abstract void On{0}(T hContex, {1} hData);
            ",
            hTransportCodeGen.Method.Name,
            "Response" + hTransportCodeGen.Method.Name);

            hSb.AppendLine(sResult);
        }
예제 #16
0
 public string MethodToCall(RpcMethodInfo hRpcInfo)
 {
     return string.Format("{0}", hRpcInfo.Method.Name);
 }
예제 #17
0
 public Task <object> Invoke(RpcMethodInfo toCall, object[] param)
 {
     return(GetClient(toCall).Invoke(toCall, param));
 }
예제 #18
0
 internal string CreateIdString(RpcMethodInfo toCall)
 {
     return($"{toCall.ServiceId}.{toCall.Name}-{string.Join("-",toCall.ParamType.Select(p=> p.FullName).ToArray())}");
 }
 public UrlNotConfiguredException(RpcMethodInfo invokeInfo) : this(invokeInfo.ServiceId)
 {
     this.invokeInfo = invokeInfo;
 }
예제 #20
0
        public RequestCodeGen(RpcMethodInfo hRpcInfo, int iProtocolCounter)
        {
            Name        = string.Format("Request{0}", hRpcInfo.Method.Name);
            RpcInfo     = hRpcInfo;

            StringBuilder hPropertyList = new StringBuilder();
            hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hPropertyList.AppendFormat("public {0}\t\t{1}\t\t\t{{ get; private set; }}{2}\t", hP.ParameterType.AsKeyword(), hP.Name, Environment.NewLine));

            StringBuilder hParamList = new StringBuilder();
            hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hParamList.AppendFormat("{0} {1},", hP.ParameterType.AsKeyword(), hP.Name));
            if (hParamList.Length > 0)
                hParamList.Remove(hParamList.Length - 1, 1);

            StringBuilder hEncodeCalls = new StringBuilder();
            hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hEncodeCalls.AppendFormat(@"              m_hWriter.Write({0});{1}", hP.Name, Environment.NewLine));
            if (hEncodeCalls.Length > 0)
                hEncodeCalls.Remove(hEncodeCalls.Length - 1, 1);

            StringBuilder hReadCalls = new StringBuilder();
            hRpcInfo.Method.GetParameters().ToList().ForEach(hP => hReadCalls.AppendFormat(@"            {0} = hReader.Read{1}();{2}", hP.Name, hP.ParameterType.Name, Environment.NewLine));
            if (hReadCalls.Length > 0)
                hReadCalls.Remove(hReadCalls.Length - 1, 1);

            string sResult = string.Format(@"
                using Netbase.Shared;
                using System;
                using System.Collections.Generic;
                using System.IO;
                using System.Text;

                namespace {0}
                {{
                    [NetbasePacket({1})]
                    public class {2} : Packet
                    {{
                        {3}

                        public {4}() : base({1}, {5})
                        {{

                        }}

                        public void Encode({6})
                        {{
                            this.BeginEncode();
                            {7}
                            this.EndEncode();
                        }}

                        public override void LoadData(BinaryReader hReader)
                        {{
                            base.LoadData(hReader);
                            {8}
                        }}
                    }}
                }}",
                hRpcInfo.Service.Pair.Client.Namespace,
                iProtocolCounter,
                Name,
                hPropertyList.ToString(),
                Name,
                1024,
                hParamList,
                hEncodeCalls,
                hReadCalls);

            Code = sResult;
        }
예제 #21
0
 public string MethodCall(RpcMethodInfo hRpc)
 {
     return string.Format("m_hMethod.Invoke(hService, new object[] {{ hContext, {0} }});", hRpc.Method.GetParametersString(false));
 }
예제 #22
0
        /// <summary>
        /// Detects if list of parameters matches the method signature
        /// </summary>
        /// <param name="parameterList">Array of parameters for the method</param>
        /// <returns>True if the method signature matches the parameterList, otherwise False</returns>
        private bool HasParameterSignature(MethodInfo method, RpcRequest rpcRequest, out RpcMethodInfo rpcMethodInfo)
        {
            JToken[] orignialParameterList;
            if (rpcRequest.Parameters == null)
            {
                orignialParameterList = new JToken[0];
            }
            else
            {
                switch (rpcRequest.Parameters.Type)
                {
                case JTokenType.Object:
                    JsonSerializer jsonSerializer            = this.GetJsonSerializer();
                    Dictionary <string, JToken> parameterMap = rpcRequest.Parameters.ToObject <Dictionary <string, JToken> >(jsonSerializer);
                    bool canParse = this.TryParseParameterList(method, parameterMap, out orignialParameterList);
                    if (!canParse)
                    {
                        rpcMethodInfo = null;
                        return(false);
                    }
                    break;

                case JTokenType.Array:
                    orignialParameterList = rpcRequest.Parameters.ToArray();
                    break;

                default:
                    orignialParameterList = new JToken[0];
                    break;
                }
            }
            ParameterInfo[] parameterInfoList = method.GetParameters();
            if (orignialParameterList.Length > parameterInfoList.Length)
            {
                rpcMethodInfo = null;
                return(false);
            }
            object[] correctedParameterList = new object[parameterInfoList.Length];

            for (int i = 0; i < orignialParameterList.Length; i++)
            {
                ParameterInfo parameterInfo = parameterInfoList[i];
                JToken        parameter     = orignialParameterList[i];
                bool          isMatch       = this.ParameterMatches(parameterInfo, parameter, out object convertedParameter);
                if (!isMatch)
                {
                    rpcMethodInfo = null;
                    return(false);
                }
                correctedParameterList[i] = convertedParameter;
            }

            if (orignialParameterList.Length < parameterInfoList.Length)
            {
                //make a new array at the same length with padded 'missing' parameters (if optional)
                for (int i = orignialParameterList.Length; i < parameterInfoList.Length; i++)
                {
                    if (!parameterInfoList[i].IsOptional)
                    {
                        rpcMethodInfo = null;
                        return(false);
                    }
                    correctedParameterList[i] = Type.Missing;
                }
            }

            rpcMethodInfo = new RpcMethodInfo(method, correctedParameterList, orignialParameterList);
            return(true);
        }
예제 #23
0
        /// <summary>
        /// Detects if list of parameters matches the method signature
        /// </summary>
        /// <param name="parameterList">Array of parameters for the method</param>
        /// <returns>True if the method signature matches the parameterList, otherwise False</returns>
        private (bool Matches, RpcMethodInfo MethodInfo) HasParameterSignature(MethodInfo method, RpcRequest rpcRequest)
        {
            object[] orignialParameterList;
            if (!rpcRequest.Parameters.HasValue)
            {
                orignialParameterList = new object[0];
            }
            else
            {
                switch (rpcRequest.Parameters.Type)
                {
                case RpcParametersType.Dictionary:
                    Dictionary <string, object> parameterMap = rpcRequest.Parameters.DictionaryValue;
                    bool canParse = this.TryParseParameterList(method, parameterMap, out orignialParameterList);
                    if (!canParse)
                    {
                        return(false, null);
                    }
                    break;

                case RpcParametersType.Array:
                    orignialParameterList = rpcRequest.Parameters.ArrayValue;
                    break;

                default:
                    orignialParameterList = new JToken[0];
                    break;
                }
            }
            ParameterInfo[] parameterInfoList = method.GetParameters();
            if (orignialParameterList.Length > parameterInfoList.Length)
            {
                return(false, null);
            }
            object[] correctedParameterList = new object[parameterInfoList.Length];

            for (int i = 0; i < orignialParameterList.Length; i++)
            {
                ParameterInfo parameterInfo = parameterInfoList[i];
                object        parameter     = orignialParameterList[i];
                bool          isMatch       = this.ParameterMatches(parameterInfo, parameter, out object convertedParameter);
                if (!isMatch)
                {
                    return(false, null);
                }
                correctedParameterList[i] = convertedParameter;
            }

            if (orignialParameterList.Length < parameterInfoList.Length)
            {
                //make a new array at the same length with padded 'missing' parameters (if optional)
                for (int i = orignialParameterList.Length; i < parameterInfoList.Length; i++)
                {
                    if (!parameterInfoList[i].IsOptional)
                    {
                        return(false, null);
                    }
                    correctedParameterList[i] = Type.Missing;
                }
            }

            var rpcMethodInfo = new RpcMethodInfo(method, correctedParameterList, orignialParameterList);

            return(true, rpcMethodInfo);
        }
예제 #24
0
 public string Namespace(RpcMethodInfo hRpcInfo)
 {
     return string.Format("{0}", hRpcInfo.Service.Pair.Client.Namespace);
 }
예제 #25
0
 public string Namespace(RpcMethodInfo RpcInfo)
 {
     return RpcInfo.Service.Pair.Server.Namespace;
 }
예제 #26
0
        /// <summary>
        /// Finds the matching Rpc method for the current request
        /// </summary>
        /// <param name="path">Rpc route for the current request</param>
        /// <param name="request">Current Rpc request</param>
        /// <param name="parameterList">Parameter list parsed from the request</param>
        /// <param name="serviceProvider">(Optional)IoC Container for rpc method controllers</param>
        /// <returns>The matching Rpc method to the current request</returns>
        private RpcMethodInfo GetMatchingMethod(RpcPath path, RpcRequest request, IRpcRouteProvider routeProvider, IServiceProvider serviceProvider)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            this.logger?.LogDebug($"Attempting to match Rpc request to a method '{request.Method}'");
            List <MethodInfo> allMethods = this.GetRpcMethods(path, routeProvider);

            //Case insenstive check for hybrid approach. Will check for case sensitive if there is ambiguity
            var requestMethodName = this.convertSnakeCaseToCamelCase ? this.ConvertSnakeCaseToCamelCase(request.Method) : request.Method;
            List <MethodInfo> methodsWithSameName = allMethods
                                                    .Where(m => string.Equals(m.Name, requestMethodName, StringComparison.OrdinalIgnoreCase))
                                                    .ToList();

            var potentialMatches = new List <RpcMethodInfo>();

            foreach (MethodInfo method in methodsWithSameName)
            {
                (bool isMatch, RpcMethodInfo methodInfo) = this.HasParameterSignature(method, request);
                if (isMatch)
                {
                    potentialMatches.Add(methodInfo);
                }
            }

            if (potentialMatches.Count > 1)
            {
                //Try to remove ambiguity with 'perfect matching' (usually optional params and types)
                List <RpcMethodInfo> exactMatches = potentialMatches
                                                    .Where(p => p.HasExactParameterMatch())
                                                    .ToList();
                if (exactMatches.Any())
                {
                    potentialMatches = exactMatches;
                }
                if (potentialMatches.Count > 1)
                {
                    //Try to remove ambiguity with case sensitive check
                    potentialMatches = potentialMatches
                                       .Where(m => string.Equals(m.Method.Name, requestMethodName, StringComparison.Ordinal))
                                       .ToList();
                    if (potentialMatches.Count != 1)
                    {
                        this.logger?.LogError("More than one method matched the rpc request. Unable to invoke due to ambiguity.");
                        throw new RpcMethodNotFoundException();
                    }
                }
            }

            RpcMethodInfo rpcMethod = null;

            if (potentialMatches.Count == 1)
            {
                rpcMethod = potentialMatches.First();
            }

            if (rpcMethod == null)
            {
                //Log diagnostics
                string methodsString = string.Join(", ", allMethods.Select(m => m.Name));
                this.logger?.LogTrace("Methods in route: " + methodsString);

                var methodInfoList = new List <string>();
                foreach (MethodInfo matchedMethod in methodsWithSameName)
                {
                    var parameterTypeList = new List <string>();
                    foreach (ParameterInfo parameterInfo in matchedMethod.GetParameters())
                    {
                        string parameterType = parameterInfo.Name + ": " + parameterInfo.ParameterType.Name;
                        if (parameterInfo.IsOptional)
                        {
                            parameterType += "(Optional)";
                        }
                        parameterTypeList.Add(parameterType);
                    }
                    string parameterString = string.Join(", ", parameterTypeList);
                    methodInfoList.Add($"{{Name: '{matchedMethod.Name}', Parameters: [{parameterString}]}}");
                }
                this.logger?.LogTrace("Methods that matched the same name: " + string.Join(", ", methodInfoList));
                this.logger?.LogError("No methods matched request.");
                throw new RpcMethodNotFoundException();
            }
            this.logger?.LogDebug("Request was matched to a method");
            return(rpcMethod);
        }
예제 #27
0
        /// <summary>
        /// Call the incoming Rpc request method and gives the appropriate response
        /// </summary>
        /// <param name="request">Rpc request</param>
        /// <param name="path">Rpc path that applies to the current request</param>
        /// <param name="httpContext">The context of the current http request</param>
        /// <returns>An Rpc response for the request</returns>
        public async Task <RpcResponse> InvokeRequestAsync(RpcRequest request, RpcPath path, IRouteContext routeContext)
        {
            try
            {
                if (request == null)
                {
                    throw new ArgumentNullException(nameof(request));
                }
            }
            catch (ArgumentNullException ex)             // Dont want to throw any exceptions when doing async requests
            {
                return(this.GetUnknownExceptionReponse(request, ex));
            }

            this.logger?.LogDebug($"Invoking request with id '{request.Id}'");
            RpcResponse rpcResponse;

            try
            {
                if (!string.Equals(request.JsonRpcVersion, JsonRpcContants.JsonRpcVersion))
                {
                    throw new RpcInvalidRequestException($"Request must be jsonrpc version '{JsonRpcContants.JsonRpcVersion}'");
                }

                RpcMethodInfo rpcMethod = this.GetMatchingMethod(path, request, routeContext.RouteProvider, routeContext.RequestServices);

                bool isAuthorized = await this.IsAuthorizedAsync(rpcMethod.Method, routeContext);

                if (isAuthorized)
                {
                    object result = null;
                    if (request.Id.HasValue)
                    {
                        this.logger?.LogDebug($"Attempting to invoke method '{request.Method}'");
                        result = await this.InvokeAsync(rpcMethod, path);

                        this.logger?.LogDebug($"Finished invoking method '{request.Method}'");
                    }
                    else
                    {
                        this.logger?.LogDebug($"Attempting to invoke notification '{request.Method}'");
                        this.FireAndForget(async() => await this.InvokeAsync(rpcMethod, path));
                    }

                    JsonSerializer jsonSerializer = this.GetJsonSerializer();
                    if (result is IRpcMethodResult)
                    {
                        this.logger?.LogTrace($"Result is {nameof(IRpcMethodResult)}.");
                        rpcResponse = ((IRpcMethodResult)result).ToRpcResponse(request.Id, obj => JToken.FromObject(obj, jsonSerializer));
                    }
                    else
                    {
                        this.logger?.LogTrace($"Result is plain object.");
                        JToken resultJToken = result != null?JToken.FromObject(result, jsonSerializer) : null;

                        rpcResponse = new RpcResponse(request.Id, resultJToken);
                    }
                }
                else
                {
                    var authError = new RpcError(RpcErrorCode.InvalidRequest, "Unauthorized");
                    rpcResponse = new RpcResponse(request.Id, authError);
                }
            }
            catch (RpcException ex)
            {
                this.logger?.LogException(ex, "An Rpc error occurred. Returning an Rpc error response");
                RpcError error = new RpcError(ex, this.serverConfig.Value.ShowServerExceptions);
                rpcResponse = new RpcResponse(request.Id, error);
            }
            catch (Exception ex)
            {
                rpcResponse = this.GetUnknownExceptionReponse(request, ex);
            }

            if (request.Id.HasValue)
            {
                this.logger?.LogDebug($"Finished request with id: {request.Id}");
                //Only give a response if there is an id
                return(rpcResponse);
            }

            this.logger?.LogDebug($"Finished request with no id.");
            return(rpcResponse);
        }