public static OperationConfiguration BuildMethod(MethodInfo method, ODataConventionModelBuilder builder,
                                                         ODataFunctionAttribute functionAttribute, ODataActionAttribute actionAttribute, out string bindingName)
        {
            OperationConfiguration configuration = null;

            bindingName = null;
            if (functionAttribute != null)
            {
                if (functionAttribute.ForType != null || functionAttribute.ForCollection != null)
                {
                    if (functionAttribute.ForType != null && functionAttribute.ForCollection != null)
                    {
                        throw new ArgumentException(
                                  $"Must specify either {nameof(ODataFunctionAttribute.ForType)} or {nameof(ODataFunctionAttribute.ForCollection)}, not both");
                    }

                    if (functionAttribute.ForType != null)
                    {
                        bindingName = functionAttribute.BindingName ?? "key";
                    }

                    var concreteMethod = MethodTypedInfo.MakeGenericMethod(
                        functionAttribute.ForType ?? functionAttribute.ForCollection);
                    try
                    {
                        configuration = (OperationConfiguration)concreteMethod
                                        .Invoke(
                            null,
                            new object[]
                        {
                            builder,
                            method.Name,
                            false,
                            functionAttribute.ForCollection != null
                        });
                    }
                    catch (Exception e)
                    {
                        throw new Exception(
                                  $"ForType: {functionAttribute.ForType?.Name}, ForCollection: {functionAttribute.ForCollection?.Name}, concrete method: {concreteMethod}", e);
                    }
                }
                else
                {
                    configuration = builder.Function(method.Name);
                }
            }

            if (actionAttribute != null)
            {
                if (actionAttribute.ForType != null || actionAttribute.ForCollection != null)
                {
                    if (actionAttribute.ForType != null && actionAttribute.ForCollection != null)
                    {
                        throw new ArgumentException(
                                  $"Must specify either {nameof(ODataActionAttribute.ForType)} or {nameof(ODataActionAttribute.ForCollection)}, not both");
                    }
                    if (actionAttribute.ForType != null)
                    {
                        bindingName = actionAttribute.BindingName ?? "key";
                    }

                    configuration = (OperationConfiguration)MethodTypedInfo.MakeGenericMethod(
                        actionAttribute.ForType ?? actionAttribute.ForCollection)
                                    .Invoke(
                        null,
                        new object[]
                    {
                        builder,
                        method.Name,
                        true,
                        actionAttribute.ForCollection != null
                    });
                }
                else
                {
                    configuration = builder.Action(method.Name);
                }
            }

            return(configuration);
        }
        private static void ApplyAttributes(IAssemblyProvider assemblyProvider, ODataConventionModelBuilder builder)
        {
            var allTypes = assemblyProvider.CandidateAssemblies.SelectMany(a => a.ExportedTypes);

            foreach (var type in allTypes)
            {
                if (type.IsAbstract)
                {
                    continue;
                }
                MethodInfo[] publicMethods = null;
                try
                {
                    publicMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
                }
                catch (FileLoadException) { }

                if (publicMethods != null)
                {
                    foreach (var method in publicMethods)
                    {
                        if (!method.IsSpecialName)
                        {
                            try
                            {
                                var functionAttribute = method.GetCustomAttribute <ODataFunctionAttribute>();
                                var actionAttribute   = method.GetCustomAttribute <ODataActionAttribute>();
                                if (functionAttribute == null && actionAttribute == null)
                                {
                                    var genericFunctionAttribute = method.GetCustomAttribute <ODataGenericFunctionAttribute>();
                                    var genericActionAttribute   = method.GetCustomAttribute <ODataGenericActionAttribute>();

                                    if (genericActionAttribute == null && genericFunctionAttribute == null)
                                    {
                                        continue;
                                    }

                                    var genericTypeDefinition = method.DeclaringType.IsGenericTypeDefinition ? method.DeclaringType : method.DeclaringType.GetGenericTypeDefinition();
                                    var genericArguments      = genericTypeDefinition.GetGenericArguments();
                                    var genericParameters     = method.DeclaringType.GetGenericArguments();
                                    Type GetTypeFromDefinition(string name)
                                    {
                                        if (string.IsNullOrWhiteSpace(name))
                                        {
                                            return(null);
                                        }
                                        for (var i = 0; i < genericArguments.Length; i++)
                                        {
                                            if (genericArguments[i].Name == name)
                                            {
                                                return(genericParameters[i]);
                                            }
                                        }

                                        throw new ArgumentException(
                                                  $"Unable to find generic parameter with name {name} on type {method.DeclaringType.Name}");
                                    }
                                    if (genericFunctionAttribute != null)
                                    {
                                        functionAttribute               = new ODataFunctionAttribute();
                                        functionAttribute.IsBound       = genericFunctionAttribute.IsBound;
                                        functionAttribute.BindingName   = genericFunctionAttribute.BindingName;
                                        functionAttribute.ForCollection =
                                            GetTypeFromDefinition(genericFunctionAttribute
                                                                  .ForCollectionTypeParameterName);
                                        functionAttribute.ForType =
                                            GetTypeFromDefinition(genericFunctionAttribute
                                                                  .ForTypeTypeParameterName);
                                    }
                                    if (genericActionAttribute != null)
                                    {
                                        actionAttribute               = new ODataActionAttribute();
                                        actionAttribute.IsBound       = genericActionAttribute.IsBound;
                                        actionAttribute.BindingName   = genericActionAttribute.BindingName;
                                        actionAttribute.ForCollection =
                                            GetTypeFromDefinition(genericActionAttribute
                                                                  .ForCollectionTypeParameterName);
                                        actionAttribute.ForType =
                                            GetTypeFromDefinition(genericActionAttribute
                                                                  .ForTypeTypeParameterName);
                                    }
                                }

                                var entityClrType = TypeHelper.GetImplementedIEnumerableType(method.ReturnType) ??
                                                    method.ReturnType;
                                entityClrType = entityClrType.UnwrapTask();
                                PrimitiveTypeConfiguration primitiveEntityType = null;
                                EntityTypeConfiguration    entityType          = null;
                                var isActionResult = typeof(IActionResult).IsAssignableFrom(entityClrType);
                                if (!isActionResult)
                                {
                                    if (entityClrType.IsPrimitiveType())
                                    {
                                        primitiveEntityType = builder.AddPrimitiveType(entityClrType);
                                    }
                                    else
                                    {
                                        entityType = builder.AddEntityType(entityClrType);
                                    }
                                }

                                var configuration =
                                    ODataMethodBuilder.BuildMethod(
                                        method,
                                        builder,
                                        functionAttribute,
                                        actionAttribute,
                                        out var bindingName);

                                if (configuration != null)
                                {
                                    if (!isActionResult)
                                    {
                                        if (primitiveEntityType == null)
                                        {
                                            configuration.ReturnType = entityType;
                                        }
                                        else
                                        {
                                            configuration.ReturnType = primitiveEntityType;
                                        }
                                    }
                                    configuration.IsComposable     = true;
                                    configuration.NavigationSource =
                                        builder.NavigationSources.FirstOrDefault(n => n.EntityType == entityType);

                                    foreach (var parameterInfo in method.GetParameters())
                                    {
                                        if (!string.IsNullOrWhiteSpace(bindingName) &&
                                            parameterInfo.Name == bindingName)
                                        {
                                            continue;
                                        }

                                        if (actionAttribute != null)
                                        {
                                            if (parameterInfo.GetCustomAttributes(typeof(FromBodyAttribute)) != null)
                                            {
                                                //if (parameterInfo.ParameterType.Name == "DummyModel")
                                                //{
                                                //    int a = 0;
                                                //}

                                                //if (parameterInfo.ParameterType.Name == "newParent")
                                                //{
                                                //    int a = 0;
                                                //}
                                                if (parameterInfo.ParameterType.IsPrimitiveType())
                                                {
                                                    AddParameter(builder, configuration, parameterInfo.ParameterType, parameterInfo.Name);
                                                }
                                                else if (builder.EntitySets.Any(t => t.ClrType == parameterInfo.ParameterType))
                                                {
                                                    AddParameter(builder, configuration, parameterInfo.ParameterType, parameterInfo.Name);
                                                }
                                                else
                                                {
                                                    foreach (var property in parameterInfo.ParameterType
                                                             .GetProperties())
                                                    {
                                                        AddParameter(builder, configuration, property.PropertyType, property.Name);
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            AddParameter(builder, configuration, parameterInfo.ParameterType, parameterInfo.Name);
                                        }
                                    }
                                }
                            }
                            catch (FileLoadException) { }
                        }
                    }
                }
            }
        }