问题 用户代理导致MVC DisplayFor ArgumentException:路径中的非法字符


我遇到一个问题,即移动设备上的用户遇到MVC中的错误,而这在常规桌面上查看网站时不会发生。我可以通过使用Chrome的开发人员工具并应用除默认值之外的任何其他UA来始终如一地重现错误。

抛出的基础异常是: 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)

使用fiddler时,将成功的请求与失败的请求进行比较时,请求的唯一区别是User-Agent(以及作为查询字符串参数的一部分的jQuery附加的缓存占用者)。

为什么只更改UA导致此异常,如何在没有针对可能发生的每个地方为系统编写特定工作的情况下避免此问题?


11751
2017-12-15 15:09


起源

你找到了解决方案吗? - Roman Mik
@RomanMik - 我实际上发现了与CSJ相同的工作,以避免在我的视图模型中使用yield块。在我更改代码以实现列表而不是使用yield之后,问题得到了解决。我仍然不完全理解为什么在某些用户代理的.NET中会发生这种情况,但至少有一种标准的解决方法。 - SignalRichard
我在相关的SO文章中找到了与ASP.NET DisplayModeProvider相关的不同解决方案 stackoverflow.com/questions/33694842/... - Mark Nadig


答案:


我有完全相同的问题,并修复它。

我的问题原来是使用了 yield 阻止在我的viewmodel中:

控制器:

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);
}

视图:

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

令人费解的是,这适用于台式机,但iPad和iPhone失败,引用完全相同的堆栈跟踪。报道了类似的问题 这里 和 这里。通过添加一个问题解决了这个问题 .ToList() 打电话,因此:

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

据推测,编译器生成的用于表示yield块的类包括一些用户代理不喜欢的字符。包括ToList()调用使用List <>。


10
2018-01-06 14:26



ToList() 我也解决了这个问题。只是用 Where(...) 似乎工作正常(所以传递给视图的实际类型是 WhereListIterator<T>),但申请后 OrderBy(...).Take(...) (所以最终的结果是 Enumerable.<TakeIterator>...),视图在移动设备上崩溃。 - Arve Systad
我猜几个IEnumerable <T>类型存在问题;也许使用IList <T>(从而阻止你忘记 ToList())在视图模型中应该是创建编译时安全网的“最佳实践”吗? - Arve Systad
我刚才遇到了同样的问题。 IEnumerable <T>和视图模型构建器使用的产量。有谁知道究竟是什么导致了这个问题?这闻起来像是视图引擎中的一个bug。 - Øyvind
生命保护。我不知道班级名称最终是路径;那有点疯了。 - toddmo