I've been trying to create a very simple MVC project in F#. Here's a brief explanation of what I've done and I'd appreciate any help with it.
/ Root
| appsettings.json
| Views
| Home
| Index.cshtml // added as "Content", "Do not copy"
HomeController.fs
Startup.fs
Program.fs
The controller is very simple:
type HomeController() =
inherit Controller()
this.Index() =
this.View()
Then, when I launch my app, I get error:
InvalidOperationException: The view 'Index' was not found. The following locations were searched:
/Views/Home/Index.cshtml
/Views/Shared/Index.cshtml
So even though my cshtml file is there, it can't be found by the runtime.
I made sure "UseStaticFiles" is enabled in the Startup class:
type Startup() =
member __.ConfigureServices(services) : unit =
services.AddControllersWithViews() |> ignore
member __.Configure(app, env) : unit =
// env.ContentRootFileProvider.Root is set to my Root folder
app.UseStaticFiles() |> ignore
app.UseRouting() |> ignore
app.UseAuthorization() |> ignore
app.UseEndpoints(fun endpoints ->
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}") |> ignore
) |> ignore
I tried walking the problem around and read the content of cshtml manually and return it as string
type HomeController() =
inherit Controller()
member this.ManualIndex() =
let html = System.IO.File.ReadAllText("/Views/Index.cshtml")
this.Content(html, "text/html")
and it worked, but from the HTML I still can't refer to any other static files, like css or js. I also tried creating wwwroot directory and putting my static content there, but then didn't help either.
It turned out that F# version of the MVC project differs slightly from its C# counterpart, while I had assumed that it's only a matter of syntax.
In order for Razor to work in an F# project, an extra NuGet package is required: Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation. Then in Startup class an extension is needed (AddRazorRuntimeCompilation):
member this.ConfigureServices(services: IServiceCollection) =
services.AddControllersWithViews().AddRazorRuntimeCompilation() |> ignore
services.AddRazorPages() |> ignore
I haven't looked that much into it, but I guess this has something about C#-F# interop. The razor's file extension (cshtml) suggests that it relies on C#. There might be some friction when attempting to use it from an F# project.
Moving forwards, I recommend creating an F# MVC project using dotnet templates. The one I needed can be created with the following command:
dotnet new mvc --language=F#