ASP.NET Core - View from Class Library
Asked Answered
S

1

5

Im trying to make my asp.net core project fully modular. So I grouped some functionalities and separated them in different class libraries. With this structure I can activate/deactivate functionalities by just adding/removing reference of dll in the asp.net project.

The C# part is working fine. Content files like images/js/css/html are builded in the output folder aswell and can be referenced in the html without problems.

But how do I use the html-file as my razor view?

Example Class Library (NoteModule): https://i.ibb.co/tb7fbxg/so-1.png


Program.cs

public static class Program
    {
        public static void Main(string[] args)
        {
            var assembly = Assembly.GetEntryAssembly();
            var assemblyLocation = assembly.Location;
            var assemblyPath = Path.GetDirectoryName(assemblyLocation);

            var builder = Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(x => x.UseWebRoot(assemblyPath).UseStartup<Startup>());
            var build = builder.Build();
            build.Run();
        }
    }

Startup.cs

public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            this.Configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddRazorPages();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseDefaultFiles(new DefaultFilesOptions
            {
                FileProvider = new PhysicalFileProvider(Path.Combine(env.WebRootPath, "Views")),
                RequestPath = "/Views",
            });
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(Path.Combine(env.WebRootPath, "Assets")),
                RequestPath = "/Assets",
            });
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(Path.Combine(env.WebRootPath, "Views")),
                RequestPath = "/Views",
            });

            //app.UseMiddleware<ContentMiddleware>();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(x =>
            {
                x.MapControllerRoute("default", "{controller=" + Constants.ROUTE_DEFAULT_CONTROLLER + "}/{action=" + Constants.ROUTE_DEFAULT_ACTION + "}/{id?}");
                x.MapRazorPages();
            });
        }
    }

I tried to inject the html-data in the response stream from a filepath via custom middleware. But this way the Razor-Commands are not executed.

How do I solve it? And is there a way which is more simple?

ContentMiddleware.cs

    public class ContentMiddleware
    {
        private RequestDelegate Next { get; }
        private IWebHostEnvironment Environment { get; }

        public ContentMiddleware(RequestDelegate next, IWebHostEnvironment env)
        {
            this.Next = next;
            this.Environment = env;
        }

        public async Task Invoke(HttpContext context)
        {
            var route = context.Request.Path.Value.Substring(1).Replace("/", "\\");
            var contentDirectory = Path.Combine(this.Environment.WebRootPath, "Views");
            var contentPath = new FileInfo(Path.Combine(contentDirectory, $"{route}.cshtml"));

            var buffer = await File.ReadAllBytesAsync(contentPath.FullName);

            context.Response.StatusCode = (int)HttpStatusCode.OK;
            context.Response.ContentLength = buffer.Length;
            context.Response.ContentType = "text/html";

            using (var stream = context.Response.Body)
            {
                await stream.WriteAsync(buffer, default, buffer.Length);
                await stream.FlushAsync();
            }

            await this.Next(context);
        }
    }
Stinker answered 22/8, 2019 at 21:19 Comment(0)
S
9

After 2 days of research I got the answer:

A Class Library is not enough. You need a Razor Class Library.

Or you can edit your .csproj:

// from
<Project Sdk="Microsoft.NET.Sdk">
// to
<Project Sdk="Microsoft.NET.Sdk.Razor">
// from
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>
// to
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
  </PropertyGroup>
Stinker answered 23/8, 2019 at 21:9 Comment(2)
Thanks, I landed here after 2 days of research too and issue resolved.Pacifier
Thanks! Using <Project Sdk="Microsoft.NET.Sdk.Razor"> in a separate class library does the job just fine. Used .NET Core 6. But I had to add both <AddRazorSupportForMvc>true</AddRazorSupportForMvc> and <EnableDefaultContentItems>false</EnableDefaultContentItems> to make it work.Downhill

© 2022 - 2024 — McMap. All rights reserved.