2

I am attempting to impliment a custom view engine to serve mobile views based on the user agent. I am following Scott Hanselman's approach from this blog post.

I have inherited from the WebFormsViewEngine and overridden the FindView method the same way that Scott describes in his blog.

I then added a few lines to my Global.asax Application_Start method to clear the view engine collection and add a new instance of my view engine.

After some testing it would appear that MVC is ignoring my view engine. When it failed to find my custom views based on the user agent of the browser I resorted to hardcoding the custom path to to append to the view and it still managed to fall back on the default view. I set a breakpoint in my FindView method and sure enough, it's not being called at all.

How can I get my custom view engine to work? Any help will be much appreciated.

My view engine looks like this:

public class MyViewEngine: WebFormsViewEngine
{
    public override ViewEngineResult FindView (ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
         ViewEngineResult result = null;

         //Serve a special view for iPhones
         if (UserAgentIs(controllerContext, "iPhone"))
         {
              result = base.FindView(controllerContext, "Mobile/iPhone/" + viewName, masterName, useCache);
         }

         //If no special view is found, fall back to the default view
         if (result == null || result.View == null)
         {
              result = base.FindView(controllerContext, viewName, masterName, useCache);
         }

         return result;
    }

    private bool UserAgentIs(ControllerContext controllerContext, string userAgentToTest)
    {
         return (controllerContext.HttpContext.Request.UserAgent.IndexOf(userAgentToTest, StringComparison.OrdinalIgnoreCase) > 0);
    }
}

And in my Global.asax:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new MyViewEngine());
}

When this setup didn't work I even tried to simplify my FindView method to this:

public override ViewEngineResult FindView (ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
         ViewEngineResult result = null;
         result = base.FindView(controllerContext, "Mobile/iPhone/" + viewName, masterName, useCache);
         return result;
    }

And that didn't work either. It still returned the default view. And yes, the view page and master page that should be found by that statement do actually exist. I'm pretty stumped as to why this is not working.

Çağdaş Tekin
  • 16,592
  • 4
  • 49
  • 58
Jeff French
  • 1,029
  • 8
  • 22
  • Is you web server properly detecting that the client is a mobile phone? – Robert Harvey Oct 23 '09 at 15:37
  • Can we see your implementation of custom view engine? – Çağdaş Tekin Oct 23 '09 at 15:45
  • Yes, added code to my view to print the user agent and it shows the proper string. However, I beleive the problem is related to MVC ignoring my view engine all together. I even removed the logic to detect mobile phone and hard coded the mobile view path and still ended up with the default view. – Jeff French Oct 23 '09 at 15:47
  • Addition to my last comment : Can we also see the code you are using to add your own viewengine to the view engine collection. – Çağdaş Tekin Oct 23 '09 at 15:54
  • I have added the code to my original question. Thanks for looking into this. – Jeff French Oct 23 '09 at 16:21
  • I wanted to see if there were any problems clearing the engine list and registering your custom one. But there isn't. It should definitely hit your ViewEngine. I just tested myself as well and couldn't reproduce the behaviour. Weird. – Çağdaş Tekin Oct 23 '09 at 16:25
  • BTW, this is not beta version of ASP.NET MVC, right? – Çağdaş Tekin Oct 23 '09 at 16:39
  • This is MVC 2 preview 2. – Jeff French Oct 23 '09 at 16:47
  • Hmm, maybe that's it. Because it works fine with MVC 1. – Çağdaş Tekin Oct 23 '09 at 16:49
  • the problem is posible because of OutputCached, if anyone know about this, please check out this question: http://stackoverflow.com/questions/2209526/output-cache-problem-on-viewengine-that-use-2-separate-view-for-1-controller – DucDigital Feb 05 '10 at 18:52

1 Answers1

2

Well this is certainly embarrasing:

When I wrote my view engine I was following the blog post from Scott Hanselman (see my original post for the link). I delcared my view engine class then decided I would just copy and paste Scott's code into my class and modify as needed. I accidentally copied his code WITH the class definition into my class creating a nested class. Therefore my view engine didn't actually contain an override for the FindView method and naturally the one in the nested class would never be called!

The lesson: when using code found online don't copy and paste! Always type it yourself.

Thanks to everyone who check this question out and tried to help me.

I'll go stand in the corner of shame and embarrassment now!

Jeff French
  • 1,029
  • 8
  • 22
  • Here's the updated/fixed ViewEngine for you: http://www.hanselman.com/blog/NuGetPackageOfTheWeek10NewMobileViewEnginesForASPNETMVC3SpeccompatibleWithASPNETMVC4.aspx – Scott Hanselman Sep 05 '11 at 22:34