@ Html.Action в Core Asp.Net
Где @Html.Action
в Asp.net Core? Я вижу @Html.ActionLink
но не прямой вызов Action, как раньше.
Был ли он заменен на ViewComponents?
- {version} в MVC4 Bundle
- Как заставить ELMAH работать с атрибутом ASP.NET MVC ?
- Вы должны добавить ссылку на System.Runtime
- Атрибуты HttpPost и HttpGet в MVC: зачем использовать HttpPost?
- Использует ViewBag в MVC плохо?
- Устранение проблем с анти-подделкой
- Как определить метод в Razor?
- Проблемы с выбором значений в ListBoxFor
- RenderAction RenderPartial
- Как сделать частичный элемент формы с помощью AJAX
- Глификон Bootstrap, не отображающийся в форме
- Должно ли быть имя параметра?
- Можно ли получить доступ к объекту MVC ViewBag из файла Javascript?
Да, ViewComponents – это новый способ сделать это, но они не совсем то же самое, что и @Html.Action
чем @Html.Action
, хотя … например, в MVC5 и ранее, вызывая «дочерние действия», также выполняли бы любые фильтры (например, если у controllerа были фильтры, украшенные на них), давая им внешний вид как обычные действия … но это не так для ViewComponents, и они выполняются в контексте фактического запроса …
Дополнительная информация о компонентах просмотра: http://www.asp.net/vnext/overview/aspnet-vnext/vc#intro
Обновить: ссылка изменена на
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components
ViewComponents великолепны, но не так хороши для Ajax.
Если вы действительно пропустите метод @ Html.RenderAction, то вот краткая реализация, которую я выбрал для AspNetCore.
using System; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Routing; namespace Microsoft.AspNetCore.Mvc.Rendering { public static class HtmlHelperViewExtensions { public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, object parameters = null) { var controller = (string)helper.ViewContext.RouteData.Values["controller"]; return RenderAction(helper, action, controller, parameters); } public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, string controller, object parameters = null) { var area = (string)helper.ViewContext.RouteData.Values["area"]; return RenderAction(helper, action, controller, area, parameters); } public static IHtmlContent RenderAction(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"); if (area == null) throw new ArgumentNullException("area"); 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 currentHttpContext = helper.ViewContext?.HttpContext; var httpContextFactory = GetServiceOrFail(currentHttpContext); var actionInvokerFactory = GetServiceOrFail(currentHttpContext); var actionSelector = GetServiceOrFail(currentHttpContext); // creating new action invocation context var routeData = new RouteData(); var routeParams = new RouteValueDictionary(parameters ?? new { }); var routeValues = new RouteValueDictionary(new { area = area, controller = controller, action = action }); var newHttpContext = httpContextFactory.Create(currentHttpContext.Features); newHttpContext.Response.Body = new MemoryStream(); foreach (var router in helper.ViewContext.RouteData.Routers) routeData.PushState(router, null, null); routeData.PushState(null, routeValues, null); routeData.PushState(null, routeParams, null); var actionDescriptor = actionSelector.DecisionTree.Select(routeValues).First(); var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor); // invoke action and retreive the response body var invoker = actionInvokerFactory.CreateInvoker(actionContext); string content = null; await invoker.InvokeAsync().ContinueWith(task => { if (task.IsFaulted) { content = task.Exception.Message; } else if (task.IsCompleted) { newHttpContext.Response.Body.Position = 0; using (var reader = new StreamReader(newHttpContext.Response.Body)) content = reader.ReadToEnd(); } }); return new HtmlString(content); } private static TService GetServiceOrFail(HttpContext httpContext) { if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); var service = httpContext.RequestServices.GetService(typeof(TService)); if (service == null) throw new InvalidOperationException($"Could not locate service: {nameof(TService)}"); return (TService)service; } } }
Вы можете вызвать из своего представления один из следующих способов:
@Html.RenderAction("action", "controller", "area", new { id = 1}) @Html.RenderAction("action", "controller", new { id = 1}) @Html.RenderAction("action", new { id = 1})
Заметка:
Имя controllerа и, при необходимости, имя области, по умолчанию будут соответствовать соответствующим значениям из ActionContext, если они не указаны.
Для ядра asp.net 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)); } } } } }
Он основан на реакции Овна. Я исправил то, что не компилировалось для 2.0, и я добавил пару настроек. Есть 2 прославленных статических значения для текущего httpcontext и текущего контекста actioncontext. Тот, который для httpcontext установлен в IHttpContextFactory.Create
и я устанавливаю значение для контекста textcontext в коде.
HttpContext – это всего лишь shell вокруг HttpContext.Features
, поэтому, если вы что-то меняете в одном, это также изменяется в другом … Я возвращаю то, что я знаю в конце try / catch.
Я удалил IUrlHelper
из кеша Items, поскольку это значение будет повторно использоваться, даже если actionContext для сборки urlHelper отличается ( IUrlHelperFactory.GetUrlHelper
).
Asp.net core 2.0 предполагает, что вы этого не сделаете, есть хорошие шансы, что есть другие кешированные вещи, поэтому я рекомендую быть осторожным при использовании этого и просто не делать этого, если вам не нужно.
Для Net Core 2.0
using Microsoft.AspNetCore.Mvc.Infrastructure;
замещать
// var actionSelector = GetServiceOrFail(currentHttpContext); var actionSelector = GetServiceOrFail(currentHttpContext);
а также
// var actionDescriptor = actionSelector.DecisionTree.Select(routeValues).First(); var actionDescriptor = actionSelector.ActionDescriptors.Items.Where(i => i.RouteValues["Controller"] == controller && i.RouteValues["Action"] == action).First();
Обходное решение от Aries для расширения помощника более не работает для Net Core 2.0, поскольку IActionSelectorDecisionTreeProvider удален из новой версии. См. Ссылку ниже.
https://github.com/Microsoft/aspnet-api-versioning/issues/154
Я использовал коды людей на этой странице, чтобы получить правильный результат.
https://stackoverflow.com/a/39951006/6778726
https://stackoverflow.com/a/46859170/6778726
Например, в старом classе при выполнении следующего кода отображается ошибка
@Html.RenderAction("About", "Home")
Исправлен следующий код :
using System; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Routing; namespace Microsoft.AspNetCore.Mvc.Rendering { public static class HtmlHelperViewExtensions { public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, object parameters = null) { var controller = (string)helper.ViewContext.RouteData.Values["controller"]; return RenderAction(helper, action, controller, parameters); } public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, string controller, object parameters = null) { var area = (string)helper.ViewContext.RouteData.Values["area"]; return RenderAction(helper, action, controller, area, parameters); } public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, string controller, string area, object parameters = null) { if (action == null) throw new ArgumentNullException(nameof(controller)); if (controller == null) throw new ArgumentNullException(nameof(action)); 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 currentHttpContext = helper.ViewContext.HttpContext; var httpContextFactory = GetServiceOrFail(currentHttpContext); var actionInvokerFactory = GetServiceOrFail(currentHttpContext); var actionSelector = GetServiceOrFail(currentHttpContext); // creating new action invocation context var routeData = new RouteData(); var routeParams = new RouteValueDictionary(parameters ?? new { }); var routeValues = new RouteValueDictionary(new { area, controller, action }); var newHttpContext = httpContextFactory.Create(currentHttpContext.Features); newHttpContext.Response.Body = new MemoryStream(); foreach (var router in helper.ViewContext.RouteData.Routers) routeData.PushState(router, null, null); routeData.PushState(null, routeValues, null); routeData.PushState(null, routeParams, null); var actionDescriptor = actionSelector.ActionDescriptors.Items.First(i => i.RouteValues["Controller"] == controller && i.RouteValues["Action"] == action); var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor); // invoke action and retreive the response body var invoker = actionInvokerFactory.CreateInvoker(actionContext); string content = null; await invoker.InvokeAsync().ContinueWith(task => { if (task.IsFaulted) { content = task.Exception.Message; } else if (task.IsCompleted) { newHttpContext.Response.Body.Position = 0; using (var reader = new StreamReader(newHttpContext.Response.Body)) content = reader.ReadToEnd(); } }); return new HtmlString(content); } private static TService GetServiceOrFail(HttpContext httpContext) { if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); var service = httpContext.RequestServices.GetService(typeof(TService)); if (service == null) throw new InvalidOperationException($"Could not locate service: {nameof(TService)}"); return (TService)service; } } }
Следующие примеры были успешно протестированы:
@Html.RenderAction("About") @Html.RenderAction("About", "Home") @Html.RenderAction("About", new { data1 = "test1", data2 = "test2" }) @Html.RenderAction("About", "Home", new { data1 = "test1", data2 = "test2" })