3.3 Implementing the services/application layer
Once all the repositories are built for single
serving, we can begin to create the services layer. Again, this layer is
responsible for assembling aggregates and performing complex actions
with our entities.
MessageService
Email
AlertService
FriendService
MessageService
The MessageService will help us in one way — sending messages. Keep in mind that to send a message, we will need to create a Message, then create a MessageRecipient for the sender's copy, and then create one-to-many MessageRecipients
for the receivers of the message. While this is not a complex task
really, it is a very appropriate series of tasks for a service object!
//Core/Impl/MessageService.cs
public void SendMessage(string Body, string Subject, string[] To)
{
Message m = new Message();
m.Body = Body;
m.Subject = Subject;
m.CreateDate = DateTime.Now;
m.MessageTypeID = (int)MessageTypes.Message;
m.SentByAccountID = _userSession.CurrentUser.AccountID;
Int64 messageID = _messageRepository.SaveMessage(m);
//create a copy in the sent items folder for this user
MessageRecipient sendermr = new MessageRecipient();
sendermr.AccountID = _userSession.CurrentUser.AccountID;
sendermr.MessageFolderID = (int) MessageFolders.Sent;
sendermr.MessageRecipientTypeID = (int) MessageRecipientTypes.TO;
sendermr.MessageID = messageID;
sendermr.MessageStatusTypeID = (int)MessageStatusTypes.Unread;
_messageRecipientRepository.SaveMessageRecipient(sendermr);
//send to people in the To field
foreach (string s in To)
{
Account toAccount = null;
if (s.Contains("@"))
toAccount = _accountRepository.GetAccountByEmail(s);
else
toAccount = _accountRepository.GetAccountByUsername(s);
if(toAccount != null)
{
MessageRecipient mr = new MessageRecipient();
mr.AccountID = toAccount.AccountID;
mr.MessageFolderID = (int)MessageFolders.Inbox;
mr.MessageID = messageID;
mr.MessageRecipientTypeID = (int) MessageRecipientTypes.TO;
_messageRecipientRepository.SaveMessageRecipient(mr);
_email.SendNewMessageNotification(_userSession. CurrentUser,toAccount.Email);
}
}
}
This should be very straightforward to follow. The first thing we do is to spin up a new instance of the Message that we are sending. We then save it via the MessageRepository and get back the new MessageID to work with down the line.
The next task is to make sure that we paste a copy of the message in the sender's Sent Items folder. We do this by creating a MessageRecipient object and tying it to the sender's account. You will notice that we have assigned it to the Sent Items folder using an enum named MessageFolders, which has IDs that map to the MessageFolders lookup table. This enum is stored next to a new domain object named MessageFolder and looks like this:
//Core/Domain/MessageFolder.cs
namespace Fisharoo.FisharooCore.Core.Domain
{
public enum MessageFolders
{
Inbox = 1,
Sent = 2,
Trash = 3,
Spam = 4
}
public partial class MessageFolder
{
}
}
The next item in the MessageService is assigning the MessageRecipientTypeID to the sender's copy. The MessageRecipientType is to let the display know whether to show the MessageRecipient as a TO, CC, or BCC recipient. This is another enum value that maps back to a lookup table in the database and looks like this:
//Core/Domain/MessageRecipientType.cs
namespace Fisharoo.FisharooCore.Core.Domain
{
public enum MessageRecipientTypes
{
TO = 1,
CC = 2,
BCC = 3
}
public partial class MessageRecipientType
{
}
}
We then move into a foreach loop in the MessageService,
which is responsible for determining whether we are looking up a
recipient via an email address or a username. It does this by testing
the To value of the MessageRecipients to see if it has an ampersand or not, which would correspond to an email address.
Depending on whether the TO value is an email address or a username, we get a copy of an Account object. Once we have a valid Account object to work with, we move on to creating a new MessageRecipient for that Account. You should note that in this implementation of the MessageRecipient, we are placing the Message subscription into the Inbox instead of the Sent Items folder. This MessageRecipient is also of MessageRecipientType TO.
Email
Once the MessageRecipient is successfully created and persisted to the database, we then move on to sending an email notification to the MessageRecipient. The most important thing to note about the additional method of SendNewMessageNotification() is that we are sending a notification — not the whole message!
I mention this because I feel it is important to
note that one of the quickest ways to get your sites' IP addresses
banned is to be determined to be a sender of spam. Since you are
entirely responsible for the content that go out in your messages, you
can't directly control what your users type in a message. So don't risk
your reputation by sending the entire contents of their messages!
public void SendNewMessageNotification(Account sender, string ToEmail)
{
foreach (string s in ToEmail.Split(new char[] {',',';'}))
{
string message = sender.FirstName + " " + sender.LastName +
" has sent you a message on " + _configuration.SiteName + "! Please log in at " + _configuration.SiteName +
" to view the message.<HR>";
SendEmail(s, "", "", sender.FirstName + " " + sender.LastName +
" has sent you a message on " +
_configuration.SiteName + "!", message);
}
}
This method breaks down all the TO
recipients and creates a new email notification using our existing
subsystem telling the recipients that they have a new message waiting
for them in their Inbox.
AlertService
We will now create these tools,
so that we can fill this placeholder out.
//TODO: MESSAGING - point to send message URL
private string GetSendMessageUrl(Int32 AccountID)
{
return "<a href=\"[rootUrl]/mail/newmessage.aspx?AccountID=" + AccountID.ToString() + "\">Click here to send message</a>";
}
This method is simply responsible for creating a link
to the new message page passing in the user you want to send a message
to. This method is already called from several of our existing AlertService methods.
FriendService
We now need to extend our FriendService.CreateFriendFromFriendInvitation()
method. Remember that this method is responsible for creating a friend
from an accepted invitation. We now want to add some logic to this that
when a friend request is accepted, we send a new Message to the creator
of that friend request letting them know that their request was
accepted.
public void CreateFriendFromFriendInvitation(Guid InvitationKey, Account InvitationTo)
{
...
//add a message to the inbox regarding the new friendship!
Message m = new Message();
m.Subject = "You and " + InvitationTo.Username + " are now friends!";
m.Body = "You and <a href=\"" + _webContext.RootUrl + InvitationTo.Username + "\">" + InvitationTo.Username + "</a> are
now friends!";
m.CreateDate = DateTime.Now;
m.MessageTypeID = (int)MessageTypes.FriendConfirm;
m.SentByAccountID = InvitationFrom.AccountID;
Int64 messageID = _messageRepository.SaveMessage(m);
MessageRecipient mr = new MessageRecipient();
mr.AccountID = InvitationTo.AccountID;
mr.MessageFolderID = (int)MessageFolders.Inbox;
mr.MessageID = messageID;
mr.MessageRecipientTypeID = (int) MessageRecipientTypes.TO;
mr.MessageStatusTypeID = (int) MessageStatusTypes.Unread;
_messageRecipientRepository.SaveMessageRecipient(mr);
}
This additional code is going through the motions of
creating a new message and a recipient for that message. In this case
though, we are giving this message the MessageTypeID of MessageTypes.FriendConfirm (or a friend confirmation). Other than that, this code is straightforward.