For those of you who have the exact same question that I had, this solution is:
I found the first step of my solution here: https://github.com/martijnboland/MvcNotification
He implemented his own Notification form. But I wanted to be able to use Toastr or any other notification options that were there.
NOTE. Anywhere you see a class that ends in "Res" is a resource file. This should keep our lines in our application more organized. So no one mixes with this.
This is how I implemented my solution. NOTE. This also works with MVC5
The first thing to do is create a Toastr object in the source code. This will be used to ultimately display a message to the user in the user interface.
public class Toast { public string type { get; set; } public string message { get; set; } public string title { get; set; } public string positionClass { get; set; } public int fadeIn { get; set; } public int fadeOut { get; set; } public int timeOut { get; set; } public int extendedTimeOut { get; set; } public bool debug { get; set; }
This uses two special enumerations that I created for Toastr display locations, and message box types so that they can be dynamic.
public enum MessageType { success, info, warning, error, };
AND
public enum DisplayType { TopRight, TopLeft, TopFull, BottomRight, BottomLeft, BottomFull, };
Once you have created the Toastr class, you need to override the OnException method of your controller. There is another way that should happen if you use ApiController, which I will also show.
You will also need to create the ToastrProperties class, as shown below.
public static class ToastrProperties // TODO: Add in the descriptions for each of these properties { /// <summary> /// /// </summary> public const string MessagesKey = "messages"; /// <summary> /// /// </summary> public const string BottomFull = "toast-bottom-full-width"; /// <summary> /// /// </summary> public const string BottomLeft = "toast-bottom-left"; /// <summary> /// /// </summary> public const string BottomRight = "toast-bottom-right"; /// <summary> /// /// </summary> public const string TopFull = "toast-top-full-width"; /// <summary> /// /// </summary> public const string TopLeft = "toast-top-left"; /// <summary> /// /// </summary> public const string TopRight = "toast-top-right"; /// <summary> /// /// </summary> }
Controller example:
I suggest creating a special base class for your controllers so that they all inherit it, and it can help with other things later in your application. Here is my base controller class.
After you have added this to your project, just install the controllers for this class instead of Controller and set this method.
WebAPI Controller Example:
This is a bit more because you cannot just inherit from the ApiController class, as in the example above. You must create an exception filter attribute that will be applied to each ApiController. I will show you how you can do this without manual use, as you will want it on every controller in any case.
First you need to create a filter attribute:
public class P3ApiExceptionFilterAttribute : ExceptionFilterAttribute
Then you need to add your filter attribute to all your Api controllers. The easiest way to do this is to enter your WebApiConfig.cs file, and inside the Register method, simply enter:
// Add the exception handler for the API controllers config.Filters.Add(new P3ApiExceptionFilterAttribute());
This will configure your WebApi controllers.
TRACK. Step
After you have added both methods, you need to do a few other things.
First of all, before we get to this, although it is important to tell you that what we do here in these two methods actually processes errors and logs them to our system. Then we use the static methods of Toast objects to serialize and deserialize the JSON into the response headers / temp of the request so that it returns to the client as JSON and can be processed by the browser for both async and reverse page requests, but we will do it in a second.
Since I did not want this to be used only to pass exception messages to the client, I also configured the extensions for the BaseController and ApiController methods so that they could call the ShowMessage method and send the Toastr methods to the client.
Here is the version of the base expansion controller:
public static class ControllerExtensions {
Here is a version of Web Api of the same extension:
public static class ApiControllerExtensions {
Like any standard extension, you need to make sure that the namespace is enabled, otherwise it will not work.
The final step:
Install the Toastr NUGET package or download it on the Internet and make sure that it is added to your packages or the method that you use to add scripts to your views.
Now you need to add Javascript to _Layout.cshtml in your application.
<script type="text/javascript"> // Setup message triggers and display all messages for this page $(document).ready(function () { var tempMessages = '@Html.Raw(TempData[ToastrProperties.MessagesKey])'; if (!tempMessages) { tempMessages = '[]'; } var viewMessages = '@Html.Raw(Response.Headers[ToastrProperties.MessagesKey])'; if (!viewMessages) { viewMessages = '[]'; } var allMessages = $.parseJSON(tempMessages).concat($.parseJSON(viewMessages)); handleAjaxMessages(); displayMessages(allMessages); }); // Display all messages that are listed within the Header of the call. // These messages are all stored in a serialized XML string that is then Decoded by the RenderMessages method function displayMessages(messages) { $.each(messages, function (idx, msg) { toastr[msg.type](msg.message, msg.title, { fadeIn: msg.fadeIn, fadeOut: msg.fadeOut, timeOut: msg.timeOut, positionClass: msg.positionClass, onclick: function() { var wnd = $("#AppMessageWindow").data("kendoWindow"); wnd.content(msg.message).center().open(); } }); }); } // Add methods for events that are both ajaxSuccess, and ajaxError function handleAjaxMessages() { $(document).ajaxSuccess(function (event, request) { checkAndHandleMessageFromHeader(request); }).ajaxError(function (event, request) { checkAndHandleMessageFromHeader(request); }); } // Get messages from the Response header of the request, and display them as // a message using Toastr function checkAndHandleMessageFromHeader(request) { // pull the messages from the Response Header var msgs = request.getResponseHeader('@ToastrProperties.MessagesKey'); if (!msgs) { msgs = '[]' } var allMessages = $.parseJSON(msgs) displayMessages(allMessages); } </script>
This requires some explanation. The first function in the script loads the initial headers of the / temp response, because there is no standard request on the page that starts on the page. Or at least I couldn’t find one that would allow access to the headers. Thus, they are put into use by Razor.
The rest should be fairly straightforward. It uses JSON to send a toastr message and adds events to Ajax requests so that any Toastr messages that return to it are handled properly.
I am sure that I have everything here. If you have any questions or something is missing when you are trying to implement it, write here or PM, and I will update the message. Hope this helps others who are trying to do the same. :)
Enjoy it!