dotnet / dotnet/aspnetcore

RazorRuntimeCompilation bug when assembly emitted by Roslyn with empty location added as MVC application part

Open
#54,024 0 comments 1 reaction 0 assignees View on GitHub
area-mvc
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

After upgraded to .NET 8.0.200, it demands me to add RazorRuntimeCompilation otherwise the application crashes because it cannot locate the MVC view.

I generated a dynamic controller assembly by Roslyn. This assembly doesn't have location because I loaded it from bytes right after generation, also it doesn't have IsDynamic=true.

Then, I created an ASP.NET Core MVC application (.NET 6, 7, 8), added RazorRuntimeCompilation and added the generated assembly as AssemblyPart. When running the application, it gave below `ArgumentException: Empty path name is not legal` error
![image](https://github.com/dotnet/aspnetcore/assets/824654/e2aba561-a587-49ba-8600-808e15b68a72)

After investigation, I found out that RazorRuntimeCompilation just get reference paths from extension method `Microsoft.AspNetCore.Mvc.ApplicationParts.AssemblyPartExtensions.GetReferencePaths(...)` which returns assembly.Location (empty for this kind of assembly).

In later code of `RazorReferenceManager`, `CreateMetadataReference(...)` method doesn't do any null/empty check on the path and caused this error.

### Expected Behavior

Those assemblies dynamically created by Roslyn should not affect RazorRuntimeCompilation due to their empty Location property.

### Steps To Reproduce

- Create ASP.NET Core MVC app
- Add RazorRuntimeCompilation
- Use Roslyn to create dynamic assembly with API controller.
- Load the assembly from stream after Roslyn's emit.
- Add loaded assembly as MVC application part using `new AssemblyPart(asm)`

### Exceptions (if any)

_No response_

### .NET Version

8.0.200

### Anything else?

**Suggestion:**
- `RazorReferenceManager.GetCompilationReferences(...)` should filter out those empty locations.

**Workaround:**
- Create my own ApplicationPart derived class and replace AssemblyPart to evade `GetReferencePaths(...)` call

```
public class MyAssemblyPart: ApplicationPart, IApplicationPartTypeProvider
{
public override string Name => Assembly.GetName().Name!;

public IEnumerable Types => Assembly.DefinedTypes;

public Assembly Assembly { get; }

public MyAssemblyPart(Assembly assembly)
{
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.