public ActionResult Feed() {
XDocument document = null;
if (Cache["feed"] == null) {
document = new XDocument(...);
// Fill the document here...
Cache["feed"] = document;
} else {
document = Cache["feed"] as XDocument;
}
return Content(document.ToString(),
"application/rss+xml");
}
The above is a stripped down example and is prone to errors in that if many users hit the method at the same time, there is no inherent locking, also the cache feed value could be ejected before it is read the second time. But we aren't here to work on that.
The issue here is the line:
return Content(document.ToString(),
"application/rss+xml");
Because we were caching the XDocument and for each request calling ToString() this would lead to some untimely deadlocks on the liver servers where requests would run for hours never ending. The only solution was to kill the process and start the web site again.
After a little digging it was clear that the ToString() call being an instance method was to blame. I trudged through the source code for it and found it using several internals to iterate over the nodes to produce the string result. There is also a hint in the documentation for XDocument http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument%28v=vs.110%29.aspx which states:
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.So the solution was to simply cache the resulting ToString() rather than the XDocument, this way there is no further processing required every time a user requests this method.
public ActionResult Feed() {
string xml = null;
if (Cache["feed"] == null) {
XDocument document = new XDocument(...);
// Fill the document here...
Cache["feed"] = document.ToString();
} else {
xml = (string) Cache["feed"];
}
return Content(xml,
"application/rss+xml");
}