| Steven's profileDevelopmentalBlogLists | Help |
|
24 February Notification Services - Part 4 - Managed APIIn the first 3 parts of this series we discovered how to define a Notification Services application via the instance and application XML. In part 2 we defined an example scenario where users are automatically subscribed to receive notifications in their email whenever someone posts a comment against their blog post. In this part we will discover how to write code to access the event schemas we defined in part 3, and how to insert subscribers. For the sake of brevity, this post will define sections of code, not entire classes. Assume a class library project in C# that will be called by our main blog ASP.NET application. The methods defined in this post would be found in such a library. This post assumes that the Notification Services instance is installed on the same machine that will be running the code. This is important because to access a NS instance, you don't use connection strings as is typical in ADO.NET. Instead, it refers to registry entries which are automatically placed by NS when the instances is 'Registered' and 'Started'. For more information, see the MSDN link. Preperation At some stage we will also need to define what our Instance name and Application name is. We could put this in a constant but ideally it would be in web.config and accessible through a property somewhere. This code will assume a class called 'Settings' which has properties called 'InstanceName' and 'ApplicationName'. Eg. string application = Settings.ApplicationName; A lot of the time we will need access to an instance of a class called NSInstance. Through this class we can get access to our NS application, by getting an instance of NSApplication. The rest of this post will refer to instances of both of these classes, so we will define some code for them now:
In Notification Services an instance can have multiple applications, even though previously we have defined only 1. Subscribers
You may remember from our application schemas that we needed to store a UserId. This was a simple string that represents the user a subscription belongs to. Before we can add subscriptions, we need to first check that the instance has the user registered as a subscriber. We can do this as follows:
As you can see we use our BlogInstance to access an enumeration of all users, which can be indexed by the user's name. We could easily modify this into a Delete method for a subscriber as follows:
Now we know how to check for a subscriber, we can write code to add one:
Simple! If we don't check for a subscriber first, an exception will occur if a name is added twice. Devices SubscriberDevice device = new SubscriberDevice(BlogInstance); DeviceName is often referenced in your application XML rule for subscriptions so it is usually important to have a naming standard for your devices. However we have not been using devices up to this point so the values you put here aren't important for now. DeliveryChannelName however is extremely important. In part 2 we defined the instance XML and part of that was the <DeliveryChannels>. In that XML we defined a protocol of type SMTPDelivery with a name of SMTP. When defining the device delivery channel name, it must match one of the channels specified in your instance XML otherwise no deliveries will be sent (no exception will occur, however when the service runs your notifications, it is at this point that it will fail, and details will be inserted into the event log). As with subscribers you can check if the device has already been added as follows:
As with subscribers, we should check the device has not already been added before commencing the insert process. And as with subscribers, deleting a device is as easy as calling the Delete method of the SubscriberDevice instance.
Because the .Net type subscription has no way of knowing at design-time what fields your subscription schema might have, it uses a common method for setting your subscription fields. This means you won't get compile errors if you don't really have a "PostId" in your subscription schema in Notification Services, but you will get a runtime exception on the subscription.Add(); method call. Important to note is that in the constructor for a Subscription takes an NSApplication instance now. This is because even though subscribers and devices are specific to an instance, an actual subscription is specific to an application only. Also note the second parameter of the constructor. This is the name of the subscription class we are subscribing to. Note that the name we supplied 'CommentSubscription' is the name we specified for our subscription class in the application XML. Once again, this will cause a runtime exception at the subscription.Add(); method call if the subscription class name is invalid. Well done! The user is now subscribed to receive notifications when comments are posted. However we still have to define how comments are posted to Notification Services so that those subscriptions can be acted upon. Events
In this code, we assume that we already have the values of the comment text, the user who posted the comment, and the original blog postId that the comment was posted against. The Event class lets us define the details to post to Notification Services through an indexer, and the EventCollector class will write the events to Notification Services for us. As usual incorrect fields specified will result in a runtime exception. Some items to note here. First, the constructor for an event needs the name of the event class we are posting to. We only defined 1 in our events schema; this was defined in the last post in our application XML. Secondly, in our last post we also defined the <Providers> node and the <NonHostedProvider> sub node (right at the end). When defining an EventCollector we must pass our provider name to the contstructor. You can not post an event to Notification Services without using one of the providers specified in your application XML. Because we are specifying events in code outside of Notification Services, our provider is a 'NonHostedProvider': not hosted by Notification Services. Summary This brings us to the end of my series on Notification Services. If there is anything else you would like to know about, please don't hesitate to contact me and I'll do my best to provide useful information. Notification Services Series Further Resources Technorati Tags: Notification Services,Sql Server,Sql Server 2005,XML,Events,Notifications,Subscriptions,C#,API 17 February Notification Services - Part 3 - Application XMLThe application XML defines the key information about your Notification Services (NS) application. This includes the schemas for event data being received, schemas for what users can subscribe to, and schemas for the information that will be sent in a notification. At the bare minimum you need 1 schema for each section. The application XML is defined with the following elements:
Here you can see the sections where we define our 3 different schemas: EventClasses, SubscriptionClasses, and NotificationClasses. Events It is important to decide early on what information you want to track about the comment. In our case, users will be subscribing to receive comments for a particular blog post. The best way to track a blog post is by its Id. Referring to the schema defined in part 2 each blog post has a 'PostId' and this is referenced as a foreign key to the Comment table. This is the first item of information we will need in our schema. No doubt we'll also need to send notifications with the comment title and contents, so we'll add those two fields to our schema as well. Our final entry for the application XML looks like this:
When your instance XML is imported into NS, and the application XML is processed, these fields will actually be created in a new table. You can also see we have defined an index that will be created in the same table. Notifications
The first part of the <NotificationClass> node is very simple to create. First we give our schema a name via the <NotificationClassName> node. Then we define our 2 fields in the <schema> node. Next we go on to define our content formatter. In our case, we want to use a stock standard XSLT to define our markup. So we specify its base path and file name. Finally, we want to define what protocol to use for this notification class. In the last post we defined our <DeliveryChannels> in the instance XML. Here, we must match a valid protocol from that list. We only defined one: of type SMTPDelivery, and called it 'SMTP'. We use that name here and go on to define all the important fields required for sending an email. Note that the <SqlExpression> field specifies the value to use. This actually is a valid SQL expression; the value you supply here is translated into an SQL statement to retrieve the values required for the notification. For example, the 'To' section specifies DeviceAddress as the value to use for this field. We'll learn about the DeviceAddress and where it comes from a little later, but suffice to say it is pulled from the database. For absolte literal values, we follow normal SQL conventions and put them in 'single quotes'. In the case you want to combine a literal value with a database field, combine them with normal SQL syntax, such as in the case of the 'Subject' field where we defined the literal '[BLOG_COMMENT] ' and the database value Name (which is the comment name). Subscriptions
As usual, we give our subscription class a name through the <SubscriptionClassName> node. Then, we define 2 parts to our subscription: the schema defining what fields can be subscribed to, and the rule that will process an event and turn it into a notification. The schema follows the same format as the <EventClasses> schema. For our application, we only want the user to be able to subscribe to a particular blog post, so we specify the PostId. However, we also want to track subscriptions on a 'per device' basis, so we also need to track what device the user is subscribing with. This manifests in our schema as follows:
Essentially, any subscription being made to the application will have to supply a device name and a PostId. However, when this schema is created as a table, Notification Services adds some other fields, such as a SubscriberId. In fact, all the schemas we've seen so far will be slightly modified by NS to keep things running smoothly. Next we must specify the rule to bring it all together. This rule takes the form of an SQL statement which joins potential subscriptions on to events. Each resulting row is a notification to be sent, and is parsed through the NotificationClass schema and formatters. Here is the <EventRule> we need to create notifications:
So first up we give our rule a name. Next, we define which event class we are comparing against for subscriptions. We only have one: NewCommentEvent. Finally the <Action> node defines our SQL statement that discovers potential notifications. Later on we define a time interval for how often NS should check for new notifications. When this interval fires, NS goes through all Event Rules and runs them. So lets delve into that a little further. Lets pretend NS is configured to fire off notification checks every 4 hours. Over a 4 hour period, our blog site gets 15 comments spread over 3 different blog posts: PostId 17, 18, and 19. NS already has received subscriptions for PostId 17 only, however 3 people are subscribed to that single post. In total 7 comments were made. The 4 hours expires, and the above SQL statement is processed. The result of the select statement will return 21 rows, which are inserted into the 'BlogCommentNotification' table. Another process fires and passes each row in this table to our XSLT formatter, and sends the notification via the defined channel (SMTP). Other Settings
This node is used to define how events get submitted to the application. If you intend to provide events through the managed API (as we are) then this must be set to a <NonHostedProvider>. The name you specify here will be used in your code. More on this in the next post. Summary Notification Services Series Further Resources Technorati Tags: Notification Services,Sql Server,Sql Server 2005,XML,Events,Notifications,Subscriptions 10 February Notification Services - Part 2 - Example Overview and Instance XMLAs mentioned in part 1 of my discussions about NS, I described how 'Subscribers' can subscribe via certain 'Devices' to 'Events' to receive 'Notifications'. In this post, I will demonstrate how to declaratively define your Notification Services instance. In following posts I will discuss how to create your application XML and talk to Notification Services using the API. Example Overview Previously we mentioned a user's blog as an example. We'll continue with that concept here. Imagine the database schema for a blog: You have 'Posts' which are performed by 'Users', and people can publish 'Comments' to them. A simple schema might look like this: You want to be able to let the Users of the blog subscribe to Comments made against particular posts. You've already built the main web application where users can login and post new blog articles. Now you want to extend the application to allow for notifications, and decide to use Notification Services as your technology. So you come up with a design and decide on the following:
You now have to do a couple of things. The first is to create the Notification Services instance/application, and the second is to modify your existing blog code to do 2 things: auto-subscribe a user who writes a post, and to also send all comments to Notification Services. Instance XML You decide to call your instance 'Intranet' and this specific NS application 'BlogNotifications'. First you have to create the instance XML, and the first draft looks something like this:
This means that you want an instance called 'Intranet' to be created on the local server. The available delivery channels to this instance are only SMTP at this stage. The name 'SmtpServer' is the name that will be used by your application code to reference what delivery channel to use for a particular subscription (more on that later). In Notification Services, anyone who is a subscriber, is defined at the instance level. This means only 1 list of subscribers is maintained for multiple applications. The application will be called 'BlogNotifications' and the 'ApplicationDefinitionFilePath' points to the second XML file we need to define. As mentioned earlier, you can have multiple applications in an instance. Here we have defined only 1, as with the Delivery Channels. It is possible to define variables to use in your instance XML to make things easier. These are called 'parameters' and when your instance xml is uploaded to Notification Services, it will prompt you for the values of any parameters you have defined. This works great in our case, because we may not want to 'hard code' the SMTP server. When testing we might use 1 server, but the production server might be somewhere else and therefore we would want to change the SMTP server at upload time. Parameters work perfect for this:
We would then alter our deliver channel code like this:
You can define any number of parameters. You can even use machine variables from the local OS in your parameters, as follows:
Finally, you can pass on values to your Application by defining some parameters for your application XML:
Here we are passing the value of a paramter called _Server_ as a parameter to the application XML called _NSServer_. That pretty much sums up the instance XML. In the next part, I'll discuss the Application XML how to link notifications to subscriptions. Notification Services Series Further Resources |
|
|