Open Simply007 opened 4 years ago
Thanks for the detailed bug report! I can reproduce locally and it certainly looks like there's a mismatch between what the page is expecting (a LandingPage
) and the model in the view data (which is definitely a Statiq document):
First step is to replicate in a failing test...
Okay, tracked this one down. The problem is that Statiq Web is being used in combination with custom pipelines. While the Index
pipeline defined explicitly does pass in a custom view model, Statiq Web also executes a whole bunch of other convention-based pipelines, one of which also attempts to render Razor files. When that pipeline runs, it doesn't have the same .WithModel()
call that the RenderRazor
module in your Index
pipeline has, so it gets to the Razor page and it's @model
directive and there's a mismatch because that RenderRazor
sets test model to the current document (the default behavior).
Even if this problem hadn't exhibited in this way, it still would have caused problems having two pipelines process the same files. There's a few different things you could do - let me know which is preferred and I'll walk you through it:
.CreateWeb(args)
looks like this:public static Bootstrapper AddWeb(this Bootstrapper boostrapper) =>
boostrapper
.AddPipelines(typeof(BootstrapperFactoryExtensions).Assembly)
.AddHostingCommands()
.AddWebServices()
.AddInputPaths()
.AddExcludedPaths()
.SetOutputPath()
.AddThemePaths()
.AddDefaultWebSettings()
.AddWebAnalyzers()
.ConfigureEngine(e => e.LogAndCheckVersion(typeof(BootstrapperExtensions).Assembly, "Statiq Web", WebKeys.MinimumStatiqWebVersion));
You could each of those directly and omit the .AddPipelines()
call. That's a maintenance burden though because if the set of stuff CreateWeb()
calls expands you'll have to take note and also expand it. You could also use the ConfigureEngine()
bootstrapper extension to iterate the pipelines once they're all added and remove any you don't want.
Turning off or removing the Statiq Web pipelines isn't great because they do a lot for you, so if you want to keep using them you could also...
The rendering calls in Statiq Web use something called templates that keeps them modular and extensible. Basically a template is a media type key with a module definition for those types of documents. The existing one looks like this:
You could customize that like this:
.ConfigureTemplates(templates =>
{
((RenderRazor)templates[MediaTypes.Razor].Module)
.WithModel(Config.FromDocument((document, context) =>
document.AsKontent<LandingPage>()));
})
Of course you'd probably want to change the module based on the document path or something, but that shows you how to adjust templates.
It looks like you're doing other stuff in that Index
pipeline though, so another option is...
You can exclude a document from processing by setting Excluded: true
in it's front matter (which means you'd also need to process that front matter out of the file with the ExtractFrontMatter
module, unless you used a sidecar file to set the Excluded
metadata). That will exclude the document from the built-in pipelines but you can still use it in your own pipelines. This probably seems the most like what you want to do.
Did all that makes sense? Happy to clarify further or help work though how to set any of these strategies up.
Thought of another approach that might work even better. If you name the index file _Index.cshtml
with an underscore the built-in Statiq Web pipelines will ignore it. Then use a SetDestination
module to change the destination to Index.html
after your RenderRazor
and you should be good to go.
Thanks a lot @daveaglick!
For now, I will stick with the _Index.cshtml
solution. I will consider using sidecar file to exclude from processing if I really need to have Index.cshtm
as a file name, but it is not an issue for me now. THX!
Internal link: https://github.com/Kentico/statiq-kontent-collaboration/issues/16
After discussion with @daveaglick, I am opening up the issue with a more general solution proposal:
Let's switch this issue from the bug to enhancement request and define the functionality.
That's exactly right. Remember, this isn't so much a case of it not working, as it working too many times.
The .CreateDefault(args)
creates a boostrapper and populates it with the default set of Statiq Framework functionality (like reading pipelines via reflection, getting settings from environment variables, etc.). Statiq Framework doesn't include any built-in pipelines though so the custom pipeline is the only one trying to read the index files.
On the other hand, .CreateWeb(args)
calls .CreateDefault(args)
internally, but also adds additional functionality from Statiq Web including the built-in Statiq Web pipelines. One of those reads .cshtml
files so it picks up the index file which is expecting a custom model, but because that built-in Statiq Web pipelines doesn't know anything about setting the custom model in its own RenderRazor
module, the custom model never gets set and the Razor engine crashes.
Just for a fill context:
In the end, I have decided to place the "top-level" templates - used for pages themselves, where I can specify the template manually store in _partials/TEMPLATE.cshtml
(i.e. /input/_partials/LandingPage.cshtml) and use display templates with sidecar file, because:
Shared/DisplayTemplates
does require the name same as the Model provided in order to use automatic matching to models when a Structure rich text rendering is used.
FYI: I have submitted a separate issue for Pipeline specific ViewModel discovery #148 - it is a bit related.
Description
When using a
Pipeline
to generate a page using Razor view with a strongly typed view model -LandingPage
- I am getting an error:Error:
Version of Statiq.Razor: 1.0.0-beta.27 I am using Kontent.Static module to pull data from Kentico Kontent headless CMS.
Pipeline
Template
@daveaglick - I have invited you to the repository with the code, so that you could check the code and the log,