diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0999d6e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +############################### +# Core EditorConfig Options # +############################### +root = true +# All files +[*] +indent_style = space + +# XML project files +[*.{csproj,fsproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# Code files +[*.{cs,csx,fs,fsx}] +indent_size = 4 +insert_final_newline = true +charset = utf-8 \ No newline at end of file diff --git a/Giraffe.Razor.sln b/Giraffe.Razor.sln index 077aa62..3f4aa1d 100644 --- a/Giraffe.Razor.sln +++ b/Giraffe.Razor.sln @@ -1,27 +1,32 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 15.0.26124.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{03CCBA43-B6F5-4FA7-8C18-432BB07225FC}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Razor", "src\Giraffe.Razor\Giraffe.Razor.fsproj", "{9B52367B-CC80-452E-9062-7583995BFAC0}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Giraffe.Razor", "src\Giraffe.Razor\Giraffe.Razor.fsproj", "{9B52367B-CC80-452E-9062-7583995BFAC0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E067A6B8-538E-4362-83C2-9ECBC486AC31}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "GiraffeRazorSample", "samples\GiraffeRazorSample\GiraffeRazorSample.fsproj", "{14818084-9969-4F42-8A66-394FC6670B50}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "GiraffeRazorSample", "samples\GiraffeRazorSample\GiraffeRazorSample.fsproj", "{14818084-9969-4F42-8A66-394FC6670B50}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_root", "_root", "{73E09F74-F64D-4C42-92FC-19731C0C5553}" -ProjectSection(SolutionItems) = preProject - .gitignore = .gitignore - .gitattributes = .gitattributes - LICENSE = LICENSE - NuGet.config = NuGet.config - README.md = README.md - RELEASE_NOTES.md = RELEASE_NOTES.md - giraffe-64x64.png = giraffe-64x64.png - CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md -EndProjectSection + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md + giraffe-64x64.png = giraffe-64x64.png + LICENSE = LICENSE + NuGet.config = NuGet.config + README.md = README.md + RELEASE_NOTES.md = RELEASE_NOTES.md + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Models", "samples\Models\Models.fsproj", "{7FF78E51-A357-4D4B-90FF-B03E148AE18C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorClassLibrary", "samples\RazorClassLibrary\RazorClassLibrary.csproj", "{0A429935-F750-4334-98BE-9FC26764A174}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -32,13 +37,6 @@ Global Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9B52367B-CC80-452E-9062-7583995BFAC0} = {03CCBA43-B6F5-4FA7-8C18-432BB07225FC} - {14818084-9969-4F42-8A66-394FC6670B50} = {E067A6B8-538E-4362-83C2-9ECBC486AC31} - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -64,5 +62,39 @@ Global {14818084-9969-4F42-8A66-394FC6670B50}.Release|x64.Build.0 = Release|Any CPU {14818084-9969-4F42-8A66-394FC6670B50}.Release|x86.ActiveCfg = Release|Any CPU {14818084-9969-4F42-8A66-394FC6670B50}.Release|x86.Build.0 = Release|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Debug|x64.ActiveCfg = Debug|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Debug|x64.Build.0 = Debug|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Debug|x86.ActiveCfg = Debug|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Debug|x86.Build.0 = Debug|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Release|Any CPU.Build.0 = Release|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Release|x64.ActiveCfg = Release|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Release|x64.Build.0 = Release|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Release|x86.ActiveCfg = Release|Any CPU + {7FF78E51-A357-4D4B-90FF-B03E148AE18C}.Release|x86.Build.0 = Release|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Debug|x64.ActiveCfg = Debug|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Debug|x64.Build.0 = Debug|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Debug|x86.ActiveCfg = Debug|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Debug|x86.Build.0 = Debug|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Release|Any CPU.Build.0 = Release|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Release|x64.ActiveCfg = Release|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Release|x64.Build.0 = Release|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Release|x86.ActiveCfg = Release|Any CPU + {0A429935-F750-4334-98BE-9FC26764A174}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9B52367B-CC80-452E-9062-7583995BFAC0} = {03CCBA43-B6F5-4FA7-8C18-432BB07225FC} + {14818084-9969-4F42-8A66-394FC6670B50} = {E067A6B8-538E-4362-83C2-9ECBC486AC31} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8D44B626-1BB8-4B87-8E9F-045072A0598C} EndGlobalSection EndGlobal diff --git a/samples/GiraffeRazorSample/GiraffeRazorSample.fsproj b/samples/GiraffeRazorSample/GiraffeRazorSample.fsproj index c56f144..ff1d0e6 100644 --- a/samples/GiraffeRazorSample/GiraffeRazorSample.fsproj +++ b/samples/GiraffeRazorSample/GiraffeRazorSample.fsproj @@ -1,7 +1,7 @@ - + - net5.0 + net6.0 GiraffeRazorSample GiraffeRazorSample false @@ -10,24 +10,17 @@ + + - - - - - + + - - - Always - - - diff --git a/samples/GiraffeRazorSample/Program.fs b/samples/GiraffeRazorSample/Program.fs index b866c00..70792ce 100644 --- a/samples/GiraffeRazorSample/Program.fs +++ b/samples/GiraffeRazorSample/Program.fs @@ -11,26 +11,9 @@ open Microsoft.AspNetCore.Http.Features open Microsoft.AspNetCore.Mvc.ModelBinding open Microsoft.Extensions.Logging open Microsoft.Extensions.DependencyInjection -open FSharp.Control.Tasks open Giraffe open Giraffe.Razor - -// --------------------------------- -// Models -// --------------------------------- - -[] -type Person = - { - Name : string - } - -[] -type CreatePerson = - { - Name : string - CheckMe : bool - } +open Models // --------------------------------- // Web app @@ -62,6 +45,10 @@ let smallFileUploadHandler = let largeFileUploadHandler = fun (next : HttpFunc) (ctx : HttpContext) -> task { + // Simply accessing this property triggers something necessary + // for the IFormFeature instance to be injected (without this, it's null) + // see https://stackoverflow.com/questions/65967338/how-do-i-enable-iformfeature-in-asp-net-kestrel + let formContentType = ctx.Request.HasFormContentType let formFeature = ctx.Features.Get() let! form = formFeature.ReadFormAsync CancellationToken.None return! (form.Files |> displayFileInfos) next ctx @@ -81,7 +68,7 @@ let renderPerson = let renderCreatePerson = let model = { Name = ""; CheckMe = true } - let viewData = dict [("Title", box "Create peson")] + let viewData = dict [("Title", box "Create person")] razorHtmlView "CreatePerson" (Some model) (Some viewData) None let createPerson = @@ -97,7 +84,7 @@ let createPerson = let url = sprintf "/person?name=%s" model.Name return! redirectTo false url next ctx else - let viewData = dict [("Title", box "Create peson")] + let viewData = dict [("Title", box "Create person")] return! razorHtmlView "CreatePerson" (Some model) (Some viewData) (Some modelState) next ctx } @@ -108,11 +95,23 @@ let viewData = "Bar", true :> obj ] +let renderIndex = + """ +

non razor index

+ + """ + |> htmlString + let webApp = choose [ GET >=> choose [ - route "/" >=> text "index" + route "/" >=> renderIndex route "/razor" >=> razorView "text/html" "Hello" None (Some viewData) None route "/person/create" >=> renderCreatePerson route "/person" >=> renderPerson @@ -132,7 +131,7 @@ let webApp = let errorHandler (ex : Exception) (logger : ILogger) = logger.LogError(EventId(), ex, "An unhandled exception has occurred while executing the request.") - clearResponse >=> ServerErrors.INTERNAL_ERROR (text ex.Message) + clearResponse >=> ServerErrors.INTERNAL_ERROR ex.Message // --------------------------------- // Main @@ -148,9 +147,14 @@ let configureServices (services : IServiceCollection) = let sp = services.BuildServiceProvider() let env = sp.GetService() services.AddGiraffe() |> ignore - Path.Combine(env.ContentRootPath, "Views") + services.AddMvc() |> ignore // Required for Razor views to work, regardless of runtime compilation or not. + // Only use Razor runtime compilation in DEBUG (For hot reload to work) + // The statically compiled views are used in Release mode. +#if DEBUG + Path.GetFullPath(Path.Combine(env.ContentRootPath, "..", "RazorClassLibrary")) |> services.AddRazorEngine |> ignore +#endif let configureLogging (loggerBuilder : ILoggingBuilder) = loggerBuilder.AddFilter(fun lvl -> lvl.Equals LogLevel.Error) @@ -168,4 +172,4 @@ let main _ = .ConfigureLogging(configureLogging) .Build() .Run() - 0 \ No newline at end of file + 0 diff --git a/samples/GiraffeRazorSample/Views/Partial.cshtml b/samples/GiraffeRazorSample/Views/Partial.cshtml deleted file mode 100644 index 39e34f9..0000000 --- a/samples/GiraffeRazorSample/Views/Partial.cshtml +++ /dev/null @@ -1,2 +0,0 @@ -

Greetings @ViewData["Title"]

-

Some partial text.

\ No newline at end of file diff --git a/samples/GiraffeRazorSample/WebRoot/main.css b/samples/GiraffeRazorSample/wwwroot/main.css similarity index 100% rename from samples/GiraffeRazorSample/WebRoot/main.css rename to samples/GiraffeRazorSample/wwwroot/main.css diff --git a/samples/Models/Models.fs b/samples/Models/Models.fs new file mode 100644 index 0000000..9dcabba --- /dev/null +++ b/samples/Models/Models.fs @@ -0,0 +1,18 @@ +namespace Models + +// --------------------------------- +// Models +// --------------------------------- + +[] +type Person = + { + Name : string + } + +[] +type CreatePerson = + { + Name : string + CheckMe : bool + } \ No newline at end of file diff --git a/samples/Models/Models.fsproj b/samples/Models/Models.fsproj new file mode 100644 index 0000000..847ab8e --- /dev/null +++ b/samples/Models/Models.fsproj @@ -0,0 +1,12 @@ + + + + net6.0 + true + + + + + + + diff --git a/samples/RazorClassLibrary/RazorClassLibrary.csproj b/samples/RazorClassLibrary/RazorClassLibrary.csproj new file mode 100644 index 0000000..68e99cb --- /dev/null +++ b/samples/RazorClassLibrary/RazorClassLibrary.csproj @@ -0,0 +1,28 @@ + + + + net6.0 + enable + enable + + + true + + + + + + + + + + + + + + + + + + + diff --git a/samples/GiraffeRazorSample/Views/CreatePerson.cshtml b/samples/RazorClassLibrary/Views/CreatePerson.cshtml similarity index 95% rename from samples/GiraffeRazorSample/Views/CreatePerson.cshtml rename to samples/RazorClassLibrary/Views/CreatePerson.cshtml index b8632e5..a556166 100644 --- a/samples/GiraffeRazorSample/Views/CreatePerson.cshtml +++ b/samples/RazorClassLibrary/Views/CreatePerson.cshtml @@ -1,11 +1,11 @@ -@model GiraffeRazorSample.CreatePerson +@model Models.CreatePerson @{ Layout = "_Layout"; } @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
-

Create Person

+

@ViewData["Title"]

diff --git a/samples/GiraffeRazorSample/Views/FileUpload.cshtml b/samples/RazorClassLibrary/Views/FileUpload.cshtml similarity index 100% rename from samples/GiraffeRazorSample/Views/FileUpload.cshtml rename to samples/RazorClassLibrary/Views/FileUpload.cshtml diff --git a/samples/GiraffeRazorSample/Views/Hello.cshtml b/samples/RazorClassLibrary/Views/Hello.cshtml similarity index 100% rename from samples/GiraffeRazorSample/Views/Hello.cshtml rename to samples/RazorClassLibrary/Views/Hello.cshtml diff --git a/samples/RazorClassLibrary/Views/Partial.cshtml b/samples/RazorClassLibrary/Views/Partial.cshtml new file mode 100644 index 0000000..745cdd3 --- /dev/null +++ b/samples/RazorClassLibrary/Views/Partial.cshtml @@ -0,0 +1,3 @@ +

Greetings @ViewData["Title"]

+

Some partial text.

+Create a new person! \ No newline at end of file diff --git a/samples/GiraffeRazorSample/Views/Person.cshtml b/samples/RazorClassLibrary/Views/Person.cshtml similarity index 81% rename from samples/GiraffeRazorSample/Views/Person.cshtml rename to samples/RazorClassLibrary/Views/Person.cshtml index c466701..0faa853 100644 --- a/samples/GiraffeRazorSample/Views/Person.cshtml +++ b/samples/RazorClassLibrary/Views/Person.cshtml @@ -1,4 +1,4 @@ -@model GiraffeRazorSample.Person +@model Models.Person @{ Layout = "_Layout"; } diff --git a/samples/GiraffeRazorSample/Views/_Layout.cshtml b/samples/RazorClassLibrary/Views/_Layout.cshtml similarity index 100% rename from samples/GiraffeRazorSample/Views/_Layout.cshtml rename to samples/RazorClassLibrary/Views/_Layout.cshtml diff --git a/samples/GiraffeRazorSample/Views/_ViewStart.cshtml b/samples/RazorClassLibrary/Views/_ViewStart.cshtml similarity index 100% rename from samples/GiraffeRazorSample/Views/_ViewStart.cshtml rename to samples/RazorClassLibrary/Views/_ViewStart.cshtml diff --git a/src/Giraffe.Razor/Giraffe.Razor.fsproj b/src/Giraffe.Razor/Giraffe.Razor.fsproj index 85ab485..243a3d9 100755 --- a/src/Giraffe.Razor/Giraffe.Razor.fsproj +++ b/src/Giraffe.Razor/Giraffe.Razor.fsproj @@ -11,7 +11,7 @@ $(NoWarn);NU5104 - net5.0 + net6.0 portable Library true @@ -45,9 +45,8 @@ - - - + + diff --git a/src/Giraffe.Razor/HttpHandlers.fs b/src/Giraffe.Razor/HttpHandlers.fs index cfca34a..9f811de 100644 --- a/src/Giraffe.Razor/HttpHandlers.fs +++ b/src/Giraffe.Razor/HttpHandlers.fs @@ -12,7 +12,6 @@ module HttpHandlers = open Microsoft.AspNetCore.Mvc.ViewFeatures open Microsoft.Extensions.DependencyInjection open Microsoft.AspNetCore.Antiforgery - open FSharp.Control.Tasks open Giraffe open RazorEngine @@ -55,4 +54,4 @@ module HttpHandlers = return! if isValid then next ctx else invalidTokenHandler (Some >> Task.FromResult) ctx - } \ No newline at end of file + } diff --git a/src/Giraffe.Razor/RazorEngine.fs b/src/Giraffe.Razor/RazorEngine.fs index 32cac04..1f203fe 100644 --- a/src/Giraffe.Razor/RazorEngine.fs +++ b/src/Giraffe.Razor/RazorEngine.fs @@ -13,7 +13,6 @@ module RazorEngine = open Microsoft.AspNetCore.Mvc.Rendering open Microsoft.AspNetCore.Mvc.ViewFeatures open Microsoft.AspNetCore.Routing - open FSharp.Control.Tasks let private extractRouteData (path : string) = // Normalize nulls @@ -80,4 +79,4 @@ module RazorEngine = do! view.RenderAsync(viewContext) tempDataDict.Save() return Ok (output.ToString()) - } \ No newline at end of file + }