HTML.Partial 未在 ASP.NET 核心中触发控制器方法
HTML.Partial not firing controller method in ASP.NET Core
为什么我的 html.partial
没有触发控制器中的 Create
方法?
这是我的 chtml 代码:
<div class="modal fade" id="UnitModal">
<div class="modal-dialog">
<div class="modal-content">
@Html.Partial("Create")
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
这是我在控制器中的代码:
// GET: Units/Create
public IActionResult Create()
{
return View();
}
// POST: Units/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(UnitViewModel unit)
{
if (ModelState.IsValid)
{
var model = _mapper.Map<Unit>(unit);
_context.Add(model);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(unit);
}
每次单击按钮显示创建模式时,从控制器获取 Create
都不会触发。但是 Post Create
正在触发,并正确保存数据。我错过了什么?
示例输出:
Sample flow, Get Create not firing
@Html.Partial()
采用视图名称而不是操作名称。所以 @Html.Partial("Create")
只会渲染名为“Create”的部分视图。
如果要执行控制器操作,请改用 @Html.Action("create", "units")
或 @Html.RenderAction("create", "units")
。
如果您使用 ASP.NET 核心 MVC,您也可以使用 View Component。
Html.Partial
只会渲染特殊视图,不会调用动作方法(Get方法)。
要执行控制器操作并在 Asp.net Core 中呈现局部视图,正如 David 所说,您可以使用 View Components。此外,您还可以参考以下步骤在 asp.net Core MVC 应用程序中使用 @Html.RenderAction()
方法。
在应用程序根路径中添加一个 TagHelpers 文件夹,然后添加 HtmlHelperViewExtensions.cs 文件:
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<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<IActionDescriptorCollectionProvider>(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<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;
}
}
在_ViewImports.cshtml
中添加文件夹引用
@using WebApplication2.TagHelpers
使用@Html.RenderAction("<action name>")
加载主视图中的局部视图。
[注意] 通过使用上述方法,加载主视图时调用了操作方法(局部视图),而不是单击“添加单元”按钮。
如果你想在点击添加按钮时加载局部视图,你最好使用JQuery来加载局部视图。示例代码如下:
<button type="button" id="btn_addunit" class="btn btn-primary" data-toggle="modal" data-target="#UnitModal">
Add Unit
</button>
<div class="modal fade" id="UnitModal">
<div class="modal-dialog">
<div class="modal-content" id="modal_content">
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
@section Scripts{
<script type="text/javascript">
$(document).ready(function () {
$("#btn_addunit").click(function () {
$("#modal_content").load("/Home/Create"); //change the controller action to yours.
});
});
</script>
}
为什么我的 html.partial
没有触发控制器中的 Create
方法?
这是我的 chtml 代码:
<div class="modal fade" id="UnitModal">
<div class="modal-dialog">
<div class="modal-content">
@Html.Partial("Create")
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
这是我在控制器中的代码:
// GET: Units/Create
public IActionResult Create()
{
return View();
}
// POST: Units/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(UnitViewModel unit)
{
if (ModelState.IsValid)
{
var model = _mapper.Map<Unit>(unit);
_context.Add(model);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(unit);
}
每次单击按钮显示创建模式时,从控制器获取 Create
都不会触发。但是 Post Create
正在触发,并正确保存数据。我错过了什么?
示例输出:
Sample flow, Get Create not firing
@Html.Partial()
采用视图名称而不是操作名称。所以 @Html.Partial("Create")
只会渲染名为“Create”的部分视图。
如果要执行控制器操作,请改用 @Html.Action("create", "units")
或 @Html.RenderAction("create", "units")
。
如果您使用 ASP.NET 核心 MVC,您也可以使用 View Component。
Html.Partial
只会渲染特殊视图,不会调用动作方法(Get方法)。
要执行控制器操作并在 Asp.net Core 中呈现局部视图,正如 David 所说,您可以使用 View Components。此外,您还可以参考以下步骤在 asp.net Core MVC 应用程序中使用 @Html.RenderAction()
方法。
在应用程序根路径中添加一个 TagHelpers 文件夹,然后添加 HtmlHelperViewExtensions.cs 文件:
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<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<IActionDescriptorCollectionProvider>(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<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; } }
在_ViewImports.cshtml
中添加文件夹引用@using WebApplication2.TagHelpers
使用
@Html.RenderAction("<action name>")
加载主视图中的局部视图。
[注意] 通过使用上述方法,加载主视图时调用了操作方法(局部视图),而不是单击“添加单元”按钮。
如果你想在点击添加按钮时加载局部视图,你最好使用JQuery来加载局部视图。示例代码如下:
<button type="button" id="btn_addunit" class="btn btn-primary" data-toggle="modal" data-target="#UnitModal">
Add Unit
</button>
<div class="modal fade" id="UnitModal">
<div class="modal-dialog">
<div class="modal-content" id="modal_content">
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
@section Scripts{
<script type="text/javascript">
$(document).ready(function () {
$("#btn_addunit").click(function () {
$("#modal_content").load("/Home/Create"); //change the controller action to yours.
});
});
</script>
}