Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using System.Collections.Immutable;
using System.Threading.Tasks;
using System.Composition;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Threading;
using System.Linq;

namespace Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CodeFixForRegistrationInASPNetCoreIntegration)), Shared]
public sealed class CodeFixForRegistrationInASPNetCoreIntegration : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds =>
ImmutableArray.Create(DiagnosticDescriptors.CorrectRegistrationExpectedInAspNetIntegration.Id);
Comment thread
surgupta-msft marked this conversation as resolved.

public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;

private const string ExpectedRegistrationMethod = "ConfigureFunctionsWebApplication";

public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
Diagnostic diagnostic = context.Diagnostics.First();
context.RegisterCodeFix(new ChangeConfigurationForASPNetIntegration(context.Document, diagnostic), diagnostic);

return Task.CompletedTask;
}

/// <summary>
/// CodeAction implementation which fixes the method configuration for ASP.NET Core Integration.
/// </summary>
private sealed class ChangeConfigurationForASPNetIntegration : CodeAction
{
private readonly Document _document;
private readonly Diagnostic _diagnostic;

internal ChangeConfigurationForASPNetIntegration(Document document, Diagnostic diagnostic)
{
this._document = document;
this._diagnostic = diagnostic;
}

public override string Title => "Change configuration for ASP.Net Core Integration";

public override string EquivalenceKey => null;

/// <summary>
/// Returns an updated Document with correct method configuration for ASP.NET Core Integration.
/// </summary>
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
SyntaxNode root = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

var currentNode = root.FindNode(this._diagnostic.Location.SourceSpan).FirstAncestorOrSelf<IdentifierNameSyntax>();

var newNode = currentNode.ReplaceNode(currentNode, SyntaxFactory.IdentifierName(ExpectedRegistrationMethod));

SyntaxNode newSyntaxRoot = root.ReplaceNode(currentNode, newNode);

return _document.WithSyntaxRoot(newSyntaxRoot);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@

### Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.Analyzers

- Analyzer to detect missing ASP.NET Core Integration registration (#1917)
- Analyzer to detect missing ASP.NET Core Integration registration (#1917)
- Code fix suggestion for correct registration in ASP.NET core integration (#1992)
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using AnalyzerTest = Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerTest<Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.RegistrationExpectedInASPNetIntegration, Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier>;
using Verifier = Microsoft.CodeAnalysis.CSharp.Testing.XUnit.AnalyzerVerifier<Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.RegistrationExpectedInASPNetIntegration>;
using CodeFixTest = Microsoft.CodeAnalysis.CSharp.Testing.CSharpCodeFixTest<Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.RegistrationExpectedInASPNetIntegration, Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.CodeFixForRegistrationInASPNetCoreIntegration, Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier>;
using CodeFixVerifier = Microsoft.CodeAnalysis.CSharp.Testing.CSharpCodeFixVerifier<Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.RegistrationExpectedInASPNetIntegration, Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.CodeFixForRegistrationInASPNetCoreIntegration, Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier>;
using Microsoft.CodeAnalysis.Testing;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
Expand Down Expand Up @@ -323,11 +325,90 @@ private static void Method2()
await test.RunAsync();
}

[Fact]
public async Task AspNetIntegration_WithIncorrectRegistration_Diagnostics_Expected_CodeFixWorks()
{
string inputCode = @"
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace AspNetIntegration
{
class Program
{
static void Main(string[] args)
{
//<docsnippet_aspnet_registration>
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.Build();
host.Run();
//</docsnippet_aspnet_registration>
}
public static void Method1()
{
}
private static void Method2()
{
}
}
}";

string expectedCode = @"
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace AspNetIntegration
{
class Program
{
static void Main(string[] args)
{
//<docsnippet_aspnet_registration>
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.Build();
host.Run();
//</docsnippet_aspnet_registration>
}
public static void Method1()
{
}
private static void Method2()
{
}
}
}";


var expectedDiagnosticResult = CodeFixVerifier
.Diagnostic("AZFW0014")
.WithSeverity(DiagnosticSeverity.Error)
.WithSpan(16, 34, 16, 66)
.WithArguments(ExpectedRegistrationMethod);

var test = new CodeFixTest
{
ReferenceAssemblies = LoadRequiredDependencyAssemblies(),
TestCode = inputCode,
FixedCode = expectedCode
};

test.ExpectedDiagnostics.AddRange(new[] { expectedDiagnosticResult });
await test.RunAsync();
}

private static ReferenceAssemblies LoadRequiredDependencyAssemblies()
{
var referenceAssemblies = ReferenceAssemblies.Net.Net60.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.19.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.14.1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.15.1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore", "1.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "5.0.0"),
Expand Down