Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make simple usage of Microsoft.OpenAPI trimmable #1114

Closed
nb-rubenoost opened this issue Dec 29, 2022 · 1 comment · Fixed by #1717
Closed

Make simple usage of Microsoft.OpenAPI trimmable #1114

nb-rubenoost opened this issue Dec 29, 2022 · 1 comment · Fixed by #1717
Labels
status:needs-discussion An issue that requires more discussion internally before resolving type:enhancement Enhancement request targeting an existing experience

Comments

@nb-rubenoost
Copy link

I'm trying to use this library in a console app. When trying to publish using trimming, I encountered the fact that this library is not trimmable for even the simplest of cases.

Is your feature request related to a problem? Please describe.

The library is not trimmable when only the following functionality is used:

  • Creating the model by hand through: new OpenApiDocument { ... }
  • Serializing the model using OpenApiJsonWriter or OpenApiYamlWriter

Since these 2 steps don't feel like they are using reflection, I would expect this to be trimmable, which it is not. AFAIK, this is due to EnumExtensions.GetDisplayName():

/_/src/Microsoft.OpenApi/Extensions/EnumExtensions.cs(27,13): Trim analysis warning IL2075: Microsoft.OpenApi.Extension
s.EnumExtensions.GetAttributeOfType<T>(Enum): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicCo
nstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicFields', 'Dynamicall
yAccessedMemberTypes.PublicNestedTypes', 'DynamicallyAccessedMemberTypes.PublicProperties', 'DynamicallyAccessedMemberT
ypes.PublicEvents' in call to 'System.Type.GetMember(String)'. The return value of method 'System.Object.GetType()' doe
s not have matching annotations. The source value must declare at least the same requirements as those declared on the
target location it is assigned to.

Describe the solution you'd like

In short, make Microsoft.OpenAPI trimmable for the simple scenario as described before (creating the model and serializing it).

The code that triggers this is:

public static string GetDisplayName(this Enum enumValue)
{
    var attribute = enumValue.GetAttributeOfType<DisplayAttribute>();
    return attribute == null ? enumValue.ToString() : attribute.Name;
}

public static T GetAttributeOfType<T>(this Enum enumValue) where T : Attribute
{
    var type = enumValue.GetType();
    var memInfo = type.GetMember(enumValue.ToString()).First();
    var attributes = memInfo.GetCustomAttributes<T>(false);
    return attributes.FirstOrDefault();
}

This is only used to associate a string with an enum value. My proposed solution is:

Wrap this logic into an IEnumDisplayValueStrategy/DefaultEnumDisplayValueStrategy that we can supply on the OpenApiWriterSettings. End users can implement this themselves, allowing the compiler to trim the DefaultEnumDisplayValueStrategy, thus removing the reflection code.

Describe alternatives you've considered

  1. Instead of using a [Display] attribute, create an extension method that maps Enum to string. This would look something like this:
public enum ParameterStyle
{
    [Display("matrix")] Matrix,
    [Display("label")] Label
}

public static class ParameterStyleExtensions
{
    public static string GetDisplayName(this ParameterStyle style)
    {
        switch (style)
        {
            case ParameterStyle.Matrix:
                return "matrix";
            case ParameterStyle.Label:
                return "label";
            default:
                return style.ToString();
        }
    }
}
  1. Use source generation to generate these methods (similar to 1. but less maintenance). Something like https://github.com/andrewlock/NetEscapades.EnumGenerators would probably suffice.

The issue with both of these solutions is that they would modify the behavior of a public method. This would be a breaking change.

@adhiambovivian adhiambovivian added status:needs-discussion An issue that requires more discussion internally before resolving type:enhancement Enhancement request targeting an existing experience labels Apr 3, 2023
@nb-rubenoost
Copy link
Author

If this is something that's wanted, I'd be happy to pick this up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:needs-discussion An issue that requires more discussion internally before resolving type:enhancement Enhancement request targeting an existing experience
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants