Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how would I go about creating a global notification class?

Still a bit new to c# and I'm in need of some pointers in the right direction with this..

I want build a notification system in C#/Asp.net that will allow different methods all over the site to add messages and message types to some static list that can be looped through on the next page load. It would be similar to how stack overflow does the banner notifications for achievements on each page load (e.g. "you earned x badge", you earned y badge"). Any idea how I might expose some global method that others could just go message.add('message', 'message type') with?

Edit:

It's been suggested that I use Session.Add("Notificiations", myList); to store the messages.

How/where would I go about initializing that "Notifications" list then do list.add() everywhere else?

like image 705
tester Avatar asked Jun 20 '11 17:06

tester


4 Answers

Showing popup banners at the top of the page on postbacks is pretty neat, but even cooler than that is using jQuery and ajax to do periodic checks with the server to see if the state of something has changed, or in your case if the user has any "new" messages.

This really works great when you have some asynchronous process running on the web server and you don't know how long it'll take (or you know for certain that it's going to take a real long time) and so you don't want your client's browser being tied up waiting for it. Using javascript and window.setInterval you can set a function to occur every 30 seconds (or whatever you like), and you then have said function do an ajax post against the server to see if the asynchronous process is complete. In your case the ajax post would simply be asking the server if the user has any "new" messages. If the user does have new messages then it's a simple matter of using jQuery to display some hidden div on the page informing the user that they have new messages.

It's a bit of a complicated solution and might be beyond the skills of an amateur, but the gains are worth it!

  • Makes your web app seem more stateful and "aware" of changes on the server
  • Dispenses with needless page refreshes that tend to disrupt the user experience

And as others have already noted, the best place to store "global" information is usually the Session (just note the limited scope of the Session). MSDN ASP.NET Session State

However, if it is data that needs to be accessed by every client then you can store it in the application Cache. ASP.NET Caching

Of course, you'll want to exercise caution with how much you're storing in either the Session or the Cache. It's easy to shoot yourself in the foot.

like image 126
Jagd Avatar answered Nov 14 '22 20:11

Jagd


You can write a class like this (I don't have any IDE near me, so I hope the code will compile):

public class MessageHelper
{
    protected const String sessionName = "messages_session";
    public List<String> Messages 
    {
        get 
        {
            List<string> list;
            if (Session[sessionName] != null)
            {
                list = (List<string>)Session[sessionName];
            }
            else 
            {
                list = new List<string>();
            }
            Session[sessionName] = list;
            return list;
        }
        set 
        {
            Session[sessionName] = value;
        }
    }

    public void AddMessage(String message) 
    {
        List<String> list = this.Messages;
        list.Add(message);
        this.Messages = list;
    }

}

To add a message, you would do:

MessageHelper messageHelper = new MessageHelper();
messageHelper.AddMessage("hello world");

(These messages are stored in the session, meaning user specific);

Let's assume you have literal in your masterpage, where you want to display your messages:

<asp:Literal ID="litMessages" runat="server" />

In your MasterPage you would add the OnInit Eventhandler:

protected override void OnInit(EventArgs e)
{
  MessageHelper messageHelper = new MessageHelper();
  String output = string.Empty;
  foreach(String message in messageHelper.Messages)
  {
    output += String.Format("{0}<br />", message);
  }
  this.litMessages.Text = output;

}

This should give you a basic overview, how you can store and display the messages. Of course you can adjust this code, either by adding a method for deleting messages, or nice client side effects (like the notifications here on StackOverflow. To find out how that is done, you can use the search. It has been discussed here several times)

I hope this helps you.

like image 45
citronas Avatar answered Nov 14 '22 18:11

citronas


I would suggest to define this as a service which can be implemented as a wcf/web service or an interface within you web app.

Having this feature as a service has couple of benefits including scalability, availability, and etc. As an example, a client using your iphone app sends the message and another client using your web site can see that.

if you prefer the 2nd approach, you need to use a DI framework such as Ninject and make sure that DI/Ioc frameworks applies singleton pattern on the instance.

I can give you an sample code here, but I can't do it until I get back home.

like image 24
gido Avatar answered Nov 14 '22 20:11

gido


I think the code I have below might be a good combination of the various answers. It uses a web service to retrieve new notifications and jquery to pull notifications on an interval. It stores the notifications in the users session.

First things first, our simple "Message" class which represents a single message. I noticed in your question that you would have multiple types of messages so i wanted to make sure to provide a solution that covered ths. My message class has only two properties: Text and Type. Type, in my demo, is used as the background color of the message.

public class Message
{
    public string Text { get; set; }
    public string Type { get; set; }
}

Next is our UserMessages class which handles message saving and retrieval. It saves all messages to the users session.

public class UserMessages
{
    protected static string _messageSessionID = "userMessages";

    public static List<Message> GetMessages()
    {
        var msg = HttpContext.Current.Session[_messageSessionID];

        if (msg == null)
        {
            return new List<Message>();
        }

        //clear existing messages
        HttpContext.Current.Session[_messageSessionID] = null;

        //return messages
        return (List<Message>)msg;
    }

    public static void AddMessage(Message message)
    {
        var msg = GetMessages();
        msg.Add(message);

        HttpContext.Current.Session[_messageSessionID] = msg;
    }
}

For my demo I decided to read the messaages using AJAX by combining an ASP.Net webservice, ScriptManager, and jquery. Here is my webservice:

--ASMX File--

<%@ WebService Language="C#" CodeBehind="~/App_Code/MessageService.cs" Class="UserNotification.MessageService" %>

--CS File--

namespace UserNotification
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.Web.Script.Services.ScriptService]
    public class MessageService : System.Web.Services.WebService
    {

        public MessageService()
        {
        }

        [WebMethod(EnableSession = true)]
        public List<Message> GetMessages()
        {
            return UserMessages.GetMessages();
        }
    }
}

On my aspx page I created a scriptmanager with a reference to my service, a div placeholder for messages and a quick and dirty message adding interface:

    <asp:ScriptManager runat="server">
        <Services>
            <asp:ServiceReference Path="~/MessageService.asmx" />
        </Services>
    </asp:ScriptManager>
    <div>
        <div id="msgArea">

        </div>

        <span>Add Message</span>
        Text: <asp:TextBox ID="txtMessage" runat="server" />
        <br />
        Type: <asp:TextBox ID="txtType" runat="server" Text="yellow" />
        <asp:Button ID="btnAdd" runat="server" Text="Add" onclick="btnAdd_Click" />
    </div>
</form>

To support message creation I added the following method in code behind to handle the button click event:

protected void btnAdd_Click(object sender, EventArgs e)
{
    UserMessages.AddMessage(new Message() {Text = txtMessage.Text, Type = txtType.Text});
}

Now for the important piece. To do the actual displaying of the messages I wrote the following block of javascript (using mostly jquery, I used v1.4.1, but you can use whichever version you wish). The timer is set on a 30 second interval. This means that it waits 30 seconds before processing the first time also. To process immediately on page load add CheckMessages(); right before the setInterval to perform an immediate check on page load. Leaving in the setInterval will allow for periodic updates to messages.

<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
    $(function () {
        setInterval('CheckMessages();', 30000);
    });

    function CheckMessages() {
        UserNotification.MessageService.GetMessages(function (result) {
            //alert('found ' + result.length.toString() + ' messages.');
            $.each(result, function (i, e) {
                var dv = $('<div />')
                            .css('background-color', e.Type)
                            .css('border', '4px solid white')
                            .css('color', 'white')
                            .css('text-align', 'center')
                            .append('<span>' + e.Text + '</span>')
                            .append(
                                $('<button />')
                                    .text('Close')
                                    .click(function () { $(this).parent().remove(); }));

                $('#msgArea').append(dv);

            });

        }, function (e) { alert(e._message); });
    }
</script>

Note in the above block of code that I use e.Text, which matches the name of our property in code, and e.Type. e.Type is our specified as our background color here but would probably be used for something else in real life. Also, in real life all of those CSS attributes would be in a CSS class (probably a single CSS class for each message type). I added a "close" button, you didn't mention it but I figured people would want to be able to close the notifications.

One cool thing about this implementation is that if down the road you realize you need to store messages NOT in the session but in, say, a database, this implementation will handle it smoothly. Just modify UserMessages.GetMessages to pull from a db/other location and you are set. Additionally you could set it up to handle global messages by reading them from the cache in addition to reading user messages from the session.

like image 1
Peter Avatar answered Nov 14 '22 20:11

Peter