diff --git a/samples/MvcSample.Web/MvcSample.Web.kproj b/samples/MvcSample.Web/MvcSample.Web.kproj
index 46bf609d42..bb973e66dd 100644
--- a/samples/MvcSample.Web/MvcSample.Web.kproj
+++ b/samples/MvcSample.Web/MvcSample.Web.kproj
@@ -39,6 +39,7 @@
+
diff --git a/samples/MvcSample.Web/Views/Shared/MyView.cshtml b/samples/MvcSample.Web/Views/Shared/MyView.cshtml
index c8d8ebb613..d2ed197537 100644
--- a/samples/MvcSample.Web/Views/Shared/MyView.cshtml
+++ b/samples/MvcSample.Web/Views/Shared/MyView.cshtml
@@ -1,7 +1,6 @@
@using MvcSample.Web.Models
@model User
@{
- Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Home Page";
string nullValue = null;
diff --git a/samples/MvcSample.Web/Views/Shared/_Layout.cshtml b/samples/MvcSample.Web/Views/Shared/_Layout.cshtml
index 4879428656..2f5901fdb6 100644
--- a/samples/MvcSample.Web/Views/Shared/_Layout.cshtml
+++ b/samples/MvcSample.Web/Views/Shared/_Layout.cshtml
@@ -27,12 +27,6 @@
@RenderBody()
-
- @if (@Model != null)
- {
- @Model.Address
- }
-
diff --git a/samples/MvcSample.Web/Views/_ViewStart.cshtml b/samples/MvcSample.Web/Views/_ViewStart.cshtml
new file mode 100644
index 0000000000..ab23e9a239
--- /dev/null
+++ b/samples/MvcSample.Web/Views/_ViewStart.cshtml
@@ -0,0 +1,3 @@
+@{
+ Layout = "/Views/Shared/_Layout.cshtml";
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs b/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs
index bfa26714cd..1b39030d2a 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs
@@ -16,6 +16,11 @@ namespace Microsoft.AspNet.Mvc.Razor
///
ViewContext ViewContext { get; set; }
+ ///
+ /// Gets the path to the page.
+ ///
+ string Path { get; set; }
+
string BodyContent { get; set; }
///
diff --git a/src/Microsoft.AspNet.Mvc.Razor/IRazorPageFactory.cs b/src/Microsoft.AspNet.Mvc.Razor/IRazorPageFactory.cs
index 0e4ecbe9ce..af2276d16e 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/IRazorPageFactory.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/IRazorPageFactory.cs
@@ -11,8 +11,8 @@ namespace Microsoft.AspNet.Mvc.Razor
///
/// Creates a for the specified path.
///
- /// The path to locate the RazorPage.
+ /// The path to locate the page.
/// The IRazorPage instance if it exists, null otherwise.
- IRazorPage CreateInstance(string viewPath);
+ IRazorPage CreateInstance(string path);
}
}
diff --git a/src/Microsoft.AspNet.Mvc.Razor/IViewStartProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/IViewStartProvider.cs
new file mode 100644
index 0000000000..47a445d04b
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Razor/IViewStartProvider.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+
+namespace Microsoft.AspNet.Mvc.Razor
+{
+ ///
+ /// Defines methods for locating ViewStart pages that are applicable to a page.
+ ///
+ public interface IViewStartProvider
+ {
+ ///
+ /// Given a view path, returns a sequence of ViewStart instances
+ /// that are applicable to the specified view.
+ ///
+ /// The path of the page to locate ViewStart files for.
+ /// A sequence of that represent ViewStart.
+ IEnumerable GetViewStartPages(string path);
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Razor/Microsoft.AspNet.Mvc.Razor.kproj b/src/Microsoft.AspNet.Mvc.Razor/Microsoft.AspNet.Mvc.Razor.kproj
index b3d6054eb8..e895509e69 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/Microsoft.AspNet.Mvc.Razor.kproj
+++ b/src/Microsoft.AspNet.Mvc.Razor/Microsoft.AspNet.Mvc.Razor.kproj
@@ -30,6 +30,9 @@
+
+
+
diff --git a/src/Microsoft.AspNet.Mvc.Razor/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Mvc.Razor/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..6d457fde04
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Razor/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("Microsoft.AspNet.Mvc.Razor.Test")]
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs
index fda790a69b..6aab1aca64 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs
@@ -42,6 +42,9 @@ namespace Microsoft.AspNet.Mvc.Razor
}
}
+ ///
+ public string Path { get; set; }
+
///
public ViewContext ViewContext { get; set; }
diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs
index 0982918fbc..ff4aefaebe 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Rendering;
@@ -17,6 +18,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
private readonly IRazorPageFactory _pageFactory;
private readonly IRazorPageActivator _pageActivator;
+ private readonly IViewStartProvider _viewStartProvider;
private readonly IRazorPage _page;
private readonly bool _executeViewHierarchy;
@@ -30,11 +32,13 @@ namespace Microsoft.AspNet.Mvc.Razor
/// view start and layout pages are executed as part of the executing the page.
public RazorView([NotNull] IRazorPageFactory pageFactory,
[NotNull] IRazorPageActivator pageActivator,
+ [NotNull] IViewStartProvider viewStartProvider,
[NotNull] IRazorPage page,
bool executeViewHierarchy)
{
_pageFactory = pageFactory;
_pageActivator = pageActivator;
+ _viewStartProvider = viewStartProvider;
_page = page;
_executeViewHierarchy = executeViewHierarchy;
}
@@ -44,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
if (_executeViewHierarchy)
{
- var bodyContent = await RenderPageAsync(_page, context);
+ var bodyContent = await RenderPageAsync(_page, context, executeViewStart: true);
await RenderLayoutAsync(context, bodyContent);
}
else
@@ -53,7 +57,9 @@ namespace Microsoft.AspNet.Mvc.Razor
}
}
- private async Task RenderPageAsync(IRazorPage page, ViewContext context)
+ private async Task RenderPageAsync(IRazorPage page,
+ ViewContext context,
+ bool executeViewStart)
{
var contentBuilder = new StringBuilder(1024);
using (var bodyWriter = new StringWriter(contentBuilder))
@@ -64,6 +70,11 @@ namespace Microsoft.AspNet.Mvc.Razor
context.Writer = bodyWriter;
try
{
+ if (executeViewStart)
+ {
+ // Execute view starts using the same context + writer as the page to render.
+ await RenderViewStartAsync(context);
+ }
await RenderPageCoreAsync(page, context);
}
finally
@@ -86,6 +97,19 @@ namespace Microsoft.AspNet.Mvc.Razor
await page.ExecuteAsync();
}
+ private async Task RenderViewStartAsync(ViewContext context)
+ {
+ var viewStarts = _viewStartProvider.GetViewStartPages(_page.Path);
+
+ foreach (var viewStart in viewStarts)
+ {
+ await RenderPageCoreAsync(viewStart, context);
+
+ // Copy over interesting properties from the ViewStart page to the entry page.
+ _page.Layout = viewStart.Layout;
+ }
+ }
+
private async Task RenderLayoutAsync(ViewContext context,
string bodyContent)
{
@@ -104,7 +128,7 @@ namespace Microsoft.AspNet.Mvc.Razor
layoutPage.PreviousSectionWriters = previousPage.SectionWriters;
layoutPage.BodyContent = bodyContent;
- bodyContent = await RenderPageAsync(layoutPage, context);
+ bodyContent = await RenderPageAsync(layoutPage, context, executeViewStart: false);
// Verify that RenderBody is called, or that RenderSection is called for all sections
layoutPage.EnsureBodyAndSectionsWereRendered();
diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs
index 4d36cf0bde..033ef985ac 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs
@@ -28,12 +28,15 @@ namespace Microsoft.AspNet.Mvc.Razor
private readonly IRazorPageFactory _pageFactory;
private readonly IRazorPageActivator _viewActivator;
+ private readonly IViewStartProvider _viewStartProvider;
public RazorViewEngine(IRazorPageFactory pageFactory,
- IRazorPageActivator viewActivator)
+ IRazorPageActivator viewActivator,
+ IViewStartProvider viewStartProvider)
{
_pageFactory = pageFactory;
_viewActivator = viewActivator;
+ _viewStartProvider = viewStartProvider;
}
public IEnumerable ViewLocationFormats
@@ -96,6 +99,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
var view = new RazorView(_pageFactory,
_viewActivator,
+ _viewStartProvider,
page,
executeViewHierarchy: !partial);
return ViewEngineResult.Found(viewName, view);
diff --git a/src/Microsoft.AspNet.Mvc.Razor/ViewStartProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/ViewStartProvider.cs
new file mode 100644
index 0000000000..2f43fd10e3
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Razor/ViewStartProvider.cs
@@ -0,0 +1,92 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Microsoft.Framework.Runtime;
+
+namespace Microsoft.AspNet.Mvc.Razor
+{
+ ///
+ public class ViewStartProvider : IViewStartProvider
+ {
+ private const string ViewStartFileName = "_ViewStart.cshtml";
+ private readonly string _appRoot;
+ private readonly IRazorPageFactory _pageFactory;
+
+ public ViewStartProvider(IApplicationEnvironment appEnv,
+ IRazorPageFactory pageFactory)
+ {
+ _appRoot = TrimTrailingSlash(appEnv.ApplicationBasePath);
+ _pageFactory = pageFactory;
+ }
+
+ ///
+ public IEnumerable GetViewStartPages([NotNull] string path)
+ {
+ var viewStartLocations = GetViewStartLocations(path);
+ var viewStarts = viewStartLocations.Select(_pageFactory.CreateInstance)
+ .Where(p => p != null)
+ .ToArray();
+
+ // GetViewStartLocations return ViewStarts inside-out that is the _ViewStart closest to the page
+ // is the first: e.g. [ /Views/Home/_ViewStart, /Views/_ViewStart, /_ViewStart ]
+ // However they need to be executed outside in, so we'll reverse the sequence.
+ Array.Reverse(viewStarts);
+
+ return viewStarts;
+ }
+
+ internal IEnumerable GetViewStartLocations(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ return Enumerable.Empty();
+ }
+
+ var viewStartLocations = new List();
+ var currentDir = GetViewDirectory(_appRoot, path);
+ while (IsSubDirectory(_appRoot, currentDir))
+ {
+ viewStartLocations.Add(Path.Combine(currentDir, ViewStartFileName));
+ currentDir = Path.GetDirectoryName(currentDir);
+ }
+
+ return viewStartLocations;
+ }
+
+ private static bool IsSubDirectory(string appRoot, string currentDir)
+ {
+ return currentDir.StartsWith(appRoot, StringComparison.OrdinalIgnoreCase);
+ }
+
+ private static string GetViewDirectory(string appRoot, string viewPath)
+ {
+ if (viewPath.StartsWith("~/"))
+ {
+ viewPath = viewPath.Substring(2);
+ }
+ else if (viewPath[0] == Path.DirectorySeparatorChar ||
+ viewPath[0] == Path.AltDirectorySeparatorChar)
+ {
+ viewPath = viewPath.Substring(1);
+ }
+
+ var viewDir = Path.GetDirectoryName(viewPath);
+ return Path.GetFullPath(Path.Combine(appRoot, viewDir));
+ }
+
+ private static string TrimTrailingSlash(string path)
+ {
+ if (path.Length > 0 &&
+ path[path.Length - 1] == Path.DirectorySeparatorChar)
+ {
+ return path.Substring(0, path.Length - 1);
+ }
+
+ return path;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs b/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs
index aaeff501d3..b55ede7a85 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs
@@ -30,14 +30,15 @@ namespace Microsoft.AspNet.Mvc.Razor
}
///
- public IRazorPage CreateInstance([NotNull] string viewPath)
+ public IRazorPage CreateInstance([NotNull] string path)
{
- var fileInfo = _fileInfoCache.GetFileInfo(viewPath);
+ var fileInfo = _fileInfoCache.GetFileInfo(path);
if (fileInfo != null)
{
var result = _compilationService.Compile(fileInfo);
var page = (IRazorPage)_activator.CreateInstance(_serviceProvider, result.CompiledType);
+ page.Path = path;
return page;
}
diff --git a/src/Microsoft.AspNet.Mvc/MvcServices.cs b/src/Microsoft.AspNet.Mvc/MvcServices.cs
index 5b356f40a5..40088f4cf6 100644
--- a/src/Microsoft.AspNet.Mvc/MvcServices.cs
+++ b/src/Microsoft.AspNet.Mvc/MvcServices.cs
@@ -43,6 +43,7 @@ namespace Microsoft.AspNet.Mvc
yield return describe.Singleton();
yield return describe.Scoped();
yield return describe.Singleton();
+ yield return describe.Singleton();
yield return describe.Singleton();
// Virtual path view factory needs to stay scoped so views can get get scoped services.
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/Microsoft.AspNet.Mvc.Razor.Test.kproj b/test/Microsoft.AspNet.Mvc.Razor.Test/Microsoft.AspNet.Mvc.Razor.Test.kproj
index f4790a60fd..75641c822d 100644
--- a/test/Microsoft.AspNet.Mvc.Razor.Test/Microsoft.AspNet.Mvc.Razor.Test.kproj
+++ b/test/Microsoft.AspNet.Mvc.Razor.Test/Microsoft.AspNet.Mvc.Razor.Test.kproj
@@ -28,6 +28,7 @@
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineTest.cs
index b967c579b2..f8c6567354 100644
--- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineTest.cs
@@ -160,15 +160,35 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
}, result.SearchedLocations);
}
+ [Fact]
+ public void FindView_ReturnsRazorView_IfLookupWasSuccessful()
+ {
+ // Arrange
+ var pageFactory = new Mock();
+ pageFactory.Setup(p => p.CreateInstance(It.IsAny()))
+ .Returns(Mock.Of());
+ var viewEngine = new RazorViewEngine(pageFactory.Object,
+ Mock.Of(),
+ Mock.Of());
+
+ // Act
+ var result = viewEngine.FindView(_controllerTestContext, "test-view");
+
+ // Assert
+ Assert.True(result.Success);
+ Assert.IsType(result.View);
+ Assert.Equal("/Views/bar/test-view.cshtml", result.ViewName);
+ }
+
private IViewEngine CreateSearchLocationViewEngineTester()
{
var pageFactory = new Mock();
pageFactory.Setup(vpf => vpf.CreateInstance(It.IsAny()))
.Returns(null);
- var pageActivator = Mock.Of();
-
- var viewEngine = new RazorViewEngine(pageFactory.Object, pageActivator);
+ var viewEngine = new RazorViewEngine(pageFactory.Object,
+ Mock.Of(),
+ Mock.Of());
return viewEngine;
}
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs
index dc4fb8deba..e2ec6a95a6 100644
--- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs
@@ -4,8 +4,8 @@
using System;
using System.IO;
using System.Threading.Tasks;
-using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.PipelineCore;
using Moq;
using Xunit;
@@ -27,6 +27,7 @@ namespace Microsoft.AspNet.Mvc.Razor
});
var view = new RazorView(Mock.Of(),
Mock.Of(),
+ CreateViewStartProvider(),
page,
executeViewHierarchy: false);
var viewContext = CreateViewContext(view);
@@ -51,9 +52,10 @@ namespace Microsoft.AspNet.Mvc.Razor
Assert.Same(viewData, v.ViewContext.ViewData);
});
var activator = new Mock();
-
+
var view = new RazorView(Mock.Of(),
activator.Object,
+ CreateViewStartProvider(),
page,
executeViewHierarchy: false);
var viewContext = CreateViewContext(view);
@@ -86,6 +88,7 @@ namespace Microsoft.AspNet.Mvc.Razor
.Verifiable();
var view = new RazorView(Mock.Of(),
activator.Object,
+ CreateViewStartProvider(),
page,
executeViewHierarchy: false);
var viewContext = CreateViewContext(view);
@@ -98,15 +101,17 @@ namespace Microsoft.AspNet.Mvc.Razor
}
[Fact]
- public async Task RenderAsync_WithoutHierarchy_DoesNotExecuteLayoutPages()
+ public async Task RenderAsync_WithoutHierarchy_DoesNotExecuteLayoutOrViewStartPages()
{
var page = new TestableRazorPage(v =>
{
v.Layout = LayoutPath;
});
var pageFactory = new Mock();
+ var viewStartProvider = CreateViewStartProvider();
var view = new RazorView(pageFactory.Object,
Mock.Of(),
+ viewStartProvider,
page,
executeViewHierarchy: false);
var viewContext = CreateViewContext(view);
@@ -116,6 +121,7 @@ namespace Microsoft.AspNet.Mvc.Razor
// Assert
pageFactory.Verify(v => v.CreateInstance(It.IsAny()), Times.Never());
+ Mock.Get(viewStartProvider).Verify(v => v.GetViewStartPages(It.IsAny()), Times.Never());
}
[Fact]
@@ -129,6 +135,7 @@ namespace Microsoft.AspNet.Mvc.Razor
});
var view = new RazorView(Mock.Of(),
Mock.Of(),
+ CreateViewStartProvider(),
page,
executeViewHierarchy: true);
var viewContext = CreateViewContext(view);
@@ -152,6 +159,7 @@ namespace Microsoft.AspNet.Mvc.Razor
});
var view = new RazorView(Mock.Of(),
Mock.Of(),
+ CreateViewStartProvider(),
page,
executeViewHierarchy: true);
var viewContext = CreateViewContext(view);
@@ -177,6 +185,49 @@ namespace Microsoft.AspNet.Mvc.Razor
.Verifiable();
var view = new RazorView(Mock.Of(),
activator.Object,
+ CreateViewStartProvider(),
+ page,
+ executeViewHierarchy: true);
+ var viewContext = CreateViewContext(view);
+
+ // Act
+ await view.RenderAsync(viewContext);
+
+ // Assert
+ activator.Verify();
+ }
+
+ [Fact]
+ public async Task RenderAsync_WithHierarchy_ExecutesViewStart()
+ {
+ // Arrange
+ var actualLayoutPath = "";
+ var layoutPath = "/Views/_Shared/_Layout.cshtml";
+ var viewStart1 = new TestableRazorPage(v =>
+ {
+ v.Layout = "/fake-layout-path";
+ });
+ var viewStart2 = new TestableRazorPage(v =>
+ {
+ v.Layout = layoutPath;
+ });
+ var page = new TestableRazorPage(v =>
+ {
+ // This path must have been set as a consequence of running viewStart
+ actualLayoutPath = v.Layout;
+ // Clear out layout so we don't render it
+ v.Layout = null;
+ });
+ var activator = new Mock();
+ activator.Setup(a => a.Activate(viewStart1, It.IsAny()))
+ .Verifiable();
+ activator.Setup(a => a.Activate(viewStart2, It.IsAny()))
+ .Verifiable();
+ activator.Setup(a => a.Activate(page, It.IsAny()))
+ .Verifiable();
+ var view = new RazorView(Mock.Of(),
+ activator.Object,
+ CreateViewStartProvider(viewStart1, viewStart2),
page,
executeViewHierarchy: true);
var viewContext = CreateViewContext(view);
@@ -231,6 +282,7 @@ foot-content";
var view = new RazorView(pageFactory.Object,
activator.Object,
+ CreateViewStartProvider(),
page,
executeViewHierarchy: true);
var viewContext = CreateViewContext(view);
@@ -264,6 +316,7 @@ foot-content";
var view = new RazorView(pageFactory.Object,
Mock.Of(),
+ CreateViewStartProvider(),
page,
executeViewHierarchy: true);
var viewContext = CreateViewContext(view);
@@ -290,6 +343,7 @@ foot-content";
var view = new RazorView(pageFactory.Object,
Mock.Of(),
+ CreateViewStartProvider(),
page,
executeViewHierarchy: true);
var viewContext = CreateViewContext(view);
@@ -344,6 +398,7 @@ body-content";
var view = new RazorView(pageFactory.Object,
Mock.Of(),
+ CreateViewStartProvider(),
page,
executeViewHierarchy: true);
var viewContext = CreateViewContext(view);
@@ -357,8 +412,8 @@ body-content";
private static ViewContext CreateViewContext(RazorView view)
{
- var httpContext = new Mock();
- var actionContext = new ActionContext(httpContext.Object, routeData: null, actionDescriptor: null);
+ var httpContext = new DefaultHttpContext();
+ var actionContext = new ActionContext(httpContext, routeData: null, actionDescriptor: null);
return new ViewContext(
actionContext,
view,
@@ -366,6 +421,16 @@ body-content";
new StringWriter());
}
+ private static IViewStartProvider CreateViewStartProvider(params IRazorPage[] viewStartPages)
+ {
+ viewStartPages = viewStartPages ?? new IRazorPage[0];
+ var viewStartProvider = new Mock();
+ viewStartProvider.Setup(v => v.GetViewStartPages(It.IsAny()))
+ .Returns(viewStartPages);
+
+ return viewStartProvider.Object;
+ }
+
private class TestableRazorPage : RazorPage
{
private readonly Action _executeAction;
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/ViewStartProviderTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/ViewStartProviderTest.cs
new file mode 100644
index 0000000000..8ccfbdfec9
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Razor.Test/ViewStartProviderTest.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using Microsoft.Framework.Runtime;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.Razor.Test
+{
+ public class ViewStartProviderTest
+ {
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void GetViewStartLocations_ReturnsEmptySequenceIfViewPathIsEmpty(string viewPath)
+ {
+ // Arrange
+ var appPath = @"x:\test";
+ var provider = new ViewStartProvider(GetAppEnv(appPath), Mock.Of());
+
+ // Act
+ var result = provider.GetViewStartLocations(viewPath);
+
+ // Assert
+ Assert.Empty(result);
+ }
+
+ public static IEnumerable