gpt4 book ai didi

c# - 在ASP.Net Core 2.2 MVC中使用端点路由时,top如何正确覆盖IUrlHelper?

转载 作者:行者123 更新时间:2023-11-30 16:37:21 27 4
gpt4 key购买 nike

我需要重写ASP.NET Core 2.2项目中的UrlHelper实现。

我创建了一个名为MyUrlHelper的类,该类覆盖了UrlHelper类,如下所示

public class MyUrlHelper : UrlHelper
{
public MyUrlHelper(ActionContext actionContext)
: base(actionContext)
{
}

public override string Content(string contentPath)
{
// do something new...

return base.Content(contentPath);
}
}


然后,我创建了一个名为 MyUrlHelperFactory的类,该类实现了 IUrlHelperFactory接口,如下所示

public class MyUrlHelperFactory : IUrlHelperFactory
{
public IUrlHelper GetUrlHelper(ActionContext context)
{
return new MyUrlHelper(context);
}
}


最后,我尝试通过在 Startup.ConfigureServices()行之后的 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)方法中添加以下行来替换DI容器中的实现。

但这引发了以下错误


  处理请求时发生未处理的异常。
  ArgumentOutOfRangeException:索引超出范围。必须为非负数并且小于集合的大小。


这是堆栈跟踪

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

System.Collections.Generic.List<T>.get_Item(int index)
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.get_Router()
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.GetVirtualPathData(string routeName, RouteValueDictionary values)
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.Action(UrlActionContext actionContext)
Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, string action, string controller, object values, string protocol, string host, string fragment)
Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateActionLink(ViewContext viewContext, string linkText, string actionName, string controllerName, string protocol, string hostname, string fragment, object routeValues, object htmlAttributes)
Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper.Process(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.RunAsync(TagHelperExecutionContext executionContext)
AspNetCore.Views_Shared__Layout.<ExecuteAsync>b__44_1()
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
AspNetCore.Views_Shared__Layout.ExecuteAsync()
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync(ViewContext context, ViewBufferTextWriter bodyWriter)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync<TFilter, TFilterAsync>()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)


但是,如果禁用框架中的“端点路由”功能,则不会收到任何错误。但是,我想使用端点路由。如何在不禁用端点路由的情况下正确覆盖UrlHelper的实现?

这是我禁用端点路由的方法

services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

最佳答案

微软对UrlHelperFactory的实现告诉我,端点路由有一个不同的url-helper类。

如果仅在使用端点路由时要覆盖UrlHelper,则需要覆盖EndpointRoutingUrlHelper类而不是UrlHelper。为了安全起见,您可能要覆盖这两个类。

不幸的是,AspNet团队将EndpointRoutingUrlHelper类声明为内部类,因此您不能直接覆盖它。那并不意味着我们不能复制源代码:)

无论如何,要覆盖UrlHelper,首先要创建我们自己的版本的端点路由帮助器(即MyEndpointRoutingUrlHelper

public class MyEndpointRoutingUrlHelper : UrlHelperBase
{
private readonly LinkGenerator _linkGenerator;

public MyEndpointRoutingUrlHelper(
ActionContext actionContext,
LinkGenerator linkGenerator)
: base(actionContext)
{
_linkGenerator = linkGenerator ?? throw new ArgumentNullException(nameof(linkGenerator));
}

public override string Action(UrlActionContext urlActionContext)
{
if (urlActionContext == null)
{
throw new ArgumentNullException(nameof(urlActionContext));
}

var values = GetValuesDictionary(urlActionContext.Values);

if (urlActionContext.Action != null)
{
values["action"] = urlActionContext.Action;

}
else if (!values.ContainsKey("action") && AmbientValues.TryGetValue("action", out var action))
{
values["action"] = action;
}

if (urlActionContext.Controller != null)
{
values["controller"] = urlActionContext.Controller;
}
else if (!values.ContainsKey("controller") && AmbientValues.TryGetValue("controller", out var controller))
{
values["controller"] = controller;
}

var path = _linkGenerator.GetPathByRouteValues(
ActionContext.HttpContext,
routeName: null,
values,
fragment: new FragmentString(urlActionContext.Fragment == null ? null : "#" + urlActionContext.Fragment));

return GenerateUrl(urlActionContext.Protocol, urlActionContext.Host, path);
}

public override string RouteUrl(UrlRouteContext routeContext)
{
if (routeContext == null)
{
throw new ArgumentNullException(nameof(routeContext));
}

var path = _linkGenerator.GetPathByRouteValues(
ActionContext.HttpContext,
routeContext.RouteName,
routeContext.Values,
fragment: new FragmentString(routeContext.Fragment == null ? null : "#" + routeContext.Fragment));

return GenerateUrl(routeContext.Protocol, routeContext.Host, path);
}

public override string Content(string contentPath)
{
// override this method how you see fit

return base.Content(contentPath);
}
}


现在,使用我们自己的url-helpers实现 IUrlHelperFactory

public class MyUrlHelperFactory : IUrlHelperFactory
{
public IUrlHelper GetUrlHelper(ActionContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}

var httpContext = context.HttpContext;

if (httpContext == null)
{
throw new ArgumentException(nameof(context.HttpContext));
}

if (httpContext.Items == null)
{
throw new ArgumentException(nameof(context.HttpContext.Items));
}

// Perf: Create only one UrlHelper per context
if (httpContext.Items.TryGetValue(typeof(IUrlHelper), out var value) && value is IUrlHelper)
{
return (IUrlHelper)value;
}

IUrlHelper urlHelper;
var endpointFeature = httpContext.Features.Get<IEndpointFeature>();
if (endpointFeature?.Endpoint != null)
{
var services = httpContext.RequestServices;
var linkGenerator = services.GetRequiredService<LinkGenerator>();

urlHelper = new MyEndpointRoutingUrlHelper(context, linkGenerator);
}
else
{
urlHelper = new MyUrlHelper(context);
}

httpContext.Items[typeof(IUrlHelper)] = urlHelper;

return urlHelper;
}
}


最后,在 Startup.ConfigureServices(...)方法中,在 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);行之后

添加此行以覆盖已注册的 IUrlHelperFactory实现。

services.Replace(new ServiceDescriptor(typeof(IUrlHelperFactory), new MyUrlHelperFactory()));


我希望这有帮助

关于c# - 在ASP.Net Core 2.2 MVC中使用端点路由时,top如何正确覆盖IUrlHelper?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58699761/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com