【问题标题】:Checking to see if ViewBag has a property or not, to conditionally inject JavaScript检查 ViewBag 是否有属性,以有条件地注入 JavaScript
【发布时间】:2012-01-28 06:45:36
【问题描述】:

考虑这个简单的控制器:

Porduct product = new Product(){
  // Creating a product object;
};
try
{
   productManager.SaveProduct(product);
   return RedirectToAction("List");
}
catch (Exception ex)
{
   ViewBag.ErrorMessage = ex.Message;
   return View("Create", product);
}

现在,在我的Create 视图中,我想检查ViewBag 对象,看看它是否具有Error 属性。如果它有错误属性,我需要在页面中注入一些 JavaScript,向我的用户显示错误消息。

我创建了一个扩展方法来检查这个:

public static bool Has (this object obj, string propertyName) 
{
    Type type = obj.GetType();
    return type.GetProperty(propertyName) != null;
}

然后,在Create视图中,我写了这行代码:

@if (ViewBag.Has("Error"))
{
    // Injecting JavaScript here
}

但是,我收到此错误:

无法对空引用执行运行时绑定

有什么想法吗?

【问题讨论】:

  • 究竟是什么代码产生了这个错误?
  • @JohnSaunders,如您所见,我在控制器中设置了ViewBag.Error?怎么可能是空的?
  • @AndrewBarber,这条线@if (ViewBag.Has("Error"))
  • @SaeedNamati:我不知道。你为什么不知道?试试@if (ViewBag == null) 看看结果如何。

标签: asp.net-mvc-3 dynamic razor null viewbag


【解决方案1】:
@if (ViewBag.Error!=null)
{
    // Injecting JavaScript here
}

【讨论】:

  • 亲爱的@jazzcat,请先检查您的代码,然后发送。如果我没有在控制器中设置ViewBag.Error,这意味着ViewBag 在运行时不会有一个名为Error 的属性,那么我会遇到异常。
  • @SaeedNamati,jazzcat 的代码对我来说效果很好。对于 ViewBag,任何未找到的项目都将为空。请记住,动态最终背后有一些实际代码。 ViewBag 是一个 DynamicViewDataDictionary,它显然决定为不存在的“属性”返回 null 而不是抛出错误。
  • 这应该是选择的答案!
  • 实际上,你可以用一些其他的魔法来改进它; @if(ViewBag.Error ?? false)。无论您是否设置布尔值,它都会起作用。
  • MVC 有一个 DynamicViewDataDictionary,ViewBag 继承了它,实现了这个 null-return 行为。请注意,如果您在 MVC 之外使用 Razor 引擎,如果您尝试访问未定义的属性而不是返回 null,则会收到异常。见github.com/jlamfers/RazorMachine/issues/35
【解决方案2】:

您的代码不起作用,因为 ViewBag 是 dynamic object 而不是“真实”类型。

以下代码应该可以工作:

public static bool Has (this object obj, string propertyName) 
{
    var dynamic = obj as DynamicObject;
    if(dynamic == null) return false;
    return dynamic.GetDynamicMemberNames().Contains(propertyName);
}

【讨论】:

  • 好建议@JeffreyABecker。谢谢,但我得到了Cannot perform runtime binding on a null reference 异常。
  • 看来我应该像((Object)ViewBag).Has("PropertyName")一样使用它。
  • Resharper 建议“返回动态!= null && dynamic.GetDynamicMemberNames().Contains(propertyName);”而不是最后两行。不错的解决方案!谢谢!
【解决方案3】:

不要使用 ViewBag,而是使用 ViewData,这样您就可以检查您正在存储的项目。 ViewData 对象用作您可以通过键引用的对象的字典,它不像 ViewBag 那样是动态的。

// Set the [ViewData][1] in the controller
ViewData["hideSearchForm"] = true;    

// Use the condition in the view
if(Convert.ToBoolean(ViewData["hideSearchForm"])
    hideSearchForm();

【讨论】:

  • 怎么样?至少给我们一个例子;)。
  • 仍然 ViewBag 似乎比 ViewData 更优雅。我不喜欢字符串索引。
  • 动态视图包的问题不允许您检查属性是否存在,在这种情况下,ViewData 是正确的选择。但是在 mvc4 中对视图包支持进行了一些改进。 beletsky.net/2012/04/new-in-aspnet-mvc4-razor-changes.html
  • @Martin 字符串索引和动态成员名称之间有什么有意义的区别?例如,ExpandoObject 只是一个隐藏的字典。
  • @emodendroket - 这主要是视觉差异,代码看起来更干净。
【解决方案4】:

我会在这里完全避免使用 ViewBag。 在这里查看我的想法: http://completedevelopment.blogspot.com/2011/12/stop-using-viewbag-in-most-places.html

另一种方法是抛出自定义错误并捕获它。您如何知道数据库是否已关闭,或者是否是业务逻辑保存错误?在上面的示例中,您只捕获一个异常,通常有更好的方法来捕获每种异常类型,然后是针对真正未处理的异常的通用异常处理程序,例如内置的自定义错误页面或使用 ELMAH。

所以在上面,我会改为 ModelState.AddModelError() 然后,您可以通过以下方式查看这些错误(假设您不打算使用内置验证) How do I access the ModelState from within my View (aspx page)?

因此,请仔细考虑在捕获“任何”异常时显示消息。

【讨论】:

  • 看起来我正在“线程化”这个 :-) 我读过你的文章,我真的在 MVC 4 中使用了强类型模型......但我没有任何疑虑反对将 ViewBag 用于简单的事情。大多数来自 C# 和其他强类型语言的人由于其传统而对动态不满意(我也是一个“强类型”的人)。但这一切都归结为测试!如果您的视图经过测试,动态变量将无关紧要。事实上,到处使用 ViewBag 并对其进行大量测试比依赖强类型来确保正确性要好得多。良好的测试使动态与强类型的选择变得毫无意义。
  • 我喜欢 JavaScript,但是我经常被它松散的类型所困扰。动态变量很重要。辅助函数中的 viewbag 在幕后有隐藏的行为,其中任何值都优先于模型中的任何值。其次,它们对于重构、查找引用和类型分配等很脆弱。测试并不是万能的,测试只是测试的好坏。没有人的测试是 100% 的,在我见过的任何地方或项目中都没有,而且很多。这是最大的努力,您肯定可以引入测试未捕获的错误,您可以更新测试以处理这些错误
  • 这个新修复,但这仍然不能阻止它。虽然我很高兴你发布了回复,但我不能同意这一点:“事实上,到处使用 ViewBag 并对其进行大量测试比依赖强类型来确保正确性要好得多”询问任何在许多项目中使用 MVC 的架构师如果他们同意该声明。 ViewModels 是首选方法,原因有很多。为什么最好使用 ViewBag 并进行大量测试,而不是在视图模型中使用属性,而根本不必担心它?
  • Adam,我认为强类型对正确性的贡献被夸大了。单元测试(和 TDD)确实是多年来对它的主要演变/贡献。虽然我在强类型环境中更自在,但我开始“接受”动态的家伙真的改变了我的假设,即强类型等于更少的错误/更多的健壮性。他们没有“语言”帮助,所以他们只能依靠单元测试。这就是为什么严肃的 Javascript 项目有这么少的错误(jQuery、node.js、CoffeeScript)。这就是为什么我不介意在 ViewBag 上传递标题 :-)
  • 'Serious' javascript 项目也有错误。 jQuery 在其生命周期中已经有数千个。测试并没有阻止错误。如果您使用的是 VieWModels,根据定义,该模式应该包含视图的信息,否则您将失去使用它们的良好优势,我无法争辩这一点。许多架构师已经意识到这一点,这就是为什么视图模型是最佳实践方法的原因。这并不意味着你的不会工作,但你确实打开了 1. 使用视图模型的不一致,以及 #2。所有前面提到的东西。
【解决方案5】:

您可以使用ViewData.ContainsKey("yourkey")

在控制器中:

ViewBag.IsExist = true;

在视图中:

if(ViewData.ContainsKey("IsExist")) {...}

【讨论】:

    【解决方案6】:

    我需要对此进行测试,但是:

    @if (ViewBag.ABoolParam ?? false)
    {
        //do stuff
    }
    

    我认为会给您 ViewBag 属性的值,或者如果缺少则返回默认值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-20
      • 2014-05-08
      • 2020-11-24
      • 1970-01-01
      • 2015-04-03
      • 2017-07-19
      相关资源
      最近更新 更多