Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET MVC Core/6:多个提交按钮_C#_Asp.net Core_Asp.net Core Mvc - Fatal编程技术网

C# ASP.NET MVC Core/6:多个提交按钮

C# ASP.NET MVC Core/6:多个提交按钮,c#,asp.net-core,asp.net-core-mvc,C#,Asp.net Core,Asp.net Core Mvc,我需要多个提交按钮来执行控制器中的不同操作 我在这里看到了一个优雅的解决方案: 使用此解决方案,可以使用自定义属性修饰操作方法。处理路由时,此自定义属性的方法将检查属性的属性是否与单击的提交按钮的名称匹配 但是在MVC核心(RC2夜间构建)中,我没有找到ActionNameSelectorAttribute(我还搜索了Github存储库)。我发现了一个类似的解决方案,它使用ActionMethodSelectorAttribute() ActionMethodSelectorAttribute可

我需要多个提交按钮来执行控制器中的不同操作

我在这里看到了一个优雅的解决方案: 使用此解决方案,可以使用自定义属性修饰操作方法。处理路由时,此自定义属性的方法将检查属性的属性是否与单击的提交按钮的名称匹配

但是在MVC核心(RC2夜间构建)中,我没有找到
ActionNameSelectorAttribute
(我还搜索了Github存储库)。我发现了一个类似的解决方案,它使用
ActionMethodSelectorAttribute
()

ActionMethodSelectorAttribute
可用,但方法
IsValidForRequest
具有不同的签名。有一个类型为
RouteContext
的参数。但是我在那里找不到post数据。因此,我没有任何东西可以与我的自定义属性进行比较


MVC Core中是否有类似于以前MVC版本的优雅解决方案?

您可以使用HTML5
属性,而不是将其路由到服务器端

<form action="" method="post">
    <input type="submit" value="Option 1" formaction="DoWorkOne" />
    <input type="submit" value="Option 2" formaction="DoWorkTwo"/>
</form>
对于较旧的浏览器,一个好的多边形填充可以是

记住。。。
  • 当用户按下回车键时,将始终选择第一个提交按钮
  • 如果发布的操作也出现错误-
    ModelState
    或其他错误,则需要将用户发送回正确的视图。(不过,如果您是通过AJAX发布,这不是问题。)

  • ASP.NET Core 1.1.0具有创建
    formaction
    属性的

    <form>
        <button asp-action="Login" asp-controller="Account">log in</button>
        <button asp-action="Register" asp-controller="Account">sign up</button>
    </form>
    
    
    登录
    注册
    
    呈现如下:

    <button formaction="/Account/Login">log in</button>
    <button formaction="/Account/Register">sign up</button>
    
    登录
    注册
    

    它还适用于
    input
    标记,这些标记是
    type=“image”
    type=“submit”

    我以前做过,过去我会将表单发布到不同的控制器操作中。问题是,在服务器端验证错误中,您可能会遇到以下问题:

  • 返回视图(vm)
    在url中保留操作后的名称…糟糕
  • 返回重定向(…)
    要求使用
    TempData
    保存
    ModelState
    。也很恶心
  • 以下是我选择做的

  • 使用按钮的
    名称
    绑定到POST上的变量
  • 按钮
    是一个用于区分提交操作的枚举。Enum是类型安全的,在switch语句中工作得更好。;)
  • 发布到与GET相同的操作名称。这样,在服务器端验证错误时,就不会在URL中获取POST操作名称
  • 如果存在验证错误,请按照正确的PGR模式重建视图模型并返回视图(viewModel)
  • 使用此技术,无需使用
    TempData

    在我的用例中,我有一个带有“添加角色”和“删除角色”操作的用户/详细信息页面

    这是按钮。它们可以是按钮而不是输入标记…;)

    删除角色
    将用户添加到角色
    
    这是控制器的动作。我将开关代码块重构为它们自己的函数,使它们更易于阅读。我必须张贴到2个不同的视图模型,所以其中一个将不会被填充,但模型绑定器不关心

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Details(
        SelectedUserRoleViewModel removeRoleViewModel, 
        SelectedRoleViewModel addRoleViewModel,
        UserDetailsSubmitAction submitAction)
    {
        switch (submitAction)
        {
            case UserDetailsSubmitAction.AddRole:
            {
                return await AddRole(addRoleViewModel);
            }
            case UserDetailsSubmitAction.RemoveRole:
            {
                return await RemoveRole(removeRoleViewModel);
            }
            default:
                throw new ArgumentOutOfRangeException(nameof(submitAction), submitAction, null);
        }
    }
    
    private async Task<IActionResult> RemoveRole(SelectedUserRoleViewModel removeRoleViewModel)
    {
        if (!ModelState.IsValid)
        {
            var viewModel = await _userService.GetDetailsViewModel(removeRoleViewModel.UserId);
            return View(viewModel);
        }
    
        await _userRoleService.Remove(removeRoleViewModel.SelectedUserRoleId);
    
        return Redirect(Request.Headers["Referer"].ToString());
    }
    
    private async Task<IActionResult> AddRole(SelectedRoleViewModel addRoleViewModel)
    {
        if (!ModelState.IsValid)
        {
            var viewModel = await _userService.GetDetailsViewModel(addRoleViewModel.UserId);
            return View(viewModel);
        }
    
        await _userRoleService.Add(addRoleViewModel);
    
        return Redirect(Request.Headers["Referer"].ToString());
    }
    
    [HttpPost]
    [ValidateAntiForgeryToken]
    公共异步任务详细信息(
    选择EdUserRoleViewModel RemoveOleViewModel,
    已选择的RoleView模型AddRoleView模型,
    用户详细信息提交(提交提交)
    {
    开关(submitAction)
    {
    案例UserDetailsSubmitAction.AddRole:
    {
    返回等待添加角色(addRoleViewModel);
    }
    案例用户详细信息SubmitAction.RemoveOLE:
    {
    返回等待移除ole(移除oleviewmodel);
    }
    违约:
    抛出新ArgumentOutOfRangeException(nameof(submitAction),submitAction,null);
    }
    }
    专用异步任务删除OLE(SelectedUserRoleViewModel删除oleViewModel)
    {
    如果(!ModelState.IsValid)
    {
    var viewModel=await\u userService.GetDetailsViewModel(removoleviewmodel.UserId);
    返回视图(viewModel);
    }
    等待_userRoleService.Remove(RemoveOleViewModel.SelectedUserRoleId);
    返回重定向(Request.Headers[“Referer”].ToString());
    }
    专用异步任务AddRole(SelectedRoleViewModelAddRoleViewModel)
    {
    如果(!ModelState.IsValid)
    {
    var viewModel=await_userService.GetDetailsViewModel(addRoleViewModel.UserId);
    返回视图(viewModel);
    }
    wait_userRoleService.Add(addRoleViewModel);
    返回重定向(Request.Headers[“Referer”].ToString());
    }
    

    作为一种选择,你可以。

    一个更好的答案是使用并忘记所有的混乱

  • 您可以为控制器操作指定语义名称
  • 您不必重定向或使用tempdata
  • 服务器端验证错误的URL中没有post操作名称
  • 在服务器端验证错误中,您可以返回一个表单或只是返回错误消息

  • 根据您喜欢与否,可以使用客户端(aka:JQuery)更改元素的实际URL。在单击偶数时,确定单击了哪个按钮,更改了元素的[action]属性并提交()了.Perfect!似乎我必须更详细地研究HTML5。奇怪的是:我有关于索引的动作。所以:
    /AreaName/ControllerName
    。单击按钮后,我得到:
    /AreaName/ButtonFormActionName
    。控制器部分丢失了。当我从
    /AreaName/ControllerName/ActionName
    开始时,它很有效。啊,好主意!在这种情况下,您将需要使用
    Url.Action(actionName,controllerName)
    helper方法为
    formaction
    属性生成正确的目标。完美的解决方案,但有一个陷阱,如果我们使用您的方式,第一个操作是/post/add,第二个是/post/addcontinue。如果用户单击addcontinue按钮,并且页面已显示va
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Details(
        SelectedUserRoleViewModel removeRoleViewModel, 
        SelectedRoleViewModel addRoleViewModel,
        UserDetailsSubmitAction submitAction)
    {
        switch (submitAction)
        {
            case UserDetailsSubmitAction.AddRole:
            {
                return await AddRole(addRoleViewModel);
            }
            case UserDetailsSubmitAction.RemoveRole:
            {
                return await RemoveRole(removeRoleViewModel);
            }
            default:
                throw new ArgumentOutOfRangeException(nameof(submitAction), submitAction, null);
        }
    }
    
    private async Task<IActionResult> RemoveRole(SelectedUserRoleViewModel removeRoleViewModel)
    {
        if (!ModelState.IsValid)
        {
            var viewModel = await _userService.GetDetailsViewModel(removeRoleViewModel.UserId);
            return View(viewModel);
        }
    
        await _userRoleService.Remove(removeRoleViewModel.SelectedUserRoleId);
    
        return Redirect(Request.Headers["Referer"].ToString());
    }
    
    private async Task<IActionResult> AddRole(SelectedRoleViewModel addRoleViewModel)
    {
        if (!ModelState.IsValid)
        {
            var viewModel = await _userService.GetDetailsViewModel(addRoleViewModel.UserId);
            return View(viewModel);
        }
    
        await _userRoleService.Add(addRoleViewModel);
    
        return Redirect(Request.Headers["Referer"].ToString());
    }