Error executing template "Designs/Swift/_parsed/Swift_Page.parsed.cshtml"
System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server) ---> System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at Dynamicweb.Data.DatabaseConnectionProvider.CreateConnection(Boolean open)
   at Dynamicweb.Data.Database.CreateConnection()
   at Dynamicweb.Data.Database.CreateDataReader(CommandBuilder commandBuilder, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout)
   at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductById(String productId, String productVariantId, String productLanguageId)
   at Dynamicweb.Ecommerce.Products.ProductService.FetchMissingProductsInternal(IProductRepository repo, IEnumerable`1 keys)
   at Dynamicweb.Caching.ServiceCache`2.GetCache(IEnumerable`1 keys)
   at Dynamicweb.Caching.ServiceCache`2.GetCache(TKey key)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, User user, Boolean showUntranslated)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, Boolean useAssortments)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId)
   at CompiledRazorTemplates.Dynamic.RazorEngine_b9e731468ed3460a811f4bc19f73fda4.Execute() in E:\Dynamicweb.Net\Solutions\Dynamicweb\dansukker.prod\Swift-Files\Templates\Designs\Swift\_parsed\Swift_Page.parsed.cshtml:line 165
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()
ClientConnectionId:00000000-0000-0000-0000-000000000000
Error Number:2,State:0,Class:20

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 2 @using System 3 @using Dynamicweb 4 @using Dynamicweb.Environment 5 @using Dynamicweb.Frontend 6 @using System.Web 7 8 @{ 9 string swiftVersion = ReadFile("~/Files/Templates/Designs/Swift/swift_version.txt"); 10 bool renderAsResponsive = Model.Area.Item.GetString("DeviceRendering", "responsive").Equals("responsive", StringComparison.OrdinalIgnoreCase); 11 bool renderMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet; 12 string responsiveHeaderClassDesktop = string.Empty; 13 string responsiveHeaderClassMobile = string.Empty; 14 if (renderAsResponsive) 15 { 16 responsiveHeaderClassDesktop = " d-none d-xl-block"; 17 responsiveHeaderClassMobile = " d-block d-xl-none"; 18 19 } 20 21 var brandingPageId = Model.Area.Item.GetLink("BrandingPage") != null ? Model.Area.Item.GetLink("BrandingPage").PageId : 0; 22 var themePageId = Model.Area.Item.GetLink("ThemesPage") != null ? Model.Area.Item.GetLink("ThemesPage").PageId : 0; 23 string customHeaderInclude = Model.Area.Item.GetFile("CustomHeaderInclude") != null ? Model.Area.Item.GetFile("CustomHeaderInclude").Name : string.Empty; 24 25 var brandingPage = Dynamicweb.Services.Pages?.GetPage(brandingPageId) ?? null; 26 var themesParagraphLastChanged = Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 27 28 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt; 29 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"~/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css")); 30 31 // Schema.org details for PDP 32 string productId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : ""; 33 bool isProductDetailsPage = !string.IsNullOrEmpty(productId); 34 string schema = Pageview.Page.NavigationTag == "Recipes" ? "Recipe" : "Product"; // Set specific schema for recipe-products pages 35 string productDetailPageSchemaOrg = isProductDetailsPage ? "itemscope=\"\" itemtype=\"https://schema.org/"+ schema + "\"" : ""; 36 37 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt) 38 { 39 //Branding page has been saved or the file is missing. Rewrite the file to disc. 40 if (brandingPageId > 0) 41 { 42 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId); 43 brandingPageview.Redirect = false; 44 brandingPageview.Output(); 45 } 46 } 47 48 49 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt) 50 { 51 //Branding page has been saved or the file is missing. Rewrite the file to disc. 52 if (themePageId > 0) 53 { 54 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId); 55 themePageview.Redirect = false; 56 themePageview.Output(); 57 } 58 } 59 60 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("~/Files/Templates/Designs/Swift/Assets/css/styles.css")); 61 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("~/Files/Templates/Designs/Swift/Assets/js/scripts.js")); 62 63 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 64 65 string headerCssClass = "sticky-top"; 66 bool movePageBehind = false; 67 string scrollInitScript = "swift.Scroll.init(); AOS.init({offset: 240, duration: 600, delay: 100}); disable: window.matchMedia('(prefers-reduced-motion: reduce)');"; 68 if (Pageview.Page.PropertyItem != null) 69 { 70 headerCssClass = Pageview.Page.PropertyItem["MoveThisPageBehindTheHeader"] != null ? Pageview.Page.PropertyItem["MoveThisPageBehindTheHeader"].ToString() : "sticky-top"; 71 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false; 72 } 73 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass; 74 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass; 75 76 string googleAnalyticsTrackingID = Model.Area.Item.GetString("GoogleAnalyticsTrackingID"); 77 string etrackerDataSecureCode = Model.Area.Item.GetString("EtrakerDataSecureCode"); 78 bool allowCookies = CookieManager.GetCookieOptInLevel() == 0 || !CookieManager.CookieOptInLevelExists ? false : true; 79 string cookieDeclarationKey = Model.Area.Item.GetString("CookieDeclarationKey"); 80 81 string gtmLanguage = Pageview.Area.CultureInfo.TwoLetterISOLanguageName; 82 bool showGtm = gtmLanguage == "sv" || gtmLanguage == "da" || gtmLanguage == "fi"; 83 84 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;"); 85 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css?{cssLastModified.Ticks}; rel=preload; as=style;"); 86 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/aos.js?{jsFileInfo.LastWriteTime.Ticks}; rel=preload; as=script;"); 87 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}; rel=preload; as=script;"); 88 //Dynamicweb.Context.Current.Response.Flush(); //This sends the headers where we are now in the rendering making the TTFB faster 89 90 SetMetaTags(); 91 92 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>(); 93 94 if (Pageview.Area.IsMaster) { 95 languages.Add(Pageview.Page); 96 if (Pageview.Page.Languages != null) { 97 foreach (var language in Pageview.Page.Languages) { 98 languages.Add(language); 99 } 100 } 101 } else { 102 languages.Add(Pageview.Page.MasterPage); 103 if (Pageview.Page.MasterPage != null) { 104 if (Pageview.Page.MasterPage.Languages != null) { 105 foreach (var language in Pageview.Page.MasterPage.Languages) { 106 languages.Add(language); 107 } 108 } 109 } 110 } 111 112 string siteLanguage = Pageview.Area.CultureInfo.Name; 113 Uri url = Dynamicweb.Context.Current.Request.Url; 114 string hostName = url.Host; // domain.com/da-dk or domain.com/en-us 115 116 var ecomCountries = Dynamicweb.Ecommerce.Services.Countries.GetCountries(); 117 var ecomCurrencies = Dynamicweb.Ecommerce.Services.Currencies.GetAllCurrencies(); 118 119 string googleSiteVerification = Model.Area.Item.GetString("GoogleSiteVerification"); 120 } 121 <!doctype html> 122 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName"> 123 <head> 124 @if (showGtm) 125 { 126 <!-- Google Tag Manager --> 127 <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 128 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 129 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 130 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 131 })(window,document,'script','dataLayer','GTM-TMPJLQW9');</script> 132 <!-- End Google Tag Manager --> 133 } 134 <!-- @swiftVersion --> 135 @* Required meta tags *@ 136 <meta charset="utf-8"> 137 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0"> 138 139 @if(!string.IsNullOrEmpty(googleSiteVerification)) 140 { 141 <meta name="google-site-verification" content="@googleSiteVerification" /> 142 } 143 144 <link rel="preconnect" href="https://fonts.gstatic.com" /> 145 146 <link rel="shortcut icon" href="~/Files/Templates/Designs/Swift/Assets/Images/favicon.png"> 147 <link rel="apple-touch-icon" href="~/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png"> 148 <link rel="apple-touch-icon" sizes="152x152" href="~/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon-152x152.png"> 149 <link rel="apple-touch-icon" sizes="180x180" href="~/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon-180x180.png"> 150 <link rel="apple-touch-icon" sizes="114x114" href="~/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon-114x114.png"> 151 <link rel="apple-touch-icon" sizes="120x120" href="~/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon-120x120.png"> 152 <link rel="apple-touch-icon" sizes="144x144" href="~/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon-144x144.png"> 153 154 155 @{ 156 // 1. Hämta SEO-sökvägen från Pageview 157 string seoPath = Pageview.SearchFriendlyUrl; 158 159 // Recept och produkter: canonical utan kategori i sökvägen (#361). Samma recept nås även via 160 // /se/recept/godis/kokostryffel, som annars blev sin egen canonical bredvid /se/recept/kokostryffel. 161 // Länken byggs som i sitemapen: sidan + ProductID (basprodukten, utan GroupID och VariantID), med webbplatsens ecom-språk. 162 // Bara när produkten finns, så att en ProductID-parameter på en annan sida inte ger en produkt-canonical. 163 string canonicalProductId = Dynamicweb.Context.Current.Request.QueryString["ProductID"]; 164 string canonicalLanguageId = Pageview.Area.EcomLanguageId; 165 if (!string.IsNullOrEmpty(canonicalProductId) 166 && Dynamicweb.Ecommerce.Services.Products.GetProductById(canonicalProductId, "", canonicalLanguageId) != null) 167 { 168 string productLink = $"Default.aspx?ID={Pageview.ID}&ProductID={HttpUtility.UrlEncode(canonicalProductId)}"; 169 string productUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(productLink, canonicalLanguageId); 170 if (!string.IsNullOrEmpty(productUrl) && productUrl.IndexOf("Default.aspx", StringComparison.OrdinalIgnoreCase) < 0 && !productUrl.Contains("?")) 171 { 172 seoPath = productUrl; 173 } 174 } 175 176 // Fallback om Pageview är tom 177 if (string.IsNullOrEmpty(seoPath) || seoPath == "/") 178 { 179 seoPath = Dynamicweb.Context.Current.Request.Url.AbsolutePath; 180 } 181 182 // 2. Rensa bort query-parametrar (?GroupFacetID...) direkt om de finns kvar 183 if (seoPath.Contains("?")) 184 { 185 seoPath = seoPath.Split('?')[0]; 186 } 187 188 // 3. Kontrollera och städa bort duplicerade slutsegment (t.ex. /dessert/dessert) 189 // Vi delar upp sökvägen i bitar baserat på "/" 190 var segments = seoPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); 191 if (segments.Length > 1 && segments[segments.Length - 1].Equals(segments[segments.Length - 2], StringComparison.OrdinalIgnoreCase)) 192 { 193 // Om de två sista segmenten är identiska, ta bort det sista och bygg ihop sökvägen igen 194 seoPath = "/" + string.Join("/", segments.Take(segments.Length - 1)); 195 } 196 197 // 4. Bygg ihop till den slutgiltiga absoluta URL:en 198 string finalCanonicalUrl = seoPath.StartsWith("http", StringComparison.OrdinalIgnoreCase) 199 ? seoPath 200 : $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{seoPath}"; 201 } 202 <link rel="canonical" href="@finalCanonicalUrl" /> 203 204 @Model.MetaTags 205 206 @{ 207 @* Languages meta data *@ 208 foreach (var language in languages) 209 { 210 if (language != null) { 211 if (!string.IsNullOrEmpty(language.Area.DomainLock)) 212 { 213 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk 214 } 215 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(language.ID); 216 string href = $"{url.Scheme}://{hostName}{friendlyUrl}"; 217 218 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href" /> 219 } 220 } 221 } 222 223 <title>@Model.Title</title> 224 @* Bootstrap + Swift stylesheet *@ 225 <link href="~/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css"> 226 @* Branding and Themes min stylesheet *@ 227 <link href="~/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_@(Model.Area.ID).min.css?@cssLastModified.Ticks" rel="stylesheet" media="all" type="text/css" data-last-modified-content="@cssLastModified"> 228 229 @* cookie Consent - Cookiebot runs from the CMS on all sites, also SE/DK/FI that have GTM (must not be added as a tag in GTM too) *@ 230 @if (!string.IsNullOrWhiteSpace(cookieDeclarationKey)) 231 { 232 <script> 233 (function (C, oo, k, ie, b, o, t) { 234 var a=C.scripts[0],d=C.createElement(ie),e=[/^\/([a-z]{2})([_-][a-z]{2})?(\/.*)?$/g. 235 exec(k),/^([a-z]{2})\./.exec(oo),/\.([a-z]{2,})$/.exec(oo)],f={au:"en",ca:"en",cz: 236 "cs",dk:"da",ee:"et",no:"nb",se:"sv",ie:"en",uk:"en"},g=0;for(g of e){e=g?g[1]:t;if(g)break} 237 e=e.length!=2?t:e;e=f[e]?f[e]:e;d.id=b;d.setAttribute("data-culture",e);d.src= 238 "https://consent.cookiebot.com/uc.js?cbid="+o;d.async=!0;a.parentNode.insertBefore( 239 d, a)})(document,location.hostname,location.pathname,"script","Cookiebot","@cookieDeclarationKey", "en") 240 </script> 241 } 242 243 <style type="text/css"> 244 a#CybotCookiebotDialogPoweredbyCybot, 245 div#CybotCookiebotDialogPoweredByText { 246 display: none; 247 } 248 249 #CookiebotWidget .CookiebotWidget-body .CookiebotWidget-main-logo { 250 display: none; 251 } 252 </style> 253 254 <script src="~/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks" defer></script> 255 <script src="~/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks" defer></script> 256 257 258 @* Global site tag (gtag.js) - Google Analytics *@ 259 @if (!string.IsNullOrWhiteSpace(googleAnalyticsTrackingID) && allowCookies) 260 { 261 <script src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsTrackingID" async></script> 262 <script>@googleAnalyticsTrackingID</script> 263 } 264 265 @* Etracker *@ 266 @if (!string.IsNullOrWhiteSpace(etrackerDataSecureCode)) 267 { 268 <!-- .SE --> 269 <!-- Copyright (c) 2000-2022 etracker GmbH. All rights reserved. --> 270 <!-- This material may not be reproduced, displayed, modified or distributed --> 271 <!-- without the express prior written permission of the copyright holder. --> 272 <!-- etracker tracklet 5.0 --> 273 <script type="text/javascript"> 274 // var et_pagename = ""; 275 // var et_areas = ""; 276 // var et_tval = 0; 277 // var et_tsale = 0; 278 // var et_tonr = ""; 279 // var et_basket = ""; 280 </script> 281 <script id="_etLoader" type="text/javascript" charset="UTF-8" data-block-cookies="true" data-respect-dnt="true" data-secure-code="@etrackerDataSecureCode" src="//code.etracker.com/code/e.js" async></script> 282 <!-- etracker tracklet 5.0 end --> 283 } 284 285 @if (!string.IsNullOrWhiteSpace(customHeaderInclude)) 286 { 287 @RenderPartial($"Components/Custom/{customHeaderInclude}") 288 } 289 290 @{ 291 // Set a body class based on Page.NavigationTag for targeted UX customizations 292 string bodyClass = Pageview.Page.NavigationTag; 293 if (!Dynamicweb.Context.Current.Items.Contains("ProductList")) 294 { 295 bodyClass = bodyClass + "Page"; 296 } 297 } 298 299 </head> 300 <body class="brand @(masterTheme) @bodyClass" id="page@(Model.ID)" onload="@scrollInitScript"> 301 @if (showGtm) 302 { 303 <!-- Google Tag Manager (noscript) --> 304 <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TMPJLQW9" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> 305 <!-- End Google Tag Manager (noscript) --> 306 } 307 @if (renderAsResponsive || !renderMobile) 308 { 309 <header class="page-header @headerCssClass top-0@(responsiveHeaderClassDesktop)" id="page-header-desktop"> 310 @if (@Model.Area.Item.GetLink("HeaderDesktop") != null) 311 { 312 @RenderGrid(@Model.Area.Item.GetLink("HeaderDesktop").PageId) 313 } 314 </header> 315 } 316 317 @if ((renderAsResponsive || renderMobile)) 318 { 319 <header class="page-header @headerCssClass top-0@(responsiveHeaderClassMobile)" id="page-header-mobile"> 320 @if (@Model.Area.Item.GetLink("HeaderMobile") != null) 321 { 322 @RenderGrid(@Model.Area.Item.GetLink("HeaderMobile").PageId) 323 } 324 </header> 325 } 326 327 <main id="content" @productDetailPageSchemaOrg> 328 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 329 @using Dynamicweb.Ecommerce.ProductCatalog 330 @using System 331 @using Dynamicweb.Extensibility; 332 @using Dynamicweb.Indexing.Querying; 333 @using CustomUtilities 334 335 336 337 @{ 338 string theme = ""; 339 string gridContent = ""; 340 341 if (Model.PropertyItem != null) 342 { 343 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? " theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 344 } 345 346 if (Model.Item != null) 347 { 348 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page"); 349 } 350 351 bool doNotRenderPage = false; 352 353 //Check if we are on the poduct detail page, and if there is data to render 354 ProductViewModel product = new ProductViewModel(); 355 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 356 { 357 358 359 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 360 if (string.IsNullOrEmpty(product.Id)) 361 { 362 doNotRenderPage = true; 363 } 364 365 var currentProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, null, product.LanguageId); 366 int pageLoadPeriod = Pageview.AreaSettings.GetInt32("PageLoadPeriod"); 367 368 if (pageLoadPeriod == 0 && Model.Area.Item != null) 369 { 370 var websiteSettings = Dynamicweb.Services.Items.GetItem(Model.Area.ItemType, Model.Area.ItemId); 371 websiteSettings["PageLoadPeriod"] = 30; 372 Dynamicweb.Services.Items.SaveItem(websiteSettings); 373 374 pageLoadPeriod = 30; 375 } 376 377 378 // Custom 404 logic for product catalog based pages 379 // because there is not separate product cataloges per site and all information is tagged as Danish 380 if (!currentProduct.Active && !Pageview.IsVisualEditorMode) 381 { 382 HttpContext.Current.Response.Redirect("/404/", true); 383 } 384 385 // The "All" index has information about which site each product catalog based pages belongs to in the field "WebsiteID" 386 // The query matches WebsiteID = Pageview.Context.WebsiteID and returns only records relevant for current síte 387 var queryService = ServiceLocator.Current.GetInstance<IQueryService>(); 388 var query = queryService.LoadQuery("All", "QueryAll"); 389 390 if (query == null) 391 { 392 throw new MissingMethodException("Specified query not found."); 393 } 394 395 IDictionary<string, object> parameters = new Dictionary<string, object>(); 396 parameters.Add("docID", product.Id); 397 var settings = new QuerySettings 398 { 399 Skip = 0, 400 Take = 10, 401 Parameters = parameters 402 }; 403 404 var result = queryService.Query(query, settings); 405 406 var autoIds = new List<long>(); 407 foreach (Dictionary<string, object> document in result.QueryResult) 408 { 409 if (document.ContainsKey("AutoID")) 410 { 411 var productAutoId = Convert.ToInt64(document["AutoID"]); 412 autoIds.Add(productAutoId); 413 } 414 } 415 var products = Dynamicweb.Ecommerce.Services.Products.GetByAutoIDs(autoIds); 416 417 // 404 redirect the product page if it did not belong to the current website accoring to the All index 418 if (products.Count() == 0 && !Pageview.IsVisualEditorMode) 419 { 420 HttpContext.Current.Response.Redirect("/404/", true); 421 } 422 423 424 Helpers helper = new Helpers(); 425 426 helper.CleanPageLoadsJsonData(currentProduct, pageLoadPeriod); 427 helper.UpdatePageLoadsJsonData(currentProduct); 428 } 429 430 //Render the page 431 if (!doNotRenderPage) 432 { 433 if (theme != "") 434 { 435 <div class="@theme"> 436 @gridContent 437 </div> 438 } 439 else 440 { 441 @gridContent 442 } 443 } 444 else 445 { 446 <div class="container"> 447 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div> 448 </div> 449 } 450 451 if (!Model.IsCurrentUserAllowed) 452 { 453 int signInPage = GetPageIdByNavigationTag("SignInPage"); 454 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage"); 455 456 if (!Pageview.IsVisualEditorMode) 457 { 458 if (signInPage != 0) 459 { 460 if (signInPage != Model.ID) 461 { 462 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage); 463 } 464 else 465 { 466 if (dashboardPage != 0) 467 { 468 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage); 469 } 470 else 471 { 472 Dynamicweb.Context.Current.Response.Redirect("/"); 473 } 474 } 475 } 476 else 477 { 478 <div class="alert alert-dark m-0" role="alert"> 479 <span>@Translate("You do not have access to this page")</span> 480 </div> 481 } 482 } 483 else 484 { 485 <div class="alert alert-dark m-0" role="alert"> 486 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span> 487 </div> 488 } 489 } 490 } 491 492 </main> 493 494 @if (renderAsResponsive || !renderMobile) 495 { 496 <footer class="page-footer d-none d-lg-block" id="page-footer-desktop"> 497 @if (@Model.Area.Item.GetLink("FooterDesktop") != null) 498 { 499 @RenderGrid(@Model.Area.Item.GetLink("FooterDesktop").PageId) 500 } 501 </footer> 502 } 503 504 @if (renderAsResponsive || renderMobile) 505 { 506 <footer class="page-footer d-block d-lg-none" id="page-footer-mobile"> 507 @if (@Model.Area.Item.GetLink("FooterMobile") != null) 508 { 509 @RenderGrid(@Model.Area.Item.GetLink("FooterMobile").PageId) 510 } 511 </footer> 512 } 513 514 @* Render any offcanvas menu here *@ 515 @RenderSnippet("offcanvas") 516 517 @* Language selector modal *@ 518 @if (languages.Count > 1 || ecomCountries.Count > 1 || ecomCurrencies.Count() > 1) 519 { 520 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true"> 521 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent"> 522 @* The content here comes from an external request *@ 523 </div> 524 </div> 525 } 526 527 @* Favorite toast *@ 528 <div aria-live="polite" aria-atomic="true"> 529 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11"> 530 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true"> 531 <div class="toast-header"> 532 <strong class="me-auto">@Translate("Favorite list updated")</strong> 533 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 534 </div> 535 <div class="toast-body d-flex gap-3"> 536 <div id="favoriteNotificationToast_Image"></div> 537 <div id="favoriteNotificationToast_Text"></div> 538 </div> 539 </div> 540 </div> 541 </div> 542 543 @* Offcanvas for dynamic content *@ 544 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas" style="width: 30rem"> 545 @* The content here comes from an external request *@ 546 </div> 547 548 <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script> 549 550 <script type="text/javascript"> 551 552 window.addEventListener('CookiebotOnDecline', function (e) { 553 if (Cookiebot.declined) 554 { 555 setOptInCookie(0); 556 } 557 }, false); 558 559 window.addEventListener('CookiebotOnAccept', function (e) { 560 if (Cookiebot.consented) 561 { 562 setOptInCookie(2); 563 } 564 }, false); 565 566 async function setOptInCookie(optInLevel) { 567 let response = await fetch("/admin/public/CookieOptInLevelConfig.aspx?cmd=SetCookieOptInLevel&OptInLevel=" + optInLevel); 568 } 569 570 </script> 571 572 </body> 573 </html> 574 575 @functions { 576 577 void SetMetaTags() 578 { 579 //Verification Tokens 580 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : ""; 581 //string siteVerificationYandex = Model.Area.Item.GetString("Yandex_Verification") != null ? Model.Area.Item.GetString("Yandex_Verification") : ""; 582 //string siteVerificationMS = Model.Area.Item.GetString("Msvalidate_01") != null ? Model.Area.Item.GetString("Msvalidate_01") : ""; 583 //string siteVerificationAlexa = Model.Area.Item.GetString("AlexaVerifyID") != null ? Model.Area.Item.GetString("AlexaVerifyID") : ""; 584 //string siteVerificationPinterest = Model.Area.Item.GetString("P_domain_verify") != null ? Model.Area.Item.GetString("P_domain_verify") : ""; 585 //string siteVerificationNorton = Model.Area.Item.GetString("Norton_safeweb_site_verification") != null ? Model.Area.Item.GetString("Norton_safeweb_site_verification") : ""; 586 587 //Generic Site Values 588 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : ""; 589 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : ""; 590 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : ""; 591 592 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : ""; 593 594 //Page specific values 595 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : ""; 596 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image"); 597 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : ""; 598 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : ""; 599 600 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : ""; 601 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : ""; 602 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : ""; 603 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image"); 604 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : ""; 605 606 if (!string.IsNullOrEmpty(siteVerificationGoogle)) 607 { 608 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle); 609 } 610 611 if (!string.IsNullOrEmpty(openGraphFacebookAppID)) 612 { 613 Pageview.Meta.AddTag("fb:app_id", openGraphFacebookAppID); 614 } 615 616 if (!string.IsNullOrEmpty(openGraphType)) 617 { 618 Pageview.Meta.AddTag("og:type", openGraphType); 619 } 620 621 if (!string.IsNullOrEmpty(openGraphSiteName)) 622 { 623 Pageview.Meta.AddTag("og:site_name", openGraphSiteName); 624 } 625 626 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"]) && !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 627 { 628 if (!string.IsNullOrEmpty(Model.Title)) 629 { 630 Pageview.Meta.AddTag("og:title", Model.Title); 631 } 632 else 633 { 634 Pageview.Meta.AddTag("og:title", openGraphSiteTitle); 635 } 636 if (!string.IsNullOrEmpty(Model.Description)) 637 { 638 Pageview.Meta.AddTag("og:description", Model.Description); 639 } 640 else 641 { 642 Pageview.Meta.AddTag("og:description", openGraphDescription); 643 } 644 } 645 646 if (openGraphImage != null) 647 { 648 Pageview.Meta.AddTag("og:image", openGraphImage.Path); 649 } 650 651 if (!string.IsNullOrEmpty(openGraphImageALT)) 652 { 653 Pageview.Meta.AddTag("og:image:alt", openGraphImageALT); 654 } 655 656 if (!string.IsNullOrEmpty(twitterCardSite)) 657 { 658 Pageview.Meta.AddTag("twitter:site", twitterCardSite); 659 } 660 661 if (!string.IsNullOrEmpty(twitterCardURL)) 662 { 663 Pageview.Meta.AddTag("twitter:url", twitterCardURL); 664 } 665 666 if (!string.IsNullOrEmpty(twitterCardTitle)) 667 { 668 Pageview.Meta.AddTag("twitter:title", twitterCardTitle); 669 } 670 671 if (!string.IsNullOrEmpty(twitterCardDescription)) 672 { 673 Pageview.Meta.AddTag("twitter:description", twitterCardDescription); 674 } 675 676 if (twitterCardImage != null) 677 { 678 Pageview.Meta.AddTag("twitter:image", twitterCardImage.Path); 679 } 680 681 if (!string.IsNullOrEmpty(twitterCardImageALT)) 682 { 683 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT); 684 } 685 } 686 } 687