ViewLocationExpanderContext should have a flag that indicates if the

lookup is for a full or partial view

Fixes #1212
This commit is contained in:
Pranav K 2015-02-20 12:47:09 -08:00
parent b821b706b7
commit 73f44889f2
11 changed files with 156 additions and 22 deletions

View File

@ -51,8 +51,10 @@ namespace Microsoft.AspNet.Mvc.Razor
var routeValues = context.ActionContext.RouteData.Values;
var controller = routeValues.GetValueOrDefault<string>(RazorViewEngine.ControllerKey);
// format is "{viewName}:{controllerName}:{areaName}:"
// format is "{viewName}:{isPartial}:{controllerName}:{areaName}:"
keyBuilder.Append(context.ViewName)
.Append(CacheKeySeparator)
.Append(context.IsPartial ? 1 : 0)
.Append(CacheKeySeparator)
.Append(controller);

View File

@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Mvc.Razor
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(viewName));
}
var pageResult = GetRazorPageResult(context, viewName);
var pageResult = GetRazorPageResult(context, viewName, isPartial: false);
return CreateViewEngineResult(pageResult, _viewFactory, isPartial: false);
}
@ -117,7 +117,7 @@ namespace Microsoft.AspNet.Mvc.Razor
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(partialViewName));
}
var pageResult = GetRazorPageResult(context, partialViewName);
var pageResult = GetRazorPageResult(context, partialViewName, isPartial: true);
return CreateViewEngineResult(pageResult, _viewFactory, isPartial: true);
}
@ -130,11 +130,12 @@ namespace Microsoft.AspNet.Mvc.Razor
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(pageName));
}
return GetRazorPageResult(context, pageName);
return GetRazorPageResult(context, pageName, isPartial: true);
}
private RazorPageResult GetRazorPageResult(ActionContext context,
string pageName)
string pageName,
bool isPartial)
{
if (IsApplicationRelativePath(pageName))
{
@ -154,12 +155,13 @@ namespace Microsoft.AspNet.Mvc.Razor
}
else
{
return LocatePageFromViewLocations(context, pageName);
return LocatePageFromViewLocations(context, pageName, isPartial);
}
}
private RazorPageResult LocatePageFromViewLocations(ActionContext context,
string pageName)
string pageName,
bool isPartial)
{
// Initialize the dictionary for the typical case of having controller and action tokens.
var routeValues = context.RouteData.Values;
@ -169,7 +171,7 @@ namespace Microsoft.AspNet.Mvc.Razor
var viewLocations = !string.IsNullOrEmpty(areaName) ? AreaViewLocationFormats :
ViewLocationFormats;
var expanderContext = new ViewLocationExpanderContext(context, pageName);
var expanderContext = new ViewLocationExpanderContext(context, pageName, isPartial);
if (_viewLocationExpanders.Count > 0)
{
expanderContext.Values = new Dictionary<string, string>(StringComparer.Ordinal);

View File

@ -11,22 +11,35 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </summary>
public class ViewLocationExpanderContext
{
/// <summary>
/// Initializes a new instance of <see cref="ViewLocationExpanderContext"/>.
/// </summary>
/// <param name="actionContext">The <see cref="Mvc.ActionContext"/> for the current executing action.</param>
/// <param name="viewName">The view name.</param>
/// <param name="isPartial">Determines if the view being discovered is a partial.</param>
public ViewLocationExpanderContext([NotNull] ActionContext actionContext,
[NotNull] string viewName)
[NotNull] string viewName,
bool isPartial)
{
ActionContext = actionContext;
ViewName = viewName;
IsPartial = isPartial;
}
/// <summary>
/// Gets the <see cref="ActionContext"/> for the current executing action.
/// Gets the <see cref="Mvc.ActionContext"/> for the current executing action.
/// </summary>
public ActionContext ActionContext { get; private set; }
public ActionContext ActionContext { get; }
/// <summary>
/// Gets the view name
/// Gets the view name.
/// </summary>
public string ViewName { get; private set; }
public string ViewName { get; }
/// <summary>
/// Gets a value that determines if a partial view is being discovered.
/// </summary>
public bool IsPartial { get; }
/// <summary>
/// Gets or sets the <see cref="IDictionary{TKey, TValue}"/> that is populated with values as part of

View File

@ -165,6 +165,33 @@ component-content";
Assert.Equal(expected, body.Trim());
}
public static TheoryData ViewLocationExpanders_PassesInIsPartialToViewLocationExpanderContextData
{
get
{
return new TheoryData<string, string>
{
{ "Index", "<expander-view><shared-views>/Shared-Views/ExpanderViews/_ExpanderPartial.cshtml</shared-views></expander-view>" },
{ "Partial", "<shared-views>/Shared-Views/ExpanderViews/_ExpanderPartial.cshtml</shared-views>" }
};
}
}
[Theory]
[MemberData(nameof(ViewLocationExpanders_PassesInIsPartialToViewLocationExpanderContextData))]
public async Task ViewLocationExpanders_PassesInIsPartialToViewLocationExpanderContext(string action, string expected)
{
// Arrange
var server = TestServer.Create(_provider, _app);
var client = server.CreateClient();
// Act
var body = await client.GetStringAsync($"http://localhost/ExpanderViews/{action}");
// Assert
Assert.Equal(expected, body.Trim());
}
public static IEnumerable<object[]> RazorViewEngine_RendersPartialViewsData
{
get

View File

@ -15,10 +15,12 @@ namespace Microsoft.AspNet.Mvc.Razor
{
get
{
yield return new[] { new ViewLocationExpanderContext(GetActionContext(), "test") };
yield return new[] { new ViewLocationExpanderContext(GetActionContext(), "test", isPartial: false) };
yield return new[] { new ViewLocationExpanderContext(GetActionContext(), "test", isPartial: true) };
var areaActionContext = GetActionContext("controller2", "myarea");
yield return new[] { new ViewLocationExpanderContext(areaActionContext, "test2") };
yield return new[] { new ViewLocationExpanderContext(areaActionContext, "test2", isPartial: false) };
yield return new[] { new ViewLocationExpanderContext(areaActionContext, "test2", isPartial: true) };
var actionContext = GetActionContext("controller3", "area3");
var values = new Dictionary<string, string>(StringComparer.Ordinal)
@ -26,11 +28,16 @@ namespace Microsoft.AspNet.Mvc.Razor
{ "culture", "fr" },
{ "theme", "sleek" }
};
var expanderContext = new ViewLocationExpanderContext(actionContext, "test3")
var expanderContext = new ViewLocationExpanderContext(actionContext, "test3", isPartial: false)
{
Values = values
};
yield return new[] { expanderContext };
expanderContext = new ViewLocationExpanderContext(actionContext, "test3", isPartial: true)
{
Values = values
};
yield return new[] { expanderContext };
}
}
@ -71,15 +78,26 @@ namespace Microsoft.AspNet.Mvc.Razor
{
yield return new object[]
{
new ViewLocationExpanderContext(GetActionContext(), "test"),
"test:mycontroller"
new ViewLocationExpanderContext(GetActionContext(), "test", isPartial: false),
"test:0:mycontroller"
};
yield return new object[]
{
new ViewLocationExpanderContext(GetActionContext(), "test", isPartial: true),
"test:1:mycontroller"
};
var areaActionContext = GetActionContext("controller2", "myarea");
yield return new object[]
{
new ViewLocationExpanderContext(areaActionContext, "test2"),
"test2:controller2:myarea"
new ViewLocationExpanderContext(areaActionContext, "test2", isPartial: false),
"test2:0:controller2:myarea"
};
yield return new object[]
{
new ViewLocationExpanderContext(areaActionContext, "test2", isPartial: true),
"test2:1:controller2:myarea"
};
var actionContext = GetActionContext("controller3", "area3");
@ -88,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ "culture", "fr" },
{ "theme", "sleek" }
};
var expanderContext = new ViewLocationExpanderContext(actionContext, "test3")
var expanderContext = new ViewLocationExpanderContext(actionContext, "test3", isPartial: false)
{
Values = values
};
@ -96,7 +114,17 @@ namespace Microsoft.AspNet.Mvc.Razor
yield return new object[]
{
expanderContext,
"test3:controller3:area3:culture:fr:theme:sleek"
"test3:0:controller3:area3:culture:fr:theme:sleek"
};
expanderContext = new ViewLocationExpanderContext(actionContext, "test3", isPartial: true)
{
Values = values
};
yield return new object[]
{
expanderContext,
"test3:1:controller3:area3:culture:fr:theme:sleek"
};
}
}

View File

@ -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 Microsoft.AspNet.Mvc;
namespace RazorWebSite.Controllers
{
public class ExpanderViewsController : Controller
{
// This result discovers the Index.cshtml from /View but the partial is executed from /Shared-Views
public ViewResult Index()
{
return View();
}
public PartialViewResult Partial()
{
return PartialView("_ExpanderPartial");
}
}
}

View File

@ -0,0 +1,35 @@
// 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 Microsoft.AspNet.Mvc.Razor;
namespace RazorWebSite
{
public class CustomPartialDirectoryViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context)
{
}
public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context,
IEnumerable<string> viewLocations)
{
if (context.IsPartial)
{
return ExpandViewLocationsCore(viewLocations);
}
return viewLocations;
}
private IEnumerable<string> ExpandViewLocationsCore(IEnumerable<string> viewLocations)
{
foreach (var location in viewLocations)
{
yield return "/Shared-Views/{1}/{0}.cshtml";
yield return location;
}
}
}
}

View File

@ -0,0 +1,3 @@
@{
throw new Exception("This view should not be executed");
}

View File

@ -0,0 +1 @@
<shared-views>@ViewContext.View.Path</shared-views>

View File

@ -27,6 +27,7 @@ namespace RazorWebSite
var expander = new LanguageViewLocationExpander(
context => context.HttpContext.Request.Query["language-expander-value"]);
options.ViewLocationExpanders.Add(expander);
options.ViewLocationExpanders.Add(new CustomPartialDirectoryViewLocationExpander());
});
});

View File

@ -0,0 +1 @@
<expander-view>@Html.Partial("_ExpanderPartial")</expander-view>