Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Azure

Service-Orientation with .NET : Utility Abstraction with a .NET Web Service

5/20/2011 5:41:42 PM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
Standard Mold is interested in creating a Notification service. They have a number of different systems that already notify people about IT system failures and outages, but this legacy architecture requires that their SMS sending software support four different SMS vendors, and has therefore become complex and expensive to maintain (Figure 1).
Figure 1. The current status of Standard Mold’s SMS-sending software.

Furthermore, they want to expand the use of their notifications, as follows:

  • they would like managers to be notified when inventory is running low

  • customers may need to be notified when specific types of new inventory arrive at the warehouse

  • the billing department may want to be able to notify customers as soon as payments are considered overdue

The team of architects responsible for designing these new notification functions is still interested in issuing notifications with SMS. Even though it is more costly and restrictive than issuing e-mail notification messages, business analysts have determined that SMS notifications are more likely to be received and read sooner.

The design of the service begins with the application of the Standardized Service Contract principle by following a contract-first approach. Architects design a NotificationMessage, a NotificationStatus type and a WSDL definition with a NotifyBySms operation and then proceed to use the WCF.blue tool to generate implementation code from the WSDL definition.

A single SMS vendor was chosen for use by the new service. This vendor provides a proprietary .NET API that the service will need to access. A sample code fragment used to interact with this API is shown here:

Example 1.
TransmitterClientProxy proxy = new TransmitterClientProxy();
int smsid =
proxy.SendShortTextMessage
(
12309723, //customer id
"T0pSecre7", //password
1, //priority
"You recieved this SMS from Standard Mold",
//message of SMS
7002348234781, //receiver
null, //delay hours
true, //delivery report wanted
"https://standardmold.com/delivery_report/{messageId}
/{state}" // delivery report address
);

Some of the parameters for this API are populated using configuration and message-specific parts of the SMS message. The actual text message and the receiving phone number is populated using the incoming request message.

The Notification service’s NotifyBySms operation and related NotifyBySmsRequest message are designed independently of this API. As a result, contract-to-logic coupling is avoided, allowing Standard Mold architects to change SMS vendors in the future, if required.

The Notification service needs to be able to perform its processing in an asynchronous fashion. Therefore, architects determine that it would be sufficient for the service to issue one-way notification messages without the need for any acknowledgement of receipt by service consumers.

Specifically, the NotifyBySms operation is designed to works as follows:

1.
When the notification request reaches the Notification service, it saves some information about the notification, gives it a NotificationId value, and puts the request in a queue.

2.
The Notification service sends a response to the service consumer containing the newly generated NotificationId. As a result, the consumer is able to use this ID value when it wants to poll for the status of the message.

3.
A transaction wraps this functionality in order to ensure the integrity of the database and the queue insertions. On the other side of the queue a Windows service is positioned to listen, send the SMS, and update the database accordingly. A transaction is also used here to ensure these steps are carried out together.

The technologies chosen for this service architecture are:

  • .NET

  • WCF

  • SQL Server

  • MSMQ

The service interface (called the Notification_receiver) is implemented using WCF. A transaction scope is defined to keep the SQL Server database (Notification_db) and MSMQ queue (Notification_queue) processing together.

To make interacting with MSMQ easier, they wrap the queue in a WCF interface. Notification_sender is the Windows service on the other end of the queue that uses a transaction scope to read a message from MSMQ, send a message using the API (not part of the transaction), and save the status of the message in the database. This architecture is illustrated in Figure 2.

Figure 2. The high level design of the Notification service.

This design allows the different parts of the service to be scaled independently, depending on future needs and requirements. The sender can be scaled out if necessary without touching the receiver, and the receiver part can be scaled out without touching the sender.

The GetNotificationStatus operation was created in order to allow consumers to find out more about the status of the notification (whether or not the SMS was sent or even opened).

Using the previously created NotificationId, service consumers can get the same kind of information as the NotifyBySms operation returns (the status of the notification). However, when calling the GetNotificationStatus operation, the consumer does get a return value signifying that the SMS was sent or opened, in case the recipient has already opened the SMS using a cell phone. This functionality was made possible by the SMS vendor and allows for a delivery report address to be added to the call using their proprietary API.

The WCF interface of the service (receiver) looks like this:

Example 2.
[ServiceContract
(Name = "Notification",
Namespace = "http://schemas.standardmold.com/
enterprise/services/v1")
]

public interface INotificationReceiver
{
[OperationContract]
NotificationResponse NotifyBySms
(NotificationMessage message);
[OperationContract]
NotificationResponse GetNotificationStatus
(Guid NotificationId);
}

The implementation of the GetNotificationStatus method is relatively straightforward. It basically gets the status of a specific NotificationId from the database.

The NotifyBySms method is also simple, in that it extracts the MessageId from the incoming message headers. The data type of the MessageId is UniqueId. From this field, a GUID is extracted and passed along with the notification message to the ProcessMessage method:

Example 3.
public NotificationResponse NotifyBySms
(NotificationMessage message)
{
UniqueId messageId = OperationContext.Current.
IncomingMessageHeaders.MessageId;
Guid messageGuid = Guid.Empty;
if (messageId.TryGetGuid(out messageGuid))
{
return this.ProcessMessage(message, messageGuid);
}
else
{
return new NotificationResponse
{
MessageStatus = Status.Failed
};
}
}

The ProcessMessage method first uses the DataAccess class to check if the notification was processed before. If not, it attempts to save the message to the database and put it in the queue. This is done inside a transaction scope, so either both or neither of these operations succeed. In case of a failure, the status of the notification in the response message is set to “failed.”

As previously mentioned, the notification may have been processed before a response is constructed using the current status of this notification that was returned from the database. In this case, the status can be saved (if the notification was not yet sent), or it can be set to another status value, such as “sent” (if the notification was sent to the consumer).

The following example shows how the message is saved to the database (with status “saved”) and placed in the queue. Possible responses include the communication of success with the NotificationId value or a response of failure in case of an exception condition.

Example 4.
private NotificationResponse ProcessMessage
(NotificationMessage message, Guid messageGuid)
{
NotificationResponse response = null;
Guid notificationId = Guid.Empty;
var notificationData =
DataAccess.GetNotificationData(messageGuid);
if (notificationData.NotificationNotProcessed)
{
try
{
using (var scope = new TransactionScope())
{
notificationId = DataAccess.SaveMessage
(message, messageGuid);
MsMqAction.SendToMsmq(message, notificationId);
scope.Complete();
}
response = new NotificationResponse
{
MessageStatus = Status.Saved,
NotificationId = notificationId
};
}
catch
{
response = new NotificationResponse
{
MessageStatus = Status.Failed
};
}
}
else
{
response = new NotificationResponse
{
MessageStatus = notificationData.MessageStatus,
NotificationId = notificationData.NotificationId
};
}
return response;
}


The DataAccess class checks the messageGuid. If it was set by the client (that is, the messageGuid is not Guid.Empty), it attempts to find it in the database using LINQ to SQL. If it was found in the database, the NotificationId and NotificationStatus properties are set in a NotificationData object:

Example 5.
public NotificationData GetNotificationData(Guid messageGuid)
{
using (NotifyDBDataContext db = new NotifyDBDataContext())
{
var notificationEntry =
(from notification in db.NotificationDataEntries
where notification.MessageId == messageGuid
select notification).SingleOrDefault();
if (notificationEntry != null)
{
return new NotificationData
{
NotificationId =
notificationEntry.NotificationId,
NotificationStatus =
notificationEntry.NotificationStatus
};
}
}
return new NotificationData();
}

The NotificationData class is also important in this example as it helps the ProcessMessage method determine if it should go on to process this notification, or simply return status information about it. If the notification was already processed, the NotificationData instance that the GetNotificationData method returns will contain values for NotificationId and NotificationStatus.

Example 6.
public class NotificationData
{
public Guid NotificationId { get; set; }
public Status NotificationStatus { get; set; }
/// <summary>
/// if NotificationId was not set this
/// notification was not processed
/// </summary>
public bool NotificationNotProcessed
{
get
{
return NotificationId.Equals(Guid.Empty);
}
}
}

The SendToMsmq method is responsible for putting the notification inside the MSMQ queue by creating an MSMQ message and then using WCF to put the message into the queue:

Example 7.
public void SendToMsmq
(NotificationMessage message, Guid notificationId)
{
IdentifiedNotification notification =
new IdentifiedNotification
{
NotificationId = notificationId,
NotificationMessage = message
};
var msmqMessage = new MsmqMessage
<IdentifiedNotification>(notification);
msmqMessage.Priority = MessagePriority.Highest;
var client = new MsmqNotificationClient
("NotificationEndpoint");
client.PutNotification(msmqMessage);
client.Close();
}

Standard Mold architects build a WCF program that communicates with MSMQ queue by creating an interface and a client implementation along with some simple configuration:

Example 8.
[ServiceContract]
public interface IMsmqNotificationQueue
{
[OperationContract(IsOneWay = true, Action = "*")]
void PutNotification(MsmqMessage
<IdentifiedNotification> msg);
}
public partial class MsmqNotificationClient :
ClientBase<IMsmqNotificationQueue>, IMsmqNotificationQueue
{
public MsmqNotificationClient() { }
public MsmqNotificationClient(string configurationName)
: base(configurationName) { }
public MsmqNotificationClient
(Binding binding, EndpointAddress address)
: base(binding, address) { }
public void PutNotification
(MsmqMessage<IdentifiedNotification> message)
{
base.Channel.PutNotification(message);
}
}


The significant configuration is as follows:

Example 9.
<client>
<endpoint
address="msmq.formatname:
DIRECT=OS:.\private$\NotificationSMS"
binding="msmqIntegrationBinding"
contract="MsMqIntegration.IMsmqNotificationQueue"
bindingConfiguration="NotificationEndpointBinding"
name="NotificationEndpoint"
/>
</client>

Developers choose to use the msmqIntegrationBinding because netMsmqBinding would make it more complicated to deserialize messages from the queue when implementing the sender.

The sender is implemented as a Windows service using the MSMQ API. It sets up a listener for the queue in the OnStar method.

Example 10.
protected override void OnStart(string[] args)
{
string queueName = ConfigurationManager.
AppSettings["queueName"];
if (!MessageQueue.Exists(queueName))
MessageQueue.Create(queueName, true);
MessageQueue queue = new MessageQueue(queueName);
queue.ReceiveCompleted +=
new ReceiveCompletedEventHandler
(MessageReceiveCompleted);
queue.BeginReceive();
}

Finally, the MessageReceive method sends the SMS using the legacy API (currently the API provided by the SMS vendor). It also removes the message from the queue and updates the notification status in the database.

Example 11.
static void MessageReceiveCompleted(object sender,
ReceiveCompletedEventArgs asyncResult)
{
var queue = (MessageQueue)sender;
using (var scope = new TransactionScope())
{
var message = queue.EndReceive(asyncResult.AsyncResult);
message.Formatter =
new XmlMessageFormatter(new Type[]
{typeof(IdentifiedNotification)});
var identifiedNotification =
(IdentifiedNotification)message.Body;
SmsSender.Send(identifiedNotification.
NotificationMessage);
DataAccess.UpdateStatus(identifiedNotification.
NotificationId, Status.Sent);
scope.Complete();
}
queue.BeginReceive();
}

The Notification service is ready for deployment. In support of applying the Service Discoverability principle, the Standard Mold team decides to publish supporting documentation alongside the service contract and SLA. This content is intended for project teams building service consumers and provides guidelines on how to effectively use the Notification service, along with sample code that demonstrates how to call the service using a WCF service consumer:

Example 12.
NotificationResponse response = null;
System.Xml.UniqueId messageId = new
System.Xml.UniqueId(Guid.NewGuid());
WcfClient.Using(new NotificationClient(), client =>
{
using (new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.
OutgoingMessageHeaders.MessageId = messageId;
response = client.NotifyBySms(new NotificationMessage
{
Recipient = "+13263827",
Message = "Please note that something happened"
});
}
});

Other -----------------
- Service-Orientation with .NET : Service Reusability and the Separation of Concerns
- Service-Orientation with .NET : Service Discoverability
- Service-Orientation with .NET : Exception Shielding
- Service-Orientation with .NET : Service Abstraction & Validation Abstraction
- Service-Orientation with .NET : Service Loose Coupling and Service Capability Granularity
- Service-Orientation with .NET : Service Façade
- Service-Orientation with .NET : Decoupled Contract
- Service-Orientation with .NET : Service Loose Coupling
- Service-Orientation with .NET : Service Contracts and Interoperability - Canonical Protocol
- Service-Orientation with .NET : Service Contracts and Interoperability - Data Model Transformation
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server