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() 方法。

  1. 在应用程序根路径中添加一个 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;
         }
     }
    
  2. 在_ViewImports.cshtml

    中添加文件夹引用
     @using WebApplication2.TagHelpers
    
  3. 使用@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>
        }