【问题标题】:Redirect to GET action method from POST action method in .NET MVC从 .NET MVC 中的 POST 操作方法重定向到 GET 操作方法
【发布时间】:2020-03-04 15:28:18
【问题描述】:

我正在尝试创建一个网络应用程序,用于使用 EF CORE 和 MVC 跟踪药房中的患者用药,但我遇到了问题。我设置了一个视图,用于使用基本的 CRUD 操作创建脚本,它工作正常,但我没有尝试实现其他功能。具体来说,我希望能够将多个项目添加到单个脚本中。我已经更新了我的数据库和现有视图,但我正在尝试找出完成这项工作的最佳方法。

我有一个 GET 控制器操作,它在给定患者 ID 的情况下创建我的视图模型的实例。然后,我的表单发布到仅创建单个项目脚本的操作或将创建脚本的操作,添加项目然后重定向回创建视图,以便将另一个项目添加到同一脚本。

有没有办法在我的控制器中从 post 操作重定向回 get 操作并同时传递一些参数?

获取操作

        [HttpGet]
        public async Task<IActionResult> Create(
            int id,
            string sort,
            string currentFilter,
            string search,
            int? pageNumber)
        {
            ViewData["NameSortParam"] = String.IsNullOrEmpty(sort) ? "name_desc" : "";
            ViewData["PackSortParam"] = sort == "pack" ? "pack_desc" : "pack";
            ViewData["GenSortParam"] = sort == "gen" ? "gen_desc" : "gen";
            ViewData["StockSortParam"] = sort == "stock" ? "stock_desc" : "stock";
            ViewData["CurrentSort"] = sort;

            if (!String.IsNullOrEmpty(search))
            {
                pageNumber = 1;
            }
            else
            {
                search = currentFilter;
            }

            ViewData["CurrentFilter"] = search;


            var drugs = from drug in _context.Drug
                        join generic in _context.Generic on drug.GenericId equals generic.Id
                        select drug;

            if (!String.IsNullOrEmpty(search))
            {
                drugs = drugs.Where(d => d.Name.Contains(search)
                                || d.Generic.Name.Contains(search));
            }

            switch (sort)
            {
                case "name_desc":
                    drugs = drugs.OrderByDescending(d => d.Name);
                    break;
                case "pack":
                    drugs = drugs.OrderBy(d => d.PackSize);
                    break;
                case "pack_desc":
                    drugs = drugs.OrderByDescending(d => d.PackSize);
                    break;
                case "cost":
                    drugs = drugs.OrderBy(d => d.CostPrice);
                    break;
                case "cost_desc":
                    drugs = drugs.OrderByDescending(d => d.CostPrice);
                    break;
                case "gen":
                    drugs = drugs.OrderBy(d => d.Generic.Name);
                    break;
                case "gen_desc":
                    drugs = drugs.OrderByDescending(d => d.Generic.Name);
                    break;
                case "stock":
                    drugs = drugs.OrderBy(d => d.StockQty);
                    break;
                case "stock_desc":
                    drugs = drugs.OrderByDescending(d => d.StockQty);
                    break;
                default:
                    drugs = drugs.OrderBy(d => d.Name);
                    break;
            }

            drugs = drugs.Include(d => d.Generic);

            int pageSize = 5;

            var patient = await _context.Patient.FindAsync(id);

            var vm = new NewScriptViewModel()
            {
                Patient = patient,
                PatientId = patient.Id,
                Prescribers = await _context.Prescriber.ToListAsync(),
                Drugs = await PaginatedList<Drug>.CreateAsync(drugs.AsNoTracking(), pageNumber ?? 1, pageSize)

            };
            ViewData["PrescriberId"] = new SelectList(_context.Prescriber, "Id", "FullName", patient.PrescriberId);


            return View(vm);
        }

POST 操作 - 将下一项添加到同一脚本

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create(bool FirstItem, [Bind("PatientId, PrescriberId")] Script script, [Bind("DrugId, Qty, Directions")] ScriptDrug scriptDrug)
        {
            if (ModelState.IsValid)
            {
                if (FirstItem)
                {
                    //create script
                    _context.Add(script);
                    await _context.SaveChangesAsync();

                    //add item
                    scriptDrug.ScriptId = script.Id;
                    var drug = _context.Drug.Find(scriptDrug.DrugId);
                    drug.StockQty -= scriptDrug.Qty;
                    _context.Add(scriptDrug);
                    await _context.SaveChangesAsync();

                    //redirect to create to add new item to same script

                }
            }
            //redirect back to view
        }

希望我已经充分解释了这一点,但如果我需要提供任何额外信息,请告诉我。

注意: 视图模型

    public class NewScriptViewModel

    {
        public int ScriptId { get; set; }
        public Patient Patient { get; set; }
        public int PatientId { get; set; }
        public IEnumerable<Prescriber> Prescribers { get; set; }
        public int PrescriberId { get; set; }
        public PaginatedList<Drug> Drugs { get; set; }
        public int DrugId { get; set; }
        public int Qty { get; set; }
        public string Directions { get; set; }
        public bool FirstItem { get; set; }

        public NewScriptViewModel()
        {
            FirstItem = true;
        }
    }

【问题讨论】:

  • 您是否尝试从您的帖子操作中调用您的获取操作return Create(/*add my parameters here*/)

标签: c# asp.net-mvc model-view-controller ef-core-3.1


【解决方案1】:

欢迎来到 StackOverflow,深奥!

是的,Post/Redirect/Get 是一种非常常见且非常需要遵循的模式。它可以防止您或您的用户两次触发相同的POST 请求。如果你已经知道了,抱歉,只是为了澄清一下。

我为你创建了一个小例子,我希望这是你正在寻找的:

HomeController.cs

namespace WebApplication4.Controllers
{
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using WebApplication4.Models;

    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IActionResult Index()
        {
            return View(new MyModel());
        }

        [HttpPost]
        public IActionResult Index(MyModel model)
        {
            ViewBag.additionalData = "Something";
            return View();
        }
    }
}

Home\Index.cshtml

@model MyModel

Get view

<form method="post">
    <input asp-for="@Model.Data" />
    <button type="submit">Post!</button>
</form>

Additional data: @ViewBag.additionalData

MyModel.cs

namespace WebApplication4.Models
{
    public class MyModel
    {
        public string Data { get; set; }
    }
}

工作流程如下:

  • [GET] Home\Index 开头。我们将在 [GET] Index 方法中结束。
  • return View(new MyModel()); 将返回给我们Views\Home\Index.cshtml(按照惯例),其中包含要填写表格的新空模型。
  • 我们填写表单值,使用POST 方法发送数据(&lt;form&gt; 标记内没有actioncontroller 属性,按照惯例它将发送[POST] Home\Index 并将我们带到同一个控制器和同一个命名的操作但是POST 版本就可以了)
  • 我们利用ViewBag 为通话保留更多数据
  • 然后我们只调用View() 来调用Home\Index(按照惯例调用与方法名称相同的控制器和视图)
  • 默认情况下,它将请求另一个[GET] Home\Index,我们回到了我们开始的位置,但在ViewBag 中使用了一些额外的值(如果我们重定向/刷新,它将消失)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 2010-12-19
    相关资源
    最近更新 更多