I know there is a way to ad c# functions inside a view and call them by using @functions{ ... }
method inside my view, but is there a way to create a shared view with those functions to include inside of the controllers view without copying the same line of code on each one? I tried by using @inject
and other methods inside the _Layout
view, but obviously those methods can't be called. I also tried to create an external class like this, but I want to use views only if it is possible:
public class Functions : RazorPage<dynamic>
{
public override Task ExecuteAsync()
{
throw new NotImplementedException();
}
public string GetTabActive(string lang)
{
if (ViewBag.lang.ToString() == lang) return "active";
return "";
}
}
Razor Pages can make coding page-focused scenarios easier and more productive than using controllers and views. If you're looking for a tutorial that uses the Model-View-Controller approach, see Get started with ASP.NET Core MVC. This document provides an introduction to Razor Pages. It's not a step by step tutorial.
Blazor is a framework that leverages the Razor components to produce dynamic HTML. The biggest difference between Razor and Blazor is that Razor is a markup language with C#, while Blazor is the framework that lets you run C# code and use the Razor view engine in the browser.
Razor Pages is a newer, simplified web application programming model. It removes much of the ceremony of ASP.NET MVC by adopting a file-based routing approach. Each Razor Pages file found under the Pages directory equates to an endpoint.
cshtml is just a file extension. razor view engine is used to convert razor pages(. cshtml) to html.
I finally found a way to do this, i needed to inject the class inside of the _ViewImports
giving a property name, like so:
@inject Functions func
And, in the StartUp
, i added a new service pointing to my abstract class like that:
services.AddSingleton<Functions>();
So, inside each view, i can use models and call my functions like that:
<h2>@func.MyFunction</h2>
Create an abstract class that inherits WebViewPage
public abstract class TestView<TViewModel> : WebViewPage<TViewModel>
{
public void TestMethod()
{
}
}
In your views use "Inherits"
@inherits TestView<dynamic>
Your method will be available
@TestMethod()
--Side note
You should not use @model in conjunction with @inherits You just want one or the other.
There are a few approaches:
RazorPage<TModel>
You can (ab)use OOP inheritance to add common members (i.e. methods/functions, but also properties) to your Razor page types by subclassing RazorPage<T>
and updating all of your pages to use your new subclass as their base type instead of defaulting to ASP.NET Core's RazorPage
or RazorPage<TModel>
.
Microsoft.AspNetCore.Mvc.Razor.RazorPage
or Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>
, e.g. class MyPage<TModel> : RazorPage<TModel>
protected
or public
, and static
or instance all work)..cshtml
files where you want to use them, change your @model MyPageModel
directive to @inherits MyPage<MyPageModel>
.Note that:
class RazorPage<TModel>
derives from the (non-generic) class RazorPage
class, so subclassing RazorPage<TModel>
will not cause those members to be visible from pages deriving from RazorPage
.
.cshtml
lacks a @model
directive, the actual page class will derive from RazorPage<dynamic>
instead of RazorPage
.RazorPage<TModel>
with a non-generic class provided you specify a concrete type for TModel
in your subclass; this is useful when you have multiple .cshtml
pages that share the same @model
type and need lots of custom C# logic.For example:
MyPage.cs:
using Microsoft.AspNetCore.Mvc.Razor;
namespace MyProject
{
public abstract class MyPage<TModel> : RazorPage<TModel>
{
protected String Foobar()
{
return "Lorem ipsum";
}
}
}
ActualPage.cshtml:
@using MyProject // <-- Or import in your _ViewImports
@inherits MyPage<ActualPageViewModel>
<div>
@( this.Foobar() ) <!-- Function is inherited -->
</div>
That said, I'm not a super-huge fan of this approach because (in my opinion) subclassing and inheritance should not be abused as a substitute for mixins (though I appreciate that C#'s lack of mixins is a huge ergonomic issue).
RazorPage
and RazorPage<TModel>
, but also for specific TModel
types.
IRazorPage
or RazorPageBase
if you really wanted to as well.RazorPage<TModel>
- and you don't care about TModel
, then make it generic type-parameter on your extension-method (see Foobar2
in my example below).this.
to be used, btw.@using
or in your _ViewImports.cshtml
file).For example:
MyPageExtensions.cs:
using Microsoft.AspNetCore.Mvc.Razor;
namespace MyProject
{
public static class MyPageExtensions
{
public static String Foobar1( this RazorPage page )
{
return "Lorem ipsum";
}
public static String Foobar2<TModel>( this RazorPage<TModel> page )
{
return "Lorem ipsum";
}
}
}
ActualPage.cshtml:
@using MyProject // <-- Or import in your _ViewImports
@model ActualPageViewModel
<div>
@( this.Foobar() ) <!-- Extension Method -->
</div>
IHtmlHelper
, IUrlHelper
, etc.You might notice that RazorPage<TModel>
does not have IHtmlHelper Html { get; }
nor IUrlHelper Url { get; }
properties - nor other useful ASP.NET MVC-specific members. That's because those members are only defined in the hidden PageName.cshtml.g.cs
file's class (it's in your obj\$(Configuration)\$(TargetPlatform)\Razor\...
directory, if your project builds okay).
In order to get access to those members you can define an interface to expose those properties, and you can direct ASP.NET Core to add that interface to the .cshtml.g.cs
classes by adding @implements
to your _ViewImports.cshtml
file.
This is what I use in my projects:
IRazorPageInjectedProperties.cs:
public interface IRazorPageInjectedProperties
{
ViewContext ViewContext { get; }
Microsoft.AspNetCore.Mvc.ModelBinding.IModelMetadataProvider ModelMetadataProvider { get; }
Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; }
Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; }
Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; }
Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; }
// Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; }
Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper HtmlHelper { get; }
}
_ViewImports.cshtml:
@using System
@using Microsoft.AspNetCore.Mvc
@* etc *@
@inject Microsoft.AspNetCore.Mvc.ModelBinding.IModelMetadataProvider ModelMetadataProvider
@inject Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper HtmlHelper
@implements MyProject.IRazorPageInjectedProperties
The IHtmlHelper
type needs an explicit @inject
directive because interface
members have to be public
(or explicit interface implementations), but the Html
property is protected
, but @inject
members are public
. The name needs to be HtmlHelper
instead of Html
otherwise it would conflict.
If subclassing RazorPage
you might notice your subclass can't really implement IRazorPageInjectedProperties
because you'd need to add the properties there (as abstract
), but @inject
properties won't override
them, but you could hack it a bit with some indirect properties, like so:
using Microsoft.AspNetCore.Mvc.Razor;
namespace MyProject
{
public abstract class MyPage<TModel> : RazorPage<TModel>
{
private IRazorPageInjectedProperties Self => (IRazorPageInjectedProperties)this;
private IHtmlHelper Html => this.Self.HtmlHelper;
private IUrlHelper Url => this.Self.Url;
protected IHtmlContent GetAHrefHtml()
{
return this.Html.ActionLink( ... );
}
protected String GetHrefUrl()
{
return this.Url.Action( ... );
}
}
}
If using extension-methods you'll need to either:
IRazorPageInjectedProperties
to extend IRazorPage
and make IRazorPageInjectedProperties
the target of your extension-methods.
GetAHrefHtml
in the example below.TPage : RazorPage
add a type-constraint to require IRazorPageInjectedProperties
.
GetHrefUrl1
in the example below.TModel
you'll need to make the extensions generic over TPage
and TModel
with IRazorPageInjectedProperties
.
GetHrefUrl2
in the example below.MyPageExtensions.cs:
using Microsoft.AspNetCore.Mvc.Razor;
namespace MyProject
{
public interface IRazorPageInjectedProperties : IRazorPage
{
// etc
}
public static class MyPageExtensions
{
public static IHtmlContent GetAHrefHtml( this IRazorPageInjectedProperties page )
{
return page.Html.ActionLink( ... );
}
public static String GetHrefUrl1<TPage>( this TPage page )
where TPage : RazorPage, IRazorPageInjectedProperties
{
return page.Url.Action( ... );
}
// to get TModel:
public static String GetHrefUrl2<TPage,TModel>( this TPage page )
where TPage : RazorPage<TModel>, IRazorPageInjectedProperties
{
return page.Url.Action( ... );
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With