/// <summary>
        /// Initializes the type of the API.
        /// </summary>
        /// <param name="doneInterfaceTypes">The done interface types.</param>
        /// <param name="routes">The routes.</param>
        /// <param name="interfaceType">Type of the interface.</param>
        /// <param name="instance">The instance.</param>
        /// <param name="settings">The settings.</param>
        /// <param name="parentApiContractAttribute">The parent API class attribute.</param>
        /// <param name="parentApiModuleAttribute">The parent API module attribute.</param>
        protected void InitializeApiType(List<string> doneInterfaceTypes, Dictionary<string, RuntimeRoute> routes, Type interfaceType, object instance, RestApiSettings settings = null, ApiContractAttribute parentApiContractAttribute = null, ApiModuleAttribute parentApiModuleAttribute = null)
        {
            if (routes != null && interfaceType != null && doneInterfaceTypes != null)
            {
                if (doneInterfaceTypes.Contains(interfaceType.FullName))
                {
                    return;
                }

                var ApiContract = parentApiContractAttribute ?? interfaceType.GetCustomAttribute<ApiContractAttribute>(true);
                var apiModule = parentApiModuleAttribute ?? interfaceType.GetCustomAttribute<ApiModuleAttribute>(true);
                var moduleName = apiModule?.ToString();

                if (ApiContract != null && !string.IsNullOrWhiteSpace(ApiContract.Version))
                {
                    var apiContractName = ApiContract.Name.SafeToString(interfaceType.FullName);

                    if (ApiContract.Version.SafeToLower().Equals(BuildInFeatureVersionKeyword))
                    {
                        throw new InvalidObjectException("ApiContract.Version", reason: "<buildin> cannot be used as version due to it is used internally.");
                    }

                    foreach (var method in interfaceType.GetMethods())
                    {
                        var apiOperationAttribute = method.GetCustomAttribute<ApiOperationAttribute>(true);
                        var apiTransportAttribute = method.GetCustomAttribute<ApiTransportAttribute>();

                        #region Initialize based on ApiOperation

                        if (apiOperationAttribute != null)
                        {
                            var permissions = new Dictionary<string, ApiPermission>();
                            var additionalHeaderKeys = new HashSet<string>();

                            var apiPermissionAttributes =
                                method.GetCustomAttributes<ApiPermissionAttribute>(true);

                            if (apiPermissionAttributes != null)
                            {
                                foreach (var one in apiPermissionAttributes)
                                {
                                    permissions.Merge(one.PermissionIdentifier, one.Permission);
                                }
                            }

                            var headerKeyAttributes = method.GetCustomAttributes<ApiHeaderAttribute>(true);
                            if (headerKeyAttributes != null)
                            {
                                foreach (var one in headerKeyAttributes)
                                {
                                    additionalHeaderKeys.Add(one.HeaderKey);
                                }
                            }

                            var routeKey = GetRouteKey(ApiContract.Version, apiOperationAttribute.ResourceName,
                                apiOperationAttribute.HttpMethod, apiOperationAttribute.Action);

                            RuntimeRoute runtimeRoute = null;

                            if (apiTransportAttribute != null)
                            {
                                runtimeRoute = new RuntimeRoute(apiTransportAttribute);
                            }
                            else
                            {
                                var tokenRequired =
                                    method.GetCustomAttribute<TokenRequiredAttribute>(true) ??
                                    interfaceType.GetCustomAttribute<TokenRequiredAttribute>(true);

                                runtimeRoute = new RuntimeRoute(method, interfaceType, instance,
                                    !string.IsNullOrWhiteSpace(apiOperationAttribute.Action),
                                    tokenRequired != null && tokenRequired.TokenRequired, moduleName, apiContractName, settings, permissions, additionalHeaderKeys.ToList());
                            }

                            if (routes.ContainsKey(routeKey))
                            {
                                throw new DataConflictException("Route", objectIdentity: routeKey, data: new
                                {
                                    existed = routes[routeKey].SafeToString(),
                                    newMethod = method.GetFullName(),
                                    newInterface = interfaceType.FullName
                                });
                            }

                            routes.Add(routeKey, runtimeRoute);
                        }

                        #endregion
                    }

                    foreach (var one in interfaceType.GetInterfaces())
                    {
                        InitializeApiType(doneInterfaceTypes, routes, one, instance, settings, ApiContract, apiModule);
                    }
                }

                doneInterfaceTypes.Add(interfaceType.FullName);
            }
        }
        /// <summary>
        /// Authenticates the specified service type.
        /// </summary>
        /// <param name="runtimeRoute">The runtime route.</param>
        /// <param name="token">The token.</param>
        /// <param name="userIdentifier">The user identifier.</param>
        /// <returns>System.Nullable&lt;Guid&gt;.</returns>
        protected BaseException Authenticate(RuntimeRoute runtimeRoute, string token, out string userIdentifier)
        {
            userIdentifier = token;
            ICredential credential = null;

            if (!string.IsNullOrWhiteSpace(token))
            {
                var eventHandlers = (runtimeRoute.Setting ?? DefaultSettings)?.EventHandlers;

                if (eventHandlers != null)
                {
                    credential = eventHandlers.GetCredentialByToken(token);

                    if (credential != null)
                    {
                        userIdentifier = credential.Name;
                    }
                }
            }

            ContextHelper.ApiContext.CurrentCredential = credential;

            if (!runtimeRoute.IsTokenRequired)
            {
                return null;
            }

            //Check permissions
            if (credential != null)
            {
                ContextHelper.ApiContext.CurrentCredential = credential;
                var userPermissions = ContextHelper.ApiContext.CurrentPermissionIdentifiers?.Permissions ?? new List<string>();
                return userPermissions.ValidateApiPermission(runtimeRoute.Permissions, token, runtimeRoute.MethodInfo.GetFullName());
            }

            return new UnauthorizedTokenException(string.Empty, new
            {
                token
            });
        }
        /// <summary>
        /// Initializes the type of the API.
        /// </summary>
        /// <param name="doneInterfaceTypes">The done interface types.</param>
        /// <param name="routes">The routes.</param>
        /// <param name="interfaceType">Type of the interface.</param>
        /// <param name="instance">The instance.</param>
        /// <param name="settings">The settings.</param>
        /// <param name="parentApiContractAttribute">The parent API class attribute.</param>
        /// <param name="parentApiModuleAttribute">The parent API module attribute.</param>
        protected void InitializeApiType(List<string> doneInterfaceTypes, Dictionary<string, RuntimeRoute> routes, Type interfaceType, object instance, RestApiSettings settings = null, ApiContractAttribute parentApiContractAttribute = null, ApiModuleAttribute parentApiModuleAttribute = null)
        {
            if (routes != null && interfaceType != null && doneInterfaceTypes != null)
            {
                if (doneInterfaceTypes.Contains(interfaceType.FullName))
                {
                    return;
                }

                var apiContract = parentApiContractAttribute ?? interfaceType.GetCustomAttribute<ApiContractAttribute>(true);
                var apiModule = parentApiModuleAttribute ?? interfaceType.GetCustomAttribute<ApiModuleAttribute>(true);
                var moduleName = apiModule?.ToString();

                if (apiContract != null && !string.IsNullOrWhiteSpace(apiContract.Version))
                {
                    if (apiContract.Version.SafeToLower().Equals(BuiltInFeatureVersionKeyword))
                    {
                        throw ExceptionFactory.CreateInvalidObjectException("apiContract.Version", reason: "<builtin> cannot be used as version due to it is used internally.");
                    }

                    foreach (var method in interfaceType.GetMethods())
                    {
                        var apiOperationAttribute = method.GetCustomAttribute<ApiOperationAttribute>(true);

                        #region Initialize based on ApiOperation

                        if (apiOperationAttribute != null)
                        {
                            var permissions = new Dictionary<string, ApiPermission>();
                            var additionalHeaderKeys = new HashSet<string>();

                            var apiPermissionAttributes =
                                method.GetCustomAttributes<ApiPermissionAttribute>(true);

                            if (apiPermissionAttributes != null)
                            {
                                foreach (var one in apiPermissionAttributes)
                                {
                                    permissions.Merge(one.PermissionIdentifier, one.Permission);
                                }
                            }

                            var headerKeyAttributes = method.GetCustomAttributes<ApiHeaderAttribute>(true);
                            if (headerKeyAttributes != null)
                            {
                                foreach (var one in headerKeyAttributes)
                                {
                                    additionalHeaderKeys.Add(one.HeaderKey);
                                }
                            }

                            var routeKey = GetRouteKey(apiContract.Version, apiOperationAttribute.ResourceName,
                                apiOperationAttribute.HttpMethod, apiOperationAttribute.Action);

                            var tokenRequired =
                                method.GetCustomAttribute<TokenRequiredAttribute>(true) ??
                                interfaceType.GetCustomAttribute<TokenRequiredAttribute>(true);

                            var runtimeRoute = new RuntimeRoute(method, interfaceType, instance,
                                   !string.IsNullOrWhiteSpace(apiOperationAttribute.Action),
                                   tokenRequired != null && tokenRequired.TokenRequired, moduleName, settings, permissions, additionalHeaderKeys.ToList());

                            if (routes.ContainsKey(routeKey))
                            {
                                throw new DataConflictException("Route", objectIdentity: routeKey, data: new
                                {
                                    existed = routes[routeKey].SafeToString(),
                                    newMethod = method.GetFullName(),
                                    newInterface = interfaceType.FullName
                                });
                            }

                            routes.Add(routeKey, runtimeRoute);
                        }

                        #endregion
                    }

                    foreach (var one in interfaceType.GetInterfaces())
                    {
                        InitializeApiType(doneInterfaceTypes, routes, one, instance, settings, apiContract, apiModule);
                    }

                    //Special NOTE:
                    // Move this add action in scope of if apiContract is valid.
                    // Reason: in complicated cases, when [A:Interface1] without ApiContract, but [Interface2: Interface] with defining ApiContract, and [B: A, Interface2], then correct contract definition might be missed.
                    doneInterfaceTypes.Add(interfaceType.FullName);
                }

            }
        }