Reputation: 39374
On ASP.NET MVC 5 I used a base ViewPage with a few properties:
public String PageTitle { get; set; }
public String PageDescription { get; set; }
public String[] BodyCssClasses { get; set; }
Then on each view I would have:
@{
PageTitle = "Title ..."
PageDescription" = "Description ..."
BodyCssClasses = new String[] { "main", "home" }
}
On the master page I would simply use something like:
<title>@Title</title>
With this approach I was able to use Strong Typed for page properties ...
Is it possible to use a Base View Page in ASP.NET MVC 6?
Since there is no Web.Config how could this be done?
Any suggestions for better options to define page head info is welcome.
UPDATE
I followed the suggested and I am using:
public abstract class ViewPageBase<TModel> : RazorPage<TModel> {
public String Title { get; set; }
} // ViewPageBase
Then on _ViewImports I have:
@inherits ViewPageBase<TModel>
On _Layout.cshtml I have:
<title>@Title</title>
And finally on a view which uses that layout I have:
@{
Title = "Page Title";
Layout = "_Layout";
}
Everything compiles and runs but the page title is always empty.
Does anyone has any idea why?
Upvotes: 9
Views: 4005
Reputation: 14748
The technique you have described in your update will technically work.
Unfortunately, as @Peter notes, you get one instance of your custom ViewPage for the view, and a different instance for the layout. Because you are using two different instances, you cannot set a property on the view and expect to access that property on the layout. That's the answer to your updated question:
Everything compiles and runs but the page title is always empty. Does anyone has any idea why?
@Peter has offered a work around using the ViewBag
. I'd like to offer an additional workaround using dependency injection.
For instance, consider placing your custom properties in their own class, with its own interface:
public interface IPageMetaData {
string PageTitle { get; set; }
string PageDescription { get; set; }
string[] BodyCssClasses { get; set; }
}
public class PageMetaData : IPageMetaData {
public string PageTitle { get; set; }
public string PageDescription { get; set; }
public string[] BodyCssClasses { get; set; }
}
Now, register this with the .Net Core dependency injection framework. Use the Scoped
lifecycle, so only one instance will be created per-web request. In a vanilla project, this takes place in Startup.cs
, in the ConfigureServices
method:
public void ConfigureServices(IServiceCollection services) {
// Add framework services.
services.AddMvc();
services.AddScoped<IPageMetaData, PageMetaData>();
}
Finally, update your _ViewImports.cshtml
file to inject this object into your views:
@inject Your.Namespace.Goes.Here.IPageMetaData MetaData;
Now your views will have a ambient MetaData
property that will correspond to a per-web request instance of the PageMetaData
class. You can access it from both views and from the layout:
@{
// In a view
MetaData.PageTitle = "Set a page title";
}
@* In a layout *@
<title>@MetaData.PageTitle</title>
Upvotes: 6
Reputation: 12711
You'll probably want to make your base view page inherit from RazorPage
.
public abstract class ViewPageBase<TModel> : RazorPage<TModel>
{
}
Then you should be able to configure all your pages to inherit from this in the _ViewImports.cshtml
file.
@inherits ViewPageBase<TModel>
UPDATE
Not sure if this is the best approach, but I wonder if you could use the common ViewBag to share data between your View and the Layout.
Back the properties in your base page class with the ViewBag:
public abstract class ViewPageBase<TModel> : RazorPage<TModel>
{
public string Title
{
get { return ViewBag.Title; }
set { ViewBag.Title = value; }
}
}
Set the property in your view:
@{
Title = "Home Page";
}
Use the property in _Layout.cshtml:
<title>@Title</title>
Upvotes: 3
Reputation: 18301
Sounds like you're looking for the @inherits
Razor directive.
For instance:
@inherits MyBaseViewPage
Upvotes: 1