Gdzie jest @Html.Action
w MVC6? Widzę @Html.ActionLink
, ale nie jest to bezpośrednie wezwanie do działania, jak wcześniej.@ Html.Action w Asp.Net Core
Czy został zastąpiony przez ViewComponents?
Gdzie jest @Html.Action
w MVC6? Widzę @Html.ActionLink
, ale nie jest to bezpośrednie wezwanie do działania, jak wcześniej.@ Html.Action w Asp.Net Core
Czy został zastąpiony przez ViewComponents?
NET rdzenia 2,0
using Microsoft.AspNetCore.Mvc.Infrastructure;
wymienić
// var actionSelector = GetServiceOrFail<IActionSelectorDecisionTreeProvider>(currentHttpContext);
var actionSelector = GetServiceOrFail<IActionDescriptorCollectionProvider>(currentHttpContext);
i
// var actionDescriptor = actionSelector.DecisionTree.Select(routeValues).First();
var actionDescriptor = actionSelector.ActionDescriptors.Items.Where(i => i.RouteValues["Controller"] == controller && i.RouteValues["Action"] == action).First();
Tak, ViewComponents byłby nowy sposób to zrobić, ale nie są one dokładnie to samo, co robił przed @Html.Action
... choć na przykład w MVC5 i wcześniejszych powołując "działań dziecka również Wykonaj dowolne filtry (na przykład, jeśli kontroler miał ozdobione filtry), nadając im wygląd regularnych działań ... ale to nie jest prawdą w ViewComponents i są one wykonywane w kontekście aktualnego żądania ...
Więcej informacji o komponentach widoku: http://www.asp.net/vnext/overview/aspnet-vnext/vc#intro
Aktualizacja: link zmieniono na
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components
Doskonały. Teraz możemy używać asynchronicznych wywołań podczas wywoływania "częściowych widoków" (teraz ViewComponents). –
ViewComponents są świetne, ale nie tak dobre dla Ajax.
Jeśli naprawdę brakuje Ci metody @ Html.RenderAction, oto krótka implementacja, którą wyrzuciłem razem dla 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<IHtmlContent> 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<IHttpContextFactory>(currentHttpContext);
var actionInvokerFactory = GetServiceOrFail<IActionInvokerFactory>(currentHttpContext);
var actionSelector = GetServiceOrFail<IActionSelectorDecisionTreeProvider>(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<TService>(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;
}
}
}
Można powołać się od widoku za pomocą jednej z następujących metod:
@Html.RenderAction("action", "controller", "area", new { id = 1})
@Html.RenderAction("action", "controller", new { id = 1})
@Html.RenderAction("action", new { id = 1})
Uwaga:
nazwa kontrolera i ewentualnie nazwa obszaru, będzie domyślnie odpowiednimi wartościami z ActionContext jeżeli nie przewidziane.
Technicznie, ten kod jest zamiennikiem dla Html.Action(), które zwraca działanie jako wartość ciągu. Html.RenderAction() zapisuje akcję bezpośrednio do strumienia odpowiedzi i zwraca nieważne. – ReflexiveCode
Próbowałem użyć tego kodu, ale kiedy wywołuję Html.RenderAction więcej niż jeden raz, pojawia się komunikat "Wystąpił jeden lub więcej błędów. (Element z tym samym kluczem został już dodany. Klucz: System.Object) ". Zdarza się ControllerActionInvoker.Next który ostatecznie kończy się w „System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException” masz jakiś pomysł, co przedmiot jest używany jako klucz i jak mogę zmienić kod, aby umożliwić wielu zastosowań w tym samym żądanie ? –
Mając ten sam błąd i nie można znaleźć sposobu na jego rozwiązanie :( Wystąpił jeden lub więcej błędów. (Dodano pozycję z tym samym kluczem: Klucz: System.Object) – brechtvhb
Obejście przez Aries dla rozszerzenia Pomocnika nie jest już możliwe do zastosowania dla Net Core 2.0, ponieważ IActionSelectorDecisionTreeProvider został usunięty z nowszej wersji. Zobacz link poniżej.
https://github.com/Microsoft/aspnet-api-versioning/issues/154
do rdzeń 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<IHtmlContent> 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<IActionContextAccessor>();
var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();
// 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<IHttpContextFactory>().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<IActionInvokerFactory>().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));
}
}
}
}
}
Opiera się na odpowiedzi od Barana. Poprawiłem to, co nie było kompilacji dla wersji 2.0 i dodałem kilka poprawek. Istnieją 2 gloryfikowane wartości statyczne dla bieżącego httpcontext i bieżącego actioncontext. Ta dla httpcontext jest ustawiona na IHttpContextFactory.Create
i ustawiam dla actioncontext w kodzie.
HttpContext to po prostu wrapper dookoła HttpContext.Features
, więc jeśli zmienisz coś w jednym, to zmieni się również w drugim ... Zresetowałem to, co wiem o tym w końcu try/catch.
Usunąłem IUrlHelper
z pamięci podręcznej elementów, ponieważ ta wartość będzie ponownie użyta, nawet jeśli działanieContext do zbudowania urlHelper jest inne (IUrlHelperFactory.GetUrlHelper
).
Asp.net core 2.0 zakłada, że tego nie zrobisz, istnieje duża szansa, że istnieją inne buforowane rzeczy, więc zalecam ostrożność podczas korzystania z tego i po prostu nie rób tego, jeśli nie musisz.
Nie jestem pewien, gdzie dokonujesz tej zmiany? Czy możesz dodać te informacje do odpowiedzi dla tych z nas, którzy nie potrafią czytać w myślach? –
Uważam, że dotyczy to niestandardowej implementacji @ Html.RenderAction poniżej. – Engin