Reputation: 916
I have a project where i want to show different views to Desktop e Mobile users, mostly for better experience and speed. Right now i'm using 51degrees to tell me if the request comes from a mobile or desktop user and then in my Action Filter i will change the view name from "Index" to "Index.Mobile", the thing is i'm getting some problems with Views where i don't want to use a Layout at all.
This is my Method:
public override void OnActionExecuted( ActionExecutedContext filterContext )
{
var result = filterContext.Result as ViewResult;
var view = filterContext.ActionDescriptor.ActionName;
//IsMobile is filled on my OnActionExecuting method
var IsMobile = filterContext.Controller.ViewBag.IsMobile;
if( result == null ) return;
string viewName;
string masterName;
if( IsMobile )
{
viewName = view + ".Mobile";
masterName = "_Layout.Mobile";
//Check if view exists
var viewResult = ViewEngines.Engines.FindView( filterContext.Controller.ControllerContext, viewName, null );
if( viewResult.View == null )
{
viewName = view;
}
}
else
{
viewName = view;
masterName = "_Layout";
}
result.ViewName = viewName;
result.MasterName = masterName;
}
What happens is, here i set a value for the MasterName or Layout and at two specific Controllers i need to set it as null but it still fetches the Layout i set before.
What i need is, this method will set the view and layout name and if need i will set the Layout as null inside the view i loaded.
Can that be done ?
EDIT
I tried to implement another method, Link, but i couldn't find a way to change the Layout view, only the action.
Upvotes: 2
Views: 1368
Reputation: 5222
Well to change view name dynamically you can also use this, which is simple
public void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.HttpContext.Request.IsLocal)
{
filterContext.Result = new ViewResult { ViewName = "Index" };
}
}
This worked for me :)
Upvotes: 1
Reputation: 916
After some debugging i saw that setting the value inside the View
wasn't working because the ViewEngine
would ignore this new value and keep the value setted on the OnActionExecuted
method.
I managed to fix my problem using the same method but with the addition of a ViewBag telling me if this particular view needs a Layout. Since the OnActionExecuted
will execute after the Controller
and before the View
it's possible to set the value as true/false at the Controller
and then read it inside the OnActionExecuted
.
This is the working example:
public override void OnActionExecuted( ActionExecutedContext filterContext )
{
var result = filterContext.Result as ViewResult;
var IsMobile = filterContext.Controller.ViewBag.IsMobile;
var view = filterContext.ActionDescriptor.ActionName;
if( result == null ) return;
string viewName;
string masterName;
bool hasLayout = filterContext.Controller.ViewBag.HasLayout ?? true;
if( IsMobile )
{
viewName = view + ".Mobile";
masterName = hasLayout ? "_Layout.Mobile" : null;
//Check if new view exists
var viewResult = ViewEngines.Engines.FindView( filterContext.Controller.ControllerContext, viewName, null );
if( viewResult.View == null )
{
viewName = view;
}
}
else
{
viewName = view;
masterName = hasLayout ? "_Layout" : null;
}
result.ViewName = viewName;
result.MasterName = masterName;
}
If anyone has a better option besides that please share, this workaround looks nice but it feels a little bit wrong.
Upvotes: 1
Reputation: 3315
You can create a folder in your project like "Areas/Mobile" and keep your views, controllers and even models (view models for mobile) in there. You just have to create a routing rule to pass across the requests coming from a mobile device to controllers inside the "Area/Mobile". It would be much easier to manage and build a mobile version of the site.
Upvotes: 1