We are using Tridion Sites 9 and DXA 2.2.6. We are implementing Content Security Policy (CSP) and therefore we need a dynamically created CSP response header with nonce tokens and on the webpages we need to set the same nonce tokens that need to change for each page request. The solution that we have build for that is that in the page view we call a helper function that creates the csp header and add a nonce token to the page.
Problem is that, since we have output caching switched on, the page is working fine only the first time it is loaded but each next time, the page is taken from the cache and then it has no longer a csp header in the response header and the nonce tokens on the page are the same as before. The only solution for this, that we found so far, is switching off the output caching but that has a performance penalty (load time of the page is approximately twice as long compared to when output caching is switched on).
We are looking for a solution that we can still use output caching and only can exclude caching for the parts that create the csp response header and the nonce tokens on the page.
I have already tried to find a solution for that. Since the csp response header and the nonce tokens are set in the page view (_Layout.cshtml), I looked in the PageController and there I saw that ActionResult Page is having the [DxaOutputCache] attribute being set. Therefore I created a custom page controller with an override of the ActionResult Page for which the [DxaNoOutputCache] is set. I was hoping that that would exclude the page view (_Layout.cshtml) from being cached. However, that did not work. After the initial load of the page, all subsequent page requests take the page from the cache.
So bottomline question is whether there is a possibility for using output caching and only exclude the parts that are needed to create dynamic output from that caching?
February 10, 2022, additional information and request for better solution
Thank you, Neil, for your replies. Although Donut-caching seemed promising, we decided not to implement that for the following reasons.
- It is old software for which no updates are published since many years.
- There is no organization that can offer support for this. Therefore, the company I work for, does not allow us to include this Donut caching in our solution.
In the meantime, I searched for other solutions. These are the possible solutions that we found
1. Switching off the output cache through the setting in the web.config. This works fine but, like said before, it has a performance penalty
2. Override of the deepcopy In this article, I read about the possibility to create dynamic view models by using an override of the deepcopy method. Also an example on Github is given for this override. https://docs.rws.com/784837/730948/sdl-digital-experience-accelerator-2-2/making-caching-work-with-dynamically-modified-view-models---net-
Unfortunately, this is only possible for entity view models and not for page view models and our code for creating a nonce token is set in a page view model. So we tried to create an entity view model by adding an embedded schema in de CMS and to create the related entity view model, called “Nonce” in the .Net solution. The logic of the nonce token creation was moved to function “Token” of this new entity. Next, in the page view model we made a reference to this new “Nonce” entity view model. However, that did not work. When running the code, it appeared that when calling Model.Nonce.Token in the page view (_Layout) the reference of the page view model to the entity view model “Nonce” was “null” all the time. So the logic for nonce token creation could not be reached.
3. Changing PageModel en RenderedOutput cache names to “noCache” In the web.config there are settings in which you can assign cache names to cache parts. We changed the cache names of “PageModel” and “RenderedOutput” to “noCache”. This worked but the performance penalty was worse than solution 1. Therefore, we do not use this solution 3.
4. Switching off the viewModel-caching In the web.config there is a setting for switching off the viewModel caching. In the comment for that setting, it is mentioned that switching of this caching might be needed for dynamically populated entity models. Unfortunately, this did not work in our case since each 2nd and next time the same page was requested, the CSP header is missing in the response and the nonce tokens are the same as for the first request.
The main questions that remains is whether someone knows a better solution that will solve the issue that only the part, that creates the nonce token, should not be cached. The settings in the web.config for switching on/off certain parts of the caching, are too general. For example, the solution for switching off the output cache, which I mention at point 1, switches off all the output caching. So, what I am looking for is a solution that will only exclude the part of the nonce token generation from being cached. All other things should still be cached. Any suggestions are welcome.