I have an ActionResult which is cached.
[OutputCache(Duration = 3600, VaryByParam = "product_Id")]
public ActionResult ProductPreview(Guid product_Id)
{
// just for testing the cache
System.Threading.Thread.Sleep(4000);
return PartialView("ProductPreview", _repository.CreateProductModel(product_Id));
}
The good part is that the cache is working. After the first load, the result is shown without any 4seconds delay.
However, i need to clear the cache when some changes has been made to that product.
I tried to clear cache doing like this:
public ActionResult RemoveCache()
{
var url = Url.Action("ProductPreview", "Common");
// also tried with parameter
// var url = Url.Action("ProductPreview", "Common", new { @product_Id = "productId" });
HttpResponse.RemoveOutputCacheItem(url);
return RedirectToAction("Index");
}
I also tried to call RemoveCache method with both ajax and full page refresh, and non of them is working.
What can i do? Where is the problem?
The RemoveOutputCacheItem
works only with route parameters, not query string. So you could modify your route definition:
routes.MapRoute(
"Default",
"{controller}/{action}/{product_Id}",
new { controller = "Home", action = "Index" }
);
Now you can use the RemoveOutputCacheItem method:
public ActionResult RemoveCache(Guid product_Id)
{
var url = Url.Action("ProductPreview", "Common", new { product_Id = product_Id });
// the url must look like this: /Common/ProductPreview/eeb2fe32-db58-4fc3-87c8-b47480fbe094
// for the RemoveOutputCacheItem method to work
HttpResponse.RemoveOutputCacheItem(url);
return RedirectToAction("Index");
}
UPDATE:
Here's my test case:
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[OutputCache(Duration = 3600, VaryByParam = "product_id")]
public ActionResult ProductPreview(Guid product_id)
{
var model = string.Format(
"{0} - {1}",
product_id,
DateTime.Now.ToLongTimeString()
)
return PartialView("_Foo", model);
}
public ActionResult RemoveCache(Guid product_id)
{
var url = Url.Action(
"ProductPreview",
"Home",
new { product_id = product_id }
);
HttpResponse.RemoveOutputCacheItem(url);
return RedirectToAction("Index");
}
}
View (~/Views/Home/Index.cshtml
):
@{
var productId = Guid.NewGuid();
}
@Html.ActionLink("product 1", "ProductPreview", new { product_id = Guid.NewGuid() })
<br/>
@Html.ActionLink("product 2", "ProductPreview", new { product_id = productId })
<br/>
@Html.ActionLink("product 3", "ProductPreview", new { product_id = Guid.NewGuid() })
<br />
@Html.ActionLink(
"clear cache for the second product",
"RemoveCache",
new { product_id = productId }
)
Partial view (~/Views/Home/_Foo.cshtml
):
@model string
@Model
and in global.asax
:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{product_id}",
new { controller = "Home", action = "Index", product_id = UrlParameter.Optional }
);
}
UPDATE 2:
Now that you have shown your code it seems that you are using the Html.RenderAction
helper and the ProductPreview
is a child action. Child actions are not stored in the same cache as normal views and the HttpResponse.RemoveOutputCacheItem
helper doesn't work at all with cached child actions. If you look carefully in my previous example you will see that I used standard links for the ProductPreview
action.
Currently what you are trying to achieve is not possible in ASP.NET MVC 3. If you want to use donut output caching I would recommend you the following article. Hopefully this functionality will be added in ASP.NET MVC 4.