在带RenderBody的Razor .cshtml组件中读取appsettings.json数据报错
Razor布局页获取AppSettings并在JS中使用时RenderBody()报错问题
问题描述
我在Blazor Server项目的Razor布局页中使用RenderBody()渲染页面主体,尝试添加代码获取appsettings配置后,RenderBody()无法执行并抛出错误。我的需求是在页面的JavaScript代码中使用appsettings里的配置值(比如给图片设置src)。
原始布局页代码
@using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.Extensions.Options @using Signumid.ESignLiteShop.Data.Models @namespace Signumid.ESignLiteShop.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <base href="~/"/> <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css"/> <link href="css/site.css" rel="stylesheet"/> <link href="Signumid.ESignLiteShop.styles.css" rel="stylesheet"/> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet"/> <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet"/> <link href="http://fonts.cdnfonts.com/css/open-sans" rel="stylesheet"> <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/> <title>eSign-Lite Shop</title> </head> <body>
导致错误的代码
添加以下代码后,RenderBody()无法正常执行并报错:
@{ public static IOptions<ShopAppSettings> _config = null!; }
包含JavaScript的完整页面代码(需使用AppSettings值)
@RenderBody() <div id="blazor-error-ui"> <environment include="Staging,Production"> An error has occurred. This application may no longer respond until reloaded. </environment> <environment include="Development"> An unhandled exception has occurred. See browser dev tools for details. </environment> <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div> <script src="./_framework/blazor.server.js"></script> <script src="./_content/MudBlazor/MudBlazor.min.js"></script> <script> "use strict"; function purchaseComplete() { window.postMessage({ type: "SIGNATOR_BILLING_PURCHASE_COMPLETED" }, "*"); //TODO: Add tooltip } function purchaseClosed() { //TODO: Add tooltip } var BillingComponent = (function () { function BillingComponent(mobilePhone, organizationId) { this.mobilePhone = mobilePhone; this.organizationId = organizationId; } BillingComponent.prototype.buyAndOpenCheckout = function (productId, quantity) { window.Paddle.Checkout.open({ product: productId, passthrough: { phoneNumber: this.mobilePhone, organizationId: this.organizationId }, quantity: quantity, allowQuantity: false, disableLogout: true, successCallback: purchaseComplete, closeCallback: purchaseClosed, }); }; BillingComponent.prototype.renderBillingModal = function () { var _this = this; document.head.appendChild(styleSheet); var getDrawerElement = document.getElementById("shop-billing-container"); //create modal content div element var modalContent = document.createElement("div"); modalContent.classList.add("billing-modal-content"); var modalContentBodyContent = document.createElement("div"); modalContentBodyContent.classList.add("billing-modal-content-body-content"); //create new package //package ONE var newPackageOneCard = document.createElement("div"); newPackageOneCard.classList.add("signator-billing-package-card"); newPackageOneCard.onclick = function () { return _this.buyAndOpenCheckout("32227"); }; var newPackageOneCardImgBox = document.createElement("div"); newPackageOneCardImgBox.classList.add("signatorCardImgBox"); var newPackageOneCardImg = document.createElement("img"); newPackageOneCardImg.classList.add("signator-package-image"); newPackageOneCardImg.src = ""; var newPackageOneCardContentBox = document.createElement("div"); newPackageOneCardContentBox.classList.add("signator-billing-package-card-content-box"); var newPackageOneCardContentTitle = document.createElement("div"); newPackageOneCardContentTitle.classList.add("signator-billing-package-card-h3"); newPackageOneCardContentTitle.textContent = "10 credits"; var newPackageOneCardContentTitleTwo = document.createElement("div"); newPackageOneCardContentTitleTwo.classList.add("signator-billing-package-card-h2"); newPackageOneCardContentTitleTwo.textContent = /*i18next.t("price_label")*/ "Price:" + @_config.Value.Test; var newPackageOneCardContentBuyButton = document.createElement("a"); newPackageOneCardContentBuyButton.classList.add("signator-billing-package-card-buy-button"); newPackageOneCardContentBuyButton.textContent = "Buy"; newPackageOneCardImgBox.appendChild(newPackageOneCardImg); newPackageOneCardContentBox.appendChild(newPackageOneCardContentTitle); newPackageOneCardContentBox.appendChild(newPackageOneCardContentTitleTwo); newPackageOneCardContentBox.appendChild(newPackageOneCardContentBuyButton); newPackageOneCard.appendChild(newPackageOneCardImgBox); newPackageOneCard.appendChild(newPackageOneCardContentBox); //package TWO var newPackageTwoCard = document.createElement("div"); newPackageTwoCard.classList.add("signator-billing-package-card"); newPackageTwoCard.onclick = function () { return _this.buyAndOpenCheckout("32228"); }; var newPackageTwoCardImgBox = document.createElement("div"); newPackageTwoCardImgBox.classList.add("signatorCardImgBox"); var newPackageTwoCardImg = document.createElement("img"); newPackageTwoCardImg.classList.add("signator-package-image"); newPackageTwoCardImg.src = ""; var newPackageTwoCardContentBox = document.createElement("div"); newPackageTwoCardContentBox.classList.add("signator-billing-package-card-content-box"); var newPackageTwoCardContentTitle = document.createElement("div"); newPackageTwoCardContentTitle.classList.add("signator-billing-package-card-h3"); newPackageTwoCardContentTitle.textContent = "50 credits"; var newPackageTwoCardContentTitleTwo = document.createElement("div"); newPackageTwoCardContentTitleTwo.classList.add("signator-billing-package-card-h2"); newPackageTwoCardContentTitleTwo.textContent = "Price:"; var newPackageTwoCardContentBuyButton = document.createElement("a"); newPackageTwoCardContentBuyButton.classList.add("signator-billing-package-card-buy-button"); newPackageTwoCardContentBuyButton.textContent = "Buy"; newPackageTwoCardImgBox.appendChild(newPackageTwoCardImg); newPackageTwoCardContentBox.appendChild(newPackageTwoCardContentTitle); newPackageTwoCardContentBox.appendChild(newPackageTwoCardContentTitleTwo); newPackageTwoCardContentBox.appendChild(newPackageTwoCardContentBuyButton); newPackageTwoCard.appendChild(newPackageTwoCardImgBox); newPackageTwoCard.appendChild(newPackageTwoCardContentBox); //package THREE var newPackageThreeCard = document.createElement("div"); newPackageThreeCard.classList.add("signator-billing-package-card"); var newPackageThreeCardImgBox = document.createElement("div"); newPackageThreeCardImgBox.classList.add("signatorCardImgBox"); var newPackageThreeCardImg = document.createElement("img"); newPackageThreeCardImg.classList.add("signator-package-image"); newPackageThreeCardImg.src = ""; var newPackageThreeCardContentBox = document.createElement("div"); newPackageThreeCardContentBox.classList.add("signator-billing-package-card-content-box"); var newPackageThreeCardContentTitle = document.createElement("div"); newPackageThreeCardContentTitle.classList.add("signator-billing-package-card-h3"); newPackageThreeCardContentTitle.textContent = "100 credits"; var newPackageThreeCardContentTitleTwo = document.createElement("div"); newPackageThreeCardContentTitleTwo.classList.add("signator-billing-package-card-h2"); newPackageThreeCardContentTitleTwo.textContent = "Price:"; var newPackageThreeCardContentBuyButton = document.createElement("a"); newPackageThreeCardContentBuyButton.classList.add("signator-billing-package-card-buy-button"); newPackageThreeCardContentBuyButton.textContent = "Buy"; newPackageThreeCardImgBox.appendChild(newPackageThreeCardImg); newPackageThreeCardContentBox.appendChild(newPackageThreeCardContentTitle); newPackageThreeCardContentBox.appendChild(newPackageThreeCardContentTitleTwo); newPackageThreeCardContentBox.appendChild(newPackageThreeCardContentBuyButton); newPackageThreeCard.appendChild(newPackageThreeCardImgBox); newPackageThreeCard.appendChild(newPackageThreeCardContentBox); //create modal footer with button var modalContentFooter = document.createElement("div"); modalContentFooter.classList.add("billing-modal-content-footer"); modalContent.appendChild(modalContentBodyContent); modalContentBodyContent.appendChild(newPackageOneCard); modalContentBodyContent.appendChild(newPackageTwoCard); modalContentBodyContent.appendChild(newPackageThreeCard); modalContent.appendChild(modalContentFooter); if (getDrawerElement) { getDrawerElement.appendChild(modalContent); } else { setTimeout(function () { var getDrawerElementAfterTimeout = document.getElementById("shop-billing-container"); getDrawerElementAfterTimeout === null || getDrawerElementAfterTimeout === void 0 ? void 0 : getDrawerElementAfterTimeout.appendChild(modalContent); }, 500); } }; return BillingComponent; }()); window.signatorBilling = { ShowBillingModal: function (number, organizationId) { var x = new BillingComponent(number, organizationId); x.renderBillingModal(); } } </script> <script src="https://cdn.paddle.com/paddle/paddle.js"></script> <script type="text/javascript"> Paddle.Environment.set("sandbox"); Paddle.Setup({vendor:1234}); </script> </body> </html>
解决方案
错误原因
在Razor布局页的代码块中直接声明静态IOptions<ShopAppSettings>字段的方式不正确,布局页需要通过依赖注入获取配置服务,而非手动声明静态字段,这会导致页面渲染逻辑出错。
正确实现步骤
在布局页顶部注入IOptions服务
在布局页的指令部分添加注入语句,让框架自动注入配置实例:@inject IOptions<ShopAppSettings> Config将配置值传递给JavaScript
可以通过两种方式传递:- 方式一:在页面中渲染全局JS变量,供后续代码使用
- 方式二:直接在JS代码中嵌入Razor表达式获取配置值
修改后的完整布局页代码
@using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.Extensions.Options @using Signumid.ESignLiteShop.Data.Models @namespace Signumid.ESignLiteShop.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @inject IOptions<ShopAppSettings> Config <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <base href="~/"/> <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css"/> <link href="css/site.css" rel="stylesheet"/> <link href="Signumid.ESignLiteShop.styles.css" rel="stylesheet"/> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet"/> <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet"/> <link href="http://fonts.cdnfonts.com/css/open-sans" rel="stylesheet"> <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/> <title>eSign-Lite Shop</title> <!-- 方式一:渲染全局配置变量 --> <script> window.appSettings = { testValue: '@Config.Value.Test', packageOneImgSrc: '@Config.Value.PackageOneImgSrc' // 假设appsettings中有这个配置项 }; </script> </head> <body> @RenderBody() <div id="blazor-error-ui"> <environment include="Staging,Production"> 发生错误,应用可能需要重新加载才能响应。 </environment> <environment include="Development"> 发生未处理的异常,请查看浏览器开发者工具获取详情。 </environment> <a href="" class="reload">重新加载</a> <a class="dismiss">🗙</a> </div> <script src="./_framework/blazor.server.js"></script> <script src="./_content/MudBlazor/MudBlazor.min.js"></script> <script> "use strict"; function purchaseComplete() { window.postMessage({ type: "SIGNATOR_BILLING_PURCHASE_COMPLETED" }, "*"); //TODO: Add tooltip } function purchaseClosed() { //TODO: Add tooltip } var BillingComponent = (function () { function BillingComponent(mobilePhone, organizationId) { this.mobilePhone = mobilePhone; this.organizationId = organizationId; } BillingComponent.prototype.buyAndOpenCheckout = function (productId, quantity) { window.Paddle.Checkout.open({ product: productId, passthrough: { phoneNumber: this.mobilePhone, organizationId: this.organizationId }, quantity: quantity, allowQuantity: false, disableLogout: true, successCallback: purchaseComplete, closeCallback: purchaseClosed, }); }; BillingComponent.prototype.renderBillingModal = function () { var _this = this; // 原代码中styleSheet未定义,此处注释避免报错 // document.head.appendChild(styleSheet); var getDrawerElement = document.getElementById("shop-billing-container"); //create modal content div element var modalContent = document.createElement("div"); modalContent.classList.add("billing-modal-content"); var modalContentBodyContent = document.createElement("div"); modalContentBodyContent.classList.add("billing-modal-content-body-content"); //create new package //package ONE var newPackageOneCard = document.createElement("div"); newPackageOneCard.classList.add("signator-billing-package-card"); newPackageOneCard.onclick = function () { return _this.buyAndOpenCheckout("32227"); }; var newPackageOneCardImgBox = document.createElement("div"); newPackageOneCardImgBox.classList.add("signatorCardImgBox"); var newPackageOneCardImg = document.createElement("img"); newPackageOneCardImg.classList.add("signator-package-image"); // 方式一:使用全局变量 newPackageOneCardImg.src = window.appSettings.packageOneImgSrc; var newPackageOneCardContentBox = document.createElement("div"); newPackageOneCardContentBox.classList.add("signator-billing-package-card-content-box"); var newPackageOneCardContentTitle = document.createElement("div"); newPackageOneCardContentTitle.classList.add("signator-billing-package-card-h3"); newPackageOneCardContentTitle.textContent = "10 credits"; var newPackageOneCardContentTitleTwo = document.createElement("div"); newPackageOneCardContentTitleTwo.classList.add("signator-billing-package-card-h2"); // 方式二:直接嵌入Razor表达式 newPackageOneCardContentTitleTwo.textContent = "Price:" + '@Config.Value.Test'; var newPackageOneCardContentBuyButton = document.createElement("a"); newPackageOneCardContentBuyButton.classList.add("signator-billing-package-card-buy-button"); newPackageOneCardContentBuyButton.textContent = "Buy"; newPackageOneCardImgBox.appendChild(newPackageOneCardImg); newPackageOneCardContentBox.appendChild(newPackageOneCardContentTitle); newPackageOneCardContentBox.appendChild(newPackageOneCardContentTitleTwo); newPackageOneCardContentBox.appendChild(newPackageOneCardContentBuyButton); newPackageOneCard.appendChild(newPackageOneCardImgBox); newPackageOneCard.appendChild(newPackageOneCardContentBox); //package TWO var newPackageTwoCard = document.createElement("div"); newPackageTwoCard.classList.add("signator-billing-package-card"); newPackageTwoCard.onclick = function () { return _this.buyAndOpenCheckout("32228"); }; var newPackageTwoCardImgBox = document.createElement("div"); newPackageTwoCardImgBox.classList.add("signatorCardImgBox"); var newPackageTwoCardImg = document.createElement("img");
相关产品推荐
相关产品推荐

