Repository: dotnet/roslyn
File: src/VisualStudio/Core/Def/LanguageService/AbstractPackage.cs (C#)

Code before:

    protected virtual void RegisterInitializeAsyncWork(PackageLoadTasks packageInitializationTasks)
    {
        // We register this task so our ComponentModel property is available during other parts of package initialization and OnAfterPackageLoaded work. The
        // expectation at this point is no work scheduled to the UI thread needs the ComponentModel, so we only schedule it for the background thread.
        packageInitializationTasks.AddTask(isMainThreadTask: false, task: EnsureComponentModelAsync);

        async Task EnsureComponentModelAsync(PackageLoadTasks packageInitializationTasks, CancellationToken token)
        {
            if (_componentModel_doNotAccessDirectly == null)
            {
                _componentModel_doNotAccessDirectly = (IComponentModel?)await GetServiceAsync(typeof(SComponentModel)).ConfigureAwait(false);
                Assumes.Present(_componentModel_doNotAccessDirectly);
            }
        }
    }

    protected virtual void RegisterOnAfterPackageLoadedAsyncWork(PackageLoadTasks afterPackageLoadedTasks)
    {
    }

    /// <summary>
    /// Registers an editor factory. This is the same as <see cref="Microsoft.VisualStudio.Shell.Package.RegisterEditorFactory(IVsEditorFactory)"/> except it fetches the service async.
    /// </summary>
    protected async Task RegisterEditorFactoryAsync(IVsEditorFactory editorFactory, CancellationToken cancellationToken)
    {
        var registerEditors = await GetServiceAsync<SVsRegisterEditors, IVsRegisterEditors>(throwOnFailure: true, cancellationToken).ConfigureAwait(true);
        Assumes.Present(registerEditors);

        ErrorHandler.ThrowOnFailure(registerEditors.RegisterEditor(editorFactory.GetType().GUID, editorFactory, out _));
    }

    protected async Task LoadComponentsInUIContextOnceSolutionFullyLoadedAsync(CancellationToken cancellationToken)
    {
        // UIContexts can be "zombied" if UIContexts aren't supported because we're in a command line build or in other scenarios.
        // Trying to await them will throw.
        if (!KnownUIContexts.SolutionExistsAndFullyLoadedContext.IsZombie)
        {
            await KnownUIContexts.SolutionExistsAndFullyLoadedContext;
            await LoadComponentsAsync(cancellationToken).ConfigureAwait(false);
        }
    }

    protected abstract Task LoadComponentsAsync(CancellationToken cancellationToken);
}


Review comment (suggestion):
>true [](http://example.com/codeflow?start=148&length=4)

double checking on CA(true) usage, as other places in this file use false

Code after:

    protected virtual void RegisterInitializeAsyncWork(PackageLoadTasks packageInitializationTasks)
    {
        // We register this task so our ComponentModel property is available during other parts of package initialization and OnAfterPackageLoaded work. The
        // expectation at this point is no work scheduled to the UI thread needs the ComponentModel, so we only schedule it for the background thread.
        packageInitializationTasks.AddTask(isMainThreadTask: false, task: EnsureComponentModelAsync);

        async Task EnsureComponentModelAsync(PackageLoadTasks packageInitializationTasks, CancellationToken token)
        {
            _componentModel_doNotAccessDirectly = (IComponentModel?)await GetServiceAsync(typeof(SComponentModel)).ConfigureAwait(false);
            Assumes.Present(_componentModel_doNotAccessDirectly);
        }
    }

    protected virtual void RegisterOnAfterPackageLoadedAsyncWork(PackageLoadTasks afterPackageLoadedTasks)
    {
    }

    /// <summary>
    /// Registers an editor factory. This is the same as <see cref="Microsoft.VisualStudio.Shell.Package.RegisterEditorFactory(IVsEditorFactory)"/> except it fetches the service async.
    /// </summary>
    protected async Task RegisterEditorFactoryAsync(IVsEditorFactory editorFactory, CancellationToken cancellationToken)
    {
        // Call with ConfigureAwait(true): if we're off the UI thread we will stay that way, but a synchronous load of our package should continue to use the UI thread
        // since the UI thread is otherwise blocked waiting for us. This method is called under JTF rules so that's fine.
        var registerEditors = await GetServiceAsync<SVsRegisterEditors, IVsRegisterEditors>(throwOnFailure: true, cancellationToken).ConfigureAwait(true);
        Assumes.Present(registerEditors);

        ErrorHandler.ThrowOnFailure(registerEditors.RegisterEditor(editorFactory.GetType().GUID, editorFactory, out _));
    }

    protected async Task LoadComponentsInUIContextOnceSolutionFullyLoadedAsync(CancellationToken cancellationToken)
    {
        // UIContexts can be "zombied" if UIContexts aren't supported because we're in a command line build or in other scenarios.
        // Trying to await them will throw.
        if (!KnownUIContexts.SolutionExistsAndFullyLoadedContext.IsZombie)
        {
            await KnownUIContexts.SolutionExistsAndFullyLoadedContext;
            await LoadComponentsAsync(cancellationToken).ConfigureAwait(false);
        }
    }

    protected abstract Task LoadComponentsAsync(CancellationToken cancellationToken);
}