更新:这个解决方案有一个微妙的错误。 MVC 框架将调用FindView/FindPartialView 两次:一次调用useCache=true,如果没有返回结果,调用一次useCache=false。由于所有类型的视图只有一个缓存,因此如果桌面浏览器最先出现,移动用户最终可能会看到桌面视图。
对于那些有兴趣使用自定义视图引擎来解决这个问题的人,Scott Hanselman 在这里更新了他的解决方案:
http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx
(为答案劫持道歉,我只是不希望其他人不得不经历这个!)
由 roufamatic (2010-11-17) 编辑
您要做的第一件事是将Mobile Device Browser File 引入您的项目。使用此文件,您可以定位您想要支持的任何设备,而无需了解这些设备在其标头中发送的具体内容。该文件已经为您完成了工作。然后,您可以使用 Request.Browser 属性来定制要返回的视图。
接下来,就如何在 Views 文件夹下组织视图提出一个策略。我更喜欢将桌面版本保留在根目录,然后有一个 Mobile 文件夹。例如,主视图文件夹如下所示:
我不同意@Mehrdad 关于使用自定义视图引擎的观点。视图引擎有不止一个用途,其中之一就是为控制器寻找视图。您可以通过覆盖 FindView 方法来做到这一点。在这种方法中,您可以检查在哪里可以找到视图。在您知道哪个设备正在使用您的网站后,您可以使用您想出的组织视图的策略来返回该设备的视图。
public class CustomViewEngine : WebFormViewEngine
{
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
// Logic for finding views in your project using your strategy for organizing your views under the Views folder.
ViewEngineResult result = null;
var request = controllerContext.HttpContext.Request;
// iPhone Detection
if (request.UserAgent.IndexOf("iPhone",
StringComparison.OrdinalIgnoreCase) > 0)
{
result = base.FindView(controllerContext, "Mobile/iPhone/" + viewName, masterName, useCache);
}
// Blackberry Detection
if (request.UserAgent.IndexOf("BlackBerry",
StringComparison.OrdinalIgnoreCase) > 0)
{
result = base.FindView(controllerContext, "Mobile/BlackBerry/" + viewName, masterName, useCache);
}
// Default Mobile
if (request.Browser.IsMobileDevice)
{
result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);
}
// Desktop
if (result == null || result.View == null)
{
result = base.FindView(controllerContext, viewName, masterName, useCache);
}
return result;
}
}
上面的代码允许你根据你的策略设置视图。如果没有为设备找到视图或没有默认的移动视图,则回退是桌面视图。
如果您决定将逻辑放在控制器中而不是创建视图引擎。最好的方法是创建一个自定义的ActionFilterAttribute,你可以用它来装饰你的控制器。然后覆盖OnActionExecuted 方法以确定哪个设备正在查看您的站点。您可以查看此blog post 了解如何操作。这篇文章还有一些不错的链接,指向一些关于这个主题的 Mix 视频。