asp.net html action,c# - @Html.Action in Asp.Net Core - Stack Overflow

Update: As of 2.2.2 HttpContextAccessor keep the context in an object (supposedly to prevent inter request mix up) and it impacts the current solution... So you need to provide the following implementation for IHttpContextAccessor (an old version) and register it as a singleton:

public class HttpContextAccessor : IHttpContextAccessor

{

private static AsyncLocal _httpContextCurrent = new AsyncLocal();

HttpContext IHttpContextAccessor.HttpContext { get => _httpContextCurrent.Value; set => _httpContextCurrent.Value = value; }

}

For asp.net core 2

using Microsoft.AspNetCore.Html;

using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Mvc.Infrastructure;

using Microsoft.AspNetCore.Routing;

using Microsoft.Extensions.DependencyInjection;

using System;

using System.IO;

using System.Threading.Tasks;

namespace Microsoft.AspNetCore.Mvc.Rendering

{

public static class HtmlHelperViewExtensions

{

public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)

{

var controller = (string)helper.ViewContext.RouteData.Values["controller"];

return Action(helper, action, controller, parameters);

}

public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)

{

var area = (string)helper.ViewContext.RouteData.Values["area"];

return Action(helper, action, controller, area, parameters);

}

public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)

{

if (action == null)

throw new ArgumentNullException("action");

if (controller == null)

throw new ArgumentNullException("controller");

var task = RenderActionAsync(helper, action, controller, area, parameters);

return task.Result;

}

private static async Task RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)

{

// fetching required services for invocation

var serviceProvider = helper.ViewContext.HttpContext.RequestServices;

var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService();

var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService();

var actionSelector = serviceProvider.GetRequiredService();

// creating new action invocation context

var routeData = new RouteData();

foreach (var router in helper.ViewContext.RouteData.Routers)

{

routeData.PushState(router, null, null);

}

routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);

routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);

//get the actiondescriptor

RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };

var candidates = actionSelector.SelectCandidates(routeContext);

var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);

var originalActionContext = actionContextAccessor.ActionContext;

var originalhttpContext = httpContextAccessor.HttpContext;

try

{

var newHttpContext = serviceProvider.GetRequiredService().Create(helper.ViewContext.HttpContext.Features);

if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))

{

newHttpContext.Items.Remove(typeof(IUrlHelper));

}

newHttpContext.Response.Body = new MemoryStream();

var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);

actionContextAccessor.ActionContext = actionContext;

var invoker = serviceProvider.GetRequiredService().CreateInvoker(actionContext);

await invoker.InvokeAsync();

newHttpContext.Response.Body.Position = 0;

using (var reader = new StreamReader(newHttpContext.Response.Body))

{

return new HtmlString(reader.ReadToEnd());

}

}

catch (Exception ex)

{

return new HtmlString(ex.Message);

}

finally

{

actionContextAccessor.ActionContext = originalActionContext;

httpContextAccessor.HttpContext = originalhttpContext;

if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))

{

helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));

}

}

}

}

}

It is based on Aries response. I corrected what wasn't compiling for 2.0 and I added a couple of tweaks. There are 2 glorified static values for the current httpcontext and the current actioncontext. The one for httpcontext is set in IHttpContextFactory.Create and I set the one for actioncontext in the code. Note that depending on the features you use IActionContextAccessor and IHttpContextAccessor may not be registered by default, so you may need to add them in your startup:

services.AddSingleton();

services.AddSingleton();

HttpContext is just a wrapper around HttpContext.Features, so if you change something in one, it also changes in the other... I reset what I know about in the finally of the try/catch.

I removed the IUrlHelper from the Items cache since this value will be reused even if the actionContext to build the urlHelper is different(IUrlHelperFactory.GetUrlHelper).

Asp.net core 2.0 assumes you won't do this, there is a good chance there are other cached things, so I recommend to be careful when using this and just don't if you don't need to.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值