调用 get 操作时未设置 ViewBag 属性

Posted

技术标签:

【中文标题】调用 get 操作时未设置 ViewBag 属性【英文标题】:ViewBag property not getting set when get action is called 【发布时间】:2019-04-11 18:47:40 【问题描述】:

在 MVC 项目中,首先是 EF DB,我使用 ViewBag 属性在下拉列表中显示值列表。这是我的 get 方法和 post 方法。-

[ HttpGet]
        public ActionResult Create()
        

            using (var context = new AdventureWorksEntities())
            
    ViewBag.Colors = new SelectList(context.Products.Select(a => 
    a.Color).Distinct().ToList());
            

            return View();

 [HttpPost]
        [ActionName("Create")]
        public ActionResult CreatePost()
        
            var producttocreate = new Product();
        try
            
                UpdateModel(producttocreate);
                if (ModelState.IsValid)
                
                    using (var context = new AdventureWorksEntities())
                    
                        context.Products.Add(producttocreate);
                        context.SaveChanges();
                    
                    return RedirectToAction("Index");
                
                return View(producttocreate);
            
            catch(Exception e)
            
                return View(producttocreate);
            

    

这里的属性 ViewBag.Colors 是有问题的属性。当我在 Post 上遇到异常时,我想传递模型并再次返回相同的 Create 视图。但是,即使每次调用 Create Get 方法时我都有设置 ViewBag.Colors 的代码,但它没有被设置,并且在渲染 Create View 时出现错误 -

具有键“Color”的 ViewData 项属于“System.String”类型,但必须属于“IEnumerable”类型

我确实在其他一些帖子中发现此异常的原因是 ViewBag.Colors 为 null ,但我不明白为什么。为什么从 Post Action 方法调用 View 时没有设置它?对此有什么解决办法?

【问题讨论】:

那么,您的代码在初始页面加载时工作,但是当您尝试提交表单并返回相同的视图时出现异常?下拉菜单是表单上的必填字段吗? M12 Bennett - 是的,它适用于初始页面加载。当我发布数据时,如果发布成功,我想返回一个索引视图,如果它不成功,我希望它返回相同的视图。正是在这一点上,我希望 ViewBag.Colors 再次在 GET 方法中设置,因为它在代码中,但它设置为 null。 M12 Bennett - 关于问题的另一部分,不是它不是必填字段,如在模型类中的属性上没有应用必填属性。 好的,明白了。需要明确的是,如果post不成功,它不会回到HttpGet方法。它将保留在 HttpPost 方法中,这意味着您必须在 HttpPost 方法中再次设置ViewBag.Colors。过去我也遇到过这种情况,我通常在方法开始时就设置它。不过这取决于你。 【参考方案1】:

之前

return View(producttocreate);

这样做

ViewData["Colors"] = new SelectList(_context.Products, "Id", "Color", ColorId);

【讨论】:

Faith Alac - 你的意思是,在 Post Action Method 中再次设置 viewdata 或 ViewBag 吗?我不明白为什么我会要求这样做。在 Get Action Method 中我正在设置它,所以当我从 Post Action Method 内部调用该方法时,为什么它仍然为空? 首先你在公共 IActionResult Create() 中选择然后 [HttpPost] 你需要知道选择的值。 我想唯一的办法就是在 Post 方法中再次填充 ViewBag 。虽然做 RedirectToAction() 的 quiqs 答案也是正确的。但是由于我使用了这个建议,我将其标记为答案。【参考方案2】:

ViewBag.Colors 为 null 的原因是,当 POST 中出现错误时,您不会重定向到 (GET) Create 操作。相反,您将模型发送回视图,绕过 (GET) Create 操作,因此不会填充 ViewBag。如果您使用RedirectToAction("Create"); 而不是View(producttocreate),则会再次填充 ViewBag.Colors。

【讨论】:

quiqs - 如果是这样,我会尝试 RedirectToAction("Create"。但是当我编写 View(model) 时会调用哪个方法? 我试过 RedirectToAction("Create") ,它不是我想要的。它正在清除所有字段,另外,我有一个 CustomValidation,那个消息没有来。我希望我输入的字段是完整的。 View() 是方法。这个方法的作用是,如果没有传递参数,它会寻找一个与封闭动作同名的视图来显示你的对象。如果提供了视图的名称,它会查找具有该名称的视图。如果您想保留 ModelState,那么 @FaithAlac 已经得到您的答案。在 ModelState.IsValid 失败后和返回视图之前在您的 POST 中填充 ViewBag。 '它寻找与显示对象的封闭操作同名的视图' - 是的,我确实想要,因为我想留在创建视图中。关于在 POST 之前填充 ViewBag ,我的犹豫是我已经在 GET 方法中填充它,所以到处都这样做看起来很奇怪。但是,如果这是唯一的解决方案,那么我会问当 POST 失败时该怎么办。我看到的每个教程都使用这种方式,为什么他们不面临这个问题?换句话说 - 创建 ViewModel 是保存这些值的唯一选择吗? ViewBag 的生命周期从控制器到视图、视图到控制器或控制器到控制器。这是单程旅行。在那之后,它就不复存在了。这就是为什么您需要在 POST 中再次填充它,但前提是您需要相同的视图,需要保留 ModelState 中的值,并向用户显示错误,所有这些都是您想要的。

以上是关于调用 get 操作时未设置 ViewBag 属性的主要内容,如果未能解决你的问题,请参考以下文章

调用 AsyncTask.get() 时未显示 ProgressDialog [重复]

在 ASP.NET MVC Core 控制器的构造函数中设置 ViewBag 属性

发送 GET 请求时未设置 CORS [关闭]

C#/ Asp.NET:在ViewData / ViewBag中设置数据是否有利于每个请求与调用操作方法获取数据?

ViewBag 名称可以与 DropDownList 中的 Model 属性名称相同吗?

使用调用控制器的路由时未识别的控制器