404 with static content in Razor Class Library (RCL)
Asked Answered
F

5

6

I am having difficulties implementing static files in razor class library (.net Core 3.1) that are consumed by an ASP.NET Core (v3.1) application.

When trying to access the static files, I only get an 404 - Not Found.

I followed the following answer on Stackoverflow: https://mcmap.net/q/360913/-can-razor-class-library-pack-static-files-js-css-etc-too or

I also cross-checked with the documentation at: https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-3.0&tabs=visual-studio#create-an-rcl-with-static-assets.

I placed a css file in the library at the following location: wwwroot\css\Base.css and I tested the following path: https://localhost:44300/_content/OurIt.Cockpit/css/Base.css, which results in a 404 Not found response.

What I've already checked:

  • Any Controller with its Views inside the RCL can be browsed and they work fine (rendered HTML code is served to the browser)
  • Having app.UseStaticFiles(); in the web application.
  • Having webBuilder.UseStaticWebAssets(); in the web application.
  • Correct Casing.
  • The Build Action of wwwroot\css\Base.css is set to Content.
  • The RCL project has the following sdk defined: <Project Sdk="Microsoft.NET.Sdk.Razor">.
  • The following properties are set in the RCL project:

    <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <AddRazorSupportForMvc>true</AddRazorSupportForMvc> <PropertyGroup>

I also tried the way described in this answer: https://mcmap.net/q/360913/-can-razor-class-library-pack-static-files-js-css-etc-too and I tried to access the file from https://localhost:44300/path/css/Base.css

Is there any chance to debug or locate the issue? Reguarding to the Microsoft documentation:

When the RCL is built, a manifest is produced that describes the static web asset locations. The consuming app reads the manifest at runtime to consume the assets from referenced projects and packages.

In order to verify that the files are in the assembly, I was trying to locate that manifrest, but I couldn't find it or don't know where to look for it (i checked the output folder). I also tried opend the RCL with ILSpy hoping to find a glue for the issue.

Any ideas (or working samples with a RCL with static content for .NET Core 3.1 - I only found samples for Controllers / Views but not with static content)?

Update 2020-02-05:

I created a sample on Github for reproduction: https://github.com/DominikAmon/RclIssueDemo

Faxon answered 3/2, 2020 at 14:2 Comment(1)
Thanks for sharing your demo project! This line in your code was super helpful. Based on my interpretation of the docs, I had replaced <script src="~/dist..." with <script src="_content/{LIBRARY}/dist...", which gave errors. After looking at your code I changed it to <script src="~/_content/{LIBRARY}/dist...". Needed the tilde.Natality
E
1

If you remove the reference to Microsoft.AspNet.Core from the RclDemo.Library project, then everything works as expected. This is the line that should be removed from the project file:

<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />

If you create a new .NET Core 3.x application, you would not include this reference as it is now included as part of the Microsoft.AspNetCore.App framework reference. Static files worked differently in .NET Core 2.2 Razor Class Libraries, and I think your inclusion of the Microsoft.AspNetCore.Mvc v2.2.0 library is breaking things. There used to be additional configuration to include static files in an RCL.

Shawn

Energetic answered 18/3, 2020 at 12:54 Comment(3)
This was indeed the problem. I created multiple test and I also figured out that the line mentioned above caused the problem. This is also why the example of @Soapberry is wokring as well: The line is commented out.Faxon
But what if dependencies from Microsoft.AspNetCore.Mvc are needed within the RCL?Fistic
I don't have this line and getting 404Scuffle
S
5

I finally got it working for me. I have added a comment on the issue you have created at https://github.com/dotnet/AspNetCore.Docs/issues/16837.

The relevant parts of my now working .csproj are:

<Project Sdk="Microsoft.NET.Sdk.Razor">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
    <GenerateMvcApplicationPartsAssemblyAttributes>true</GenerateMvcApplicationPartsAssemblyAttributes>
    <RazorCompileOnBuild>true</RazorCompileOnBuild>
    <IncludeRazorContentInPack>false</IncludeRazorContentInPack>
    <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
    <EnableDefaultRazorGenerateItems>true</EnableDefaultRazorGenerateItems>
  </PropertyGroup>

 <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.1" />
  </ItemGroup>

  <PropertyGroup>
    <StaticWebAssetBasePath Condition="$(StaticWebAssetBasePath) == ''">/</StaticWebAssetBasePath>
  </PropertyGroup>
</Project>

Maybe not all of those settings above are required, but since it is working, I do not want to touch it too much - if it works, don't touch :-)

Now, here are other issues that were getting in the way:

  • Because I wanted to test my NuGet packages locally, I wanted to first push the packages to a local repository folder so I could consume them from a test application. However, no where it is documented that dotnet nuget can also push to local directories, so I thought I would have to use the standalone nuget.exe to achieve this. Well, apparently it is not a good idea to use nuget.exe with RCL libraries. Instead, you can use:
dotnet nuget push .\bin\Release\DynamicVML.1.0.32.nupkg -s c:\Projects\nuget

(note that the -s option is described as a server URL in the documentation but it can actually be a local folder, and this is not explained)

  • There are so many outdated articles and StackOverflow answers around that could set you up in the wrong path. What happened with me was that at some point I was trying to follow tutorials from different sources which turned out to be outdated for .NET Core 3.1. I ended up messing a little my project files and forgot to undo some of the changes I had made. To get it all working, make sure that:

  • The views / .cshtml files have to be set to "Build Action: Content";

  • The static files / js files have to be set to "Build Action: Content";

Now, to the consumer application part:

  • I did not have to add webBuilder.UseStaticWebAssets(); in Program.cs as for a moment I thought I had. So my CreateHostBuilder simply looks like this:
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

I did not have to add any of the FileProvider functionality that is described in the outdated tutorials. My ConfigureServices is as clean as this:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseInMemoryDatabase("BookAuthors"));
}

and my Configure is just the baseline one:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

With the above settings, everything works. I can include js files from the RCL library even though they are not physically present on the consumer project wwwroot (I know that this is documented in the current documentation, but at some point I was trying to debug the issue by adding a UseDirectoryBrowser to my configure and inspecting the contents of the served folders - this does not work, the static files from the RCL will not show up).

Also, a note for others with similar issues: with the above settings (due the last configuration block, more specifically) I can consume the static files from /. I am not using the /_content/LibraryName/... paths. In my RCL, I have the following structure

- wwwroot
---- lib
------- myFolder
---------- myScript.js

From the consumer app, I simply consume the .js file using

@section Scripts {
    <script src="~/lib/myFolder/myScript.js"></script>
}

... and it works!

Soapberry answered 9/5, 2020 at 6:11 Comment(2)
Update: I have created a RCL library others can use as an example. I included tips how to build a RCL at dynamic-vml.github.io/samples.html#razor-class-libraries-rclSoapberry
I manged to get it working without reseting StaticWebAssetBasePath. So the "_content" folder works as well. The issue was like Shown Paige described and also explains, why your code works: In your example you dont have the line <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" /> - If you would add it, the solution stops workingFaxon
A
2

I follow this article and it work well. https://dev.to/j_sakamoto/how-to-deal-with-the-http-404-content-foo-bar-css-not-found-when-using-razor-component-package-on-asp-net-core-blazor-app-aai

In the Program.cs add in the StaticWebAssetsLoader to include the static file and it able load the css and javascript in the Razor library class

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.ConfigureAppConfiguration((ctx, cb) =>
                    {
                        StaticWebAssetsLoader.UseStaticWebAssets(
                          ctx.HostingEnvironment,
                          ctx.Configuration);
                    });
                });
Adulterant answered 15/12, 2020 at 9:10 Comment(0)
E
1

If you remove the reference to Microsoft.AspNet.Core from the RclDemo.Library project, then everything works as expected. This is the line that should be removed from the project file:

<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />

If you create a new .NET Core 3.x application, you would not include this reference as it is now included as part of the Microsoft.AspNetCore.App framework reference. Static files worked differently in .NET Core 2.2 Razor Class Libraries, and I think your inclusion of the Microsoft.AspNetCore.Mvc v2.2.0 library is breaking things. There used to be additional configuration to include static files in an RCL.

Shawn

Energetic answered 18/3, 2020 at 12:54 Comment(3)
This was indeed the problem. I created multiple test and I also figured out that the line mentioned above caused the problem. This is also why the example of @Soapberry is wokring as well: The line is commented out.Faxon
But what if dependencies from Microsoft.AspNetCore.Mvc are needed within the RCL?Fistic
I don't have this line and getting 404Scuffle
L
1

I looked at your github example and fixed it. I removed the two package references in RclDemo.Library.csproj. Don't know if you need those for your full project, but at least you can maybe find out if you need them or if you need to configure something for them.

code:


    <Project Sdk="Microsoft.NET.Sdk.Razor">
        <PropertyGroup>
            <TargetFramework>netcoreapp3.1</TargetFramework>
            <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
        </PropertyGroup>
        <ItemGroup>
            <!--<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
            <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.1" />-->
            <FrameworkReference Include="Microsoft.AspNetCore.App" />
        </ItemGroup>
    </Project>

Lindly answered 8/6, 2020 at 14:18 Comment(1)
As Shawn Paige mentioned, the issue is actually only <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />. I have no idea how this line actually was configured at all, but I guess it was part of the RCL template. At least with the latest version of Visual Studio 2019, this line of code is not included anymoreFaxon
Y
1

I am using a plain Blazor Server template with a project reference to my RCL. Everything was working fine without any extra code.

My issue occurred after I added Nuget Package properties. The Package Id was different than the Assembly Name.

In this pattern:

_content/{LIBRARY NAME}/ Assembly Name = Library Name.

after adding Nuget Properties PackageId = Library Name

Hope this helps others.

Yonatan answered 19/4, 2021 at 11:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.