Mvc ViewBag - 由于它是非可空值类型,无法将 null 转换为 'bool'

16
我想在控制器中设置一个布尔值为真,当生成特定视图时,然后相应地更改视图的标题。这应该非常简单,但结果是:

无法对空引用执行运行时绑定异常详细信息: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:无法对空引用执行 运行时绑定

我所做的只是在控制器中:
[AllowAnonymous]
public ActionResult Register()
{
    ViewBag.IsRegistration = true;
    return View();
}

然后在视图中:

@if (ViewBag.IsRegistration)
{
    <legend>Register using another service.</legend>
}
else
{
    <legend>Use another service to log in.</legend>
}

但它无法应对以下情况:

@if (ViewBag.IsRegistration)

更新

相关控制器代码:

[AllowAnonymous]
public ActionResult Register()
{
    ViewBag.IsRegistration = "true";
    return View();
}

注册页面:

@model Mvc.Models.RegisterViewModel
@{
     Layout = "~/Views/Shared/_AccountLayout.cshtml";
     ViewBag.Title = "Register";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
</hgroup>

<div class="row">
<div class="col-lg-6">
    @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary()

        <fieldset class="form-horizontal">
            <legend>Create a new account.</legend>
            <div class="control-group">
                @Html.LabelFor(m => m.UserName, new { @class = "control-label" })
                <div class="controls">
                    @Html.TextBoxFor(m => m.UserName)
                </div>
            </div>
            <div class="control-group">
                @Html.LabelFor(m => m.Password, new { @class = "control-label" })
                <div class="controls">
                    @Html.PasswordFor(m => m.Password)
                </div>
            </div>
            <div class="control-group">
                @Html.LabelFor(m => m.ConfirmPassword, new { @class = "control-label" })
                <div class="controls">
                    @Html.PasswordFor(m => m.ConfirmPassword)
                </div>
            </div>
            <div class="form-actions no-color">
                <input type="submit" value="Register" class="btn" />
            </div>
        </fieldset>
    }
</div>
    <div class="col-lg-6"></div>
  <section id="socialLoginForm">
            @Html.Action("ExternalLoginsList", new { ReturnUrl = ViewBag.ReturnUrl })
        </section>
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

ExternalLoginsList局部视图文件:

@using Glimpse.Core.Extensions
@using Microsoft.Owin.Security
@model ICollection<AuthenticationDescription>

@if (Model.Count == 0)
{
    <div class="message-info">
        <p>There are no external authentication services configured</p>
    </div>
}
else
{
    using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }))
    {
    @Html.AntiForgeryToken()

        <fieldset id="socialLoginList">
            @if (!string.IsNullOrEmpty(ViewBag.IsRegistration))
            {
            <legend>Register using another service.</legend>
            }
            else
            {
            <legend>Use another service to log in.</legend>
            }
            <p>
                @foreach (AuthenticationDescription p in Model) {
                    <button type="submit" class="btn" id="@p.AuthenticationType" name="provider" value="@p.AuthenticationType" title="Log in using your @p.Caption account">@p.AuthenticationType</button>
                }
            </p>
        </fieldset>
    }
}

只是猜测,也许ViewBag不能处理布尔值?你尝试过 ViewBag.IsRegistration = "true"; 并且检查字符串 ViewBag.IsRegistration == "true" 吗? - Trevor
@AirL - 那行不通。这不是同样的事情吗? - rism
1
嗯,看起来ViewBag实际上没有被设置。如果你尝试将ViewBag打印到HTML中,它能工作吗? - Trevor
不仅仅是bool变量的问题。你的ViewBag是否有任何设置?我觉得问题出在其他地方。 - YK1
1
@rism,我认为你的问题在于你正在Register Action中设置ViewBag.IsRegistration = "true";,并在ExternalLoginPartial中进行检查。你需要在返回ExternalLoginPartial的操作中设置它。 - Flood Gravemind
显示剩余5条评论
8个回答

61

试试:

@if (ViewBag.IsRegistration == true)

4
最简单和最快的解决方案。 - Daniel Kmak
不要忘记检查空值 - Prageeth godage
需要检查 null 吗? - GorvGoyl
2
你不必检查 null,因为 null == true 的计算结果是 false。如果没有 == true,那么 null 将不是 @if 条件的有效值。 - acfrancis
2
有趣的解决方案。 我唯一能看到的缺点是另一个开发者可能不理解为什么要这样做,可能会认为删除“== true”是代码的快速简化。 - Brady Moritz

23

我知道这是一个老问题,但我认为我有一个优雅的答案,所以万一有人在搜索后读到这个问题,这是我的答案:

@if (ViewBag.IsRegistration ?? false)

1
我只是稍微喜欢这个选项比 "==true" 更多一点,因为它更明显地表明你正在进行空值检查。 - Brady Moritz

1
尝试这个:
替换您的控制器中的行:
ViewBag.IsRegistration = true;

带有。
ViewBag.IsRegistration = new bool?(true);

将以下行替换为您的视图中的行:

@if (ViewBag.IsRegistration)

带有。
@if ((ViewBag.IsRegistration as bool?).Value)

有效地,您将一个可空布尔值放入ViewBag,然后进行解包。

1
谢谢,但是使用那段代码会出现“可空对象必须具有值”错误。 - rism

1

在检查true之前,先检查null

if (ViewBag.IsRegistration != null && ViewBag.IsRegistration)

这就是别人建议的,但问题在于它总是为空。因此进行检查可以防止错误,这很好,但它永远不会成立。 - rism
2
错误。如果你设置了它,它将是真 - 布尔值。如果你没有设置它,它将是空。 - Nenad

1

好的,根据评论中Flood建议,我需要传递参数。从父视图的ViewBag不能流经到局部视图。

因此,在Register View的代码中,我需要进行更改:

 <section id="socialLoginForm">
       @Html.Action("ExternalLoginsList", new {ReturnUrl = ViewBag.ReturnUrl})
 </section>

to

<section id="socialLoginForm">
    @Html.Action("ExternalLoginsList",
            new {ReturnUrl = ViewBag.ReturnUrl,
                 IsRegistering = @ViewBag.IsRegistering })
</section>

然后进入我的账户控制器并更改以下内容:

[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl)
{
    ViewBag.ReturnUrl = returnUrl;
    return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}

to

[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl, string isRegistering) {
   ViewBag.IsRegistering = (isRegistering.ToLower() == "true");
   ViewBag.ReturnUrl = returnUrl;
   return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}

然后在ExternalLogins中,我只需:
@if (ViewBag.IsRegistering)

根据需要。

因此,我将IsRegistering布尔值从控制器传递到主视图,然后再传递回控制器的操作方法,最终通过ViewBag在子部分视图中访问该布尔值。

非常感谢。


1

尝试使用TempData代替ViewBag。

将您的代码从

控制器

ViewBag.IsRegistration=true;

TempData["IsReg"]=true;

和在视图中

@if((bool)TempData["IsReg"])

看起来你正在使用子部分视图中的值,并且在父操作中添加数据。ViewBag 中的值无法将数据从一个操作传递到另一个操作的视图中。而 TempData 使用会话,可以用于将数据从一个操作传递到另一个操作的视图中。


0

在Viewbag中使用布尔值总是很棘手的。可以尝试使用以下方法

[AllowAnonymous]
        public ActionResult Register()
        {
            ViewBag.Registration = "x";//x or whatever
            return View();
        }

@if (!String.IsNullorEmpty(ViewBag.Registration))
        {
        <legend>Register using another service.</legend>
        }
        else
        {
        <legend>Use another service to log in.</legend>
        }

这样可以停止错误信息,但它永远不会识别IsRegistration ==“true”。 - rism
你只需要检查字符串是否为null或空!String.IsNullorEmpty(ViewBag.Registration)。如果它不是null或空,那么就是true。 - Flood Gravemind
是的,这就是我正在做的事情。@if (!string.IsNullOrEmpty(ViewBag.IsRegistration)),但它从未识别我在控制器中设置了ViewBag.IsRegistration =“true”或任何其他字符串。 - rism
我刚刚检查了代码,首先检查了空值或空字符串,然后检查了字符串的值。我甚至检查了布尔值,你确定你设置了ViewBag.IsRegistration属性吗? - Flood Gravemind
我刚刚更新了帖子并添加了一些代码。但是,是的,我确定我设置了它。 - rism

0
也许是这样的:
@if ((ViewBag.IsRegistration != null) && (ViewBag.IsRegistration is bool) && (bool)ViewBag.IsRegistration)
{
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接