Areas feature - Phase I
1. Areas defined by the Area attribute 2. Areas are a routeconstraint on the actiondescriptor 3. Areas find pages through route values Other changes: 1. Remove Path from ActionDescriptor - It doesn't make sense with this change 2. Add sample Area
This commit is contained in:
parent
072e2cc1f1
commit
cfb06c0de3
|
|
@ -0,0 +1,13 @@
|
|||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace MvcSample.Web
|
||||
{
|
||||
[Area("Travel")]
|
||||
public class Flight : Controller
|
||||
{
|
||||
public IActionResult Fly()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
@using MvcSample.Web.Models
|
||||
@model User
|
||||
@{
|
||||
Layout = "/Views/Shared/_Layout.cshtml";
|
||||
ViewBag.Title = "This is the FLY action";
|
||||
}
|
||||
|
||||
<div class="jumbotron">
|
||||
<h1>ASP.NET</h1>
|
||||
<p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
|
||||
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more »</a></p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<h2>Getting started</h2>
|
||||
<p>
|
||||
ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
|
||||
enables a clean separation of concerns and gives you full control over markup
|
||||
for enjoyable, agile development.
|
||||
</p>
|
||||
<p><a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkId=301865">Learn more »</a></p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h2>Get more libraries</h2>
|
||||
<p>NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.</p>
|
||||
<p><a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkId=301866">Learn more »</a></p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h2>Web Hosting</h2>
|
||||
<p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
|
||||
<p><a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkId=301867">Learn more »</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -31,6 +31,9 @@ namespace MvcSample.Web
|
|||
DefaultHandler = new MvcApplication(serviceProvider),
|
||||
};
|
||||
|
||||
// TODO: Add support for route constraints, so we can potentially constrain by existing routes
|
||||
routes.MapRoute("{area}/{controller}/{action}");
|
||||
|
||||
routes.MapRoute(
|
||||
"{controller}/{action}",
|
||||
new { controller = "Home", action = "Index" });
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@
|
|||
@RenderBody()
|
||||
<hr />
|
||||
<address>
|
||||
@Model.Address
|
||||
@if (@Model != null)
|
||||
{
|
||||
@Model.Address
|
||||
}
|
||||
</address>
|
||||
<footer>
|
||||
<p>© @DateTime.Now.Year - My ASP.NET Application</p>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,8 @@ using System.Diagnostics;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
[DebuggerDisplay("{Path}:{Name}")]
|
||||
public class ActionDescriptor
|
||||
{
|
||||
public virtual string Path { get; set; }
|
||||
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
public List<RouteDataActionConstraint> RouteConstraints { get; set; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
public class AreaAttribute : RouteConstraintAttribute
|
||||
{
|
||||
public AreaAttribute(string areaName)
|
||||
: base("area", areaName, blockNonAttributedActions: true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(areaName))
|
||||
{
|
||||
throw new ArgumentException("Area name must not be empty", "areaName");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ReflectedRouteConstraintsActionDescriptorProvider : IActionDescriptorProvider
|
||||
{
|
||||
public int Order
|
||||
{
|
||||
get { return ReflectedActionDescriptorProvider.DefaultOrder + 100; }
|
||||
}
|
||||
|
||||
public void Invoke([NotNull]ActionDescriptorProviderContext context, Action callNext)
|
||||
{
|
||||
var removalConstraints = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Iterate all the Reflected Action Descriptor providers and add area or other route constraints
|
||||
if (context.Results != null)
|
||||
{
|
||||
foreach (var actionDescriptor in context.Results.OfType<ReflectedActionDescriptor>())
|
||||
{
|
||||
var routeConstraints = actionDescriptor.
|
||||
ControllerDescriptor.
|
||||
ControllerTypeInfo.
|
||||
GetCustomAttributes<RouteConstraintAttribute>().
|
||||
ToArray();
|
||||
|
||||
foreach (var routeConstraint in routeConstraints)
|
||||
{
|
||||
if (routeConstraint.BlockNonAttributedActions)
|
||||
{
|
||||
removalConstraints.Add(routeConstraint.RouteKey);
|
||||
}
|
||||
|
||||
// Skip on duplicates
|
||||
if (!ContainsKey(actionDescriptor, routeConstraint.RouteKey))
|
||||
{
|
||||
actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
|
||||
routeConstraint.RouteKey, routeConstraint.RouteValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var actionDescriptor in context.Results.OfType<ReflectedActionDescriptor>())
|
||||
{
|
||||
foreach (var key in removalConstraints)
|
||||
{
|
||||
if (!ContainsKey(actionDescriptor, key))
|
||||
{
|
||||
actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(key, RouteKeyHandling.DenyKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callNext();
|
||||
}
|
||||
|
||||
private bool ContainsKey(ActionDescriptor actionDescript, string routeKey)
|
||||
{
|
||||
return actionDescript.RouteConstraints.Any(rc => string.Equals(rc.RouteKey, routeKey, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using System.Reflection;
|
|||
using Microsoft.AspNet.Abstractions;
|
||||
using Microsoft.AspNet.DependencyInjection;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
|
|||
|
|
@ -7,18 +7,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
[DebuggerDisplay("CA {Path}:{Name}(RC-{RouteConstraints.Count})")]
|
||||
public class ReflectedActionDescriptor : ActionDescriptor
|
||||
{
|
||||
public override string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return ControllerDescriptor.Name;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new InvalidOperationException("Cannot override path");
|
||||
}
|
||||
}
|
||||
|
||||
public string ControllerName
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public class ReflectedActionDescriptorProvider : IActionDescriptorProvider
|
||||
{
|
||||
public static readonly int DefaultOrder = 0;
|
||||
|
||||
private readonly IControllerAssemblyProvider _controllerAssemblyProvider;
|
||||
private readonly IActionDiscoveryConventions _conventions;
|
||||
private readonly IControllerDescriptorFactory _controllerDescriptorFactory;
|
||||
|
|
@ -30,7 +32,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public int Order
|
||||
{
|
||||
get { return 0; }
|
||||
get { return DefaultOrder; }
|
||||
}
|
||||
|
||||
public void Invoke(ActionDescriptorProviderContext context, Action callNext)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public abstract class RouteConstraintAttribute : Attribute
|
||||
{
|
||||
protected RouteConstraintAttribute([NotNull]string routeKey, [NotNull]string routeValue, bool blockNonAttributedActions)
|
||||
{
|
||||
RouteKey = routeKey;
|
||||
RouteValue = routeValue;
|
||||
BlockNonAttributedActions = blockNonAttributedActions;
|
||||
}
|
||||
|
||||
public string RouteKey { get; private set; }
|
||||
public string RouteValue { get; private set; }
|
||||
public bool BlockNonAttributedActions { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
internal static class DictionaryExtensions
|
||||
{
|
||||
public static T GetValueOrDefault<T>([NotNull] this IDictionary<string, object> dictionary, [NotNull] string key)
|
||||
{
|
||||
object valueAsObject;
|
||||
if (dictionary.TryGetValue(key, out valueAsObject))
|
||||
{
|
||||
if (valueAsObject is T)
|
||||
{
|
||||
return (T)valueAsObject;
|
||||
}
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
private static readonly string[] _viewLocationFormats =
|
||||
{
|
||||
"/Areas/{2}/Views/{1}/{0}.cshtml",
|
||||
"/Areas/{2}/Views/Shared/{0}.cshtml",
|
||||
"/Views/{1}/{0}.cshtml",
|
||||
"/Views/Shared/{0}.cshtml",
|
||||
};
|
||||
|
|
@ -30,8 +32,6 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
var actionContext = (ActionContext)context;
|
||||
|
||||
// TODO: We plan to change this on the next CR, so we don't have a strong depenedency directly on the specific
|
||||
// type of the action descriptor
|
||||
var actionDescriptor = actionContext.ActionDescriptor;
|
||||
|
||||
if (actionDescriptor == null)
|
||||
|
|
@ -59,11 +59,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
else
|
||||
{
|
||||
var controllerName = actionDescriptor.Path;
|
||||
var controllerName = actionContext.RouteValues.GetValueOrDefault<string>("controller");
|
||||
var areaName = actionContext.RouteValues.GetValueOrDefault<string>("area");
|
||||
|
||||
var searchedLocations = new List<string>(_viewLocationFormats.Length);
|
||||
for (int i = 0; i < _viewLocationFormats.Length; i++)
|
||||
{
|
||||
string path = String.Format(CultureInfo.InvariantCulture, _viewLocationFormats[i], viewName, controllerName);
|
||||
string path = String.Format(CultureInfo.InvariantCulture, _viewLocationFormats[i], viewName, controllerName, areaName);
|
||||
IView view = await _virtualPathFactory.CreateInstance(path);
|
||||
if (view != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
yield return describe.Transient<INestedProvider<ActionDescriptorProviderContext>,
|
||||
ReflectedActionDescriptorProvider>();
|
||||
yield return describe.Transient<INestedProvider<ActionDescriptorProviderContext>,
|
||||
ReflectedRouteConstraintsActionDescriptorProvider>();
|
||||
yield return describe.Transient<INestedProvider<ActionInvokerProviderContext>,
|
||||
ReflectedActionInvokerProvider>();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue