Skip to content

Commit a3572a1

Browse files
authored
Try fixing connector for AspNetAndMSDI (#156)
* enable running the tests for VsExtConnectorTestSamples.AspNetAndMSDI * the one-line fix, but... * resolve dependencies from NuGet in a smarter way (not just from the first folder we find) * apply the fix selectively * add comment about _shortFrameworkName * update CHANGELOG * Add VsExtConnectorTestSamples.AspNetAndMSDI sample # Conflicts: # Tests/VsExtConnectorTestSamples/VsExtConnectorTestSamples.slnx
1 parent 798e0ec commit a3572a1

89 files changed

Lines changed: 83122 additions & 8 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
## Bug fixes:
1010

11+
* Fix: Binding discovery for .NET 10 projects that depend on an ASP.NET project and use the MSDI plugin (#156)
12+
1113
*Contributors of this release (in alphabetical order):* @304NotModified, @clrudolphi, @gasparnagy
1214

1315
# v2025.3.395 - 2025-12-17

Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/AssemblyLoading/NugetCacheAssemblyResolver.cs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ namespace ReqnrollConnector.AssemblyLoading;
55

66
public class NugetCacheAssemblyResolver : ICompilationAssemblyResolver
77
{
8+
private const string NetStandard20 = "netstandard2.0";
9+
private readonly string _targetFramework;
10+
11+
public NugetCacheAssemblyResolver(string targetFramework)
12+
{
13+
_targetFramework = targetFramework;
14+
}
15+
816
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string>? assemblies)
917
{
1018
if (library.Path == null || assemblies == null)
@@ -15,14 +23,31 @@ public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string>? as
1523
if (!Directory.Exists(directory))
1624
return false;
1725

18-
var libs = Directory.GetDirectories(directory);
19-
foreach (var lib in libs)
26+
string assemblyFileName = library.Name + ".dll";
27+
28+
// If the target framework folder exists, use it, even if it doesn't contain the assembly.
29+
// An empty folder indicates that the package is included to the target framework by default.
30+
if (Directory.Exists(Path.Combine(directory, _targetFramework)))
31+
{
32+
assemblies.Add(Path.Combine(directory, _targetFramework, assemblyFileName));
33+
return true;
34+
}
35+
36+
// Fallback to netstandard2.0, similarly
37+
if (Directory.Exists(Path.Combine(directory, NetStandard20)))
38+
{
39+
assemblies.Add(Path.Combine(directory, NetStandard20, assemblyFileName));
40+
return true;
41+
}
42+
43+
// Finally, check if the assembly exists directly under lib (old .NET Framework style packages)
44+
if (Directory.Exists(Path.Combine(directory, assemblyFileName)))
2045
{
21-
var assemblyFilePath = Path.Combine(lib, library.Name + ".dll");
22-
assemblies.Add(assemblyFilePath);
46+
assemblies.Add(Path.Combine(directory, assemblyFileName));
47+
return true;
2348
}
2449

25-
return libs.Any();
50+
return false;
2651
}
2752

2853
private string NugetCacheExpandedPath()

Connectors/Reqnroll.VisualStudio.ReqnrollConnector.Generic/AssemblyLoading/TestAssemblyLoadContext.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public TestAssemblyLoadContext(
4141
new ReferenceAssemblyPathResolver(),
4242
new PackageCompilationAssemblyResolver(),
4343
new AspNetCoreAssemblyResolver(),
44-
new NugetCacheAssemblyResolver()
44+
new NugetCacheAssemblyResolver(_shortFrameworkName)
4545
}, _log);
4646
}
4747

@@ -187,6 +187,12 @@ private IEnumerable<string> SelectAssets(IReadOnlyList<RuntimeAssetGroup> runtim
187187

188188
private CompilationLibrary GetRequestedLibrary(AssemblyName assemblyName)
189189
{
190+
// Using a x.y.z path allows finding the library in NuGet cache folders.
191+
// This causes problems with System.* assemblies (e.g. System.Text.Encodings.Web in .NET 8.0), so we use the full version string for those.
192+
string path = !assemblyName.Name!.StartsWith("System.", StringComparison.InvariantCultureIgnoreCase) ?
193+
Path.Combine(assemblyName.Name!, $"{assemblyName.Version!.Major}.{assemblyName.Version!.Minor}.{assemblyName.Version!.MajorRevision}".ToString()) :
194+
Path.Combine(assemblyName.Name!, $"{assemblyName.Version}".ToString());
195+
190196
// This reference might help finding dependencies that are otherwise not listed in the
191197
// deps.json file of the test assembly. E.g. Microsoft.AspNetCore.Hosting.Abstractions in the ReqOverflow.Specs.API project of the https://github.com/reqnroll/Sample-ReqOverflow sample
192198
return new CompilationLibrary(
@@ -197,7 +203,7 @@ private CompilationLibrary GetRequestedLibrary(AssemblyName assemblyName)
197203
new[] {assemblyName.Name + ".dll"},
198204
Array.Empty<Dependency>(),
199205
true,
200-
Path.Combine(assemblyName.Name!, $"{assemblyName.Version}".ToString()),
206+
path,
201207
string.Empty);
202208
}
203209

Tests/Connector/Reqnroll.VisualStudio.ReqnrollConnector.Tests/ExternalSampleTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public void ReqOverflow(string testCase, string projectFile, string repositoryDi
1818
}
1919

2020
private const string IgnoredExploratoryTestProjects =
21-
"SpecFlowCompatibilityProject.Net472;CleanReqnrollProject.Net481.x86;VsExtConnectorTestSamples";
21+
"SpecFlowCompatibilityProject.Net472;CleanReqnrollProject.Net481.x86;VsExtConnectorTestSamples.NetFwSystemDataDep";
2222

2323
[Theory]
2424
[MemberData(nameof(GetProjectsForRepository), "https://github.com/reqnroll/Reqnroll.ExploratoryTestProjects", $"BigReqnrollProject;SpecFlowProject;OldProjectFileFormat.Empty;ReqnrollFormatters.CustomizedHtml;CustomPlugins.TagDecoratorGeneratorPlugin;{IgnoredExploratoryTestProjects}")]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Diagnostics;
2+
using Microsoft.AspNetCore.Mvc;
3+
using VsExtConnectorTestSamples.AspNetAndMSDI.App.Models;
4+
5+
namespace VsExtConnectorTestSamples.AspNetAndMSDI.App.Controllers;
6+
7+
public class HomeController : Controller
8+
{
9+
public IActionResult Index()
10+
{
11+
return View();
12+
}
13+
14+
public IActionResult Privacy()
15+
{
16+
return View();
17+
}
18+
19+
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
20+
public IActionResult Error()
21+
{
22+
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
23+
}
24+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace VsExtConnectorTestSamples.AspNetAndMSDI.App.Interfaces;
2+
3+
public interface IDateTimeService
4+
{
5+
DateTime GetDateTime();
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace VsExtConnectorTestSamples.AspNetAndMSDI.App.Models;
2+
3+
public class ErrorViewModel
4+
{
5+
public string? RequestId { get; set; }
6+
7+
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
8+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using VsExtConnectorTestSamples.AspNetAndMSDI.App.Interfaces;
2+
using VsExtConnectorTestSamples.AspNetAndMSDI.App.Services;
3+
4+
namespace VsExtConnectorTestSamples.AspNetAndMSDI.App;
5+
6+
public class Program
7+
{
8+
public static void Main(string[] args)
9+
{
10+
var builder = WebApplication.CreateBuilder(args);
11+
12+
// Add services to the container.
13+
builder.Services.AddControllersWithViews();
14+
builder.Services.AddSingleton<IDateTimeService, DateTimeService>();
15+
16+
var app = builder.Build();
17+
18+
// Configure the HTTP request pipeline.
19+
if (!app.Environment.IsDevelopment())
20+
{
21+
app.UseExceptionHandler("/Home/Error");
22+
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
23+
app.UseHsts();
24+
}
25+
26+
app.UseHttpsRedirection();
27+
app.UseRouting();
28+
29+
app.UseAuthorization();
30+
31+
app.MapStaticAssets();
32+
app.MapControllerRoute(
33+
name: "default",
34+
pattern: "{controller=Home}/{action=Index}/{id?}")
35+
.WithStaticAssets();
36+
37+
app.Run();
38+
}
39+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using VsExtConnectorTestSamples.AspNetAndMSDI.App.Interfaces;
2+
3+
namespace VsExtConnectorTestSamples.AspNetAndMSDI.App.Services;
4+
5+
public class DateTimeService : IDateTimeService
6+
{
7+
public DateTime GetDateTime()
8+
{
9+
return DateTime.Now;
10+
}
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@{
2+
ViewData["Title"] = "Home Page";
3+
}
4+
5+
<div class="text-center">
6+
<h1 class="display-4">Welcome</h1>
7+
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
8+
</div>

0 commit comments

Comments
 (0)