asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search










Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Creating an Extensible Windows Service - Part 2: Plug-In Development
By Robert Chartier
Rating: 4.5 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Creating the Plug-In Interface

    With the Windows Service mostly finished, we can focus on the actual plug-ins. We need to create a class (plug-in) that can be loaded at run time by referencing its file name and class name in the Windows Service's config file. Enter the "Interface".

    An interface is a forced contract. We must define the contract, and then another class implements that interface, meaning the class must fully create all of the members of the interface.

    For example, if we define a simple method in our interface:

    
    string[] Execute();
    
    
    any class that wishes to implement this interface must also define and implement it as so:
    
    public string[] Execute() {
    	return new string[]{"Ive been Implemented"};
    }
    
    
    Of course the actual code provided within the implementation can be anything that is relevant to the task at hand.

    Why are we using an interface for plug-ins? We use an interface because the contract is being met when we code against a set of classes that are based on the same interface; therefore, you can then create or cast objects as the type of the interface. If you do not fully understand interfaces, I recommend you read my article on OOP techniques at http://www.15seconds.com/Issue/020508.htm. We will build on top of the content found there.

    download source code for this article

    Step One: The Interface

    We want to keep the interface separate from the actual Windows Service. Let's add a New C# Class Library to our existing solution. I named mine "ServicesCore".

    Rename the default Class1.cs to "IServices.cs". Our interface is pretty small and easy to create.

    
    namespace scheduler_net {
    	public interface IServices {
    		string[] Execute();
    		string ToString();
    	}
    }
    
    
    The "Execute()" method takes in no parameters. It only returns a "string[]". I've decided a typical result of all plug-ins will be a string[], so we can transmit messages (most likely errors) out of the plug-in and to the caller. This will be the main method called on each plug-in to perform its job.

    I forced the "ToString()" method, so we can easily get the name of the plug-in at any time. This could be useful for logging situations or conditional actions based on the specific plug-in.

    Step Two: Creating a Schedule Manager To Manage Our Plug-Ins

    n our new project, we need to create two classes. The first will hold an individually scheduled item. It will contain items such as:

    1. the instance of the plug-in itself
    2. its schedule
    3. its file name, and class name
    It will also use its own internal schedule to execute the plug-in. Name this "Schedule.cs"

    The second class will hold a collection of all the scheduled items, iterate its entire collection, and instruct each individual schedule to run. Name this "ScheduleManager.cs"

    Most of the code for this class (see figure 1.4) deals with implementing two other interfaces, the IEnumerable and IEnumerator classes. These interfaces let us create and use a custom collection. If you do not understand how this works, please consult the documentation.

    Figure 1.3 Schedule Source Listing

    
    using System;
    
    namespace scheduler_net {
    	public class Schedule {
    		protected Scheduler.Net.IServices plugin=null;
    		protected string assemblyName;
    		protected string className;
    		protected long scheduleTicks;
    		protected System.DateTime lastRan=System.DateTime.MaxValue;
    		public Schedule(Scheduler.Net.IServices PlugIn, string AssemblyName, 
    string ClassName, long ScheduleTicks) {
    			plugin=PlugIn;
    			assemblyName=AssemblyName;
    			className=ClassName;
    			scheduleTicks=ScheduleTicks;
    		}
    		public Scheduler.Net.IServices PlugIn{get{return 
    plugin;}set{plugin=value;}}
    		public string AssemblyName{get{return 
    assemblyName;}set{assemblyName=value;}}
    		protected string ClassName{get{return 
    className;}set{className=value;}}
    		protected long ScheduleTicks{get{return 
    scheduleTicks;}set{scheduleTicks=value;}}
    		protected System.DateTime LastRan{get{return 
    lastRan;}set{lastRan=value;}}
    		public bool CanRunNow { 
    			get {
    				if(lastRan==System.DateTime.MaxValue) return true;
    				System.TimeSpan ts = new 
    System.TimeSpan(System.DateTime.Now.Ticks - lastRan.Ticks);
    				return (ts.Ticks > scheduleTicks);
    			}
    		}
    		public string[] Execute() {
    			string[] tmp;
    			if(CanRunNow) {
    				tmp = this.PlugIn.Execute();
    				this.lastRan=System.DateTime.Now;
    			} else 
    				tmp = new string[]{this.PlugIn.ToString()+ ": Not 
    Scheduled to run at this time."};
    			
    			return tmp;
    		}
    	}
    }
    
    
    Figure 1.4 ScheduleManager Listing
    
    using System;
    
    namespace scheduler_net {
    	public class ScheduleManager : System.Collections.IEnumerable, 
    System.Collections.IEnumerator {
    		public ScheduleManager() {
    			Reload();
    		}
    		public void Reload() {
    			try {
    				string pluginlist = 
    System.Configuration.ConfigurationSettings.AppSettings["pluginlist"];
    				string[] plugins = pluginlist.Split(";".ToCharArray());
    				string location = 
    System.Reflection.Assembly.GetEntryAssembly().Location;
    				location = location.Substring(0, 
    location.LastIndexOf(@"\")+1);
    				foreach(string plugin in plugins) {
    					try {
    						string[] pluginproperties = 
    plugin.Split(",".ToCharArray());
    						System.Reflection.Assembly asm = 
    System.Reflection.Assembly.LoadFrom(location + pluginproperties[1]);
    						System.Type type = 
    asm.GetType(pluginproperties[0]);
    						Scheduler.Net.Schedule newSched = new 
    Scheduler.Net.Schedule((Scheduler.Net.IServices)Activator.CreateInstance(type), 
    pluginproperties[1], pluginproperties[0], Convert.ToInt64(pluginproperties[2]));
    						this.Add(newSched);
    					}catch(Exception plugInFailure) {
    						string bar=plugInFailure.ToString();
    						
    					}
    				}
    
    			}catch(Exception loadupFailure) {
    				string foo=loadupFailure.ToString();
    			}
    		}
    		public string[] Execute() {
    			System.Collections.ArrayList log = new 
    System.Collections.ArrayList();
    			log.Add("System: Log Started");
    			foreach(Scheduler.Net.Schedule sched in this) {
    				foreach(string logitem in sched.Execute()) {
    					log.Add(logitem);
    				}
    			}
    			log.Add("System: Log Ended");
    			string[] tmp = new string[log.Count];
    			log.CopyTo(tmp);
    			return tmp;
    		}
    		protected System.Collections.ArrayList scheduledItems = new 
    System.Collections.ArrayList();
    		protected int counter=-1;
    
    		public System.Collections.IEnumerator GetEnumerator() {
    			return scheduledItems.GetEnumerator();
    		}
    		public object Current {get{return scheduledItems[counter];}}
    
    		public object this[int index] {
    			get {return scheduledItems[index];}
    			set {scheduledItems[index]=value;}
    		}
    		public void Reset() {
    			counter=-1;
    		}
    		public bool MoveNext() {
    			counter++;
    			return(counter<=scheduledItems.Count);
    		}
    		public void Add(object Item) { 
    			scheduledItems.Add(Item);
    		}
    		public void Remove(object Item) { 
    			scheduledItems.Remove(Item);
    		}
    		public bool Contains(object Item) { 
    			return scheduledItems.Contains(Item);
    		}
    		public int IndexOf(object Item) { 
    			return scheduledItems.IndexOf(Item);
    		}
    	}
    }
    
    
    Let's examine the "Reload()" method in figure 1.4. It reads in from our config file the value for "pluginlist". Here is an example of that node in the config file:
    
    <add key="pluginlist" value="Scheduler.Net.TemplatePlugin,TemplatePlugin.dll,36000000000;" />
    
    
    Next, the method splits apart this string into sections for each plug-in based on the ";" delimiter, which splits up each plug-in. Then for each plug-in, it splits out the class name, the assembly file, and its schedule (or ticks). I chose ticks for the duration of wait time before the next plug-in run time. This approach makes coding easy but doesn't lend itself well to power and flexibility. For example, you cannot specify start or end values, or even an exclusion list (don't run this plug-in between the hours of 3 am to 5 am), etc.

    You now see the reason why I chose to use an interface for the plug-in.

    We use reflection to load up the plug-in assembly and get a reference to the specified type. Next we use the System.Activator to create an instance of that type. We now have a reference to that plug-in, and since they all use our interface we can cast this instance to that interface when we create our new schedule item. Casting it as the interface allows us to use the methods specified in the interface's contract. That means calling the "Execute()" and "ToString()" methods.

    The end result will be a single instance of a schedule item, which can be added to our schedule manager's collection. Now that we have a collection of scheduled items, we need a way to automatically iterate over the collection and call each item's "Execute()" method. The "Execute()" method in the ScheduleManager does just this.

    Step Three: Finalizing the Service

    With the plug-in interface, scheduler, and loader developed, we only need to add the instance of our schedule manager to our service.

    First create the variable at class scope:

    
    Scheduler.Net.ScheduleManager sm;
    
    
    And then in the ServiceTimer_Tick event handler, we create an instance of our ScheduleManager class, which will automatically call the "Reload()" function in its constructor to load up the entire collection of plug-ins.
    
    if(sm==null) sm = new Scheduler.Net.ScheduleManager();
    
    
    Lastly, let's call the Execute() method to execute all the plug-ins based on their individual schedules.
    
    sm.Execute();
    
    

    Step Four: Installing the Service

    Included in the .NET Framework SDK there is a utility named "InstallUtil.exe". This utility is used to execute installers on a given assembly. In part 1 step 2, we discussed how to use the ServiceInstaller and ServiceProcessInstaller to install our service on the desired machine. Executing "InstallUtil.exe" on our Windows Service assembly will (hopefully) install the Windows Service.

    To install our service from the command line type:

    
    installutil scheduler_net.exe
    
    
    and to uninstall it, add the "/u" parameter:
    
    installutil scheduler_net.exe  /u
    
    
    Finally, launch the services plug-in in the Microsoft Management Console and start the service.

    Take time now to review the project that I have included for download. The complete source is intact, and you should only need to install the service using the included binary.

    Now it's time for plug-in creation.

    Creating a Simple Plug-In : MoreOver.com

    MoreOver.com gives us free access to news feeds for personal use, so I felt it was a good place to start. We can simply hold a list of the categories (http://w.moreover.com/categories/category_list.html) on our config file, which our plug-in will use to populate the database with news items from each list.

    Step One: Setup the Database

    I have created a simple table based on the sample XML file to hold in-coming data. Figure 2.1 shows the structure of the table.

    Figure 2.1 The MoreOver Table Diagram Next we need one stored procedure to insert the data into this table.

    
    create procedure addArticle
    	@url nvarchar(150),
    	@headline_text nvarchar(250), 
    	@source nvarchar(100), 
    	@media_type nvarchar(50), 
    	@cluster nvarchar(50), 
    	@tagline nvarchar(50), 
    	@document_url nvarchar(150), 
    	@harvest_time nvarchar(50), 
    	@access_registration nvarchar(50), 
    	@access_status nvarchar(50)
    as
    
    if exists(select url from [DataFeeds].[dbo].[MoreOver] where url=@url)
    begin
    
    UPDATE [DataFeeds].[dbo].[MoreOver]
    SET [url]=@url, [headline_text]=@headline_text, [source]=@source, 
    [media_type]=@media_type, [cluster]=@cluster, [tagline]=@tagline,
    [document_url]=@document_url, [harvest_time]=@harvest_time, 
    [access_registration]=@access_registration, [access_status]=@access_status
    where url=@url
    end
    
    else 
    
    begin
    INSERT INTO [DataFeeds].[dbo].[MoreOver]([url], [headline_text], [source], [media_type], [cluster], [tagline], [document_url], [harvest_time],
     [access_registration], [access_status])
    VALUES(	@url, 
    	@headline_text, 
    	@source, 
    	@media_type, 
    	@cluster, 
    	@tagline, 
    	@document_url, 
    	@harvest_time, 
    	@access_registration, 
    	@access_status)
    end
    
    GO
    
    

    Step Two: Implementation

    With the database setup and read, we implement the actual plug-in. Let's add a whole new C# class library to this solution, named "MoreOverPlugin", and then set it up for our plug-in. Add a reference for this project to our "ServicesCore" project, and rename the default to "MoreOverPlugin.cs".

    In the .NET Framework SDK there is a tool named "xsd.exe". This tool is used to generate schema and class files from a given source. It takes an XML file and generates a schema (XSD) file. From XSD files we generate class files (CS).

    Let's use this tool to automatically create a class. Download one of the XML feeds from MoreOver.com and save it in the project directory for our plug-in (I gave it the name "moreover.xml"). Dump to a DOS prompt, navigate to that folder, and then execute this command:

    
    xsd moreover.xml
    
    
    You should see a message similar to:
    
    Writing file 'F:\RobWorking\Services\Scheduler.Net\MoreOverPlugin\moreover.xsd'.
    
    
    Now that we have a schema for the XML document, we use the same tool to generate a class based on that schema. Execute this command:
    
    xsd /classes moreover.xsd
    
    
    You should see a message similar to:
    
    Writing file 'F:\RobWorking\Services\Scheduler.Net\MoreOverPlugin\moreover.cs'.
    
    
    We're now done with the DOS prompt. If you return to the VS .NET solution and view all the files in the project, you'll see the new "moreover.cs" file. Right click it and include it in this project. Using the xsd.exe tool to generate your classes means that you can also serialize between XML and classes easily. I'll show more on this later.

    In the article's download package, I've supplied a plug-in template. It has all the necessary functions required by the interface, including some error handling and logging members. It's easiest to simply copy the template code into your plug-ins, and then modify that. Do this for the MoreOverPlugins project.

    Now let's dive into the "Execute()" function line by line. If you feel more comfortable seeing the entire method, open up the "MoreOverPlugin.cs" file from the download package.

    
    protected System.Collections.Specialized.NameValueCollection MoreOverSettings = 
    (System.Collections.Specialized.NameValueCollection)System.Configuration.Configu
    rationSettings.GetConfig("PlugInSettings/MoreOverSettings");
    
    
    I previously discussed creating specific sections in our config file for our plug-ins. This line creates a NameValueCollection for our custom settings node in that file.

    Here is the relevant MoreOverSettings entries:

    
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <sectionGroup name="PlugInSettings">
    <section name="MoreOverSettings" type="System.Configuration.NameValueSectionHandler" />
        </sectionGroup>
      </configSections>
    
    <PlugInSettings>
    <MoreOverSettings>
    <!-- add specific categories -->
    <add key="categoriescount" value="2" />
    <add key="category1Name" value="Developer news" />
    <add key="category1Max" value="10" />
    
    <!-- or use a database list -->  
    <!--
    <add key="categoriessource" value="MoreOverCatList" />  
    -->
    <add key="ConnectionString" value="Data Source=localhost;Integrated 
    Security=SSPI;Initial Catalog=DataFeeds" />        
    </MoreOverSettings>
    
    </PlugInSettings>
    
    </configuration>
    
    
    In the MoreOver plug-in, either specify the categories directly in the config file or specify the stored procedure as the "categoriessource", which will return the list. View my version of the plug-in to understand how to use either the settings in the config file or query the database to get the list of categories. The result of either will give us a System.Collections.Hashtable of categories (named "categories") to use in our "Execute()" method.

    Step Three: Program Flow

    The method flow is pretty straight forward:

    1. for every category we need to download

    
    foreach(string cat in categories.Keys) {
    
    
    a. download the xml file based on the category name
    
    request = new Scheduler.Net.HttpRequest("http://p.moreover.com/cgi-
    local/page?o=xml&c="+cat.Replace(" ", "%20"), 
    Scheduler.Net.HttpRequest.HttpMethodValues.GET);
    
    System.IO.TextReader reader = new 
    System.IO.StreamReader(request.GetHttpStream());
    
    
    b. serialize this xml to our class we generated previously
    
    System.Xml.Serialization.XmlSerializer serializer = new 
    System.Xml.Serialization.XmlSerializer(typeof(Scheduler.Net.moreovernews));
    
    Scheduler.Net.moreovernews  moNews = 
    (Scheduler.Net.moreovernews)serializer.Deserialize(reader);
    
    
    c. for every article item we just downloaded
    
    foreach(Scheduler.Net.moreovernewsArticle article in moNews.Items) {
    
    
    i. save it
    
    SaveArticle(article);
    
    
    I want to review three things from the flow process in more detail. First is the "Scheduler.Net.HttpRequest" class. I wrote this class to simplify HTTP GET and POST requests. It's a wrapper for the "System.Net.HttpWebRequest" class. Feel free to view that source and use it in your own solutions.

    The second item is serialization (1b). Remember that we used the utility "xsd.exe" to generate class files for the moreover XML feed. The first line creates an XmlSerializer based on the generated class's type. The XmlSerializer deserializes our XML stream that we retrieved from the HttpRequest into an instance of the moreovernews type.

    Third is saving the article using the "SaveArticle()" method. In this method we call the stored procedure, load it up with all the parameters that I pull from my deserialized class, and execute the query.

    Step Four: Installing the Plug-In

    To install the plug-in, stop the Windows Service, add the needed items to the config file, and then start the service. Along with the above portions that I included for the MoreOverSettings in the config file, we need to update the "pluginlist" entry in the main "appSettings" node. The new version is:

    
    <add key="pluginlist" 
    value="Scheduler.Net.MoreOverPlugin,MoreOverPlugin.dll,36000000000;" />
    
    
    Notice it is scheduled to only download new content once per day (36000000000). Change this to your preference. Now start the Windows Service, and it will immediately download the content and update your database as per the schedule.

    You have now developed your first plug-in. You do not need to continue with the next section "Creating an E-Mail Queue" if you want to start developing your own plug-ins; skip to the conclusion.

    Creating an E-Mail Queue

    We will create an automated e-mail-queue sending application in this plug-in. Sometimes one of the most valuable features in an application is the ability to communicate with external parties via e-mail. We are all aware that the Internet can be unstable. In a common application that sends an e-mail, the developer typically uses an existing object (COM or .NET Assembly) to connect to a mail server and send it appropriate commands for sending e-mail. In .NET this is simplified with the System.Web.Mail namespace (ms-help://MS.VSCC/MS.MSDNVS/cpref/html/frlrfSystemWebMail.htm), which is simply a wrapper for the COM based CDOSYS (Collaboration Data Objects for Windows 2000) message component.

    Given the fact that the Internet can be unstable, problems may occur if your application attempts to directly connect to your mail server and send out the e-mail. What happens if at that given time the mail server is down or any given network point in between has failed? The e-mail will not be sent, and it will most likely be lost. This plug-in will solve this issue.

    Step One: Setup the Database

    As we did in the MoreOver plug-in, setup the table and the appropriate stored procedure in the database.

    Figure 2.1 The EmailQueue Table

    Figure 2.2 Get Email Queue Stored Procedure

    
    CREATE Procedure GetEmailQueue
    as
    SELECT [Attachments], [Bcc], [Body], [BodyEncoding], [BodyFormat], [Cc], [From], [Headers], [Priority], [Subject], [To], 
    [UrlContentLocation], [UrlContentBase], [Server] FROM [DataFeeds].[dbo].[EmailQueue] where sent=0
    update emailqueue set sent=1
    GO
    
    
    Notice the simplicity of the stored procedure in this example. I'm sure most of you will want to add more functionality, including only updating "sent=1" for items which had no errors during the actual send from the plug-in.

    Step Two: Implementation

    Open VS .NET and create a new C# Class Library; name it "EmailSenderPlugin". Since we are not using the existing solution, we will add a reference to our "ServicesCore.dll". This allows us to develop our plug-in independent of anything else. Rename the default "Class1.cs" to "EmailSenderPlugin.cs" and also copy the code from the template plug-in to this class (don't forget to name the namespace and class appropriately. Mine is named "EmailSenderPlugin. SendEmails").

    Our Settings for this plug-in look similar to (only relevant sections included):

    
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <sectionGroup name="PlugInSettings">
          <section name="EmailSenderSettings" 
    type="System.Configuration.NameValueSectionHandler" />
        </sectionGroup>
      </configSections>
      <PlugInSettings>
        <EmailSenderSettings>
          <add key="ConnectionString" value="Data Source=localhost;Integrated 
    Security=SSPI;Initial Catalog=DataFeeds" />
          <add key="MailServer" value="mail.santra.com" />
          <add key="FromAddress" value="support@santra.com" />
        </EmailSenderSettings>
      </PlugInSettings>
    </configuration>
    
    

    Step Three: Program Flow

    This plug-in's program flow is simple:

    1. Query the database and grab all items that need to be sent

    
    cmd = conn.CreateCommand();
    cmd.CommandType = System.Data.CommandType.StoredProcedure;
    cmd.CommandText = "GetEmailQueue";
    rdr = cmd.ExecuteReader();
    
    
    2. Loop for each item
    
    while(rdr.Read()) {
    
    
    a. Create a System.Web.Mail.MailMessage for the item
    
    System.Web.Mail.MailMessage msg = new System.Web.Mail.MailMessage();
    
    
    If you refer to my copy of the plug-in, you will see that there are about 60 lines of code needed to fully create the MailMessage from the database reader. Notice that if there is no "From" address specified in the table, we will pull the default out of the config file.

    b. Setup the SmtpServer

    
    System.Web.Mail.SmtpMail.SmtpServer = EmailSenderSettings["MailServer"];
    
    
    c. Send the Message System.Web.Mail.SmtpMail.Send(msg); Install it the same way you installed the MoreOver plug-in. Here is my new pluginlist config entry:
    
    <add key="pluginlist" value="Scheduler.Net.MoreOverPlugin,MoreOverPlugin.dll,36000000000;EmailSenderPlugin.SendEmails,
    EmailSenderPlugin.dll,50000000;" />
    
    
    Notice how the EmailSenderPlugin is set very short, 5 seconds. This is because we want very little, if any, delay for outgoing mails.

    That's all there is for this plug-in. You now have automated offline e-mail-queue processing.

    Conclusion

    In this article you've experienced just how easy it is to create an extensible Windows Service in .NET using a fairly basic OOP principle (Interfaces). If you would like to work on improving the core of this application or would like to make your custom plug-ins available to everyone else, you can check out the SourceForge project at http://www.sourceforge.net/projects/scheduler-net/. Send me an e-mail with your SourceForge Unix name if you would like to be added as a developer to this project.

    About the Author

    Robert Chartier has developed IT solutions for more than nine years with a diverse background in both software and hardware development. He is internationally recognized as an innovative thinker and leading IT architect with frequent speaking engagements showcasing his expertise. He's been an integral part of many open forums on cutting-edge technology, including the .NET Framework and Web Services. His current position as vice president of technology for Santra Technology (http://www.santra.com) has allowed him to focus on innovation within the Web Services market space.

    He uses expertise with many Microsoft technologies, including .NET, and a strong background in Oracle, BEA Systems, Inc.'s BEA WebLogic, IBM, Java 2 Platform Enterprise Edition (J2EE), and similar technologies to support his award-winning writing. He frequently publishes to many of the leading developer and industry support Web sites and publications. He has a bachelor's degree in Computer Information Systems.

    Robert Chartier can be reached at rob@aspfree.com.

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Other Articles
    Jul 28, 2005 - N-Tier Web Applications using ASP.NET 2.0 and SQL Server 2005 - Part 2
    In the second part of his series on building N-tier web applications using ASP.NET 2.0 and SQL Server 2005, Thiru Thangarathinam covers the business logic and user interface layers. In the process, he also examines some new features in ASP.NET 2.0 that greatly simplify the development process.
    [Read This Article]  [Top]
    Jul 14, 2005 - An Innovative Technique for Creating Reusuable Page Templates in ASP.NET 1.x
    Code reusuability is one of the major goals of any good object-oriented programmer. While the ASP.NET framework has made code reusuability easier and more elegant than it was in classic ASP, one area where reusuability could be improved is at the UI level. This article outlines a technique that you can use in ASP.NET 1.x that allows every page in your web application to inherit not only the functionality of a base page, but its UI as well.
    [Read This Article]  [Top]
    Jun 23, 2005 - Monitoring SharePoint Usage through an ASP.NET Web Application
    In this article, Gayan Peiris looks at creating an ASP.NET web application that will display the usage details of a selected SharePoint site. Building such an application enables SharePoint administrators to gather all SharePoint usage data from a central location.
    [Read This Article]  [Top]
    May 12, 2005 - Retrieving SharePoint Site Information in an ASP.NET Web Application
    In this article, Gayan Peiris examines using the SharePoint Object Model to access SharePoint site information from an ASP.NET web application. It should be of particular interest to SharePoint administrators who can use the included code as a starting point for development of their own web-based SharePoint administration application.
    [Read This Article]  [Top]
    Dec 23, 2004 - Automated Deployment for Side By Side .NET Web Apps for Visual Studio .NET 2003
    In this article, David Every outlines a step-by-step account of how he solved the problems he encountered while implementing an auto-deployment process. He also describes how to create a stable process for automated remote .NET deployment featuring "side-by-side" capability.
    [Read This Article]  [Top]
    Sep 29, 2004 - Developing Web Parts with ICellConsumer Interface
    Most default SharePoint Server Web Parts can be connected across organizations. The third article in this series shows how to develop connectable Web Parts that consume information provided by other Web Parts.
    [Read This Article]  [Top]
    Aug 10, 2004 - Implementing and Promoting Daily Builds
    Automatic daily builds is a well known software engineering best practice. This article introduces a strategy for implementing and promoting daily builds and offers tips and tricks for preventing and fixing breaks.
    [Read This Article]  [Top]
    Jun 21, 2004 - Using Open Source .NET Tools for Sophisticated Builds
    Building an application can be more than pressing F5. With an increasing number of quality packages being released, developers for the .NET platform now have options to create a very sophisticated build process. Aaron Junod describes a sample build environment and shows how a number of tools can work together to make reliable, predictable, and value-added builds.
    [Read This Article]  [Top]
    Jun 24, 2003 - Programming for the Palm Part 1 - Creating the Palm Application
    The first part of this three part series walks through the process of creating a mobile blog application using a BASIC development environment for Palm OS devices called NS Basic. Subsequent articles will focus on synchronizing the data to the desktop using C# and creating an installer.
    [Read This Article]  [Top]
    Jun 18, 2003 - Online Database Functions Testing Tool
    This short article provides source code for a classic ASP online database functions testing application and shows how to configure and use the tool for either SQL Server or Oracle.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers