- Modern Web Development with ASP.NET Core 3
- Ricardo Peres
- 1162字
- 2021-06-18 18:36:03
Using view engines
It was mentioned at the start of the chapter that ASP.NET Core only includes one view engine, Razor, but nothing prevents us from adding more. This can be achieved through the ViewEngines collection of MvcViewOptions, as illustrated in the following code snippet:
services
.AddMvc()
.AddViewOptions(options =>
{
options.ViewEngines.Add(new CustomViewEngine());
});
A view engine is an implementation of IViewEngine, and the only included implementation is RazorViewEngine.
Again, view engines are searched sequentially when ASP.NET Core is asked to render a view and the first one that returns one is the one that is used. The only two methods defined by IViewEngine are as follows:
- FindView (ViewEngineResult): Tries to find a view from ActionContext
- GetView(ViewEngineResult): Tries to find a view from a path
Both methods return null if no view is found.
A view is an implementation of IView, and the ones returned by RazorViewEngine are all RazorView. The only notable method in the IView contract is RenderAsync, which is the one responsible for actually rendering a view from ViewContext.
A Razor view is a template composed essentially of HTML, but it also accepts fragments—which can be quite large, actually—of server-side C# code. Consider the requirements for it, as follows:
- First, you may need to define the type of model that your view receives from the controller. By default, it is dynamic, but you can change it with a @model directive, like this:
@model MyNamespace.MyCustomModel
- Doing this is exactly the same as specifying the base class of your view. This is accomplished by using @inherits, like this:
@inherits RazorPage<MyNamespace.MyCustomModel>
- If you don't want to write the full type name, you can add as many @using declarations as you want, as illustrated in the following code snippet:
@using My.Namespace
@using My.Other.Namespace
- You can intermix HTML with Razor expressions, which are processed on the server side. Razor expressions always start with the @ character. For example, if you want to output the currently logged-in user, you could write this:
User: @User.Identity.Name
- You can output any method that returns either a string or an IHtmlContent directly, like this:
@Html.Raw(ViewBag.Message)
- If you need to evaluate some simple code, you will need to include it inside parentheses, like this:
Last week: @(DateTime.Today - TimeSpan.FromDays(7))
Remember—if your expression has a space, you need to include it inside parentheses, the only exception being the await keyword, as illustrated in the following code snippet:
@await Component.InvokeAsync("Process");
- You can encode HTML (implicitly using the HtmlEncoder instance supplied in the HtmlEncoder property), like this:
@("<span>Hello, World</span>")
This will output an HTML-encoded string, as illustrated in the following code snippet:
<span>Hello, World</span>
More complex expressions, such as the definition of variables, setting values to properties, or calling of methods that do not return a stringy result (string, IHtmlContent) need to go in a special block, in which you can put pretty much anything you would like in a .NET method, as illustrated in the following code snippet:
@{
var user = @User.Identity.Name;
OutputUser(user);
Layout = "Master";
}
A variable defined in this way can be used in any other place in the view—after the declaration, of course.
Let's look at conditionals (if, else if, else and switch) now, which are nothing special. Have a look at the following code snippet:
//check if the user issuing the current request is authenticated somehow
@if (this.User.Identity.IsAuthenticated)
{
<p>Logged in</p>
}
else
{
<p>Not logged in</p>
}
//check the authentication type for the current user
@switch (this.User.Identity.AuthenticationType)
{
case "Claims":
<p>Logged in</p>
break;
case null:
<p>Not logged in</p>
break;
}
The first condition checks whether the current user is authenticated, and displays an HTML block accordingly. On the second, we have a switch instruction, on which we can specify multiple possible values; in this case, we are only looking at two, "Claims" and null, which essentially yields the same result as the first condition.
Loops use a special syntax, where you can mix together HTML (any valid Extensible Markup Language (XML) element) and code, as illustrated in the following code snippet:
@for (var i = 0; i < 10; i++)
{
<p>Number: @i</p>
}
Note that this will not work because Number is not included inside an XML element, as illustrated in the following code snippet:
@for (var i = 0; i < 10; i++)
{
Number: @i
}
But the following syntax (@:) would work:
@:Number: @i
This makes the rest of the line be treated as an HTML chunk.
The same syntax can be used in foreach and while.
Now, let's have a look at try/catch blocks, shown in the following code snippet:
@try
{
SomeMethodCall();
}
catch (Exception ex)
{
<p class="error">An error occurred: @ex.Message</p>
Log(ex);
}
Consider the @using and @lock blocks shown in the following code snippet:
@using (Html.BeginForm())
{
//the result is disposed at the end of the block
}
@lock (SyncRoot)
{
//synchronized block
}
Now, what if you want to output the @ character? You need to escape it with another @, like this:
<p>Please enter your username @@domain.com</p>
But Razor views recognize emails and do not force them to be encoded, as illustrated in the following code snippet:
<input type="email" name="email" value="nobody@domain.com"/>
Finally, comments—single or multiline—are also supported, as illustrated in the following code snippet:
@*this is a single-line Razor comment*@
@*
this
is a multi-line
Razor comment
*@
Inside a @{} block, you can add C# comments too, as illustrated in the following code snippet:
@{
//this is a single-line C# comment
/*
this
is a multi-line
C# comment
*/
}
Of course, because a view is essentially HTML, you can also use HTML comments, as illustrated in the following code snippet:
<!-- this is an HTML comment -->
We can add functions (which are actually, in object-oriented terminology, methods) to our Razor views; these are just .NET methods that are only visible in the scope of a view. To create them, we need to group them inside a @functions directive, like this:
@functions
{
int Count(int a, int b) { return a + b; }
public T GetValueOrDefault<T>(T item) where T : class, new()
{
return item ?? new T();
}
}
It is possible to specify visibility. By default, this happens inside a class, which is called a private class. It is probably pointless to specify visibility since the generated class is only known at runtime, and there is no easy way to access it.
The @functions name is actually slightly misleading, as you can declare fields and properties inside of it, as can be seen in the following code block:
@functions
{
int? _state;
int State
{
get
{
if (_state == null)
{
_state = 10;
}
return _state;
}
}
}
This example shows a simple private field that is encapsulated behind a property that has some logic behind it: the first time it is accessed, it sets the field to a default value; otherwise, it just returns what the current value is.
- Oracle WebLogic Server 12c:First Look
- 密碼學原理與Java實現
- Visual FoxPro程序設計教程(第3版)
- Python自動化運維快速入門
- Python 3網絡爬蟲實戰
- MATLAB定量決策五大類問題
- Visual FoxPro程序設計
- 焊接機器人系統操作、編程與維護
- 蘋果的產品設計之道:創建優秀產品、服務和用戶體驗的七個原則
- HTML5權威指南
- .NET 4.5 Parallel Extensions Cookbook
- IDA Pro權威指南(第2版)
- Django Design Patterns and Best Practices
- Deep Learning for Natural Language Processing
- Yii2 By Example