Search code examples
c#angularjsasp.net-mvchttp-headersiis-8

Seeking source of Http Response Headers in MVC application


I've inherited a .NET C# MVC application. I noticed that different pages interact differently with the server when the user uses the Back and Forward buttons built into the browser. Some pages would hit the server and some would not. I used Postman to hit the various URLs and found that different pages are returning different response headers.

  1. Cache-Control: private
  2. Cache-Control: public, no-store, max-age=0

Pages in the first set are cached in the browser's "private" cache. There is no hit against the server when this page is loaded in the browser via the Back or Forward button.

The second control string is somewhat of a conflict, however the most restrictive directive of no-store overrides. These pages hit the server every time the page is loaded.

I've searched the codebase. I've located related meta tags in various page template markup files but I'm looking specifically for the headers. Moreover, the meta tags are all the same, so that could not account for the different headers in different pages.

IIS is not configured to add this header. Moreover, when I run this application in debug, out of Visual Studio / IIS Express, I see these headers sent back with the response. Different headers for different pages.

I can't find any explicit code which is emitting these headers on the server (I searched for Response.AddHeader and didn't find anything) so I'm thinking that there might be different configurations of the different MVC Templates which is implicitly generating these headers? Does that make sense? (I don't have a lot of experience with MVC.) I'll keep looking, but if you have knowledge of MVC which could point me in the right direction, I'd really appreciate that.

I continued looking into this. As Alexei Levenkov pointed out, Angular is executing client side. Not the right place to be looking.

Here's an image of a Debug session processing the page request. At this point there are exactly two headers in the Response.Headers collection.

enter image description here

After this statement executes, the response received by the browser contains many more headers. The View() method is not my code so I have no ability to trace into it. Clearly though, the View() method reacts to some declarative configuration somewhere which results in different response headers for different templates. As I mentioned before, I'm no Angular.js expert and I'm not much better with MVC. I'm probably missing something very basic.

Within this transaction there is nothing which executes after the return View() statement. Step over that statement, step off the closing method brace and the content returns to the client.

Postman shows 11 response headers, including the one in particular which interests me.

enter image description here

Now here I am stepping into a different request which returns a different Cache-Control header. Again, we see the same two headers in the Response.Headers collection.

enter image description here

Yet, the View method returns 13 response headers and a different Cache-Control header:

enter image description here

Here's a clue: The different pages which return different headers are grouped into different controllers. One controller returns Cache-Control: private, while the other controller returns Cache-Control: public, no-store, max-age=0.

I suppose, ultimately, the question boils down to the following: How are controllers defined in MVC to return specific headers on the response? (Like I said, I'm not an MVC expert so this might be a very long-winded presentation to get to a very basic question. Thanks for your help!)


Solution

  • I believe this is the answer. It's a meta-tag on the Controller. (As a declarative, this would not be seen when stepping through the code. An examination of the source is necessary and of course, it helps to know what you are looking for. Now I know!)

    namespace rater8.RMM.Web.Controllers
    {
        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public class RMMController : Controller
        {
          ...
        }
      ...
    }
    

    The other controller did not have any such meta-tag. It appears that not specifying this meta-tag results in Cache-Control: private, which allows browsers to preserve the page in the local cache for Back and Froward navigation without hitting the server.

    Specifying the meta-tag as shown in the code example above results in Cache-Control: public, no-store, max-age=0 (That's a strange cache-control value where public is in conflict with no-store but the latter wins out as it is the more restrictive attribute.)