User Agent Causes MVC DisplayFor ArgumentException: Illegal characters in path

I’m having a problem where users on mobile devices are encountering an error in MVC that does not occur when viewing the site on a regular desktop. I can consistently reproduce the error by using Chrome’s developer tools and applying any other UA than the default.

The underlying exception thrown is:
ArgumentException: Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
at System.IO.Path.GetExtension(String path)
at System.Web.WebPages.DefaultDisplayMode.TransformPath(String virtualPath, String suffix)
at System.Web.WebPages.DefaultDisplayMode.GetDisplayInfo(HttpContextBase httpContext, String virtualPath, Func'2 virtualPathExists)
at System.Web.WebPages.DisplayModeProvider.GetDisplayInfoForVirtualPath(String virtualPath, HttpContextBase httpContext, Func'2 virtualPathExists, IDisplayMode currentDisplayMode, Boolean requireConsistentDisplayMode)
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPathFromGeneralName(ControllerContext controllerContext, List'1 locations, String name, String controllerName, String areaName, String cacheKey, String[]& searchedLocations)
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations)
at System.Web.Mvc.VirtualPathProviderViewEngine.FindPartialView(ControllerContext controllerContext, String partialViewName, Boolean useCache)
at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClass2.<FindPartialView>b__1(IViewEngine e)
at System.Web.Mvc.ViewEngineCollection.Find(Func'2 lookup, Boolean trackSearchedPaths)
at System.Web.Mvc.ViewEngineCollection.FindPartialView(ControllerContext controllerContext, String partialViewName)
at System.Web.Mvc.Html.TemplateHelpers.ExecuteTemplate(HtmlHelper html, ViewDataDictionary viewData, String templateName, DataBoundControlMode mode, GetViewNamesDelegate getViewNames, GetDefaultActionsDelegate getDefaultActions)
at System.Web.Mvc.Html.TemplateHelpers.TemplateHelper(HtmlHelper html, ModelMetadata metadata, String htmlFieldName, String templateName, DataBoundControlMode mode, Object additionalViewData, ExecuteTemplateDelegate executeTemplate)
at System.Web.Mvc.Html.TemplateHelpers.TemplateHelper(HtmlHelper html, ModelMetadata metadata, String htmlFieldName, String templateName, DataBoundControlMode mode, Object additionalViewData)
at System.Web.Mvc.Html.TemplateHelpers.TemplateFor[TContainer,TValue](HtmlHelper'1 html, Expression'1 expression, String templateName, String htmlFieldName, DataBoundControlMode mode, Object additionalViewData, TemplateHelperDelegate templateHelper)
at System.Web.Mvc.Html.TemplateHelpers.TemplateFor[TContainer,TValue](HtmlHelper'1 html, Expression'1 expression, String templateName, String htmlFieldName, DataBoundControlMode mode, Object additionalViewData)
at System.Web.Mvc.Html.DisplayExtensions.DisplayFor[TModel,TValue](HtmlHelper'1 html, Expression'1 expression)

Using fiddler, the only difference in requests when comparing a successful one to a failed request is the User-Agent (and the cache buster appended by jQuery as part of the query string parameters).

Why is only changing the UA causing this exception and how can I avoid this issue without writing a specific work around into the system for every place that this is and could occur?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I had the exact same problem, and fixed it.

My problem turned out to be the use of a yield block in my viewmodel:

Controller:

var vm = new BigVM {
    SmallVMs = BuildSmallOnes()
};
return View(vm);

private IEnumerable<SmallVM> BuildSmallOnes()
{
    // complex logic
    yield return new SmallVM(1);
    yield return new SmallVM(2);
}

View:

@model BigVM
@Html.DisplayFor(x => x.SmallVMs)   <-- died

Inexplicably, this worked for desktops but failed for iPads and iPhones, citing the exact same stacktrace. Similar problems were reported here and here. The problem was solved by adding a .ToList() call, thus:

var vm = new BigVM {
    SmallVMs = BuildSmallOnes().ToList()
};

Presumably the class that the compiler generates to represent the yield block includes some characters that some User Agents just don’t like. Including the ToList() call uses a List<> instead.

Method 2

I believe that the reason we are having this issue is MultipleViews and DisplayMode providers introduced for handling mobile devices separately. This is code that is still in .NET 4 but has been deprecated.

A solution to disable the functionality entirely can be found here.
Illegal characters in path depending on User-Agent?


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x