예제 #1
0
    public static async Task <IImmutableSet <string> > DetectFeaturesAsync(
        Compilation compilation,
        CancellationToken cancellationToken = default)
    {
        var symbols = new StartupSymbols(compilation);

        if (!symbols.HasRequiredSymbols)
        {
            // Cannot find ASP.NET Core types.
            return(ImmutableHashSet <string> .Empty);
        }

        var features = ImmutableHashSet.CreateBuilder <string>();

        // Find configure methods in the project's assembly
        var configureMethods = ConfigureMethodVisitor.FindConfigureMethods(symbols, compilation.Assembly);

        for (var i = 0; i < configureMethods.Count; i++)
        {
            var configureMethod = configureMethods[i];

            // Handles the case where a method is using partial definitions. We don't expect this to occur, but still handle it correctly.
            var syntaxReferences = configureMethod.DeclaringSyntaxReferences;
            for (var j = 0; j < syntaxReferences.Length; j++)
            {
                var semanticModel = compilation.GetSemanticModel(syntaxReferences[j].SyntaxTree);

                var syntax    = await syntaxReferences[j].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);
                var operation = semanticModel.GetOperation(syntax, cancellationToken);

                // Look for a call to one of the SignalR gestures that applies to the Configure method.
                if (operation
                    .Descendants()
                    .OfType <IInvocationOperation>()
                    .Any(op => StartupFacts.IsSignalRConfigureMethodGesture(op.TargetMethod)))
                {
                    features.Add(WellKnownFeatures.SignalR);
                }
            }
        }

        return(features.ToImmutable());
    }
예제 #2
0
    public void FindConfigureMethods_AtDifferentScopes()
    {
        // Arrange
        var source = @"
using Microsoft.AspNetCore.Builder;

public class GlobalStartup
{
    public void Configure(IApplicationBuilder app)
    {
    }
}

namespace Another
{
    public class AnotherStartup
    {
        public void Configure(IApplicationBuilder app)
        {
        }
    }
}

namespace ANamespace
{
    public class Startup
    {
        public void ConfigureDevelopment(IApplicationBuilder app)
        {
        }

        public class NestedStartup
        {
            public void ConfigureTest(IApplicationBuilder app)
            {
            }
        }
    }
}

namespace ANamespace.Nested
{
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
        }

        public class NestedStartup
        {
            public void Configure(IApplicationBuilder app)
            {
            }
        }
    }
}";

        var expected = new string[]
        {
            "global::ANamespace.Nested.Startup.Configure",
            "global::ANamespace.Nested.Startup.NestedStartup.Configure",
            "global::ANamespace.Startup.ConfigureDevelopment",
            "global::ANamespace.Startup.NestedStartup.ConfigureTest",
            "global::Another.AnotherStartup.Configure",
            "global::GlobalStartup.Configure",
        };

        var compilation = TestCompilation.Create(source);
        var symbols     = new StartupSymbols(compilation);

        // Act
        var results = ConfigureMethodVisitor.FindConfigureMethods(symbols, compilation.Assembly);

        // Assert
        var actual = results
                     .Select(m => m.ContainingType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + "." + m.Name)
                     .OrderBy(s => s)
                     .ToArray();

        Assert.Equal(expected, actual);
    }