Adding URL generation to WebFX for controllers and views
This follows a similar pattern to html helpers - a minimal basis interface that performs the main functionality, and a set of extension methods that make up the rich API.
This commit is contained in:
parent
9af7c2bbfb
commit
0ce2c511d4
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
|
namespace MvcSample
|
||||||
|
{
|
||||||
|
public class LinkController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult Details()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string About()
|
||||||
|
{
|
||||||
|
return Url.Action(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Get()
|
||||||
|
{
|
||||||
|
return Url.Route(new { controller = "Home", action = "Details" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,6 +49,7 @@ namespace MvcSample
|
||||||
new { controller = "Home" });
|
new { controller = "Home" });
|
||||||
|
|
||||||
builder.UseRouter(routes);
|
builder.UseRouter(routes);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
|
@Url.Action("About")
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNet.Abstractions;
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
using Microsoft.AspNet.Routing;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class ActionContext
|
public class ActionContext
|
||||||
{
|
{
|
||||||
public ActionContext(HttpContext httpContext, IDictionary<string, object> routeValues, ActionDescriptor actionDescriptor)
|
public ActionContext(HttpContext httpContext, IRouter router, IDictionary<string, object> routeValues, ActionDescriptor actionDescriptor)
|
||||||
{
|
{
|
||||||
HttpContext = httpContext;
|
HttpContext = httpContext;
|
||||||
|
Router = router;
|
||||||
RouteValues = routeValues;
|
RouteValues = routeValues;
|
||||||
ActionDescriptor = actionDescriptor;
|
ActionDescriptor = actionDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpContext HttpContext { get; private set; }
|
public HttpContext HttpContext { get; private set; }
|
||||||
|
|
||||||
|
public IRouter Router { get; private set; }
|
||||||
|
|
||||||
public IDictionary<string, object> RouteValues { get; private set; }
|
public IDictionary<string, object> RouteValues { get; private set; }
|
||||||
|
|
||||||
public ActionDescriptor ActionDescriptor { get; private set; }
|
public ActionDescriptor ActionDescriptor { get; private set; }
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
string locationsText = String.Join(Environment.NewLine, result.SearchedLocations);
|
string locationsText = String.Join(Environment.NewLine, result.SearchedLocations);
|
||||||
const string message = @"The view '{0}' was not found. The following locations were searched:{1}.";
|
const string message = @"The view '{0}' was not found. The following locations were searched:{1}.";
|
||||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, message, viewName, locationsText));
|
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, message, viewName, locationsText));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.View;
|
return result.View;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public HttpContext Context { get; set; }
|
public HttpContext Context { get; set; }
|
||||||
|
|
||||||
|
public IRenderUrl Url { get; set; }
|
||||||
|
|
||||||
public ViewData<object> ViewData { get; set; }
|
public ViewData<object> ViewData { get; set; }
|
||||||
|
|
||||||
public dynamic ViewBag
|
public dynamic ViewBag
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
Action = action,
|
Action = action,
|
||||||
};
|
};
|
||||||
var actionContext = new ActionContext(context.HttpContext, context.RouteValues, action);
|
var actionContext = new ActionContext(context.HttpContext, null, context.RouteValues, action);
|
||||||
var actionBindingContext = await _bindingProvider.GetActionBindingContextAsync(actionContext);
|
var actionBindingContext = await _bindingProvider.GetActionBindingContextAsync(actionContext);
|
||||||
|
|
||||||
foreach (var parameter in action.Parameters.Where(p => p.ParameterBindingInfo != null))
|
foreach (var parameter in action.Parameters.Where(p => p.ParameterBindingInfo != null))
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Reflection;
|
||||||
using Microsoft.AspNet.Abstractions;
|
using Microsoft.AspNet.Abstractions;
|
||||||
using Microsoft.AspNet.DependencyInjection;
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNet.Routing;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -58,6 +59,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
prop.SetValue(controller, modelState);
|
prop.SetValue(controller, modelState);
|
||||||
}
|
}
|
||||||
|
else if (prop.Name == "Url" && prop.PropertyType == typeof(IRenderUrl))
|
||||||
|
{
|
||||||
|
var generator = new DefaultRenderUrl(
|
||||||
|
actionContext.HttpContext,
|
||||||
|
actionContext.Router,
|
||||||
|
actionContext.RouteValues);
|
||||||
|
|
||||||
|
prop.SetValue(controller, generator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var method = controllerType.GetRuntimeMethods().FirstOrDefault(m => m.Name.Equals("Initialize", StringComparison.OrdinalIgnoreCase));
|
var method = controllerType.GetRuntimeMethods().FirstOrDefault(m => m.Name.Equals("Initialize", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
@ -72,6 +82,5 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
method.Invoke(controller, args);
|
method.Invoke(controller, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
using Microsoft.AspNet.Routing;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class DefaultRenderUrl : IRenderUrl
|
||||||
|
{
|
||||||
|
private readonly HttpContext _httpContext;
|
||||||
|
private readonly IRouter _router;
|
||||||
|
private readonly IDictionary<string, object> _ambientValues;
|
||||||
|
|
||||||
|
public DefaultRenderUrl(HttpContext httpContext, IRouter router, IDictionary<string, object> ambientValues)
|
||||||
|
{
|
||||||
|
_httpContext = httpContext;
|
||||||
|
_router = router;
|
||||||
|
_ambientValues = ambientValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Action(string action, string controller, object values)
|
||||||
|
{
|
||||||
|
var valuesDictionary = new RouteValueDictionary(values);
|
||||||
|
|
||||||
|
if (action != null)
|
||||||
|
{
|
||||||
|
valuesDictionary["action"] = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller != null)
|
||||||
|
{
|
||||||
|
valuesDictionary["controller"] = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RouteCore(valuesDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Route(object values)
|
||||||
|
{
|
||||||
|
return RouteCore(new RouteValueDictionary(values));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string RouteCore(IDictionary<string, object> values)
|
||||||
|
{
|
||||||
|
var context = new VirtualPathContext(_httpContext, _ambientValues, values);
|
||||||
|
var path = _router.GetVirtualPath(context);
|
||||||
|
|
||||||
|
// We need to add the host part in here, currently blocked on http abstractions support.
|
||||||
|
// The intent is to use full URLs by default.
|
||||||
|
return _httpContext.Request.PathBase + path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var actionContext = new ActionContext(context.HttpContext, context.Values, actionDescriptor);
|
var actionContext = new ActionContext(context.HttpContext, context.Router, context.Values, actionDescriptor);
|
||||||
var invoker = ActionInvokerFactory.CreateInvoker(actionContext);
|
var invoker = ActionInvokerFactory.CreateInvoker(actionContext);
|
||||||
if (invoker == null)
|
if (invoker == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Abstractions;
|
using Microsoft.AspNet.Abstractions;
|
||||||
using Microsoft.AspNet.DependencyInjection;
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -17,10 +16,14 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
protected TextWriter Output { get; set; }
|
protected TextWriter Output { get; set; }
|
||||||
|
|
||||||
|
public IRenderUrl Url { get; set; }
|
||||||
|
|
||||||
private string BodyContent { get; set; }
|
private string BodyContent { get; set; }
|
||||||
|
|
||||||
public virtual async Task RenderAsync(ViewContext context, TextWriter writer)
|
public virtual async Task RenderAsync(ViewContext context, TextWriter writer)
|
||||||
{
|
{
|
||||||
|
Url = context.RenderUrl;
|
||||||
|
|
||||||
var contentBuilder = new StringBuilder(1024);
|
var contentBuilder = new StringBuilder(1024);
|
||||||
using (var bodyWriter = new StringWriter(contentBuilder))
|
using (var bodyWriter = new StringWriter(contentBuilder))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -17,6 +16,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
public HtmlHelper<TModel> Html { get; set; }
|
public HtmlHelper<TModel> Html { get; set; }
|
||||||
|
|
||||||
|
public IRenderUrl RenderUrl { get; set; }
|
||||||
|
|
||||||
public override Task RenderAsync(ViewContext context, TextWriter writer)
|
public override Task RenderAsync(ViewContext context, TextWriter writer)
|
||||||
{
|
{
|
||||||
var viewData = context.ViewData as ViewData<TModel>;
|
var viewData = context.ViewData as ViewData<TModel>;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public interface IRenderUrl
|
||||||
|
{
|
||||||
|
string Action(string action, string controller, object values);
|
||||||
|
|
||||||
|
string Route(object values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public static class RenderUrlExtension
|
||||||
|
{
|
||||||
|
public static string Action(this IRenderUrl generator)
|
||||||
|
{
|
||||||
|
return generator.Action(null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Action(this IRenderUrl generator, string action)
|
||||||
|
{
|
||||||
|
return generator.Action(action, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Action(this IRenderUrl generator, string action, object values)
|
||||||
|
{
|
||||||
|
return generator.Action(action, null, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Action(this IRenderUrl generator, string action, string controller)
|
||||||
|
{
|
||||||
|
return generator.Action(action, controller, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue