Using the SQL-NS Hosting API


Building an application that hosts the SQL-NS engine is exceedingly simple. In the hosting application's code, you use the SQL-NS Hosting API to instantiate, start, and stop the engine. Between starting and stopping, the hosted engine manages its own resources, including the threads on which it executes, so nothing else is needed in the hosting application's code.

The SQL-NS Hosting API consists of exactly one classand it's one you've already seen: NSInstance. Previous chapters showed the NSInstance class used to encapsulate the properties needed to connect to a SQL-NS instance's database. But the NSInstance class has other members, not shown in previous chapters, that relate to hosting the SQL-NS engine. Specifically, NSInstance provides a StartInstance() method to start the engine, a StopInstance() method to stop the engine, an IsRunning property used to query the state of the engine, and an Error event that communicates fatal errors from the engine. This section describes the general usage of these NSInstance members. The following section shows a practical example of their use in a sample hosting application.

Note

Don't confuse the NSInstance class, which is part of the standard SQL-NS API, with the Instance class that is part of NMO. NSInstance was first introduced in Chapter 7, "The SQL-NS Subscription Management API," to represent connections to the instance database. The Instance class, covered in Chapter 16, "Using Notification Services Management Objects," fully encapsulates all the properties that define an instance.


Creating and Starting a Hosted Engine

Hosting begins with the creation of an NSInstance object. In the NSInstance constructor, you specify an instance name; the resulting NSInstance object can then be used to host the engine for that instance. Because the NSInstance constructor reads configuration information from the instance's Registry key, the instance must have been previously registered. The NSInstance constructor throws an exception if the specified instance isn't registered on the local machine.

Note

When registering an instance, you need not install the SQL-NS Windows service if the engine will only be hosted in a custom application. However, installing the service does no harm. The engine can still be hosted, even if the service is installed. All three registration mechanisms (nscontrol register, Management Studio, and NMO) provide options for registering an instance without installing its Windows service.


After creating an NSInstance object, you call its StartInstance() method to start the engine. Internally, StartInstance() creates a separate thread of execution on which the engine's startup operations are performed. This means that the StartInstance() method returns fairly quicklyit does not block waiting for the engine to start.

On startup, the engine carries out the same operations it does when hosted in the SQL-NS service: it connects to the databases and determines which SQL-NS components should run on the local computer. It then begins the execution of those components, creating and managing threads as needed. The only difference in a hosted scenario is that these components run in the hosting application's process, rather than in the SQL-NS service.

Note

The Hosting API wraps the same engine implementation used in the SQL-NS Windows service. In fact, the SQL-NS Windows service can be thought of as another hosting application. Internally, the SQL-NS Windows service uses the Hosting API to start and manage the engine.


Hosting opens up the possibility of several copies of the same SQL-NS engine being started concurrently on a single machine. For example, a hosting application could be started two (or more) times in parallel. Or a hosting application and the SQL-NS Windows service could be started at the same time. Even two threads in the same hosting application process could each create and start an engine for the same SQL-NS instance.

Having more than one engine for the same instance running on the same machine would obviously cause problems. Each one would try to run the same components, leading to conflicts and possible corruption of the instance state stored in the database. To prevent this, the hosting API explicitly blocks multiple copies of the same engine from running on the same machine. Using machinewide synchronization mechanisms, the API ensures that only the first engine started for a given instance is allowed to run. Subsequent attempts to start the same instance's engine (whether in another hosting process, the SQL-NS Windows service, or another thread in the same process) will fail.

Note

The restriction that only one copy of an engine may run at a time applies only to a single instance and a single machine. Engines for different instances may run concurrently on a single machine. Also, different machines can each run a copy of the same instance's engine concurrently. This is in fact needed to support the distributed scale-out scenario described in the section "Scaling Out the SQL-NS Engine" (p. 454) in Chapter 13, "Deploying a SQL-NS Instance." On each machine, the engine runs only the components configured to run on that machine.

Across instances and machines, you can mix and match hosting applications with the SQL-NS Windows service. In other words, on one machine in a distributed deployment, the engine can run in a custom hosting application, and on another machine, it can run in the Windows service. On the same machine, the engine for one instance can run in a hosting application and the engine for another instance can run in the Windows service.


The IsRunning property of an NSInstance object returns a Boolean value that indicates whether the engine is currently running. However, it's important to note that the check performed by the IsRunning property is limited to the specific NSInstance object on which it is accessed. IsRunning returns true only if the running engine was started by calling that particular object's StartInstance() method. If the engine is running but was started via another NSInstance object or the Windows service, IsRunning returns false.

Authentication and Security Issues in Hosting the SQL-NS Engine

A hosted SQL-NS engine can connect to the database via Windows Authentication or SQL Server Authentication. With Windows Authentication, the engine connects using the credentials of the account under which the hosting application runs. Alternatively, a SQL username and password can be used for SQL Server Authentication.

The choice of authentication mode is determined by the way the NSInstance object is constructed in the hosting application's code. If the NSInstance constructor is passed only an instance name, the engine connects via Windows Authentication. If the constructor is passed a SQL username and password, in addition to the instance name, the engine uses SQL Server Authentication.

Caution

When hosted in a custom application, the SQL-NS engine never reads SQL credentials from the SQL-NS instance's Registry key. Even if a SQL username and password are supplied at registration time and stored in the Registry, they are not made available to the hosted engine. Credentials stored in the instance's Registry key are available only to the SQL-NS Windows service.

This means that if you use SQL Server Authentication, you must manage the SQL username and password for the engine on your own and supply them to the NSInstance constructor. If your application stores credentials, it's strongly recommended that you use the Windows Data Protection API (DP API) to encrypt them. Documentation for the DP API is available in MSDN or online at http://msdn.microsoft.com/library/en-us/dnsecure/html/windataprotection-dpapi.asp.


Regardless of the SQL authentication mode you choose, it's good practice to always run the SQL-NS engine with the fewest possible privileges. When the engine runs in the SQL-NS service, this is accomplished by configuring the service to run as a low privileged account to which you selectively grant only the permissions needed. When hosted, the engine runs in the security context of the Windows account under which the hosting application runs. Always try to keep the permissions granted to this account to a minimum. Hosting the engine in an application that requires high levels of privilege may introduce security vulnerabilities.

Stopping the Hosted Engine

The StopInstance() method of the NSInstance class stops a hosted SQL-NS engine. Hosting applications save a reference to the NSInstance object on which they call StartInstance() and then use this to call StopInstance() as needed.

StopInstance() succeeds only when called from the same process that started the instance via StartInstance(). Calling StopInstance() in any other process results in an exception. This enforces the concept that only one process manages the SQL-NS engine for a given instance at a time (on a single machine). You cannot, for example, create an NSInstance object and call its StopInstance() method to stop an engine started by another process.

A hosted engine is automatically stopped if its NSInstance object is garbage collected. Therefore, a hosting application should always keep at least one reference to each NSInstance object on which it calls StartInstance(), to prevent these objects from being prematurely garbage collected. After calling StopInstance(), all references can be released, allowing normal garbage collection to proceed.

Receiving Error Events from the Hosted Engine

During the course of a SQL-NS engine's execution, it may encounter a fatal error that causes it to stop. Applications that host the engine may need to react to such errors by displaying a message to the user, attempting to restart the engine, or taking some other corrective action.

The NSInstance class exposes an event called Error that is raised whenever a fatal error occurs during the engine's execution. Hosting applications can attach an event handler delegate to this event. Whenever the event is raised, the event handler is called and can deal with the error by taking the appropriate action.

The delegate for NSInstance.Error event handlers is declared as follows:

 public delegate void ErrorEventHandler(object sender, ErrorEventArgs e); 


In the hosting application's code, you declare an event handler with this signature, create a delegate to the handler, and attach it to the Error event on an NSInstance object. It's important to note that when the event is raised, the event handler is called from the SQL-NS engine's execution thread. This is always a different thread from the one on which the NSInstance object's StartInstance() method was called. Therefore, any operations done inside the event handler need to be thread-safe.

The Error event is raised only for errors that cause the engine to stop. Other nonfatal engine errors, such as failures to deliver notifications, are not communicated through this event. Nonfatal errors are written to the Application Event Log, just as they are when the engine runs in the Windows service.

As explained in the "Setting the Logging Level" section (p. 486) in Chapter 14, "Administering a SQL-NS Instance," the amount of information written to the Application Event Log is controlled by settings in the NSService.exe.config file when the engine runs in the SQL-NS Windows service. When hosting the engine in a custom application, you can control the logging level with a similar configuration file.

The name of the configuration file must be the name of the hosting application's executable file, with .config appended. For example, if the hosting application's executable is called EngineHost.exe, its configuration file must be called EngineHost.exe.config. The configuration file must be placed in the same directory as the executable. Listing 17.1 shows the configuration file elements that control the SQL-NS engine's logging levels. You can include these elements in the configuration file for any hosting application, to control the information the hosted engine writes to the event log.

Listing 17.1. Configuration File Settings That Control the SQL-NS Logging Level

 <configuration>     ...     <system.diagnostics>         <switches>             <add name="LogAdministrative" value="2"/>             <add name="LogService" value="2"/>             <add name="LogEventProvider" value="2"/>             <add name="LogEventCollector" value="2"/>             <add name="LogGenerator" value="2"/>             <add name="LogDistributor" value="2"/>             <add name="LogVacuumer" value="2"/>             <add name="LogOther" value="2"/>             <add name="LogPerformanceMonitor" value="2"/>         </switches>     </system.diagnostics>     ... </configuration> 

The valid values for each log switch are explained in Chapter 14 (in the "Setting the Logging Level" section, p. 486). If a hosting application does not have a configuration file, or if the configuration file does not contain settings for the SQL-NS log switches, the hosted engine will not log any information to the Application Event Log. Therefore, you should always create a configuration file for your hosting applications and specify at least a minimal logging level. In most cases, a logging level of 2 is sufficient. (This is the default for the SQL-NS service.)




Microsoft SQL Server 2005 Notification Services
Microsoft SQL Server 2005 Notification Services
ISBN: 0672327791
EAN: 2147483647
Year: 2006
Pages: 166
Authors: Shyam Pather

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net