Category: MVC Messaging System

Implementations GUI details

When creating a GUI you must think to give user some good feeling about what the software can do – so I started to MVC 4 website, that have mobile support integrated.

More, you must demonstrate some features right away to the user – so what’s best if not a message from system admin to the user  to “welcome” him ?

For this , I have to  implement a template with RazorEngine – simple to used from his code

string template = "Hello @Model.Name! Welcome to Razor!";
  string result = Razor.Parse(template, new { Name = "World" });

Summary of modifications for this simple operation – send and display a message  from Admin when a user registers

  1. Add connectionstrings to web.config – to connect to database + SiteUtils static class to retrieve it.
  2. RegisterAdmin user in Application_Start – in order to have user Admin in the database ( generate a GUID and put into a const)
  3. Add “welcome.txt” file
  4. Add RazorEngine to parse message
  5. Modify  Register action in order to send message after a user registers
  6. Add an area “Messaging” in order to can have the messaging separated from main site( to be easier to xcopy)
  7. Add an Index action( display read/unread messages) + View
  8. Add an DisplayMessage action (display a message) + View

All for this picture where it shows number of unread messages(1) and list :

image

You will find code at http://messagemvc.codeplex.com/SourceControl/changeset/changes/81924

Homework:

Think about the user actions . He will be interested in the following for existing messages:

  1. Unread messages
  2. View of all messages (paginating)
  3. Search messages:
    • Messages from a date
    • Messages from someone
    • Search

What do you think it will be done for implementing those?

Creating Edmx files and testing

The favorite ORM in .NET world for me it is edmx files. It gives you the database plain – and have generators for POCO (http://blogs.msdn.com/b/adonet/archive/2010/01/25/walkthrough-poco-template-for-the-entity-framework.aspx) as for EF4.1 DBContext(http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-model-amp-database-first-walkthrough.aspx).

I will use this one – because of the new ! But the template is over simplistic  -so I improved . I do not want you to bother you with my experience – I want to say that, after playing with Data attributes – I decide that Fluent Configuration suits all. The template is here:

DBContext-SecondVersion.zip

 

For example, the default template

Also for testing I use the fact the default EF4.1  Model1.Context.tt generates this code:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

( see playing on safe side to NOT drop the existing database?!)

Mine Model1.Context.tt generates this:


 protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
    		var prefix = System.Configuration.ConfigurationManager.AppSettings["prefixTable"]??"";
    		bool Continue=true;
            OnBeginModelCreating(modelBuilder,prefix, ref Continue);
    		if(!Continue)
    			return;
    
    		//construct default
    		#region smsg_Message 
    		modelBuilder.Entity<smsg_Message>().ToTable(prefix  + "smsg_Message");
    		modelBuilder.Entity<smsg_Message>().HasKey(item => item.IDMessage);
    
    
    		#endregion
    		#region smsg_Message_Archive 
    		modelBuilder.Entity<smsg_Message_Archive>().ToTable(prefix  + "smsg_Message_Archive");
    		modelBuilder.Entity<smsg_Message_Archive>().HasKey(item => item.IDMessageArchive);
    
    
    		#endregion
    		#region smsg_MessageThread 
    		modelBuilder.Entity<smsg_MessageThread>().ToTable(prefix  + "smsg_MessageThread");
    		modelBuilder.Entity<smsg_MessageThread>().HasKey(item => item.IDMessageThread);
    
    		modelBuilder.Entity<smsg_MessageThread>()
                    .HasRequired(item => item.IDMessage_IDMessageInitial)
                    .WithMany(u => u.IDMessage_IDMessageInitial)
                    .HasForeignKey(x => x.IDMessageInitial)
                    .WillCascadeOnDelete(false);
    
    		
    		modelBuilder.Entity<smsg_MessageThread>()
                    .HasRequired(item => item.IDMessage_IDMessageReply)
                    .WithMany(u => u.IDMessage_IDMessageReply)
                    .HasForeignKey(x => x.IDMessageReply)
                    .WillCascadeOnDelete(false);
    
    		
    		modelBuilder.Entity<smsg_MessageThread>()
                    .HasRequired(item => item.IDMessageArchive_IDMessageInitial)
                    .WithMany(u => u.IDMessageArchive_IDMessageInitial)
                    .HasForeignKey(x => x.IDMessageInitial)
                    .WillCascadeOnDelete(false);
    
    		
    		modelBuilder.Entity<smsg_MessageThread>()
                    .HasRequired(item => item.IDMessageArchive_IDMessageReply)
                    .WithMany(u => u.IDMessageArchive_IDMessageReply)
                    .HasForeignKey(x => x.IDMessageReply)
                    .WillCascadeOnDelete(false);
    
    		
    
    		#endregion
    	
    		OnFinishModelCreating(modelBuilder, prefix);
    		
        }

More, for giving you a smell of what the templates generates, look at this function for reading messages sent:


 public  IEnumerable<IUserMessage<IUser<String>,string>> RetrieveMessageSent(DateTime dt)
        {
            using (smsg_Message_List ml = new smsg_Message_List(ConnectionMessaging))
            {
                ml.LoadFromDB.AddToCustomPredicate(smsg_Message_FindDB.fexp_FromUser(this.Key));
                ml.LoadFromDB.AddToCustomPredicate(smsg_Message_FindDB.fexp_DateInsertedBetweenEqDate(dt, dt));
                ml.LoadFromDB.LoadFindCustomPredicate();
                return ml;
            }
        }

The class smsg_Message_List and the AddToCustomPredicate , LoadFindCustomPredicate and the expression fexp_FromUser and fexp_DateInsertedBetweenEqDate are automatically generated by the template.
I do not think that the template is perfect – it just helps me a lot!

For the database tests, I was thinking of NUnit – but was deprecated by xUnit. It has a nice project, named SpecificationExample – and it generates data in BDD style .
For example, this code:


 public void CreateUsersAndSendMessage()
        {
            
            List<SimpleUser> users = null;

            "When create two users".Context(() => users = CreateUsersAndDeleteItFirst());
            "it will be friends".Assert(() => FindFriend(users).ShouldNotBeNull());
            
            "and when send message from first user to second user".Do(() => SendMessage(users));

            
            "we will retrieve it searching message from first user ".Assert(() => RetrieveMessageSent( users[0]).ShouldEqual(1));

            "we will NOT retrieve it searching message from second user".Assert(() => RetrieveMessageSent(users[1]).ShouldEqual(0));

            "we will retrieve searching messages received by second user".Assert(() => RetrieveMessageReceived(users[1]).ShouldEqual(1));

            "we will retrieve count of unread messages :1 ".Assert(() => RetrieveMessageUnreadCount(users[1]).ShouldEqual(1));

            


        }

run by this command:

xunit.console.clr4.x86.exe "$(TargetPath)" /html "$(TargetDir)a.html" 

in Build events it will generate the following HTML


————————————————————————

✔  When create two users and when send message from first user to second user, it will be friends

Output
Before : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage
After : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage

0.060s

✔  When create two users and when send message from first user to second user, we will NOT retrieve it searching message from second user

Output
Before : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage
After : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage

0.099s

✔  When create two users and when send message from first user to second user, we will retrieve count of unread messages :1

Output
Before : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage
After : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage

0.032s

✔  When create two users and when send message from first user to second user, we will retrieve it searching message from first user

Output
Before : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage
After : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage

0.053s

✔  When create two users and when send message from first user to second user, we will retrieve searching messages received by second user

Output
Before : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage
After : testXunit.clsTestUserSendMessage.CreateUsersAndSendMessage

—————————————–


Nice , isn’t it?

Homework :
1. use the ITLIst.tt template , search for

//TODO: prefix

and make generating same prefix for the table as in the Model1.Context.tt( search prefix)
( Do not forget the change the edmx file name in the .tt file!)
2. Make a .t4 file to share commonalities( such as edmx name)

Interfaces and more

 

Summary:

If you want common behavior, you need an interface. And from the first one is a small step to re-organizing the program.

Body:

When you make a component for other people, you must make the possibility for those to

1. customize your software with their software

2. provide a default implementation

For the messaging component, the first customization is to provide a way for the site using the messaging to use their users.

The first step is to create a custom project which can provide guidance to the users that want to implement. VS provides XML documentation –I have checked and put also “warnings as error”

clip_image002

Next , I have create the User interface:

/// <summary>
    /// the user that can send messages
    /// TODO version 2: make pagination
    /// </summary>
    /// <typeparam name="UserPrimaryKey">the type of primary key</typeparam>
    public interface IUser<UserPrimaryKey>
    {
        /// <summary>
        /// the user primary key
        /// </summary>
        UserPrimaryKey Key { get; set; }
        /// <summary>
        /// the user name to be displayed
        /// </summary>
        string UserNameToDisplay { get; set; }
        /// <summary>
        /// other info for the user
        /// </summary>
        string OtherInfo { get; set; }

        /// <summary>
        /// find friends
        /// </summary>
        /// <param name="search">find user by name</param>
        /// <returns></returns>
        IEnumerable<KVPNew<UserPrimaryKey, string>> FindFriends(string search);

        /// <summary>
        /// find friends online
        /// </summary>
        /// <param name="search"></param>
        /// <returns></returns>
        IEnumerable<KVPNew<UserPrimaryKey, string>> FindFriendsOnline(string search);

        /// <summary>
        /// sends a message 
        /// </summary>
        /// <param name="message"></param>
        void SendMessage(IUserMessage<IUser<UserPrimaryKey>, UserPrimaryKey> message);

    }
 

Two methods are interesting : SendMessage and FindFriends

Let’s take first SendMessage. It was obviously clear that I need another interface – the message to be sent. So the next interface created:

/// <summary>
    /// the message to be sent to the user
    /// TODO version 2: allow messaging for more than 1 user
    /// TODO version 2: message importance
    /// </summary>
    /// <typeparam name="TheUser">user interface</typeparam>
    ///  /// <typeparam name="UserPrimaryKey">user primary key</typeparam>
    public interface IUserMessage<TheUser, UserPrimaryKey>
        where TheUser : IUser<UserPrimaryKey>
    {
        /// <summary>
        /// subject of the message
        /// </summary>
        string Subject { get; set; }
        /// <summary>
        /// body of the message
        /// </summary>
        string Body { get; set; }
        /// <summary>
        /// to the user
        /// </summary>
        TheUser To { get; set; }
        /// <summary>
        /// from the user
        /// </summary>
        TheUser From { get; set; }
        /// <summary>
        /// cc - as in email
        /// </summary>
        TheUser CC { get; set; }

        /// <summary>
        /// date of message
        /// </summary>
        DateTime DateInserted { get; set; }

        /// <summary>
        /// if recipient have read
        /// </summary>
        bool MessageRead { get; set; }
        // <summary>
        // bcc - as in email
        // </summary>
        //TheUser BCC { get; set; }



    }

Let’s take the other : IEnumerable<KVPNew<UserPrimaryKey, string>> FindFriends(string search);

It is clear that a user can send emails to friends( maybe to anybody if we make an intranet site for an enterprise) and I must somehow have the names and id’s of the friends. I could use KeyValuePair – but it is a struct and can not be compared with null . More, usually I need more data to be transferred – so I have created long ago a KVPNew class:

 /// <summary>
    /// this is the correspondent class of KeyValuePair structure from .net
    /// The features:
    /// 1. it is a class-  can be compared fastly with null
    /// 2. can be used in a search and display <paramref name="AdditionalData">AdditionalData </paramref>
    /// </summary>
    /// <typeparam name="TKEY">Key - it is compared in equals and GetHashCode</typeparam>
    /// <typeparam name="TValue">Value to be displayed</typeparam>
    public class KVPNew<TKEY, TValue>
    {
        public KVPNew() { }
        public KVPNew(TKEY key, TValue value):this()
        {
            this.Key = key;
            this.Value = value;

        }
        public TKEY Key { get; set; }
        public TValue Value { get; set; }
        public string AdditionalData { get; set; }
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            var o = obj as KVPNew<TKEY, TValue>;
            if (o == null)
                return false;
            return this.Key.Equals(o.Key);

        }
        public override int GetHashCode()
        {
            return this.Key.GetHashCode();
        }
    }

And, being to interfaces, I have created also an interface for admin people to find users

/// <summary>

/// used by application to load plugins to find users

/// because each application can have it’s own way to find users

/// <summary>
    /// used by application to load plugins to find users
    /// because each application can have it's own way to find users
    /// used by admins to find users
    /// Improvement version 2 : pagination 
    /// </summary>
    /// <typeparam name="T">user </typeparam>
    /// <typeparam name="UserKey">user key </typeparam>
    public interface IUsersFind<T,UserKey>
        where T:IUser<UserKey>
    {
        /// <summary>
        /// used to find users online to send message
        /// </summary>
        /// <param name="UserThatMakesTheSearch"> the user that makes the search </param>
        /// <param name="Search">search string - could be null</param>
        /// <returns> a list of users</returns>
        IEnumerable<KVPNew<T, string>> FindUsersOnline(T UserThatMakesTheSearch, string Search);
        /// <summary>
        /// used to find users (online or not )to send message
        /// </summary>
        /// <param name="UserThatMakesTheSearch"> the user that makes the search </param>
        /// <param name="Search">search string - could be null</param>
        /// <returns> a list of users</returns>
        IEnumerable<KVPNew<T, string>> FindUsers(T UserThatMakesTheSearch, string Search);
        /// <summary>
        /// find a user by his key
        /// </summary>
        /// <param name="key">the user key</param>
        /// <returns></returns>
        IUser<UserKey> FindUser(UserKey key);
            
    }


/// <summary>
    /// operations with the database
    /// </summary>
    /// <typeparam name="User"></typeparam>
    /// <typeparam name="UserPrimaryKey"></typeparam>
    public interface IUserList<User, UserPrimaryKey>: IDisposable
        where User : IUser<UserPrimaryKey>
    {
        /// <summary>
        /// fast delete all from database - good for testing
        /// </summary>
        void FastDeleteAll();
        
        /// <summary>
        /// add to internal list
        /// </summary>
        /// <param name="u">the user to be added </param>
        void Add(User u);
         
        /// <summary>
        /// save changes for new and old members
        /// </summary>
        void SaveNew();
        /// <summary>
        /// save changes for old members
        /// </summary>
        void SaveExisting();

        /// <summary>
        /// for retrieving 
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        User Find(int i);
        
    }

The final interfaces are in this picture:

clip_image004

Next time we will create the database EF4.1 files from DatabaseFirst and we will modify .tt templates to behave nicely with relationships.

Homework:

  • Add to IUserMessage a BCC field
  • What if To from IUserMessage will be directed to more than one person ?How do you implement it?
  • Do you think that is something missed from KVPNew class?( Hint == operator and GetHashCode)

Simple messaging system -database configuration

Contents
We will create the database tables and user to access the database from the application
You will find at bottom the

  1. scripts for creating database
  2. materials to read further
  3. homework for you

As an older database programmer, I have started with database configuration.

The selected database engine is Sql Server 2008 R2 Express – the free version that can be downloaded from here : http://www.microsoft.com/express
To create tables , just start Sql Server Management Studio, point to your database, right click “Tables” node and press “New Table”
I have created the following tables in the diagram:

image

Several comments:

  1. The smsg_User table can ( and will !) be replaced by the owner of the site with his table of users . More, this will be configurable by the owner. That’s why I choose IDUser being varchar(150) – maybe the user id will be GUID ?
  2. The messages are stored in the smsg_Message
  3. The message archive table(smsg_Message_Archive) is simply to make the search faster on smsg_Message table. We will put here the messages older than (1 month? 2 months?)
  4. The smsg_MessageThread contains the possibility for the user to reply more than one time to a message.
  5. IDMessage is bigint . We can also put guid to have unlimited number of messages -but 9,223,372,036,854,775,807 messages ( * 2 -we will see it in action) will be enough for a small site.
  6. You can download the script from here:
    http://msprogrammer.serviciipeweb.ro/wp-content/uploads/MVC-4_94F/smsgV1.zip

Also you should not rely on Windows Identity to access the database. Why ? Because , usually , on Web hosting you have only some user name and password for database – not Active Directory user.

We will create an user that can access the Database and have full rights. We will manage further the rights for everyone.

Open SQL Server Management Studio and go to Security.

Please right click on “Logins ” in “Microsoft SQL Server Management Studio”
clip_image001[4]
Step 2: Please left click on “New Login… “
clip_image002[4]
Step 3: Please introduce “smsg” in “Login – New”
clip_image003[4]
Step 4: Please left click on “SQL Server authentication ” in “Login – New”
clip_image004[4]
Step 5: Please left click on “Password ” in “Login – New”
clip_image005[4]
Step 6: Please put “smsg” in “Login – New”
clip_image006[4]
Step 7: Please “smsg” in “Login – New” for confirm password
clip_image007[4]
Step 8: Please left click in “Login – New”
clip_image008[4]
Step 9: Please left click on “Enforce password policy ” in “Login – New”
clip_image009[4]
Step 10: Please left click on “Database ” in “Login – New”
clip_image010[4]
Step 11: Please keyboard input in “Login – New” […]
clip_image012[4]
Step 12: Add rights : Please left click on “SMsgS “
clip_image013[4]
Step 13: Please left click on “User Mapping ” in “Login – New”
clip_image014[4]
Step 15: Please mouse drag end on “Current view pane ” in “Login – New”
clip_image015[4]
Step 16: Please left click on “Smsg” database
clip_image016[4]
Step 17: smsg user will be in the dbo schema
clip_image017[4]
Step 18: Please put “dbo” as schema
clip_image018[4]
Step 19: Please select “db_datareader “
clip_image019[4]
Step 20: Please select on “db_datawriter ” in “Login – New”
clip_image020[4]
Step 21: Please select “db_owner ” in “Login – New”
clip_image021[4]
Step 22: Please left click on “OK ” in “Login – New”
clip_image022[4]
Now we will verify on database:
Step 23: Please left click on “Object Explorer Hierarchy ” in “Microsoft SQL Server Management Studio”
clip_image023[4]
Step 24: Please left click on “Object Explorer Hierarchy ” in “Microsoft SQL Server Management Studio”
clip_image024[4]
Step 25: Please left click on “smsg ” in “Microsoft SQL Server Management Studio”
clip_image025[4]

Summary
We have created database tables . We also generate a script for you that can be found here:
http://msprogrammer.serviciipeweb.ro/wp-content/uploads/MVC-4_94F/smsgV1.zip

But the security login ( user : smsg , pwd: smsg) you do have to do yourself.
You can also download the database backup from http://messagemvc.codeplex.com/releases/view/74250

To read:
3 Normal Form from Database Normalization, http://en.wikipedia.org/wiki/Database_normalization

Homework:
What if we want to send messages to a further date( let’s say, after on day 1 on the next month) ? What database changes do you envision ?

MVC4 and Simple messaging system

 

MVC4  Developer preview with mobile support just released. And, because best way to deal with is within an application, I decide to create a simple messaging system for any site that is made with MVC.

Description:

I begin with a registered user. What he can do:

1. Create messages ( subject + body ) to send to another registered user. The list of the users on the system will be taken either from database, either from an Application variable. The message will be recorded to a database( configured by the owner of the site )  with the possibility to be send also by email

2. When login, the registered user can see the list of messages and replies send to/by him. Also, if he has unread messages he can see an advertisement.

3. The application could be seen also from a mobile device.

What should be done also:

4. The install of the application should be easy for any developer ( xcopy or some package – like Nuget or recipe)

Wish me luck to finish !

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.