Update a control on a Master Page

Creating a Master Page in Visual Studio makes simplifies the development of ASP.NET websites. Master Page's allow for the creation of consistent and standard layouts (template) for a group of pages or an entire website. ContentPlaceHolders are used to designate where on a page based on a Master Page will have variable content. Sometimes it may be necessary to update a control that is part of the Master Page, rather within the ContentPlaceHolder area. There are several ways to update a control on a Master Page. A page's Master property allows for access to a page’s Master Page content. The following code is one example of how to update a control on a master page. The code would be run from the page based on a Master Page.

Image MasterLogo = (Image) Master.FindControl ( "Logo" );
        if ( MasterLogo != null )
        {
            MasterLogo.ImageUrl = "~/images/logo.gif";
        }

        Label MasterLabel = (Label) Master.FindControl ( "Label1" );
        if ( MasterLabel != null )
        {
            MasterLabel.Text = "Set from page";
        }



   

A little System.Diagnostics

I am not going to get overly verbose here; however the importance of application logging is immeasurable. When applications are deployed, obtaining ‘real life’ application can assist in diagnostic and overall application health situations. Excessive logging can be ineffective (too much to analyze) and burdensome (logging to a text file that grows forever) if not implemented appropriately.

When developing and deploying an application having the flexibility of what, when and how to log can alleviate the burden and ineffectiveness of logging. The System.Diagnostics namespace has a number of classes available that allow for this type of flexible logging. The applied use of these classes allows a developer to specify what to log in an application at various levels of detail within one application without the need to deploy diagnostic builds. Depending on diagnostic needs, the application’s config file can specify the level of diagnostic information to write and where. A simple Logging class (this is the class I created to use this functionality) can be developed as follows:

using System;
using System.Diagnostics;

namespace BPSoftware
{
    public class Logging
    {
        /// <summary>
        /// strNameSpace is the base namespace for use in the logging message.
        /// </summary>
        public static string strNameSpace;

        /// <summary>
        /// GeneralTraceSwitch is a traceswitch object for logging.  Switch level is set through 
        /// the application config switches section.  The destination listener is also set through
        /// the application config file.
        /// </summary>
        //public static TraceSwitch GeneralTraceSwitch = new TraceSwitch ( "TraceSwitch", "Config file TraceSwitch" );
        public static TraceSwitch GeneralTraceSwitch = new TraceSwitch ( "General", "General Trace Switch" );

        #region Methods
        /// <summary>
        /// Writeline is the base logging method. Messages are logged to the listener specified
        /// in the application config file.
        /// </summary>
        /// <param name="strClassName">Calling class name.</param>
        /// <param name="strMethodName">Calling method name.</param>
        /// <param name="strMessage">The message sent to the listener.</param>
        private static void WriteLine( string strClassName, string strMethodName, string strMessage )
        {
            lock ( typeof ( Logging ) )
            {
                Trace.WriteLine ( string.Concat (
                    new object[] { 
                        "(", DateTime.Now, ") ", 
                        strNameSpace, ".", strClassName, ".", strMethodName, " -->", strMessage 
                    }
                 ) );
            }
        }

        /// <summary>
        /// Pass information to the base WriteLine if the TraceError switch is set.
        /// </summary>
        /// <param name="strClassName">Calling class name.</param>
        /// <param name="strMethodName">Calling method name.</param>
        /// <param name="strMessage">The message sent to the listener.</param>
        public static void WriteLineTraceError( string strClassName, string strMethodName, string strMessage )
        {
            if ( Logging.GeneralTraceSwitch.TraceError )
                WriteLine ( strClassName, strMethodName, strMessage );
        }

        /// <summary>
        /// Pass information to the base WriteLine if the TraceWarning switch is set.
        /// </summary>
        /// <param name="strClassName">Calling class name.</param>
        /// <param name="strMethodName">Calling method name.</param>
        /// <param name="strMessage">The message sent to the listener.</param>
        public static void WriteLineTraceWarning( string strClassName, string strMethodName, string strMessage )
        {
            if ( Logging.GeneralTraceSwitch.TraceWarning )
                WriteLine ( strClassName, strMethodName, strMessage );
        }

        /// <summary>
        /// Pass information to the base WriteLine if the TraceInfo switch is set.
        /// </summary>
        /// <param name="strClassName">Calling class name.</param>
        /// <param name="strMethodName">Calling method name.</param>
        /// <param name="strMessage">The message sent to the listener.</param>
        public static void WriteLineTraceInfo( string strClassName, string strMethodName, string strMessage )
        {
            if ( Logging.GeneralTraceSwitch.TraceInfo )
                WriteLine ( strClassName, strMethodName, strMessage );
        }

        /// <summary>
        /// Pass information to the base WriteLine if the TraceVerbose switch is set.
        /// </summary>
        /// <param name="strClassName">Calling class name.</param>
        /// <param name="strMethodName">Calling method name.</param>
        /// <param name="strMessage">The message sent to the listener.</param>
        public static void WriteLineTraceVerbose( string strClassName, string strMethodName, string strMessage )
        {
            if ( Logging.GeneralTraceSwitch.TraceVerbose )
                WriteLine ( strClassName, strMethodName, strMessage );
        }
        #endregion
    }
}

Throughout the application logging messages can be added:
catch ( Exception ex)
        {
            Logging.WriteLineTraceError( "ClassName", "Method", "Exception: " + ex.Message );
        }

        Logging.WriteLineTraceInfo( "ClassName", "Method",,
            String.Format( "{0}: {1}", e.ActionType.ToString(), e.Message )



The application’s config file can then be altered to determine the appropriate level and location of the logging based upon certain diagnostic needs. The switches node specifies what level of logging should occur. The switches operate in a hierarchial fashion (3 includes 3, 2 and 1; 2 includes 2 and 1):

1 <system.diagnostics>
2 <trace autoflush="true" indentsize="4">
3 <!-- Specify listener output -->
4 <listeners>
5 <remove name="Default" />
6 <!-- Write to a log file -->
7 <add name="Default"
8 type="System.Diagnostics.TextWriterTraceListener"
9 initializeData="AFileSync.log" />
10 <!-- Write to the Event Log-->
11 <!-- <add name="Default"
12 type="System.Diagnostics.EventLogTraceListener"
13 initializeData="Application" /> -->
14 </listeners>
15 </trace>
16 <switches>
17 <!-- Off = 0, Error = 1, Warning = 2, Info = 3, Verbose = 4 -->
18 <add name="General" value="3" />
19 </switches>
20 </system.diagnostics>



Using the application’s config file to specify the level of logging allows for the capture of diagnostic information of a stable build to capture ‘real world’ information. The flexibility of the listener to write to (you can create customer listeners) is an added bonus!



   

Control and List Windows Services

As I whipped up my file synchronizing service application, to synchronize files between my computer and my NAS), I worked with the System.ServiceProcess Namespace. The System.ServiceProcess Namespace "provides classes that allow you to implement, install, and control Windows service applications".

My file synchronization needs did not require that my application service to be "running" all the time. In, fact I only needed the service to run under certain situations. It was easy enough to get the service written and installed and now I wanted to 'automatically' (programmatically) start and stop my service when certain conditions were met.

Entrance - the ServiceController Class. The ServiceController Class "Represents a Windows service and allows you to connect to a running or stopped service, manipulate it, or get information about it." In order to get acclimated to the ServiceController Class I created a simple application to list and display information about the installed services.

 

using System;
using System.ServiceProcess;
using System.Windows.Forms;

namespace Services1
{
    public partial class Form1 : Form
    {
        ServiceController controller;

        public Form1()
        {
            controller = new ServiceController ();
            controller.MachineName = ".";
            InitializeComponent ();
            lstServices.DisplayMember = "DisplayName";
            lstServices.ValueMember = "ServiceName";
            lstServices.DataSource = ServiceController.GetServices ();
        }

        private void StartService( string servicename )
        {
            controller.ServiceName = servicename;
            controller.Start ();

        }

        private void PauseService( string servicename )
        {
            controller.ServiceName = servicename;
            if ( controller.CanPauseAndContinue )
                controller.Pause ();
        }

        private void StopService( string servicename )
        {
            controller.ServiceName = servicename;
            if ( controller.CanStop )
                controller.Stop ();
        }


        private void listBox1_SelectedIndexChanged( object sender, EventArgs e )
        {
            if ( lstServices.SelectedItems.Count > 0 )
            {
                try
                {
                    controller.ServiceName = lstServices.SelectedValue.ToString ();
                    textBox1.Text = String.Format (
                        "Service Name: {0}\r\nDisplay Name: {1}\r\nType: {2}\r\nStatus: {3}",
                        controller.ServiceName,
                        controller.DisplayName,
                        controller.ServiceType.ToString (),
                        controller.Status.ToString ()
                        );
                }
                catch ( Exception ex )
                {
                    textBox1.Text = String.Format ( "Error: \r\n{0}", ex.Message );
                }
            }
            else
            {
                textBox1.Clear ();
            }
        }

        private void btnStart_Click( object sender, EventArgs e )
        {
            StartService ( lstServices.SelectedValue.ToString () );
        }

        private void btnPause_Click( object sender, EventArgs e )
        {
            PauseService ( lstServices.SelectedValue.ToString () );
        }

        private void btnStop_Click( object sender, EventArgs e )
        {
            StopService ( lstServices.SelectedValue.ToString () );
        }
    }
}