2

I am writing an app using .NET Web API (4.6 Framework)

I have an attribute that I use: [ApiExplorerSettings(IgnoreApi = true)] to hide certain controllers from my Swagger.

This attribute is a part of : System.Web.Http.Description

Basically I want to create an AppSetting in my web.config file so when I publish to Development, the controllers show up (IgnoreApi = false) and when I publish to Production, the controllers are hidden (IgnoreApi = true).

I've tried accessing ConfigurationManager.AppSettings directly in the attribute, but that seems to not work as expected.

Perhaps I need to find a way to override that attribute so that on the getter/setter of IgnoreApi, it can pull the correct value from my web.config?

MadScout
  • 21
  • 1
  • 2
  • You'll probably have to create a derived attribute that does a lookup based on a constant value (see [here](http://stackoverflow.com/questions/6665187/how-to-set-dynamic-value-in-my-attribute) for an example), but Swagger may be looking for that exact attribute while ignoring derived attributes. Only one way to find out I guess :) – user247702 Oct 28 '16 at 15:21
  • Possible duplicate of [Using config settings in attributes](http://stackoverflow.com/questions/18619184/using-config-settings-in-attributes) – Michael Freidgeim Apr 24 '17 at 04:42

1 Answers1

0

Extending the "ApiExplorerSettingsAttribute" class seems straightforward but its sealed. So ended up with the following workaround;

  • A custom attribute which inherits from the base calss "Attribute".

IncludeInApiExplorerAttribute.cs class

public class IncludeInApiExplorerAttribute : Attribute
{
    private readonly bool value;
    public IncludeInApiExplorerAttribute(string IsInAPI=null)
    {
        if (!string.IsNullOrEmpty(IsInAPI))
        {
            value = Convert.ToBoolean(ConfigurationManager.AppSettings[IsInAPI]); //Reads the app config value
        }
        else
        {
            value = true;
        }
    }
    public bool Value { get { return value; } }
}
  • Then we can implement a custom ApiExplorer as below.

OptApiExplorer.cs Class

    public class OptApiExplorer : ApiExplorer
{
    public OptApiExplorer(HttpConfiguration configuration)
        : base(configuration)
    {

    }

    //Overrides the method from the base class
    public override bool ShouldExploreAction(string actionVariableValue, HttpActionDescriptor actionDescriptor, IHttpRoute route)
    {
        var includeAttribute = actionDescriptor.GetCustomAttributes<IncludeInApiExplorerAttribute>().FirstOrDefault(); //Get the given custom attribute from the action
        if (includeAttribute != null)
        {
            return includeAttribute.Value && MatchRegexConstraint(route, "action", actionVariableValue); //If it is not null read the includeAttribute.Value which is set in app.config and return true or false based on the includeAttribute.Value and MatchRegexConstraint return value
        }
        var includeControlAttribute = actionDescriptor.ControllerDescriptor.GetCustomAttributes<IncludeInApiExplorerAttribute>().FirstOrDefault(); //If the action does not have any given type of custom attribute then chekc it in the controller level
        if (includeControlAttribute != null)
        {
            return includeControlAttribute.Value && MatchRegexConstraint(route, "action", actionVariableValue);//Similar to action level
        }
        return true && MatchRegexConstraint(route, "action", actionVariableValue);
    }


    //This method is as it is in the base class
    private static bool MatchRegexConstraint(IHttpRoute route, string parameterName, string parameterValue)
    {
        IDictionary<string, object> constraints = route.Constraints;
        if (constraints != null)
        {
            object constraint;
            if (constraints.TryGetValue(parameterName, out constraint))
            {
                string constraintsRule = constraint as string;
                if (constraintsRule != null)
                {
                    string constraintsRegEx = "^(" + constraintsRule + ")$";
                    return parameterValue != null && Regex.IsMatch(parameterValue, constraintsRegEx, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
                }
            }
        }
        return true;
    }
}
  • Web config settings

This is the value read by our custom attribute. Add this to web.config file

  <appSettings>
    <add key="IsInAPI" value="false"/>
  </appSettings>
  • In WebAPI.config.cs file add the following

There we have replaced the IApiExplorer with the custom class.

      config.Services.Replace(typeof(IApiExplorer), new OptApiExplorer(config));
  • Then in your Controller or in the Action you can add the custom attribute as below.

    [IncludeInApiExplorer("IsInAPI")]
    

    IsInApi is the web.config value which we can set to true or false. If it is not set then it will default set to true as we have implemented in IncludeInApiExplorerAttribute class.

Refer this post for more insight on this.