【问题标题】:ActionLink in Table MVC表 MVC 中的 ActionLink
【发布时间】:2014-11-13 14:21:37
【问题描述】:

编辑:我已经阅读并实现了 this article 中的方法,但这不起作用。

我有正确填充的下表。

<table class="table">
   <tr>
       <th>Product</th>
       <th>File Name</th>
       <th>Release Date</th>
       <th>Size</th>
       <th></th>
   </tr>
   @{
       if (Model != null)
       {
           foreach (var item in Model.Uploads)
           {
               <tr>
                   <td>@Html.DisplayFor(modelItem => item.Product)</td>
                   <td>@Html.DisplayFor(modelItem => item.DisplayName)</td>
                   <td>@Html.DisplayFor(modelItem => item.ReleaseDate)</td>
                   <td>@Html.DisplayFor(modelItem => item.Size)</td>
                   <td>@Html.ActionLink("Delete File", "Upload", "Tools", new { id = item.DisplayName }, null)</td>
               </tr>
           }
       }
   }
</table>

我也有一个带有动作的控制器

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteUser(
    AdministratorViewModel model, string userName)
{
    // Do amazing stuff...
    return Index();
}

我想将选择删除的用户名传递给此操作。我想我可以用上面的@Html.ActionLink 来实现这一点,但这不是要走的路。

如何将选定的用户名传递给我的操作方法?

感谢您的宝贵时间。


编辑:将Ajax代码改成如下(使用Index作为被调用方法)

@Ajax.ActionLink(
    "Remove",
    "Index", 
    "Tools",
    new
    {
        model = item,
        userName = item.UserName
    },
    new AjaxOptions
    {
        InsertionMode = InsertionMode.Replace,
        HttpMethod = "POST"
    })

并将DeleteUser(AdministratorViewModel model, string userName) 方法的名称更改为Index(AdministratorViewModel model, string userName)。现在这会触发ToolsController 中的Index 方法。但是调用的方法是 NON-POST 属性方法(!?)所以我现在有两个问题:

  1. 怎么会调用未标记[HttpPost]属性的方法?
  2. 为什么我可以使用下面 Ben Griffiths 的回答来调用 DeleteUser 方法?
  3. 如何在 Tools 控制器中调用我的 DeleteUser 方法并传入模型和我要删除的用户名?

感谢您的宝贵时间。

【问题讨论】:

    标签: c# asp.net html razor asp.net-mvc-5


    【解决方案1】:

    调用时使用的ActionLink扩展方法重载的第四个参数

    Html.ActionLink("Delete File", "Upload", "Tools", new { id = item.DisplayName }, null)
    

    用于route values 参数,可用于将数据传回控制器。

    目前,在上述调用中,Tools 控制器上的Upload 操作方法将接收id 参数。如果您想将显示名称传递回您的 DeleteUser 操作方法,您可以使用

    Html.ActionLink("Delete User", "DeleteUser", "[ControllerName]", new { userName = item.DisplayName }, null)
    

    但是,DeleteUser 方法被 HttpPost 属性修饰,这意味着该操作将只接受使用 post 方法的请求。这意味着您有三个选择:

    (1) 从 action 方法中删除 [HttpPost] 属性 - 可能不是一个好主意,因为我想你不想公开这个 action 来获取请求。

    (2) 使用包含提交输入和隐藏的 DisplayName 输入的表单,而不是链接。

    (3) 使用 AjaxHelper.ActionLink 扩展方法对控制器进行异步回发。例如:

    Ajax.ActionLink("Delete User", "DeleteUser", "[ControllerName]", new { userName = item.DisplayName }, new AjaxOptions{ HttpMethod = "Post" })
    

    更新:第三个选项的更完整示例

    这是第三个选项的一个工作示例(尽管非常简单)。我不能 100% 确定最终目标是什么,因此我没有尝试提供一个现实的示例,而是尝试创建一个简单但清晰的示例。请注意,为了清晰起见,我省略了防伪令牌的处理,但我坚持使用 async 操作方法,以免偏离现实生活太远。

    控制器:

    public class HomeController : Controller {
    
        private async Task<string> Delete(string displayName) {
            Thread.Sleep(1000);
            return string.Format("{0} has been deleted", displayName);
        }
    
        [HttpPost]
        [AllowAnonymous]
        public async Task<JsonResult> DeleteItem(string displayName, int product) {
    
            Task<string> deleteTask = Delete(displayName);
    
            return new JsonResult() {
                Data = new { 
                    product = product,
                    result = await deleteTask }
            };
        }
    
    
    
        public ActionResult Index() {
    
            AdministratorViewModel model = new AdministratorViewModel() {
                Uploads = new List<ItemModel>() {
                    new ItemModel() {
                        DisplayName = "First one",
                        Product = 1,
                        ReleaseDate = DateTime.Now,
                        Size = 11
                    },
                    new ItemModel() {
                        DisplayName = "Second one",
                        Product = 2,
                        ReleaseDate = DateTime.Now.AddDays(1),
                        Size = 12
                    }
                }
            };
    
    
            return View(model);
        }
    
    }
    

    型号:

    public class AdministratorViewModel {
        public IEnumerable<ItemModel> Uploads { get; set; }
    }
    

    布局:

    <!DOCTYPE html>
    <html>
        <head>
            <title>Demo</title>
        </head>
        <body>
            @RenderBody()
            <script src="~/Scripts/jquery-1.10.2.js"></script>
            <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
            @RenderSection("scripts", false)
        </body>
    </html>
    

    主页/索引视图:

     @model AdministratorViewModel
    
     <table class="table">
        <tr>
            <th>Product</th>
            <th>File Name</th>
            <th>Release Date</th>
            <th>Size</th>
            <th></th>
        </tr>
        @{
            if (Model != null) {
                foreach (var item in Model.Uploads) {
                    <tr>
                        <td>@Html.DisplayFor(modelItem => item.Product)</td>
                        <td>@Html.DisplayFor(modelItem => item.DisplayName)</td>
                        <td>@Html.DisplayFor(modelItem => item.ReleaseDate)</td>
                        <td>@Html.DisplayFor(modelItem => item.Size)</td>
                        <td>@Ajax.ActionLink("Remove", "DeleteItem", "Home", new { displayName = item.DisplayName, product = item.Product }, new AjaxOptions { HttpMethod = "POST", OnComplete = "itemDeleted" }, new { id = item.Product })</td>
                    </tr>
                }
            }
        }
    </table>
    
    @section scripts {
        <script>
            var itemDeleted = function (data) {
                var $link = $('#' + data.responseJSON.product);
                $link.parents('tr')
                     .children()
                     .css('text-decoration', 'line-through');
    
                $link.remove();
    
                alert(data.responseJSON.result);
            };
        </script>
    }
    

    【讨论】:

    • 这个 @Ajax.ActionLink 将我发送到 URL http://localhost:52531/Tools/DeleteUser?userName=Alan,这不是我想要的。我怎样才能做到这一点?
    • 您要发帖的网址是什么?
    • 我只想在ToolsController 中调用我的Action 方法。我要调用的动作方法是DeleteUser,控制器叫做ToolsController,所以我尝试了以下@Ajax.ActionLink("Remove", "DeleteUser", "Tools", new { userName = item.UserName }, new AjaxOptions { HttpMethod = "Post" }),我该如何修改它来调用动作?
    • 啊,我明白你的意思了 - 浏览器正在重定向到那个 URL?您需要在页面上加载 MVC Unobtrusive Ajax JavaScript 库才能使其正常工作 - 您需要一个类似于 &lt;script type="text/javascript" src="~/scripts/jquery.unobtrusive-ajax.js"&gt;&lt;/script&gt; 的脚本
    • 嗨,本,这对我没有帮助。不知道为什么这些操作如此困难。我有一本书,但它就像在读一个谜......
    【解决方案2】:

    我认为首先你必须通过添加路由来处理 url

    routes.MapRoute(
                    name: "Default",
                    url: "{User}/{DeleteUser}/{username}",
                    defaults: new { controller = "Home", action = "Index", username = UrlParameter.Optional }
                );
    

    【讨论】:

    • 感谢您的帮助。再加上上面的答案,我相信我快到了。我现在收到“'/' 应用程序中的服务器错误。找不到资源。描述:HTTP 404。您正在寻找的资源(或其依赖项之一)可能已被删除、更改名称或暂时不可用。请检查以下 URL 并确保拼写正确。请求的 URL:/Tools/DeleteUser”,请求的 URL 是“localhost:52531/Tools/DeleteUser?userName=Alan”,但上面的 MapRoute 是默认的...
    • 除非您已经进行了复杂的路由设置,否则您不太可能需要添加自定义路由来实现此目的? - 否则,我会单独留下您的路由表。 DeleteUser 方法是否是您的工具控制器上的操作,并且工具控制器是否位于您站点的根目录(即不在区域内)?
    猜你喜欢
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    • 2011-08-18
    • 1970-01-01
    相关资源
    最近更新 更多