private object[] GetParameters(ObjectMethodExecutor executor, GrainRouteValues route) { //short circuit if no parameters if (executor.MethodParameters == null || executor.MethodParameters.Length == 0) { return(Array.Empty <object>()); } // loop through binders, in order // first suitable binder wins // so the order of registration is important ExceptionDispatchInfo lastException = null; try { var param = _parameterBinder.BindParameters(executor.MethodParameters, route); if (param.Length == executor.MethodParameters.Length) { return(param); } else { throw new UnableToFindDownstreamRouteException("The request parameter is inconsistent with the parameter that executes the action."); } } catch (Exception ex) { // continue on next suitable binder // but keep the exception when no other suitable binders are found lastException = ExceptionDispatchInfo.Capture(ex); } lastException?.Throw(); return(Array.Empty <object>()); }
private object[] GetParameters(ObjectMethodExecutor executor, GrainRouteValues route) { //short circuit if no parameters if (executor.MethodParameters == null || executor.MethodParameters.Length == 0) { return(Array.Empty <object>()); } // loop through binders, in order // first suitable binder wins // so the order of registration is important ExceptionDispatchInfo lastException = null; try { return(_parameterBinder.BindParameters(executor.MethodParameters, route)); } catch (Exception ex) { // continue on next suitable binder // but keep the exception when no other suitable binders are found lastException = ExceptionDispatchInfo.Capture(ex); } lastException?.Throw(); return(Array.Empty <object>()); }
public Response <bool> Authorise(ClaimsPrincipal claimsPrincipal, GrainRouteValues route) { var attrs = route.GrainMethod.GetCustomAttributes <AuthorizeAttribute>(true); if (attrs.Count() == 0) { return(new OkResponse <bool>(true)); } foreach (var attr in attrs) { if (!string.IsNullOrEmpty(attr.Roles)) { var response = this.AuthoriseRole(claimsPrincipal, attr.Roles); if (response.IsError || !response.Data) { return(response); } } if (!string.IsNullOrEmpty(attr.Policy)) { var response = this.AuthorisePolicy(claimsPrincipal, attr.Policy); if (response.IsError || !response.Data) { return(response); } } } return(new OkResponse <bool>(true)); }
public async Task <object> Invoke(GrainReference grain, GrainRouteValues route) { var executors = _cachedExecutors.GetOrAdd($"{grain.GrainType.FullName}.{route.GrainMethod}", (key) => { //Get grainType IEnumerable<MethodInfo> var mis = ReflectionUtil.GetMethodsIncludingBaseInterfaces(grain.GrainType) .Where(x => string.Equals(x.Name, route.GrainMethod, StringComparison.OrdinalIgnoreCase)).ToList(); if (mis.Count <= 0) { throw new ArgumentNullException(nameof(MethodInfo)); } List <ObjectMethodExecutor> _executors = new List <ObjectMethodExecutor>(); foreach (var mi in mis) { var exe = ObjectMethodExecutor.Create(mi, grain.GrainType.GetTypeInfo()); _executors.Add(exe); } _executors.Sort((x, y) => - x.MethodParameters.Count().CompareTo(y.MethodParameters.Count()) ); return(_executors); }); foreach (var executor in executors) { var parameters = await GetParameters(executor, route.HttpContext.Request); if (executor.MethodParameters.Count() == parameters.Length) { return(await executor.ExecuteAsync(grain.Grain, parameters)); } } throw new InvalidOperationException("No suitable parameter binder found for request"); }
public GrainReference GetGrain(GrainRouteValues route) { var grain = _GrainReferenceCache.GetOrAdd(route.GrainType.FullName, key => this.GetGrainReference(route)); var option = _options.Clients[route.SiloName]; if ((bool)option?.IsAuthorizationBearer) { this.SetAuthorization(route.HttpContext); } return(grain); }
private void GivenHeaderSuccess() { var route = new GrainRouteValues(); _routeValuesBuilder.Setup(x => x.Build(this.context)).Returns(new OkResponse <GrainRouteValues>(route)); _authorisation.Setup(x => x.Authorise(this.context.HttpContext.User, route)).Returns(new OkResponse <bool>(true)); var grain = new GrainReference(null, null); _clusterClientBuilder.Setup(x => x.Build(route, this.context)).Returns(new OkResponse <GrainReference>(grain)); Response <OrleansResponseMessage> response = new OkResponse <OrleansResponseMessage>(new OrleansResponseMessage(null, HttpStatusCode.OK)); _grainInvoker.Setup(x => x.Invoke(grain, route)).Returns(Task.FromResult(response)); }
public Response <GrainRouteValues> Build(DownstreamContext context) { try { GrainRouteValues route = this.GetRequestRoute(context); if (route == null) { return(this.SetUnableToFindDownstreamRouteError(context, $"The request address is invalid URL:{context.DownstreamRequest.ToUri()}")); } this._logger.LogDebug($"Http address translation Orleans request address {context.DownstreamRequest.ToUri()}"); //Get client option based on serviceName if (!_options.Clients.ContainsKey(route.SiloName)) { return(this.SetUnableToFindDownstreamRouteError(context, $"{nameof(OrleansClientOptions)} without {route.SiloName} configured ")); } route.ClientOptions = _options.Clients[route.SiloName]; //Find the request corresponding to the Orleans interface route.GrainType = this.GetGrainType(route); if (route.GrainType == null) { return(this.SetUnableToFindDownstreamRouteError(context, $"The request address is invalid,No corresponding Orleans interface found. URL:{route.RequestUri}")); } //Find the request corresponding to the method in the Orleans interface route.GrainMethod = this.GetGtainMethods(route); if (route.GrainMethod == null) { return(this.SetUnableToFindDownstreamRouteError(context, $"The request address is invalid and the corresponding method in the Orleans interface {route.SiloName}_#_{route.GrainName} was not found. {route.GrainMethodName}. URL:{route.RequestUri}")); } return(new OkResponse <GrainRouteValues>(route)); } catch (OrleansConfigurationException ex) { this._logger.LogError($"{nameof(OrleansConfigurationException)} {ex.Message}", ex); return(this.SetUnknownError(ex.Message)); } catch (OrleansGrainReferenceException ex) { this._logger.LogError($"{nameof(OrleansGrainReferenceException)} {ex.Message}", ex); return(this.SetUnknownError(ex.Message)); } catch (Exception ex) { this._logger.LogError(ex.Message, ex); return(this.SetUnknownError(ex.Message)); } }
private IClusterClient BuildClusterClient(GrainRouteValues routeValues, DownstreamContext context) { var clientOptions = routeValues.ClientOptions; IClientBuilder build = new ClientBuilder(); build.Configure <ClusterOptions>(opt => { opt.ClusterId = clientOptions.ClusterId; opt.ServiceId = clientOptions.ServiceId; }); build = this.UseServiceDiscovery(build, context); var client = build.Build(); return(this.ConnectClient(routeValues.GrainName, client)); }
private MethodInfo GetGtainMethods(GrainRouteValues route) { var methods = _MethodInfoCache.GetOrAdd($"{route.SiloName}_#_{route.GrainName}_#_{route.GrainMethodName}", (key) => { //Get grainType IEnumerable<MethodInfo> return(ReflectionUtil.GetMethodsIncludingBaseInterfaces(route.GrainType) .Where(x => string.Equals(x.Name, route.GrainMethodName, StringComparison.OrdinalIgnoreCase)).ToList()); }); if (methods.Count == 0) { return(null); } //Get the first method, temporarily only support one method with the same name return(methods.FirstOrDefault()); }
public object[] BindParameters(ParameterInfo[] parameters, GrainRouteValues routeValues) { if (parameters == null || parameters.Length <= 0) { return(Array.Empty <object>()); } var result = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { try { var param = parameters[i]; object value = null; if (param.ParameterType.CanHaveChildren()) { value = this.BindClassType(param, routeValues.Body); } else { value = this.BindPrimitiveType(param, routeValues.Querys, routeValues.Body); if (value == null) { if (param.HasDefaultValue) { value = param.DefaultValue; } else { return(new object[0]); } } } result[i] = value; } catch (Exception ex) { throw new OrleansGrainReferenceException("Bind this parameters data failed", ex); } } return(result); }
private GrainRouteValues GetRequestRoute(DownstreamContext context) { GrainRouteValues routeValues = new GrainRouteValues(); string[] route = context.DownstreamRequest.AbsolutePath.Split('/') .Where(s => !string.IsNullOrEmpty(s)) .ToArray(); if (route.Length < 2 || route.Length > 3) { return(null); } routeValues.SiloName = context.DownstreamReRoute.ServiceName; routeValues.GrainName = route[0]; routeValues.GrainMethodName = route[1]; routeValues.RequestUri = context.DownstreamRequest.ToUri(); //Claims to Claims Tranformation Whether to inject GrainKey var claim = context.HttpContext.User.FindFirst("GrainKey"); if (claim != null) { routeValues.GrainId = claim.Value; } else { routeValues.GrainId = (route.Length == 3) ? route[2] : null; } try { routeValues.Querys = this.GetQueryParameter(context.DownstreamRequest.Query); routeValues.Body = this.GetBodyParameter(context.DownstreamRequest, context.HttpContext.Request); } catch (Exception ex) { throw new OrleansGrainReferenceException("Error parsing request parameters ...", ex); } return(routeValues); }
public Response Build(GrainRouteValues routeValues, DownstreamContext context) { try { string clientKey = this.GetClientKey(routeValues.GrainType); if (clusterClientCache.Keys.Where(f => f == clientKey).Count() > 0) { return(new OkResponse()); } clusterClientCache.GetOrAdd(clientKey, (key) => { return(this.BuildClusterClient(routeValues, context)); }); return(new OkResponse()); } catch (Exception ex) { this._logger.LogError(ex.Message, ex); return(new ErrorResponse <GrainRouteValues>(new UnknownError(ex.Message))); } }
private Type GetGrainType(GrainRouteValues route) { return(_GrainTypeCache.GetOrAdd($"{route.SiloName}_#_{route.GrainName}", (key) => { this._logger.LogDebug($"Looking for the {route.ClientOptions.ServiceName} Grain interface"); if (this._config == null || this._config.MapRouteToGraininterface == null) { throw new OrleansConfigurationException($"{route.ClientOptions.ServiceName}Route map Grain interface configured to set"); } try { string grainInterface = this._config.MapRouteToGraininterface.Invoke(route); var types = route.ClientOptions.Assembly.GetExportedTypes(); return types.Where(f => typeof(IGrain).IsAssignableFrom(f) && f.Name.Equals(grainInterface, StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); } catch (Exception ex) { throw new OrleansConfigurationException($"{route.ClientOptions.ServiceName} Orleans Client Options configuration error, unable to find Grain interface", ex); } })); }
public Response <GrainReference> GetGrainReference(GrainRouteValues route) { try { var grainFunc = _GrainReferenceCache.GetOrAdd(route.GrainType.FullName, key => { return(this.BuildFactoryMethod(route.GrainType)); }); var grain = grainFunc(route.GrainId); var grainReference = new GrainReference(route.GrainType, grain); return(new OkResponse <GrainReference>(grainReference)); } catch (UnableToFindDownstreamRouteException ex) { this._logger.LogWarning(ex.Message); return(new ErrorResponse <GrainReference>(new UnableToFindDownstreamRouteError(route.RequestUri, "orleans"))); } catch (Exception ex) { this._logger.LogError(ex.Message, ex); return(new ErrorResponse <GrainReference>(new UnknownError(ex.Message))); } }
public async Task <Response <OrleansResponseMessage> > Invoke(GrainReference grain, GrainRouteValues route) { try { string key = $"{route.SiloName}.{route.GrainName}.{route.GrainMethodName}"; var executor = _cachedExecutors.GetOrAdd(key, (_key) => { ObjectMethodExecutor _executor = ObjectMethodExecutor.Create(route.GrainMethod, grain.GrainType.GetTypeInfo()); return(_executor); }); var parameters = GetParameters(executor, route); var result = await this.ExecuteAsync(executor, grain, parameters); var message = new OrleansResponseMessage(new OrleansContent(result, this._jsonSerializer), HttpStatusCode.OK); return(new OkResponse <OrleansResponseMessage>(message)); } catch (Exception ex) { _logger.LogError(ex.Message, ex); return(new ErrorResponse <OrleansResponseMessage>(new UnknownError(ex.Message))); } }
public GrainReference GetGrainReference(Type type, GrainRouteValues route) { var grain = this.BuildFactoryMethod(type)(route.GrainId); return(new GrainReference(type, grain)); }
private GrainRouteValues GetRequestRoute(DownstreamContext context) { GrainRouteValues routeValues = new GrainRouteValues(); string[] route = context.DownstreamRequest.AbsolutePath.Split('/') .Where(s => !string.IsNullOrEmpty(s)) .ToArray(); if (route.Length < 2 || route.Length > 3) { return(null); } routeValues.SiloName = context.DownstreamReRoute.ServiceName; routeValues.GrainName = route[0]; routeValues.GrainMethodName = route[1]; routeValues.RequestUri = context.DownstreamRequest.ToUri(); //Claims to Claims Tranformation Whether to inject GrainKey var claim = context.HttpContext.User.FindFirst("GrainKey"); if (claim != null) { routeValues.GrainId = claim.Value; } else { routeValues.GrainId = (route.Length == 3) ? route[2] : null; } try { routeValues.Querys = this.GetQueryParameter(context.DownstreamRequest.Query); var body = this.ReadBodyStream(context.DownstreamRequest); if (body != null && body.Length > 0) { var requestContentType = context.HttpContext.Request.GetTypedHeaders().ContentType; if (requestContentType == null) { routeValues.Body = null; } else { this._logger.LogInformation($"Http request ContentType :{requestContentType.MediaType.ToString()}"); if (requestContentType.MediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase)) { routeValues.Body = this.GetJsonParameter(body, context.HttpContext.Request); } else { routeValues.Body = this.GetFormDataParameter(body, context.HttpContext.Request); } } } } catch (Exception ex) { throw new OrleansGrainReferenceException("Error parsing request parameters ...", ex); } return(routeValues); }
private GrainReference GetGrainReference(GrainRouteValues route) { return(_grainReferenceProvider.GetGrainReference(route.GrainType, route)); }
public async Task <Response <OrleansResponseMessage> > Invoke(GrainReference grain, GrainRouteValues route) { ObjectMethodExecutor executor; object[] parameters; try { string key = $"{route.SiloName}.{route.GrainName}.{route.GrainMethodName}"; executor = _cachedExecutors.GetOrAdd(key, (_key) => { ObjectMethodExecutor _executor = ObjectMethodExecutor.Create(route.GrainMethod, grain.GrainType.GetTypeInfo()); return(_executor); }); parameters = GetParameters(executor, route); } catch (Exception ex) { _logger.LogError($"Binding parameter failed", ex); return(new ErrorResponse <OrleansResponseMessage>(new UnknownError(ex.Message))); } try { return(await this.Invoke(executor, grain, parameters)); } catch (Exception ex) { _logger.LogError($"Request {grain.GrainType.Name} Orleans failed,", ex); if (ex.InnerException != null && ex.InnerException is Orleans.Runtime.OrleansMessageRejectionException) { await Task.Delay(1); return(await this.Invoke(executor, grain, parameters)); } throw ex; } }