Modify search location for views.

When areas are not provided area locations are not searched for views.  Also
added tests for search locations in RazorViewEngine failures.
This commit is contained in:
N. Taylor Mullen 2014-04-15 14:46:49 -07:00
parent 3671e8c5b4
commit d46389888d
3 changed files with 138 additions and 9 deletions

View File

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.AspNet.Mvc.Rendering;
namespace Microsoft.AspNet.Mvc.Razor
@ -9,10 +9,15 @@ namespace Microsoft.AspNet.Mvc.Razor
public class RazorViewEngine : IViewEngine
{
private static readonly string[] _viewLocationFormats =
{
"/Views/{1}/{0}.cshtml",
"/Views/Shared/{0}.cshtml",
};
private static readonly string[] _areaViewLocationFormats =
{
"/Areas/{2}/Views/{1}/{0}.cshtml",
"/Areas/{2}/Views/Shared/{0}.cshtml",
"/Views/{1}/{0}.cshtml",
"/Views/Shared/{0}.cshtml",
};
@ -56,27 +61,47 @@ namespace Microsoft.AspNet.Mvc.Razor
{
var controllerName = context.GetValueOrDefault<string>("controller");
var areaName = context.GetValueOrDefault<string>("area");
var potentialPaths = GetViewSearchPaths(viewName, controllerName, areaName);
var searchedLocations = new List<string>(_viewLocationFormats.Length);
for (int i = 0; i < _viewLocationFormats.Length; i++)
foreach (var path in potentialPaths)
{
var path = String.Format(CultureInfo.InvariantCulture, _viewLocationFormats[i], viewName, controllerName, areaName);
IView view = _virtualPathFactory.CreateInstance(path);
var view = _virtualPathFactory.CreateInstance(path);
if (view != null)
{
return ViewEngineResult.Found(viewName, view);
}
searchedLocations.Add(path);
}
return ViewEngineResult.NotFound(viewName, searchedLocations);
return ViewEngineResult.NotFound(viewName, potentialPaths);
}
}
private static bool IsSpecificPath(string name)
{
char c = name[0];
return (name[0] == '/');
return name[0] == '~' || name[0] == '/';
}
private IEnumerable<string> GetViewSearchPaths(string viewName, string controllerName, string areaName)
{
IEnumerable<string> unformattedPaths;
if (string.IsNullOrEmpty(areaName))
{
// If no areas then no need to search area locations.
unformattedPaths = _viewLocationFormats;
}
else
{
// If there's an area provided only search area view locations
unformattedPaths = _areaViewLocationFormats;
}
var formattedPaths = unformattedPaths.Select(path =>
string.Format(CultureInfo.InvariantCulture, path, viewName, controllerName, areaName)
);
return formattedPaths;
}
}
}

View File

@ -23,6 +23,7 @@
<ItemGroup>
<Compile Include="MvcRazorCodeParserTest.cs" />
<Compile Include="RazorCompilationServiceTest.cs" />
<Compile Include="RazorViewEngineTest.cs" />
<Compile Include="RazorViewTest.cs" />
<Compile Include="SpanFactory.cs" />
</ItemGroup>

View File

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.Rendering;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Razor.Test
{
public class RazorViewEngineTest
{
private static readonly Dictionary<string, object> _areaTestContext = new Dictionary<string, object>()
{
{"area", "foo"},
{"controller", "bar"},
};
private static readonly Dictionary<string, object> _controllerTestContext = new Dictionary<string, object>()
{
{"controller", "bar"},
};
[Fact]
public void FindPartialViewFailureSearchesCorrectLocationsWithAreas()
{
// Arrange
var searchedLocations = new List<string>();
var viewEngine = CreateSearchLocationViewEngineTester();
// Act
var result = viewEngine.FindPartialView(_areaTestContext, "partial");
// Assert
Assert.False(result.Success);
Assert.Equal(new[] {
"/Areas/foo/Views/bar/partial.cshtml",
"/Areas/foo/Views/Shared/partial.cshtml",
"/Views/Shared/partial.cshtml",
}, result.SearchedLocations);
}
[Fact]
public void FindPartialViewFailureSearchesCorrectLocationsWithoutAreas()
{
// Arrange
var viewEngine = CreateSearchLocationViewEngineTester();
// Act
var result = viewEngine.FindPartialView(_controllerTestContext, "partialNoArea");
// Assert
Assert.False(result.Success);
Assert.Equal(new[] {
"/Views/bar/partialNoArea.cshtml",
"/Views/Shared/partialNoArea.cshtml",
}, result.SearchedLocations);
}
[Fact]
public void FindViewFailureSearchesCorrectLocationsWithAreas()
{
// Arrange
var viewEngine = CreateSearchLocationViewEngineTester();
// Act
var result = viewEngine.FindView(_areaTestContext, "full");
// Assert
Assert.False(result.Success);
Assert.Equal(new[] {
"/Areas/foo/Views/bar/full.cshtml",
"/Areas/foo/Views/Shared/full.cshtml",
"/Views/Shared/full.cshtml",
}, result.SearchedLocations);
}
[Fact]
public void FindViewFailureSearchesCorrectLocationsWithoutAreas()
{
// Arrange
var viewEngine = CreateSearchLocationViewEngineTester();
// Act
var result = viewEngine.FindView(_controllerTestContext, "fullNoArea");
// Assert
Assert.False(result.Success);
Assert.Equal(new[] {
"/Views/bar/fullNoArea.cshtml",
"/Views/Shared/fullNoArea.cshtml",
}, result.SearchedLocations);
}
private IViewEngine CreateSearchLocationViewEngineTester()
{
var virtualPathFactory = new Mock<IVirtualPathViewFactory>();
virtualPathFactory.Setup(vpf => vpf.CreateInstance(It.IsAny<string>())).Returns<IView>(null);
var viewEngine = new RazorViewEngine(virtualPathFactory.Object);
return viewEngine;
}
}
}