Monthly Archives: May 2010

Raising Errors in SQL Server

This link was handy in learning a little about error handling in SQL Server, though it is dated:
Error Handling in SQL Server – a Background
This article explained the usage of RAISERROR. It also suggests that TRY / CATCH blocks can be used to raise
specific errors for specific sections in a stored proc:
Using RAISERROR

Advertisements

Getting the Rolling Log File Setting from your app.config

I couldn’t find an easy way to retrieve the log file location setting from the rolling log file settings in my Logging Application Block settings and after writing a query at a few places, decided that I would have to do it by reading the XML and parsing through to the log setting.

It was not too difficult, but I figured I would post it here so I could remember what I did and for others to find…

Here is a simple form that finds and lists the rolling log file name (you must put a copy of your config file into the bin\debug folder and name it “configData.xml” where this little program runs in order for it to find it):

using System;
using System.Windows.Forms;
using System.Xml.XPath;

namespace GetTheRollingLogFiles
{
 /// <summary>
 /// Summary description for Form1.
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
 private System.Windows.Forms.Button button1;
 private System.Windows.Forms.ListBox listBox1;
 /// <summary>
 /// Required designer variable.
 /// </summary>
 private System.ComponentModel.Container components = null;

 public Form1()
 {
 // Required for Windows Form Designer support
 InitializeComponent();
 // TODO: Add any constructor code after InitializeComponent call
 }

 /// <summary>
 /// Clean up any resources being used.
 /// </summary>
 protected override void Dispose( bool disposing )
 {
 if( disposing )
 {
 if (components != null)
 {
 components.Dispose();
 }
 }
 base.Dispose( disposing );
 }

 #region Windows Form Designer generated code
 /// <summary>
 /// Required method for Designer support - do not modify
 /// the contents of this method with the code editor.
 /// </summary>
 private void InitializeComponent()
 {
 this.button1 = new System.Windows.Forms.Button();
 this.listBox1 = new System.Windows.Forms.ListBox();
 this.SuspendLayout();
 //
 // button1
 //
 this.button1.Location = new System.Drawing.Point(12, 12);
 this.button1.Name = "button1";
 this.button1.Size = new System.Drawing.Size(152, 24);
 this.button1.TabIndex = 0;
 this.button1.Text = "GO!";
 this.button1.Click += new System.EventHandler(this.button1_Click);
 //
 // listBox1
 //
 this.listBox1.Location = new System.Drawing.Point(12, 42);
 this.listBox1.Name = "listBox1";
 this.listBox1.Size = new System.Drawing.Size(428, 433);
 this.listBox1.TabIndex = 1;
 //
 // Form1
 //
 this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
 this.ClientSize = new System.Drawing.Size(455, 502);
 this.Controls.Add(this.listBox1);
 this.Controls.Add(this.button1);
 this.Name = "Form1";
 this.Text = "Form1";
 this.Load += new System.EventHandler(this.Form1_Load);
 this.ResumeLayout(false);

 }
 #endregion

 /// <summary>
 /// The main entry point for the application.
 /// </summary>
 [STAThread]
 static void Main()
 {
 Application.Run(new Form1());
 }

 private void button1_Click(object sender, System.EventArgs e)
 {
 listBox1.Items.Clear();

 string fileName = "configData.xml";
 XPathDocument doc = new XPathDocument(fileName);
 XPathNavigator nav = doc.CreateNavigator();

 // Compile a standard XPath expression
 XPathExpression expr;
 expr = nav.Compile("/configuration/loggingConfiguration/listeners/*");
 XPathNodeIterator iterator = nav.Select(expr);

 // Iterate on the node set
 listBox1.Items.Clear();
 try
 {
 while (iterator.MoveNext())
 {
 XPathNavigator nav2 = iterator.Current.Clone();
 string rollingLogFileName = "";
 listBox1.Items.Add(nav2.Name);
 listBox1.Items.Add("HasAttributes: " + nav2.HasAttributes.ToString());
 if (nav2.MoveToFirstAttribute())
 {
 bool isRollingLogConfig = false;
 string fileNameHolder = "";
 while (true)
 {
 listBox1.Items.Add(nav2.Name + ": " + nav2.Value);
 if ((nav2.Name.ToLower() == "type") && nav2.Value.Contains("RollingFlatFileTraceListener"))
 isRollingLogConfig = true;

 if (nav2.Name == "fileName")
 fileNameHolder = nav2.Value;

 if (!nav2.MoveToNextAttribute()) break;
 }
 if (isRollingLogConfig)
 {
 rollingLogFileName = fileNameHolder;
 listBox1.Items.Add("Rolling Log file is: " + rollingLogFileName);
 }
 }
 }
 }
 catch(Exception ex)
 {
 MessageBox.Show(ex.Message);
 }
 }

 private void Form1_Load(object sender, System.EventArgs e)
 {
 }
 }
}

Rolling Log Setting for Application Logging Block

I still have a catch-all acting as the conduit for the rolling log, but it is the first combination I found that worked and I have stuck with it for now. As I refine this and learn more, I will publish again. Comments are welcome.

Note that the Rolling log settings use the file name “LoggerTest.log”. I used the following values and got the results as described below:

rollFileExistsBehavior=”Increment”

When the log hits the size limit or begins a new day, it opens a new file and increments an integer at the end of the filename. Thus the main log file is as named above, but an older one would be named:

LoggerTest.2010-05-06.1.log

LoggerTest.2010-05-06.2.log

etc. Very handy…

rollInterval=”Day”

This is the amount of time to allow to go by while writing to a single log. Once passed, it will open a new one.
Set to “Midnight”, it would roll over at exactly midnight and each day would be in a separate log.

rollSizeKB=”1000″

This is the size limit, so once the log goes beyond 1MB in size, it will create another.

timeStampPattern=”yyyy-MM-dd”

This is the pattern to use when creating a log “archive.” The latest log file is always named according to the setting in the configuration. I have not found a setting for controlling a limit on the number of files that are kept, so I might have to write a cleanup function. I was very surprised that there is no purge setting for this application block. I have built something that should work for that, and once I have done some testing will post it.

<loggingConfiguration name="Logging Application Block" tracingEnabled="true" defaultCategory="Default Category" logWarningsWhenNoCategoriesMatch="true">
 <listeners>
 <add source="Enterprise Library Logging" formatter="Text Formatter"
 log="Application" machineName="" listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 name="Formatted EventLog TraceListener" />
 <add fileName="D:\Temp\LoggerTest.log"
 formatter="One Line Formatter" rollFileExistsBehavior="Increment"
 rollInterval="Midnight" rollSizeKB="10000" timeStampPattern="yyyy-MM-dd"
 listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 name="Rolling Flat File" />
 </listeners>
 <formatters>
 <add template="Timestamp: {timestamp(local)}

Message: {message}

Category: {category}

Priority: {priority}

EventId: {eventid}

Severity: {severity}

Title:{title}

Machine: {machine}

Application Domain: {appDomain}

Process Id: {processId}

Process Name: {processName}

Win32 Thread Id: {win32ThreadId}

Thread Name: {threadName}

Extended Properties: {dictionary({key} - {value}

)}"
 type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 name="Text Formatter" />
 <add template="{timestamp(local)}	Cat: {category}	Pri: {priority}	EId: {eventid}	Sev: {severity}	{message}	Title:{title}	Machine: {machine}	Application Domain: {appDomain}	Process Id: {processId}	Process Name: {processName}	Win32 Thread Id: {win32ThreadId}	Thread Name: {threadName}	Extended Properties: {dictionary({key} - {value}

)}"
 type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 name="One Line Formatter" />
 </formatters>
 <logFilters>
 <add name="LogEnabled Filter"
 type="Microsoft.Practices.EnterpriseLibrary.Logging.Filters.LogEnabledFilter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 enabled="true" />
 </logFilters>
 <categorySources>
 <add switchValue="Warning" name="Default Category">
 <listeners>
 <add name="Formatted EventLog TraceListener" />
 </listeners>
 </add>
 </categorySources>
 <specialSources>
 <allEvents switchValue="All" name="All Events">
 <listeners>
 <add name="Rolling Flat File" />
 </listeners>
 </allEvents>
 <errors switchValue="All" name="Logging Errors &amp; Warnings">
 <listeners>
 <add name="Formatted EventLog TraceListener" />
 </listeners>
 </errors>
 </specialSources>
 </loggingConfiguration>

“This Application has Failed to Start” -or- fix your project settings…

Ok, this was a particularly fun one. I am working on a windows service and attempting to install and run it for the first time. I have been successfully running it from my development machine as a console program, and it was working great.

I created the setup and installed the msi locally. I got the error:
“The xxxxx service failed to start due to the following error:
This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.”

I searched the Application log in the event logger and found that the application never even got started – there were no events in the Application log or in my rolling log file.

I then looked at the System log and found the error that was displayed above and found two messages preceding it having to do with “SideBySide.” They were giving me an error in my configuration file at the last section I had in there. Changing this section did not help.

I then took to searching and found this article:
Syntax error in manifest or policy file | Creative Code Design

It turns out that a setting on the windows service project settings regarding resources was set to:
“Embed manifest with default settings”
when it needed to be set to:
“Create application without manifest”
since I did not have a manifest getting generated.

I have not delved into why this came up as an error on my configuration pointing to the beginning of a custom section. But changing this setting got me onto the next bug…

HTH

Remove Special Characters using a Regular Expression

This link:

Mareo Code » Regular Expressions: Remove all special characters from a string, allowing only alphanumeric and chars: ‘.’ and ‘-’

was helpful in giving me a simple way to remove all special characters and just have alphanumerics. The idea is pretty simple, yet it performs a very useful task. Using the replace option in the regex, you can effectively strip out all of the unwanted characters. The Regex for me boiled down to:

[^\w_]

which used in conjunction with the replace command selects only alphanumerics and the underscore character. I used Expresso to test it, which if you don’t have in your development arsenal, you should!

This note is just intended to help a few who may be dealing with the WSFTPApi. If you have a license to this api, and the programmer who initially used it is no longer with you, you might just be in the same spot I was in creating new functionality with no support. This ActiveX control while it seems well written, and you can get to the documentation, is no longer being sold and has no support once your support has expired. Thus you are left to whatever you can put together from the documentation (which is quite large). Ipswitch has the documentation online here (however, the link seems to be broken), but no forums that I could find that deal with it.

So here’s a code snippet I used to test the api and get it working.


private void XferFile()
 {
WsftpConnection remoteServer = GetFtpConnection();

 if (!remoteServer.PutFile(@"d:\temp",
 "temp.bin",
 "/test",
 "temp.bin",
 (int)WsftpTransferModes.WSFTP_TFF_BINARY,
 0))
 MessageBox.Show("failed");
 else
 MessageBox.Show("succeeded");

 }

 private WsftpConnection GetFtpConnection()
 {
 // Command timeout
 _wsftpApi.CommandTimeout = 30;

 WsftpConnection toReturn = null;

 // Create connection
 toReturn = _wsftpApi.CreateConnection(
 "localhost",
 "username", "password",
 (int) WsftpConnectionTypes.WSFTP_CT_FTP,
 21);

 if (toReturn == null)
 throw new Exception("CreateConnection returned null object.");

 return toReturn;
 }

Custom Configuration in .Net

In working through some custom configuration issues I found the following articles very helpful…

ConfigurationPropertyAttribute Class (System.Configuration) (MSDN)
Unraveling the Mysteries of .NET 2.0 Configuration – CodeProject
C# ConfigurationManager.GetSection could not load file or assembly – Stack Overflow
Advanced .NET Configuration techniques

I also was pleased to see how much strong typing and validation could be built into the configuration manager, saving the trouble of building it all. Much of this is not obvious and can be difficult to sort out via web search, and yet config files are often leaned on pretty heavily.

I was stuck trying to get a set of multiple elements without the named collection. The last article helped clear that up.

Here is a sample of what can be done:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text;

namespace MyConfiguration
{
public class MyConfig : ConfigurationSection
{
/// <summary>Gets the timespan value - not required to be set and will default to 1 minute. If set must be in range 30 seconds to 5 minutes.</summary>
[ConfigurationProperty("TimespanValue", DefaultValue = "0:01:0", IsRequired = false)]
[TimeSpanValidator(MinValueString = "0:0:30", MaxValueString = "0:05:0", ExcludeRange = false)]
public TimeSpan TimespanValue
{
get { return (TimeSpan)this["TimespanValue"]; }
set { this["TimespanValue"] = value.ToString(); }
}

/// <summary>Gets required string value. If not set in config will raise a very clear exception telling user what value is missing.</summary>
[ConfigurationProperty("RequiredString", DefaultValue = "", IsRequired = true)]
public string RequiredString
{
get { return (string)this["RequiredString"]; }
set { this["RequiredString"] = value; }
}

/// <summary>Gets int value. If not set in config will default to 2. If set must be in range 0 to 8.</summary>
[ConfigurationProperty("MyIntValue", DefaultValue = "2")]
[IntegerValidator(MinValue = 0, MaxValue = 8)]
public int MyIntValue
{
get { return (int)this["MyIntValue"]; }
set { this["MyIntValue"] = value; }
}

}

}

namespace MyConfiguration
{
public class MyApplicationMethods
{
MyConfig config = new MyConfig();

public MyApplicationMethods()
{
string myString = config.RequiredString;
int myInt = config.MyIntValue;
TimeSpan ts = config.TimespanValue;
}
}
}