Skip to content

Question: why ActivatableType and not [DynamicDependency]?Β #612

@jonpryor

Description

@jonpryor

Less an issue, more a question:

I'm trying to use NativeAOT in various projects, and eventually encountered an InvalidOperationException when attempting to construct UriReplacementHandler<UriReplacementHandlerOption>. Subsequent investigation found that (the royal) you fixed this problem in commit a2800ab, by:

  1. Obsoleting KiotaClientFactory.GetDefaultHandlerTypes().
  2. Introducing KiotaClientFactory.GetDefaultHandlerActivatableTypes().
  3. Introducing a new KiotaClientFactory.ActivatableType type.

I understand (3), as it provides a useful place to use [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] so that constructors on UriReplacementHandler<UriReplacementHandlerOption> would be preserved.

However, as a "student" trying to better understand the ins, outs, why's, wherefores, etc. of supporting NativeAOT, I have to wonder:

Why did you do it this way?

One and a half alternatives come to mind.

Firstly, you could have used DynamicDependencyAttribute on the existing KiotaClientFactory.GetDefaultHandlerTypes() method:

partial class KiotaClientFactory
{
    [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(UriReplacementHandler<UriReplacementHandlerOption>))]
    [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(RetryHandler))]
    // …
    public static IList<Type> GetDefaultHandlerTypes()
    {
        return new List<Type> {
            typeof(UriReplacementHandler<UriReplacementHandlerOption>),
            typeof(RetryHandler),
            // …
        };
    }
}

Pro: you're not "breaking" or obsoleting API. Consumers need only update the NuGet package version, and it just works.

Con: whenever you add a new type to the body of GetDefaultHandlerTypes(), you need to remember to add a [DynamicDependency] attribute. That's fair, but IMHO the Pro more than makes up for it.

The "and a half" solution is that I think you could have added KiotaClientFactory.GetDefaultHandlerActivatableTypes() as you did, and also update KiotaClientFactory.GetDefaultHandlerTypes() to chain to GetDefaultHandlerActivatableTypes():

partial class KiotaClientFactory
{
    public static IList<Type> GetDefaultHandlerTypes()
        => GetDefaultHandlerActivatableTypes().Select(at => at.Type).ToList();
}

I believe that this would still "appease" NativeAOT and cause the UriReplacementHandler<UriReplacementHandlerOption>/etc. constructors to be preserved, and also maintain backward compatibility: you wouldn't be required to use the new KiotaClientFactory.GetDefaultHandlerActivatableTypes() method to get NativeAOT support.

Is there a reason this wasn't done or wouldn't work?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Needs Triage πŸ”

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions