How to use Vue 3 with ASP.NET Razor
TLDR
- It is recommended to use the Vue 3 Options API for development in lightweight or non-build tool environments.
- Through custom
TagHelpers, ASP.NET CoreDataAnnotationscan be automatically converted intovee-validatevalidation rules. - When integrating, be aware of conflicts between
v-modeland the nativevalueattribute; it is recommended to use aTagHelperto automatically remove thevalueattribute. - Use
axiosinterceptors to automatically inject theRequestVerificationTokento ensure theValidateAntiForgeryTokenmechanism functions correctly. - Warning: This architecture was found to have issues with
asp-page-handlernot functioning correctly and failing to properly parseDisplayNamein subsequent tests. It is recommended to evaluate switching to Blazor or other more stable integration solutions.
Integration Architecture and Core Implementation
Integrating Vue 3 into ASP.NET Razor Pages primarily aims to leverage frontend packages (such as vee-validate) for validation while retaining Razor's server-side rendering capabilities.
Handling Vue and Razor Attribute Conflicts
When does this issue occur: When using asp-for to generate an input tag in a Razor page while simultaneously adding v-model, the native value attribute causes warnings or exceptions in Vue's data binding.
The solution is to create a VueInputTagHelper that automatically removes the value attribute when v-model is detected:
[HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)]
public class VueInputTagHelper : TagHelper {
private const string ForAttributeName = "asp-for";
private const string VueModelAttributeName = "v-model";
public override void Process(TagHelperContext context, TagHelperOutput output) {
string[] excludeTypes = new string[] { "radio", "checkbox" };
if (context.AllAttributes.ContainsName(VueModelAttributeName) && !excludeTypes.Contains(context.AllAttributes["type"].Value)) {
output.Attributes.RemoveAt(output.Attributes.IndexOfName("value"));
}
}
}Automating Frontend Validation Rules
When does this issue occur: When manually maintaining frontend validation rules that are inconsistent with backend DataAnnotations.
Through a custom VeeValidateInputTagHelper, attributes like Required and StringLength can be automatically converted into rules strings recognizable by vee-validate:
private string? GetRules() {
List<string> items = new List<string>();
// Iterate through and convert validation attributes in Metadata
foreach (var validationAttribute in For.Metadata.ValidatorMetadata) {
switch (validationAttribute) {
case RequiredAttribute _:
items.Add("required");
break;
case EmailAddressAttribute _:
items.Add("email");
break;
// Other attribute conversion logic...
}
}
return items.Any() ? $"{string.Join("|", items)}" : null;
}Security and Ajax Requests
When does this issue occur: When sending POST requests using axios, failing to include the RequestVerificationToken will cause ASP.NET Core's ValidateAntiForgeryToken validation to fail.
Configure an axios interceptor in site.js to ensure that every request includes the token:
axios.interceptors.request.use(
config => {
let token = document.querySelector('input[name="__RequestVerificationToken"]');
if (token !== null) {
config.headers = {
RequestVerificationToken: token.value
}
}
return config;
}
);Pitfalls and Architectural Evaluation
WARNING
This architecture was found to have the following severe limitations during subsequent maintenance:
- The
<v-form>generated byVeeValidateFormTagHelpercausesasp-page-handlerto stop functioning correctly. - Error messages cannot correctly display field names set by attributes like
DisplayName. - Due to frequent updates to frontend frameworks, this type of "hybrid" architecture is prone to compatibility issues.
Based on the reasons above, it is recommended that developers consider the following when choosing a technology stack:
- For larger projects, it is recommended to adopt ASP.NET Core Blazor directly to avoid decoupling frontend and backend validation logic.
- If Vue 3 must be used, consider making the frontend a completely independent SPA project and communicating via APIs, rather than forcing DOM-level integration with Razor Pages.
Change Log
- 2023-01-30 Initial document creation.
- 2024-04-07 Added issues not addressed by the article's architecture.
