/// <summary>
        /// Gets or creates the convention builder for the specified controller.
        /// </summary>
        /// <typeparam name="TController">The <see cref="Type">type</see> of controller to build conventions for.</typeparam>
        /// <returns>A new or existing <see cref="IControllerConventionBuilder{T}"/>.</returns>
        public virtual IControllerConventionBuilder <TController> Controller <TController>()
            where TController : notnull
#if WEBAPI
#pragma warning disable SA1001 // Commas should be spaced correctly
        , IHttpController
#pragma warning restore SA1001 // Commas should be spaced correctly
#endif
        {
            var key = GetKey(typeof(TController));

            if (!ControllerConventionBuilders.TryGetValue(key, out var builder))
            {
                var newBuilder = new ControllerApiVersionConventionBuilder <TController>();
                ControllerConventionBuilders[key] = newBuilder;
                return(newBuilder);
            }

            if (builder is IControllerConventionBuilder <TController> typedBuilder)
            {
                return(typedBuilder);
            }

            // this should only ever happen if a subclass overrides Controller(Type) and adds a
            // IControllerConventionBuilder that is not covariant with IControllerConventionBuilder<TController>
            throw new InvalidOperationException(SR.ConventionStyleMismatch.FormatDefault(key.Name));
        }
        bool InternalApplyTo(Model model)
        {
            var key = model.ControllerType;
            var hasExplicitConventions = ControllerConventionBuilders.TryGetValue(key, out var builder);
            var applied = hasExplicitConventions;

            if (!hasExplicitConventions)
            {
                var hasNoExplicitConventions = ControllerConventions.Count == 0;

                if (hasNoExplicitConventions && !(applied = HasDecoratedActions(model)))
                {
                    return(false);
                }

                builder = new ControllerApiVersionConventionBuilder(model.ControllerType);
            }

            foreach (var convention in ControllerConventions)
            {
                applied |= convention.Apply(builder !, model);
            }

            if (applied)
            {
                builder !.ApplyTo(model);
            }

            return(applied);
        }
        /// <summary>
        /// Gets or creates the convention builder for the specified controller.
        /// </summary>
        /// <param name="controllerType">The <see cref="Type">type</see> of controller to build conventions for.</param>
        /// <returns>A new or existing <see cref="IControllerConventionBuilder"/>.</returns>
        public virtual IControllerConventionBuilder Controller(Type controllerType)
        {
            var key = GetKey(controllerType);

            if (!ControllerConventionBuilders.TryGetValue(key, out var builder))
            {
                var newBuilder = NewGenericControllerConventionBuilder(controllerType);
                ControllerConventionBuilders[key] = newBuilder;
                return(newBuilder);
            }

            return(builder);
        }
        /// <summary>
        /// Gets or creates the convention builder for the specified controller.
        /// </summary>
        /// <param name="controllerType">The <see cref="Type">type</see> of controller to build conventions for.</param>
        /// <returns>A new or existing <see cref="ControllerApiVersionConventionBuilder"/>.</returns>
        public virtual ControllerApiVersionConventionBuilder Controller(Type controllerType)
        {
            Arg.NotNull(controllerType, nameof(controllerType));
            Contract.Ensures(Contract.Result <ControllerApiVersionConventionBuilder>() != null);

            var key = GetKey(controllerType);

            if (!ControllerConventionBuilders.TryGetValue(key, out var builder))
            {
                var newBuilder = new ControllerApiVersionConventionBuilder(controllerType);
                ControllerConventionBuilders[key] = newBuilder;
                return(newBuilder);
            }

            if (builder is ControllerApiVersionConventionBuilder typedBuilder)
            {
                return(typedBuilder);
            }

            throw new InvalidOperationException(SR.ConventionStyleMismatch.FormatDefault(key.Name));
        }
        /// <summary>
        /// Gets or creates the convention builder for the specified controller.
        /// </summary>
        /// <typeparam name="TController">The <see cref="Type">type</see> of controller to build conventions for.</typeparam>
        /// <returns>A new or existing <see cref="ControllerApiVersionConventionBuilder{T}"/>.</returns>
        public virtual ControllerApiVersionConventionBuilder <TController> Controller <TController>()
#if WEBAPI
            where TController : IHttpController
#endif
        {
            Contract.Ensures(Contract.Result <ControllerApiVersionConventionBuilder <TController> >() != null);

            var key = GetKey(typeof(TController));

            if (!ControllerConventionBuilders.TryGetValue(key, out var builder))
            {
                var newBuilder = new ControllerApiVersionConventionBuilder <TController>();
                ControllerConventionBuilders[key] = newBuilder;
                return(newBuilder);
            }

            if (builder is ControllerApiVersionConventionBuilder <TController> typedBuilder)
            {
                return(typedBuilder);
            }

            throw new InvalidOperationException(SR.ConventionStyleMismatch.FormatDefault(key.Name));
        }