ASP.NET MVC Disable view caching in overridden VirtualPathProvider - asp.net-mvc

I am doing some dev work using portable areas so I have an overridden VirtualPathProvider.
My public override bool FileExists(string virtualPath) seems to get called only every few minutes, meaning that MVC is caching the views.
This is probably great in production but I can't figure out how to turn it off in dev. I want the VirtualPathProvider to get called on each and every use of the view.
Any suggestions?

Answering my own question for the sake of future generations....
We ended up overriding the GetCacheDependency call to ensure that the view is never cached. (We cache views manually). We had to create a FakeCacheDependency that lets us use the last modified date from our cache.
In our application, our virtual views are called CondorVirtualFiles. (When building a views engine, you need to give it a cool name.)
public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
{
var view = this.GetFile(virtualPath);
if (view is CondorVirtualFile)
{
FakeCacheDependency fcd = new FakeCacheDependency((view as CondorVirtualFile).LastModified);
return fcd;
}
return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
public class FakeCacheDependency : System.Web.Caching.CacheDependency
{
public FakeCacheDependency(DateTime lastModified)
{
base.SetUtcLastModified(lastModified);
}
public FakeCacheDependency()
{
base.SetUtcLastModified(DateTime.UtcNow);
}
}

Related

ASP.NET MVC ViewHelpers and Dependency Injection

I'd like to create a ViewHelper to localize my ASP.NET MVC application. Something like this:
public class Translator
{
private readonly ITranslationRepository _repo;
public Translator(ITranslationRepository repo)
{
_repo = repo;
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}
Usage in a (Razor) View looks like this:
<p>#Translator.Translate(TranslationEnum.WelcomeMessage)</p>
Now the problem is of course, I cannot make the Translate method static, because I need to access the instance variable _repo.
How can I inject the repository into a ViewHelper so I can use it in a View like above?
The responsibility of the view is just to transform the data that comes back from the controller to a HTML structure. Views are hard (to impossible) to test automatically, so best is to keep them as dumb as possible.
Instead of using the Translator in your view, inject it into your controller and let the controller call the Translator. This solves a range of problems:
It keeps the view simple.
It improves maintainability.
It improves testability.
It improves the verifiability of your object graphs (because you don't fall back on static method calls or the Service Locator anti-pattern).
Long story short, add a property to the controller's view model and return that to the view. Example:
public class HomeController : Controller {
private readonly ITranslator translator;
public HomeController(ITranslator translator) {
this.translator = translator
}
public ActionResult Index() {
this.View(new HomeViewModel {
WelcomeMessage = this.translator.Translate(TranslationEnum.WelcomeMessage)
});
}
}
And your view can look as follows:
#model HomeViewModel
<p>#Model.WelcomeMessage</p>
first of all, the intention of your design is wrong because it violates the single responsibility principal. Why is a translator dependent on repository?
secondly, why do you need a translator, you can use asp.net globalization?
click me We should not reinvent the wheel.
thirdly, all the html helpers are extension methods which have to be static.
so my suggestion is if you have to use translator, please refactor the Translator class, decouple the repository from it then create a extension methods from there.
or you can use globalization, it sounds horrible to start with but trust me it's not as hard as it looks.
public class Translator
{
private static ITranslationRepository _repo;
public static ITranslationRepository Repo
{
get { /*check null here before return*/ return _repo; } set { _repo = Repo; }
}
public Translator()
{
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}

CacheDependency and the VirtualPathProvider for paths wirh dependencies

We are using the BundleTransformer library in an ASP.NET MVC 4 setup. Our web application is a rather thin layer, with all server logic handled in a backend service.
After an installation all resource will be installed along side the web application on the file system, but for update reasons we need to be able to serve resources like JavaScript and CSS (LESS) from the service - they will then override the local (file system) versions.
In essence, if available from the service, we serve a requested resource from there. If not, we fall-back to the file system and serve the file from there.
It was all working like a charm, then we introduced LESS and #import statements, now things are not working so fine anymore.
We still want to cache the result of the LESS transformation in the Http Cache, and we would like to invalidate that result whenever a dependency changes. The current implementation in the VirtualPathProvider does that, but if I update a single file (a JavaScript file for instance), it will not be updated.
My VirtualPathProvider looks like this:
public class ViewsAndScriptsPathProvider : VirtualPathProvider {
private static IApplicationServiceResourcesManager ResourceManager {
get { return InstanceProvider.Get<IApplicationServiceResourcesManager>(); }
}
public override bool FileExists(string virtualPath) {
var exists = ResourceManager.Exists(virtualPath);
return exists || base.FileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath) {
VirtualFile file;
if (ResourceManager.TryGet(virtualPath, out file)) {
return file;
}
return base.GetFile(virtualPath);
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) {
bool isRelevant = ResourceManager.IsRelevant(virtualPath);
if (isRelevant) {
var cachekeys = virtualPathDependencies.Cast<string>().Where(dependency => virtualPath != dependency).ToArray();
return new CacheDependency(null, cachekeys);
}
if (IsBundle(virtualPath)) {
return new CacheDependency(null, new[] { ResourceManager.ComponentCacheKey }, utcStart);
}
return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
private bool IsBundle(string virtualPath) {
return virtualPath.StartsWith("~/bundles/", StringComparison.InvariantCultureIgnoreCase)
|| virtualPath.StartsWith("~/css/", StringComparison.InvariantCultureIgnoreCase);
}
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) {
byte[] bhash;
string filehash;
if (ResourceManager.TryGetFileHash(virtualPath, out bhash)) {
filehash = BitConverter.ToString(bhash);
} else {
filehash = Previous.GetFileHash(virtualPath, virtualPathDependencies);
}
return filehash;
}
}
Think of the ResourceManager as a proxy / cache towards the service.
My big issue is that I don't understand exactly the CacheDependency work. If I add a cachekey (the second parameter) that includes the virtualPath itself, then I get an infinite loop in the server.
If I simply return null it won't work for LESS #imports.
If anybody could explain or point to how the VirtualPathProvider is supposed to implement the GetCacheDependency and the GetFileHash functions, I might be able to solve this one.
I actually worked out a solution some time ago, and it has to do with how the HttpCache works with the CacheDependency object. It is rather complex however.
Basically I have three scenarios:
The resource is hosted only on the file system.
The resource is hosted only at the service.
The resource is hosted at both the service and the local file system.
For 1. I use the CacheDependency object for the file location. This is standard and how the VirtualPathProvider works by default.
For 2. I use a custom (derived) ResourceCacheDependency which implement logic to invalidate itself when the proxy has a new version.
For 3. I use the AggregateCacheDependency object that has both a CacheDependency to the physical file and a ResourceCacheDependency object.
For all virtual path dependencies (the list of dependencies for the resource) I repeat the above assumptions, and build it into the AggreateCacheDependency (it will potentially have a lot of dependencies).
In my custom implementation of the VirtualPathProvider I override the GetCacheDependency method to return the relevant CacheDependency object based on the above analysis.

Property Injection and/or Adding a Controller to an Alternate MenuItem View

I'm trying (and failing) to get property injection working in Orchard CMS.
This is necessary, because the below code is acting something like a code-behind for a view (horrible I know). The reason being that the view doesn't have a controller that I can use constructor injection on, because this is an alternate view for a MenuItem, i.e. MenuItemLink-MyCustomMenuItem.cshtml.
Not much more to say than that, except what's in the comments (note the NULL comment for the property that I am trying to set in the code below).
Oh, I've also tried adapting the property injection code from Orchard's LoggingModule, but equally that doesn't work for me either.
How do I :
a. get the below property injection to work? (I'm pretty sure I will need it at some point regardless)
b. (if possible) get my own controller/driver in the way of the view so I can use constructor injection on the controller instead?
using System.Diagnostics;
using System.Xml.Linq;
using Autofac;
using Autofac.Core;
using Orchard;
using Module = Autofac.Module;
namespace MyCo.MyCustomMenuItem.Services
{
public class MyCustomMenuItemModule : Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
if (implementationType.ToString() ==
"MyCo.MyCustomMenuItem.Services.MyCustomMenuItem")
{
// this does get called, but doesn't have the desired effect
registration.Activated += (s, e) =>
e.Context.InjectUnsetProperties(e);
}
}
}
public interface IFeedX : IDependency
{
XDocument GetResource();
}
public class FeedX : IFeedX
{
public XDocument GetResource()
{
return new XDocument();
}
}
public interface IMyCustomMenuItem : IDependency
{
XDocument GetResourceData();
IFeedX FeedX { get; set; }
}
public class MyCustomMenuItem : IMyCustomMenuItem
{
public IFeedX FeedX { get; set; }
// called direct by razor view
public XDocument GetResourceData()
{
Debug.WriteLine(FeedX); // NULL??
return FeedX.GetResource();
}
}
}
You definitely should not do anything of the sort in the view. I think this article describes a scenario that is close to what you're trying to achieve: http://www.davidhayden.me/blog/dynamically-injecting-menu-items-in-orchard-cms

Persist data between different controllers from a base page

I am not sure I am asking the right question here.
I have a shared page (master page) that calls a couple of partial pages for side menu, header, footer etc.. and all my controllers inherit a BaseController.
Now, depending on the user login status, I need to show different data in all those partial pages and I thought where is the best place to check whether a user is logged in or not - BaseController.
And therein lies my problem. I need to contact one of my web services to see if a user is logged in and get some relevant data if he is. I only need to do this once, and since all controllers inherit from BaseController, each of those partial page calls results in the web service call.
Obviously, I cannot just stick a private bool variable isUserAuthenticated and check for flag, as, each controller will have a new instance of the base controller.
In traditional asp.net projects, I would put this stuff in HttpContext.Current.Items[] and use re-use it but I cannot (somehow) access that in MVC.
I cannot just not inherit from basepage on partial pages as they can also be called independently and I need to know the user login status then too.
What is the best way to call a function just once, or, rather, store a bool value for the duration of one call only? - accessible between controlers..
How do people do this?
thanks, sorry, I'm a newbie to mvc!
You can still use HttpContext.Items, but you'll need to access it via a HttpContextBase instance.
For backwards compatibility you can wrap an HttpContext in an HttpContextWrapper, like so
var context = new HttpContextWrapper(HttpContext.Current);
#iamserious's answer above suggests using a static property - which I strongly disagree with. Setting a static variable is application wide and would mean each and every user would be using the same variable - so all would have the same login data. You want to store it either per user in Session or per Request via HttpContext.Items.
I'd suggest doing something using like this approach, then no matter where you call ContextStash.GetInstance, you'll receive the same instance for the lifetime of the same request. You could also follow the same pattern and use HttpContext.Session instead of HttpContext.Items:
// could use this.HttpContext inside a controller,
// or this.Context inside a view,
// or simply HttpContext.Current
var stash = ContextStash.GetInstance(this.HttpContext);
if(!stash.IsSomething)
{
// do something to populate stash.IsSomething
}
// class
public class ContextStash
{
const string cacheKey = "ContextStash";
public ContextStash(HttpContextBase context)
{
// do something with context
}
// your shared properties
public bool IsSomething { get; set; }
public string Foo { get; set; }
public int Bar { get; set; }
// instance methods
public static ContextStash GetInstance()
{
return GetInstance(new HttpContextWrapper(HttpContext.Current));
}
public static ContextStash GetInstance(HttpContext context)
{
return GetInstance(new HttpContextWrapper( context ));
}
public static ContextStash GetInstance(HttpContextBase context)
{
ContextStash instance = context.Items[cacheKey] as ContextStash;
if(null == instance)
{
context.Items[cacheKey] = instance = new ContextStash(context);
}
return instance;
}
}
well, if you just want to one variable across several instances of BaseController, use the static keyword, like so:
public class BaseController : Controller
{
private static bool isUserAuthenticated;
}
Now, no matter how many instances of BaseController you have, they all will share a single isUserAuthenticated variable, you change value in one, you change it in all.
This is the very basic of most object oriented programming and you should really take some time out to go through the concepts of OOP, if you don't mind me saying.

One Controller is Sometimes Bound Twice with Ninject

I have the following NinjectModule, where we bind our repositories and business objects:
/// <summary>
/// Used by Ninject to bind interface contracts to concrete types.
/// </summary>
public class ServiceModule : NinjectModule
{
/// <summary>
/// Loads this instance.
/// </summary>
public override void Load()
{
//bindings here.
//Bind<IMyInterface>().To<MyImplementation>();
Bind<IUserRepository>().To<SqlUserRepository>();
Bind<IHomeRepository>().To<SqlHomeRepository>();
Bind<IPhotoRepository>().To<SqlPhotoRepository>();
//and so on
//business objects
Bind<IUser>().To<Data.User>();
Bind<IHome>().To<Data.Home>();
Bind<IPhoto>().To<Data.Photo>();
//and so on
}
}
And here are the relevant overrides from our Global.asax, where we inherit from NinjectHttpApplication in order to integrate it with Asp.Net Mvc (The module lies in a separate dll called Thing.Web.Configuration):
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
//routes and areas
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
//Initializes a singleton that must reference this HttpApplication class,
//in order to provide the Ninject Kernel to the rest of Thing.Web. This
//is necessary because there are a few instances (currently Membership)
//that require manual dependency injection.
NinjectKernel.Instance = new NinjectKernel(this);
//view model factory.
NinjectKernel.Instance.Kernel.Bind<IModelFactory>().To<MasterModelFactory>();
}
protected override NinjectControllerFactory CreateControllerFactory()
{
return base.CreateControllerFactory();
}
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load("Thing.Web.Configuration.dll");
return kernel;
}
Now, everything works great, with one exception: For some reason, sometimes Ninject will bind the PhotoController twice. This leads to an ActivationException, because Ninject can't discern which PhotoController I want. This causes all requests for thumbnails and other user images on the site to fail.
Here is the PhotoController in it's entirety:
public class PhotoController : Controller
{
public PhotoController()
{
}
public ActionResult Index(string id)
{
var dir = Server.MapPath("~/" + ConfigurationManager.AppSettings["UserPhotos"]);
var path = Path.Combine(dir, id);
return base.File(path, "image/jpeg");
}
}
Every controller works in exactly the same way, but for some reason the PhotoController gets double-bound. Even then, it only happens occasionally (either when re-building the solution, or on staging/production when the app pool kicks in). Once this happens, it continues to happen until I redeploy without changing anything.
So...what's up with that?
As noted in the comments of your answer to another similar question, this was a race condition bug in Ninject 2.0, which was fixed in version 2.2. I can't find any release notes for Ninject, but it solved this exact problem for me.

Resources