Search code examples
c#asp.net-mvcrazorasp.net-mvc-5viewbag

There's a Hole in my ViewBag Dear Liza


I have the following simple view that is used to send invitations out to register for our web-site. This is in an admin-only view and once the email address is filled out the admin can click and send the invite. The code is

 @using (Html.BeginForm("Upload", "Tools", FormMethod.Post,
        new { @class = "form-horizontal", role = "form" }))
    {
        @Html.AntiForgeryToken()
        <h2>Invite Users</h2>
        <div class="form-group">
            @Html.LabelFor(m => m.EmailAddress, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(m => m.EmailAddress, 
                    new { @class = "form-control", id = "email" })
                @Html.ValidationMessageFor(m => m.EmailAddress)
            </div>
        </div>
        <div class="form-group">
            @Html.Label("Access To", new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.DropDownList("Product", new SelectList(
                    new List<Object> {
                        new { Text = "D", Value = "D" },
                        new { Text = "U", Value = "U" },
                        new { Text = "All", Value = "All" }},
                        "Value",
                        "Text"),
                        new { @class = "form-control", id = "product" })
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <span class="label label-danger">@ViewBag.FailedMessage</span>
                <span class="label label-success">@ViewBag.SuccessMessage</span>
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="button" value="Invite User" class="btn btn-primary" />
            </div>
        </div>
    }

To post back to the controller on the button click with the selected combo-box selection, I use the following Java Script

<script>
    $(function () {
        $("input[type=button]").click(function () {
            var data_email = $('#email').val();
            var data_product = $('#product option:selected').text();
            $.ajax({
                url: 'Tools/SendInvite',
                type: 'POST',
                data: { email: data_email, product: data_product },
                success: function (result) {
                }
            });
        });
    });
 </script>

The controller method for this is

[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> SendInvite(
    string email, string product)
{
    ApplicationUser user = null;
    if (ModelState.IsValid)
    {
        user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user.IsAdmin != null && (bool)user.IsAdmin)
        {
            string key = String.Empty;
            string subMsg = String.Empty;
            var accessDB = new AccessHashesDbContext();
            switch (product) { /* do stuff */ }

            // Send email.
            try
            {
                await Helpers.SendEmailAsync(new List<string>() { email }, null, "my message string");
                ViewBag.FailedMessage = String.Empty;
                ViewBag.SuccessMessage = String.Format(
                    "Invitation successfully sent to \"{0}\"",
                    email);
            }
            catch (Exception)
            {
                ViewBag.SuccessMessage = String.Empty;
                ViewBag.FailedMessage = String.Format(
                    "Invitation to \"{0}\" failed",
                    email);
            }
        }
    }
    return View();
}

This code works and sends my email template off to the required recipient. However, I want to notify that the email has been sent or has failed to send via the ViewBag. This code seems to work, but in the view the ViewBag is empty and no messages are displayed, what am I doing wrong here?

Thanks for your time.


Edit. by using @yhax's answer below, I have come to the following attempted solution; in my controller I have

[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> SendInvite(string email, string product)
{
    ApplicationUser user = null;
    string result = "{\"invite_result\":\"{0}\",\"invite_success\":\"{1}\"}";
    if (ModelState.IsValid)
    {
        user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user.IsAdmin != null && (bool)user.IsAdmin)
        {
            string key = String.Empty;
            string subMsg = String.Empty;
            var accessDB = new AccessHashesDbContext();
            switch (product) { /* do stuff */ }

            // Send email.
            try
            {
                await Helpers.SendEmailAsync(new List<string>() { email }, null, "my message string");
                result = String.Format(result, 
                    String.Format("Invitation successfully sent to \"{0}\"", email), 
                    "true");
                return Content(result);
            }
            catch (Exception)
            {
                result = String.Format(result, 
                    String.Format("Invitation to \"{0}\" failed", email), 
                    "false");
                return Content(result);
            }
        }
    }
    result = String.Format(result, "Invite Failed", "false");
    return Content(result);
}

In my JavaScript within my view I now have:

<script>
    $(function () {
        $("input[type=button]").click(function () {
            var data_email = $('#email').val();
            var data_product = $('#product option:selected').text();
            $.ajax({
                url: 'Tools/SendInvite',
                type: 'POST',
                data: { email: data_email, product: data_product },
                success: function (result) {
                    var obj = JSON.parse(jsontext);
                    if (obj.invite_success == "true") {
                        $('#fail_message').val("");
                        $('#success_message').val(obj.invite_result);
                    }
                    else {
                        $('#fail_message').val(obj.invite_result);
                        $('#success_message').val("");
                    }
                },
                error: function () {
                    alert("Invite Failure");
                }
            });
        });
    });
</script>

This is always hitting the error condition and shows an alert. When I comment this error: function() out, then my post does not fire to the controller! What am I doing wrong in this case?


Solution

  • I think you want something like this:

    Controller:

    [HttpPost]
    [AllowAnonymous]
    public async Task<ActionResult> SendInvite(
        string email, string product)
    {
        ApplicationUser user = null;
        if (ModelState.IsValid)
        {
            user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
            if (user.IsAdmin != null && (bool)user.IsAdmin)
            {
                string key = String.Empty;
                string subMsg = String.Empty;
                var accessDB = new AccessHashesDbContext();
                switch (product) { /* do stuff */ }
    
                // Send email.
                try
                {
                    await Helpers.SendEmailAsync(new List<string>() { email }, null, "my message string");
                    return Content(String.Format("Invitation successfully sent to \"{0}\"", email));
                }
                catch (Exception)
                {
                    return Content(String.Format(
                        "Invitation to \"{0}\" failed",
                        email));
                }
            }
        }
    // you could redirect to another action, or return some other message
        return Content("not valid etc etc");
    }
    

    and then in here you could do something with the returned message:

    <script>
        $(function () {
            $("input[type=button]").click(function () {
                var data_email = $('#email').val();
                var data_product = $('#product option:selected').text();
                $.ajax({
                    url: 'Tools/SendInvite',
                    type: 'POST',
                    data: { email: data_email, product: data_product },
                    success: function (result) {
    // do something here... show a box with the message, whatever you like
    console.log(result);
                    }
                });
            });
        });