-
Notifications
You must be signed in to change notification settings - Fork 266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Attempt to integrate razor view engine #6
Conversation
Hi, I wanted to let you know that I saw your pull request and I already started to look into it. You are right, it seems to be difficult to find a Razor library for .NET Core at the moment. RazorLight looks cool, but I saw a potential issue with it which I raised with the maintainer now. Apart from that I like what you have done. There's a few things I would suggest to improve (e.g. have Many thanks for helping out here and taking the initiative to resolve #1. I appreciate it a lot and will do my best to get this polished with you before merging. Just FYI I am travelling tomorrow and will be back on Sunday late night, so might not be able to respond or work on this for the next 2 days, but will get back to it as soon as possible. Many thanks again! |
razor (EngineFactory.CreatePhysical(views)) | ||
|
||
let defaultRazor () = configureRazor "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that instead of having to create the RazorLightEngine
every time you could merge all 3 functions to one like this perhaps:
let razorView (viewName : string) (model : obj) =
fun (ctx : HttpHandlerContext) ->
let engine = ctx.Services.GetService<IRazorLightEngine>()
let view = engine.Parse(viewName, model)
setHttpHeader "Content-Type" "text/html"
>>= setBodyAsString view
<| ctx
Here the HttpHandler tries to resolve an IRazorLightEngine
from the service provider.
You could create an extension method like this:
type IServiceCollection with
member this.AddRazorEngine (viewsFolderPath : string) =
this.AddSingleton<IRazorLightEngine>(EngineFactory.CreatePhysical(viewsFolderPath));
... which then can be used like this:
type Startup() =
member __.ConfigureServices (services : IServiceCollection) =
services.AddRazorEngine("C:\\SampleApp\\views") |> ignore
I think this would be more incline with existing ASP.NET Core patterns and it would allow users to configure the engine only once as a singleton or provide a custom implementation.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not creating the engine on each call (i think so), those functions configure
and default
returns a partial applied function with the engine, so, in the app you do let view = razor ()
and now the engine is created once and you can use it wherever view "foo" model
But, however, hey! I like your approach, uses the built in DI and looks more "aspnet friendly" 😸
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah looking back at the code you're right, it was instantiated only once.
"Program.fs" | ||
] | ||
} | ||
}, | ||
"embed": [ "**/*.cshtml" ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using the physical RazorLight engine then the views don't need to be embedded and this line can be removed.
} | ||
}, | ||
"preserveCompilationContext": true, | ||
"embed": [ "Person.cshtml" ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here as well.
[<CLIMutable>] | ||
type Person = { | ||
Name : string | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only formatting, but to be consistent I'd prefer to stick with this style please:
type Person =
{
Name : string
}
src/AspNetCore.Lambda/project.json
Outdated
@@ -35,7 +35,8 @@ | |||
"Microsoft.AspNetCore.Hosting": "1.1.0", | |||
"Microsoft.AspNetCore.Diagnostics": "1.1.0", | |||
"Newtonsoft.Json": "9.0.1", | |||
"DotLiquid": "2.0.64" | |||
"DotLiquid": "2.0.64", | |||
"RazorLight": "1.0.0-rc1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't tested it, but could imagine that the trailing ,
might cause a json formatting error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please have a look at my comments and what you think of the suggestions. Also the unit tests seem to have failed in the AppVeyor build. If you fix these things I'd be happy to merge.
hi, sorry for delay, was a busy week. I've updated the implementation following all of your comments on my last commit. Let me know if there is any other issue on this! ❤️ |
Hi, thanks! I am currently out but will have a look later tonight! |
src/AspNetCore.Lambda/Common.fs
Outdated
|
||
let combinePaths (path1 : string) (path2 : string) = | ||
Path.GetFullPath(Path.Combine(path1, path2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is probably not needed anymore.
setHttpHeader "Content-Type" "text/html" | ||
>>= setBodyAsString view | ||
<| ctx |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add some XML documentation to the handler. Example:
/// Parses and compiles a Razor view with the associated model and then writes its content to the body of the response.
/// It also sets the HTTP header Content-Type to text/html.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Only two minor things to change please and if you could please update the README with this new handler as well?
Hi again, man, thanks for your guidance and patience on this PR! I've added the comments and updated the readme as you suggested. Let me know if there is any other issue on this! |
Hey no worries. There's been many changes happening since the last merge again, so there are more conflicts again which prohibit me from merging your PR. This weekend I will take everything you've done and update a branch with it and then probably merge it back into dev/master from there if that is okay with you? |
sure! |
Hi! i think i get done the merge with
Even though my tests, both of them, main tests and sample app's tests, are broken... can't find the View! i've added a |
Thanks for the effort!!! |
I hope this closes the #1
I googled about razor engine and F# and found some interesting projects like FSRazor, Shaver and RazorEngine. But none of those is .net core 😢 Then, i found a nice C# implementation based on SO this answer so i decided to use this.
By now you can configure where your views (
.cshtml
s) are placed:let view = configureRazor "views"
or use a default config withlet view = defaultRazor ()
, then you call yourview
function likeview "Person.cshtml" model
There are some pitfalls, like you must use
namespaces
on your models other way razor can't find the@model
on.cshtml
.