예제 #1
0
        protected Parameter GetPrimitiveParameter(ControllerParameterDescriptor apiParam)
        {
            var netType  = apiParam.ParameterType;
            var ramlType = MapParam(netType);

            return(GetParameter(apiParam, ramlType, netType));
        }
        private ControllerActionDescriptor CreateActionDescriptor(string httpMethod, string routeTemplate, MethodInfo methodInfo,
                                                                  string controllerName, GrainKeyParamterInfo grainKey)
        {
            var descriptor = new ControllerActionDescriptor();

            descriptor.SetProperty(new ApiDescriptionActionData());
            descriptor.ControllerTypeInfo = methodInfo.DeclaringType.GetTypeInfo();
            descriptor.MethodInfo         = methodInfo;
            descriptor.FilterDescriptors  = descriptor.MethodInfo.GetCustomAttributes <ProducesResponseTypeAttribute>()
                                            .Select((filter) => new FilterDescriptor(filter, FilterScope.Action))
                                            .ToList();
            descriptor.RouteValues = new Dictionary <string, string> {
                { "controller", controllerName }
            };
            descriptor.ActionConstraints = new List <IActionConstraintMetadata>();
            if (httpMethod != null)
            {
                descriptor.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod }));
            }

            descriptor.Parameters = new List <ParameterDescriptor>();
            List <ParameterInfo> ParameterInfos = descriptor.MethodInfo.GetParameters().ToList();

            if (grainKey.ParameterType != typeof(Guid))
            {
                ParameterInfos.Insert(0, grainKey);
            }
            foreach (var parameterInfo in ParameterInfos)
            {
                var parameterDescriptor = new ControllerParameterDescriptor
                {
                    Name          = parameterInfo.Name,
                    ParameterType = parameterInfo.ParameterType,
                    ParameterInfo = parameterInfo,
                    BindingInfo   = new BindingInfo()
                    {
                        BinderModelName = parameterInfo.Name,
                        BindingSource   = BindingSource.Query,
                        BinderType      = parameterInfo.ParameterType
                    }
                };
                if (parameterInfo.ParameterType.CanHaveChildren())
                {
                    parameterDescriptor.BindingInfo.BindingSource = BindingSource.Body;
                }

                if (parameterInfo is GrainKeyParamterInfo)
                {
                    routeTemplate += "/{" + grainKey.Name + "}";
                    parameterDescriptor.BindingInfo.BindingSource = BindingSource.Path;
                }
                descriptor.Parameters.Add(parameterDescriptor);
            }
            ;
            descriptor.AttributeRouteInfo = new AttributeRouteInfo {
                Template = routeTemplate
            };

            return(descriptor);
        }
        private bool TryMatch(IList <ParameterDescriptor> parameters, IList <string> availableKeys, ODataOptionalParameter optionalWrapper)
        {
            // use the parameter name to match.
            foreach (var p in parameters)
            {
                string parameterName = p.Name.ToLowerInvariant();
                if (availableKeys.Contains(parameterName))
                {
                    continue;
                }

                ControllerParameterDescriptor cP = p as ControllerParameterDescriptor;
                if (cP != null && optionalWrapper != null)
                {
                    if (cP.ParameterInfo.IsOptional && optionalWrapper.OptionalParameters.Any(o => o.Name.ToLowerInvariant() == parameterName))
                    {
                        continue;
                    }
                }

                return(false);
            }

            return(true);
        }
예제 #4
0
        public ActionArgument(ControllerParameterDescriptor descriptor, object value)
        {
            Guard.EnsureIsNotNull(descriptor, nameof(descriptor));

            Descriptor   = descriptor;
            Value        = value;
            DefaultValue = descriptor.ParameterInfo.DefaultValue;
        }
예제 #5
0
        public IActionResult CallByName([FromBody] JObject body)
        {
            Guard.NotNull(body, nameof(body));

            try
            {
                if (!this.rpcSettings.Server)
                {
                    return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method not allowed when RPC is disabled."));
                }

                StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase;
                string           methodName = (string)body.GetValue("methodName", ignoreCase);

                ControllerActionDescriptor actionDescriptor = null;
                if (!this.GetActionDescriptors()?.TryGetValue(methodName, out actionDescriptor) ?? false)
                {
                    throw new Exception($"RPC method '{ methodName }' not found.");
                }

                // Prepare the named parameters that were passed via the query string in the order that they are expected by SendCommand.
                List <ControllerParameterDescriptor> paramInfos = actionDescriptor.Parameters.OfType <ControllerParameterDescriptor>().ToList();

                var paramsAsObjects = new object[paramInfos.Count];
                for (int i = 0; i < paramInfos.Count; i++)
                {
                    ControllerParameterDescriptor pInfo = paramInfos[i];
                    bool hasValue = body.TryGetValue(pInfo.Name, ignoreCase, out JToken jValue);
                    if (hasValue && !jValue.HasValues)
                    {
                        paramsAsObjects[i] = jValue.ToString();
                    }
                    else
                    {
                        paramsAsObjects[i] = pInfo.ParameterInfo.DefaultValue?.ToString();
                    }
                }

                RPCRequest request = new RPCRequest(methodName, paramsAsObjects);

                // Build RPC request object.
                RPCResponse response = this.SendRPCRequest(request);

                // Throw error if any.
                if (response?.Error?.Message != null)
                {
                    throw new Exception(response.Error.Message);
                }

                // Return a Json result from the API call.
                return(this.Json(response?.Result));
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred: {0}", e.ToString());
                return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()));
            }
        }
예제 #6
0
        public ApiParameterMeta(ControllerParameterDescriptor descriptor)
        {
            Check.NotNull(descriptor, nameof(descriptor));

            this.ParameterName = descriptor.Name;
            //this.ParameterType = descriptor.ParameterType;
            this.IsOptional   = descriptor.ParameterInfo.IsOptional;
            this.DefaultValue = descriptor.ParameterInfo.DefaultValue;
        }
예제 #7
0
        private string GetParameterName(ControllerParameterDescriptor parameter)
        {
            var routeAttr  = parameter.ParameterInfo.GetCustomAttribute <FromRouteAttribute>();
            var queryAttr  = parameter.ParameterInfo.GetCustomAttribute <FromQueryAttribute>();
            var headerAttr = parameter.ParameterInfo.GetCustomAttribute <FromHeaderAttribute>();
            var formAttr   = parameter.ParameterInfo.GetCustomAttribute <FromFormAttribute>();

            return(routeAttr?.Name ?? queryAttr?.Name ?? headerAttr?.Name ?? formAttr?.Name ?? parameter.Name);
        }
 public ParameterFilterContext(
     ApiParameterDescription apiParameterDescription,
     ControllerParameterDescriptor controllerParameterDescriptor,
     ISchemaRegistry schemaRegistry)
 {
     ApiParameterDescription       = apiParameterDescription;
     ControllerParameterDescriptor = controllerParameterDescriptor;
     SchemaRegistry = schemaRegistry;
 }
예제 #9
0
        public async Task BindModelAsync_ForParameter_UsesValidationFromParameter_WhenDerivedModelIsSet()
        {
            // Arrange
            var method              = GetType().GetMethod(nameof(TestMethodWithAttributes), BindingFlags.NonPublic | BindingFlags.Instance);
            var parameter           = method.GetParameters()[0];
            var parameterDescriptor = new ControllerParameterDescriptor
            {
                ParameterInfo = parameter,
                Name          = parameter.Name,
            };

            var actionContext         = GetControllerContext();
            var modelMetadataProvider = new TestModelMetadataProvider();

            var model = new DerivedPerson {
                DerivedProperty = "SomeValue"
            };
            var modelBindingResult = ModelBindingResult.Success(model);

            var parameterBinder = new ParameterBinder(
                modelMetadataProvider,
                Mock.Of <IModelBinderFactory>(),
                new DefaultObjectValidator(
                    modelMetadataProvider,
                    new[] { TestModelValidatorProvider.CreateDefaultProvider() },
                    new MvcOptions()),
                _optionsAccessor,
                NullLoggerFactory.Instance);

            var modelMetadata = modelMetadataProvider.GetMetadataForParameter(parameter);
            var modelBinder   = CreateMockModelBinder(modelBindingResult);

            // Act
            var result = await parameterBinder.BindModelAsync(
                actionContext,
                modelBinder,
                CreateMockValueProvider(),
                parameterDescriptor,
                modelMetadata,
                value : null);

            // Assert
            Assert.True(result.IsModelSet);
            Assert.Same(model, result.Model);

            Assert.False(actionContext.ModelState.IsValid);
            Assert.Collection(
                actionContext.ModelState,
                kvp =>
            {
                Assert.Equal(parameter.Name, kvp.Key);
                var error = Assert.Single(kvp.Value.Errors);
                Assert.Equal("Always Invalid", error.ErrorMessage);
            });
        }
        private static ParameterDescriptor CreateParameterDescriptor(ParameterModel parameterModel)
        {
            var parameterDescriptor = new ControllerParameterDescriptor()
            {
                Name          = parameterModel.ParameterName,
                ParameterType = parameterModel.ParameterInfo.ParameterType,
                BindingInfo   = parameterModel.BindingInfo,
                ParameterInfo = parameterModel.ParameterInfo,
            };

            return(parameterDescriptor);
        }
예제 #11
0
        public ApiParameterMeta(ControllerParameterDescriptor descriptor)
        {
            if (descriptor == null)
            {
                throw new ArgumentNullException(nameof(descriptor));
            }

            ParameterName = descriptor.Name;
            ParameterType = descriptor.ParameterType;
            IsOptional    = descriptor.ParameterInfo.IsOptional;
            DefaultValue  = descriptor.ParameterInfo.DefaultValue;
        }
예제 #12
0
        /// <summary>
        /// 嘗試取得相應的模型綁定器
        /// </summary>
        /// <param name="context">綁定內容</param>
        /// <returns>模型綁定器實例</returns>
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }


            if (context.Metadata.IsComplexType)
            {
                var propName  = context.Metadata.PropertyName;
                var propInfo  = context.Metadata.ContainerType?.GetProperty(propName);
                var attribute = propInfo
                                ?.GetCustomAttributes(typeof(FromJsonAttribute), false)
                                ?.FirstOrDefault();

                // 直接將整個FormData綁定至單一複雜類型的參數上
                if (propName != null && propInfo != null && attribute != null)
                {
                    return(new MultipartJsonModelBinderProvider());
                }

                if (context?.Metadata?.BinderType?.GetCustomAttribute <FromJsonAttribute>() != null)
                {
                    return(new MultipartJsonModelBinderProvider());
                }

                var visited = context.GetType().GetProperty("Visited", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

                ControllerParameterDescriptor cpd = null;
                foreach (var item in (IEnumerable)visited.GetValue(context))
                {
                    var temp       = item.GetType().GetProperty("Key").GetValue(item);
                    var tokenField = temp.GetType().GetField("_token", BindingFlags.Instance | BindingFlags.NonPublic);
                    cpd = tokenField.GetValue(temp) as ControllerParameterDescriptor;

                    if (cpd != null)
                    {
                        break;
                    }
                }

                if (cpd != null && cpd.ParameterInfo.GetCustomAttribute <FromJsonAttribute>() != null)
                {
                    return(new MultipartJsonModelBinderProvider());
                }
            }

            return(null);
        }
예제 #13
0
        protected Parameter GetParameter(ControllerParameterDescriptor apiParam, string ramlType, Type parameterType)
        {
            var parameter = new Parameter
            {
                Default = apiParam.ParameterInfo.HasDefaultValue
                    ? null
                    : apiParam.ParameterInfo.DefaultValue.ToString(),
                Required    = !apiParam.ParameterInfo.IsOptional,
                Type        = ramlType,
                DisplayName = apiParam.Name
            };

            return(parameter);
        }
예제 #14
0
        /// <summary>
        /// 创建接口参数
        /// </summary>
        /// <param name="pams"></param>
        /// <param name="schemaRegistry"></param>
        /// <returns></returns>
        public IParameter CreateParamters(ControllerParameterDescriptor pams, ISchemaRegistry schemaRegistry)
        {
            var location = GetParameterLocation(pams);

            var schema = (pams.ParameterType == null) ? null : schemaRegistry.GetOrRegister(pams.ParameterType);

            if (location == "body")
            {
                return(new BodyParameter
                {
                    Name = pams.Name,
                    Description = pams.Name,
                    Schema = schema
                });
            }

            if (location != "header" && location != "query")
            {
                location = "path";
            }

            var nonBodyParam = new NonBodyParameter
            {
                Name     = pams.Name,
                In       = location,
                Required = (location == "path"),
            };

            if (schema == null)
            {
                nonBodyParam.Type = "string";
            }
            else
            {
                nonBodyParam.PopulateFrom(schema);
            }

            if (nonBodyParam.Type == "array")
            {
                nonBodyParam.CollectionFormat = "multi";
            }

            return(nonBodyParam);
        }
        private void GetQueryParameter(ControllerParameterDescriptor apiParam, Dictionary <string, Parameter> queryParams)
        {
            Parameter parameter;

            if (!IsPrimitiveType(apiParam.ParameterType))
            {
                var typeName = typeBuilder.Add(apiParam.ParameterType);
                parameter = GetParameter(apiParam, typeName, apiParam.ParameterType);
            }
            else
            {
                parameter = GetPrimitiveParameter(apiParam);
            }

            if (!queryParams.ContainsKey(apiParam.Name))
            {
                queryParams.Add(apiParam.Name, parameter);
            }
        }
예제 #16
0
        /// <summary>
        /// Get the first parameter with the MapFromBody attribute for the specified action descriptor.
        /// </summary>
        /// <param name="actionDescriptor">The action descriptor on which to search for the parameter.</param>
        /// <param name="parameterDescriptor">Parameter descriptor result.</param>
        /// <param name="mapFromBodyAttribute">MapFromBodyAttribute instance result.</param>
        public static void GetMapFromBodyParameter(this ActionDescriptor actionDescriptor, out ControllerParameterDescriptor parameterDescriptor, out MapFromBodyAttribute mapFromBodyAttribute)
        {
            ControllerParameterDescriptor resultParamDescriptor = null;
            MapFromBodyAttribute          resultAttribute       = null;

            var controllerParameters = actionDescriptor.Parameters.OfType <ControllerParameterDescriptor>();

            foreach (var param in controllerParameters)
            {
                resultAttribute = param.ParameterInfo.GetCustomAttribute <MapFromBodyAttribute>();
                if (resultAttribute != null)
                {
                    resultParamDescriptor = param;
                    break;
                }
            }

            parameterDescriptor  = resultParamDescriptor;
            mapFromBodyAttribute = resultAttribute;
        }
예제 #17
0
 public void OnResourceExecuting(ResourceExecutingContext context)
 {
     // 如果是api控制器,则处理
     if (context.ActionDescriptor.FilterDescriptors.FirstOrDefault(x => x.Filter is ApiControllerAttribute) !=
         null)
     {
         var p = context.ActionDescriptor.Parameters[0] as ControllerParameterDescriptor;
         ControllerParameterDescriptor cpd = new ControllerParameterDescriptor()
         {
             Name          = p.Name,
             BindingInfo   = p.BindingInfo,
             ParameterType = typeof(Args <>).MakeGenericType(p.ParameterType),
             ParameterInfo = p.ParameterInfo,
         };
         p.ParameterType = typeof(Args <>).MakeGenericType(p.ParameterType);
         MyParameterInfo mp = new MyParameterInfo(p.ParameterInfo);
         mp.ChangeType   = p.ParameterType;
         p.ParameterInfo = mp;
     }
 }
 public void OnProvidersExecuted(ApiDescriptionProviderContext context)
 {
     foreach (ApiDescription desc in context.Results)
     {
         foreach (ApiParameterDescription param in desc.ParameterDescriptions)
         {
             // Mvc chokes on parameters with [Required] on them. Give it a hand.
             ControllerParameterDescriptor actionParam = desc.ActionDescriptor.Parameters
                                                         .OfType <ControllerParameterDescriptor>()
                                                         .FirstOrDefault(p => p.Name == param.Name);
             if (actionParam != null)
             {
                 if (actionParam.ParameterInfo.GetCustomAttributes()
                     .Any(a => a.GetType().Name == "RequiredAttribute"))
                 {
                     param.ModelMetadata = new SetRequiredModelMetadata(param.ModelMetadata);
                 }
             }
         }
     }
 }
예제 #19
0
        private object GetBodyData(ActionExecutingContext actionContext, IValidator bodyValidator)
        {
            ControllerParameterDescriptor descriptor = actionContext.ActionDescriptor
                                                       .Parameters
                                                       .Cast <ControllerParameterDescriptor>()
                                                       .SingleOrDefault(prm => prm.ParameterInfo.GetCustomAttributes(typeof(FromBodyAttribute), inherit: true)
                                                                        .Any());

            if (descriptor == null)
            {
                throw new ArgumentException("Method must have FromBodyAttribute");
            }

            if (bodyValidator.CanValidateInstancesOfType(descriptor.ParameterType) == false)
            {
                throw new ArgumentException(
                          $"Validator {bodyValidatorType.Name} can't validate object type {descriptor.ParameterType}");
            }

            return(actionContext.ActionArguments[descriptor.Name]);
        }
        public async Task BinderTypeOnParameterType_WithData_EmptyPrefix_GetsBound(BindingInfo bindingInfo)
        {
            // Arrange
            var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
            var parameters      = typeof(TestController).GetMethod(nameof(TestController.Action)).GetParameters();
            var parameter       = new ControllerParameterDescriptor
            {
                Name          = "Parameter1",
                BindingInfo   = bindingInfo,
                ParameterInfo = parameters[0],
                ParameterType = typeof(Address),
            };

            var testContext = ModelBindingTestHelper.GetTestContext();
            var modelState  = testContext.ModelState;

            // Act
            var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext);

            // Assert
            // ModelBindingResult
            Assert.True(modelBindingResult.IsModelSet);

            // Model
            var address = Assert.IsType <Address>(modelBindingResult.Model);

            Assert.Equal("SomeStreet", address.Street);

            // ModelState
            Assert.True(modelState.IsValid);
            var kvp = Assert.Single(modelState);

            Assert.Equal("Street", kvp.Key);
            var entry = kvp.Value;

            Assert.NotNull(entry);
            Assert.Equal(ModelValidationState.Valid, entry.ValidationState);
            Assert.NotNull(entry.RawValue); // Value is set by test model binder, no need to validate it.
        }
        public IActionResult CallByName([FromQuery] string methodName)
        {
            try
            {
                ControllerActionDescriptor actionDescriptor = null;
                if (!this.GetActionDescriptors()?.TryGetValue(methodName, out actionDescriptor) ?? false)
                {
                    throw new Exception($"RPC method '{ methodName }' not found.");
                }

                // Prepare the named parameters that were passed via the query string in the order that they are expected by SendCommand.
                List <ControllerParameterDescriptor> paramInfo = actionDescriptor.Parameters.OfType <ControllerParameterDescriptor>().ToList();
                var param = new object[paramInfo.Count];
                for (int i = 0; i < paramInfo.Count; i++)
                {
                    ControllerParameterDescriptor       pInfo        = paramInfo[i];
                    KeyValuePair <string, StringValues> stringValues = this.Request.Query.FirstOrDefault(p => p.Key.ToLower() == pInfo.Name.ToLower());
                    param[i] = (stringValues.Key == null) ? pInfo.ParameterInfo.HasDefaultValue ? pInfo.ParameterInfo.DefaultValue.ToString() : null : stringValues.Value[0];
                }

                // Build RPC request object.
                RPCResponse response = this.SendRPCRequest(new RPCRequest(methodName, param));

                // Throw error if any.
                if (response?.Error?.Message != null)
                {
                    throw new Exception(response.Error.Message);
                }

                // Return a Json result from the API call.
                return(this.Json(response?.Result));
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred: {0}", e.ToString());
                return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()));
            }
        }
예제 #22
0
        private List <ApiDescriptionGroup> CreateDescriptors()
        {
            var groups    = new List <ApiDescriptionGroup>();
            var grainList = DiscoverGrainTypesToMap(grainInterfaceFeature);

            foreach (var grainType in grainList)
            {
                var typeDescription = grainType.GetCustomAttribute <DescriptionAttribute>();
                var groupName       = typeDescription?.Description ?? grainType.Name;
                var apiItems        = new List <ApiDescription>();
                var methods         = grainType.GetMethods().Where(m => m.GetCustomAttributes(true)
                                                                   .Any(attr => attr.GetType() == _routeAttributeType || _methodAttributeTypes.Contains(attr.GetType()))).ToArray();


                foreach (var methodInfo in methods)
                {
                    var methodAttributes = methodInfo.GetCustomAttributes(true)
                                           .Where(attr => attr is Orleans.Http.Abstractions.MethodAttribute).SingleOrDefault() as Orleans.Http.Abstractions.MethodAttribute;
                    if (null == methodAttributes)
                    {
                        continue;
                    }
                    var descriptor = new ControllerActionDescriptor()
                    {
                        ControllerName     = groupName,
                        ActionName         = methodInfo.Name,
                        DisplayName        = methodInfo.Name,
                        MethodInfo         = methodInfo,
                        ControllerTypeInfo = methodInfo.DeclaringType.GetTypeInfo(),
                        RouteValues        = new Dictionary <string, string>()
                        {
                            { "controller", groupName }
                        },
                        AttributeRouteInfo = new AttributeRouteInfo()
                        {
                            Name     = methodInfo.Name,
                            Template = methodAttributes.Pattern
                        },
                        ActionConstraints = new List <IActionConstraintMetadata>()
                        {
                            new HttpMethodActionConstraint(new[] { methodAttributes.Method })
                        },
                        Parameters        = new List <ParameterDescriptor>(),
                        BoundProperties   = new List <ParameterDescriptor>(),
                        FilterDescriptors = new List <FilterDescriptor>(),
                        Properties        = new Dictionary <object, object>()
                    };

                    var description = new ApiDescription()
                    {
                        ActionDescriptor = descriptor,
                        GroupName        = groupName,
                        HttpMethod       = methodAttributes.Method,
                        RelativePath     = $"grains/{methodAttributes.Pattern}"
                    };

                    var methodParams = methodInfo.GetParameters();

                    foreach (var parameter in methodParams)
                    {
                        var bindsource = BindingSource.Path;
                        var attribute  = parameter.GetCustomAttributes()
                                         .Where(attr => _parameterAttributeTypes.Contains(attr.GetType())).FirstOrDefault();
                        if (attribute != null)
                        {
                            if (attribute is Orleans.Http.Abstractions.FromBodyAttribute)
                            {
                                bindsource = BindingSource.Body;
                            }
                            else if (attribute is Orleans.Http.Abstractions.FromQueryAttribute)
                            {
                                bindsource = BindingSource.Query;
                            }
                        }
                        var parameterDescriptor = new ControllerParameterDescriptor()
                        {
                            Name          = parameter.Name,
                            ParameterType = parameter.ParameterType,

                            /* BindingInfo = new BindingInfo()
                             * {
                             *   BinderModelName = parameter.Name,
                             *   BindingSource = bindsource,
                             *   BinderType = parameter.ParameterType
                             * },*/
                            ParameterInfo = parameter
                        };

                        descriptor.Parameters.Add(parameterDescriptor);

                        description.ParameterDescriptions.Add(new ApiParameterDescription()
                        {
                            ModelMetadata = metadataProvider.GetMetadataForType(parameter.ParameterType),
                            Name          = parameter.Name,
                            RouteInfo     = new ApiParameterRouteInfo(),
                            Type          = parameter.ParameterType,
                            Source        = bindsource,
                            IsRequired    = true
                        });
                    }
                    //support path route ?

                    description.SupportedRequestFormats.Add(new ApiRequestFormat()
                    {
                        MediaType = "application/json"
                    });
                    description.SupportedResponseTypes.Add(new ApiResponseType()
                    {
                        ApiResponseFormats = new List <ApiResponseFormat>()
                        {
                            new ApiResponseFormat()
                            {
                                MediaType = "application/json"
                            }
                        },
                        ModelMetadata = metadataProvider
                                        .GetMetadataForType(/*methodInfo.ReturnType*/ typeof(System.Text.Json.JsonElement)),
                        Type       = methodInfo.ReturnType,
                        StatusCode = (int)System.Net.HttpStatusCode.OK
                    });;
                    //InferRequestContentTypes(description);
                    apiItems.Add(description);
                }

                var group = new ApiDescriptionGroup(groupName, new ReadOnlyCollection <ApiDescription>(apiItems));

                groups.Add(group);
            }
            return(groups);
        }
예제 #23
0
 private bool IsFromRoute(ControllerParameterDescriptor parameter)
 {
     return(parameter.ParameterInfo.GetCustomAttribute <FromRouteAttribute>() != null);
 }
예제 #24
0
        /// <inheritdoc />
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            // Special logic for body, treat the model name as string.Empty for the top level
            // object, but allow an override via BinderModelName. The purpose of this is to try
            // and be similar to the behavior for POCOs bound via traditional model binding.
            string modelBindingKey;

            if (bindingContext.IsTopLevelObject)
            {
                modelBindingKey = bindingContext.BinderModelName ?? string.Empty;
            }
            else
            {
                modelBindingKey = bindingContext.ModelName;
            }

            var httpContext = bindingContext.HttpContext;

            // Get the mapping source type and its metadata info
            var controllerParameters = bindingContext.ActionContext.ActionDescriptor.Parameters.OfType <ControllerParameterDescriptor>();
            ControllerParameterDescriptor mapFromBodyParameter = null;
            MapFromBodyAttribute          mapFromBodyAttribute = null;

            foreach (var param in controllerParameters)
            {
                mapFromBodyAttribute = param.ParameterInfo.GetCustomAttribute <MapFromBodyAttribute>();
                if (mapFromBodyAttribute != null)
                {
                    mapFromBodyParameter = param;
                    break;
                }
            }

            // Set the formatter context for the mapped parameter if found

            InputFormatterContext formatterContext = null;

            if (mapFromBodyParameter == null || mapFromBodyAttribute == null)
            {
                formatterContext = new InputFormatterContext(
                    httpContext,
                    modelBindingKey,
                    bindingContext.ModelState,
                    bindingContext.ModelMetadata,
                    _readerFactory);
            }
            else
            {
                var mappedModelMetadata = _modelMetadataProvider.GetMetadataForType(mapFromBodyAttribute.SourceType);
                formatterContext = new InputFormatterContext(
                    httpContext,
                    modelBindingKey,
                    bindingContext.ModelState,
                    mappedModelMetadata,
                    _readerFactory);
            }

            var formatter = (IInputFormatter)null;

            for (var i = 0; i < _formatters.Count; i++)
            {
                if (_formatters[i].CanRead(formatterContext))
                {
                    formatter = _formatters[i];
                    break;
                }
            }

            if (formatter == null)
            {
                var message = string.Format("Unsupported content type '{0}'.", httpContext.Request.ContentType);

                var exception = new UnsupportedContentTypeException(message);
                bindingContext.ModelState.AddModelError(modelBindingKey, exception, bindingContext.ModelMetadata);
                return;
            }

            try
            {
                var previousCount = bindingContext.ModelState.ErrorCount;
                var result        = await formatter.ReadAsync(formatterContext);

                var model = result.Model;

                if (result.HasError)
                {
                    // Formatter encountered an error. Do not use the model it returned.
                    return;
                }

                if (mapFromBodyParameter != null && mapFromBodyAttribute != null)
                {
                    // Map the model to the desired model in the action
                    model = _mapper.Map(model, mapFromBodyAttribute.SourceType, bindingContext.ModelType);
                }

                bindingContext.Result = ModelBindingResult.Success(model);
                return;
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError(modelBindingKey, ex, bindingContext.ModelMetadata);
                return;
            }
        }
예제 #25
0
        /// <summary>
        /// Checks whether the a controller action matches the current route by comparing the parameters
        /// of the action with the data in the route.
        /// </summary>
        /// <param name="context">The current <see cref="RouteContext"/></param>
        /// <param name="actionDescriptor">The action descriptor</param>
        /// <param name="parameters">Parameters of the action. This excludes the <see cref="ODataPath"/> and <see cref="Query.ODataQueryOptions"/> parameters</param>
        /// <param name="availableKeys">The names of the keys found in the uri (entity set keys, related keys, operation parameters)</param>
        /// <param name="optionalWrapper">Used to check whether a parameter is optional</param>
        /// <param name="totalParameterCount">Total number of parameters in the action method</param>
        /// <param name="availableKeysCount">The number of key segments found in the uri.
        /// This might be less than the size of <paramref name="availableKeys"/> because some keys might have alias names</param>
        /// <returns></returns>
        private bool TryMatch(
            RouteContext context,
            ActionDescriptor actionDescriptor,
            IList <ParameterDescriptor> parameters,
            IList <string> availableKeys,
            ODataOptionalParameter optionalWrapper,
            int totalParameterCount,
            int availableKeysCount)
        {
            if (actionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
            {
                // if this specific method was selected (e.g. via AttributeRouting)
                // then we return a match regardless of whether or not the parameters of
                // the method match the keys in the route
                if (context.RouteData.Values.TryGetValue(ODataRouteConstants.MethodInfo, out object method) && method is MethodInfo methodInfo)
                {
                    if (controllerActionDescriptor.MethodInfo == methodInfo)
                    {
                        return(true);
                    }
                }

                // if action has [EnableNestedPaths] attribute, then it doesn't
                // need to match parameters, since this action is expected to
                // match arbitrarily nested paths even if it doesn't have any parameters
                if (controllerActionDescriptor.MethodInfo
                    .GetCustomAttributes <EnableNestedPathsAttribute>().Any())
                {
                    return(true);
                }
            }

            // navigationProperty is optional in some cases, therefore an action
            // should not be rejected simply because it does not declare a navigationProperty parameter
            if (availableKeys.Contains(ODataRouteConstants.NavigationProperty.ToLowerInvariant()))
            {
                availableKeysCount -= 1;
            }

            // reject action if it doesn't declare a parameter for each segment key
            // e.g. Get() will be rejected for route /Persons/1
            if (totalParameterCount < availableKeysCount)
            {
                return(false);
            }

            bool matchedBody = false;
            IDictionary <string, object> conventionsStore = context.HttpContext.ODataFeature().RoutingConventionsStore;

            // use the parameter name to match.
            foreach (ParameterDescriptor p in parameters)
            {
                string parameterName = p.Name.ToLowerInvariant();
                if (availableKeys.Contains(parameterName))
                {
                    continue;
                }

                if (conventionsStore != null)
                {
                    // the convention store can contain the parameter as key
                    // with a nested property (e.g. customer.Name)
                    if (conventionsStore.Keys.Any(k => k.Contains(p.Name)))
                    {
                        continue;
                    }
                }

                if (context.HttpContext.Request.Query.ContainsKey(p.Name))
                {
                    continue;
                }

                ControllerParameterDescriptor cP = p as ControllerParameterDescriptor;
                if (cP != null && optionalWrapper != null)
                {
                    if (cP.ParameterInfo.IsOptional && optionalWrapper.OptionalParameters.Any(o => o.Name.ToLowerInvariant() == parameterName))
                    {
                        continue;
                    }
                }

                // if we can't find the parameter in the request, check whether
                // there's a special model binder registered to handle it
                if (ParameterHasRegisteredModelBinder(p))
                {
                    continue;
                }

                // if parameter is not bound to a key in the path,
                // assume that it's bound to the request body
                // only one parameter should be considered bound to the body
                if (!matchedBody && RequestHasBody(context))
                {
                    matchedBody = true;
                    continue;
                }

                return(false);
            }

            return(true);
        }
예제 #26
0
        /// <summary>
        /// Checks whether the a controller action matches the current route by comparing the parameters
        /// of the action with the data in the route.
        /// </summary>
        /// <param name="context">The current <see cref="RouteContext"/></param>
        /// <param name="parameters">Parameters of the action. This excludes the <see cref="ODataPath"/> and <see cref="Query.ODataQueryOptions"/> parameters</param>
        /// <param name="availableKeys">The names of the keys found in the uri (entity set keys, related keys, operation parameters)</param>
        /// <param name="optionalWrapper">Used to check whether a parameter is optional</param>
        /// <param name="totalParameterCount">Total number of parameters in the action method</param>
        /// <param name="availableKeysCount">The number of key segments found in the uri.
        /// This might be less than the size of <paramref name="availableKeys"/> because some keys might have alias names</param>
        /// <returns></returns>
        private bool TryMatch(
            RouteContext context,
            IList <ParameterDescriptor> parameters,
            IList <string> availableKeys,
            ODataOptionalParameter optionalWrapper,
            int totalParameterCount,
            int availableKeysCount)
        {
            // navigationProperty is optional in some cases, therefore an action
            // should not be rejected simply because it does not declare a navigationProperty parameter
            if (availableKeys.Contains(ODataRouteConstants.NavigationProperty.ToLowerInvariant()))
            {
                availableKeysCount -= 1;
            }

            // reject action if it doesn't declare a parameter for each segment key
            // e.g. Get() will be rejected for route /Persons/1
            if (totalParameterCount < availableKeysCount)
            {
                return(false);
            }

            bool matchedBody      = false;
            var  conventionsStore = context.HttpContext.ODataFeature().RoutingConventionsStore;

            // use the parameter name to match.
            foreach (var p in parameters)
            {
                string parameterName = p.Name.ToLowerInvariant();
                if (availableKeys.Contains(parameterName))
                {
                    continue;
                }

                if (conventionsStore != null)
                {
                    // the convention store can contain the parameter as key
                    // with a nested property (e.g. customer.Name)
                    if (conventionsStore.Keys.Any(k => k.Contains(p.Name)))
                    {
                        continue;
                    }
                }

                if (context.HttpContext.Request.Query.ContainsKey(p.Name))
                {
                    continue;
                }

                ControllerParameterDescriptor cP = p as ControllerParameterDescriptor;
                if (cP != null && optionalWrapper != null)
                {
                    if (cP.ParameterInfo.IsOptional && optionalWrapper.OptionalParameters.Any(o => o.Name.ToLowerInvariant() == parameterName))
                    {
                        continue;
                    }
                }

                // if we can't find the parameter in the request, check whether
                // there's a special model binder registered to handle it
                if (ParameterHasRegisteredModelBinder(p))
                {
                    continue;
                }

                // if parameter is not bound to a key in the path,
                // assume that it's bound to the request body
                // only one parameter should be considered bound to the body
                if (!matchedBody && RequestHasBody(context))
                {
                    matchedBody = true;
                    continue;
                }

                return(false);
            }

            return(true);
        }
예제 #27
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="operation">Operation</param>
        /// <param name="context">OperationFilterContext</param>
        public void Apply(Operation operation, OperationFilterContext context)
        {
            var pars = context.ApiDescription.ParameterDescriptions;

            foreach (var par in pars)
            {
                var swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name);

                ControllerParameterDescriptor parameterDescriptor = par.ParameterDescriptor as ControllerParameterDescriptor;
                System.Collections.Generic.IEnumerable <System.Reflection.CustomAttributeData> attributes = null;

                if (parameterDescriptor != null)
                {
                    attributes = parameterDescriptor.ParameterInfo.CustomAttributes;
                }

                if (attributes != null && attributes.Count() > 0 && swaggerParam != null)
                {
                    // Required - [Required]
                    var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute));
                    if (requiredAttr != null)
                    {
                        swaggerParam.Required = true;
                    }

                    // Regex Pattern [RegularExpression]
                    var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute));
                    if (regexAttr != null)
                    {
                        string regex = (string)regexAttr.ConstructorArguments[0].Value;
                        if (swaggerParam is NonBodyParameter)
                        {
                            ((NonBodyParameter)swaggerParam).Pattern = regex;
                        }
                    }

                    // String Length [StringLength]
                    int?minLenght = null, maxLength = null;
                    var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute));
                    if (stringLengthAttr != null)
                    {
                        if (stringLengthAttr.NamedArguments.Count == 1)
                        {
                            minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value;
                        }
                        maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value;
                    }

                    var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute));
                    if (minLengthAttr != null)
                    {
                        minLenght = (int)minLengthAttr.ConstructorArguments[0].Value;
                    }

                    var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute));
                    if (maxLengthAttr != null)
                    {
                        maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value;
                    }

                    if (swaggerParam is NonBodyParameter)
                    {
                        ((NonBodyParameter)swaggerParam).MinLength = minLenght;
                        ((NonBodyParameter)swaggerParam).MaxLength = maxLength;
                    }

                    // Range [Range]
                    var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute));
                    if (rangeAttr != null)
                    {
                        int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value;
                        int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value;

                        if (swaggerParam is NonBodyParameter)
                        {
                            ((NonBodyParameter)swaggerParam).Minimum = rangeMin;
                            ((NonBodyParameter)swaggerParam).Maximum = rangeMax;
                        }
                    }
                }
            }
        }