TODO:
Have you ever wanted to change the Font of your Navigation bar text?
SOLUTION:
//Put this public override bool FinishedLaunching of AppDelegate
UITextAttributes titleTextAttributes = new UITextAttributes();
titleTextAttributes.Font = UIFont.FromName("Chalkduster", 20);
rootNavigationController.NavigationBar.SetTitleTextAttributes(titleTextAttributes);
NOTES:
In AppDelegate, put the lines of code above in your FinishedLaunching method. rootNavigationController is the root nav control you have declared in that class.
TODO:
Have you ever wanted the 3rd Monay of the month, or some other similar scenario? Below is a method that will do this for you, as well as some sample calls to it.
int xDayOfMonth = GetNthDayOfMonth(2, System.DayOfWeek.Sunday); //get the 2nd Sunday of the current month
xDayOfMonth = GetNthDayOfMonth(5, System.DayOfWeek.Tuesday); //get the LAST tuesday of the current month
xDayOfMonth = GetNthDayOfMonth(3, System.DayOfWeek.Saturday); //get the third Saturday of the current month
SOLUTION:
public int GetNthDayOfMonth(int nth, DayOfWeek dayOfWeek)
{
int day = (int)dayOfWeek;
DateTime now = DateTime.Now; //get now, in case we span days
DateTime firstDayOfMonthDate = new DateTime(now.Year, now.Month, 1); //now get the first day of month
DayOfWeek firstDayOfWeek = firstDayOfMonthDate.DayOfWeek; //now get the day of week
int firstOfMonthDay = (int)firstDayOfWeek;
int returnDay = 0;
int x = (int)System.DayOfWeek.Sunday;
//now compare day to curr day (sunday==0 fyi)
if (firstOfMonthDay == day)
{
//the first day of the month is what we need, so do the simple math
returnDay = 1 + (7 * (nth - 1));
}
else if (firstOfMonthDay < day) //( ex: wed < thurs )
{
//ex. 3rd thurs of Feb 2012 - 1 + (7 *(3-1)) + (4-3) = 16 (16th day of month)
returnDay = 1 + (7 * (nth - 1)) + (day - firstOfMonthDay);
}
else //(firstday > day) ex: wed > mon )
{
//ex. 3rd mon of Feb 2012 - 1 + (7 *(3-1)) + (3+1) = 20 (20th day of month)
returnDay = 1 + (7 * (nth - 1)) + (firstOfMonthDay + day) + 1; //add one at end to fix 0 offset of DayOfWeek
}
//in this case we need to make sure we are not in an invalid date scenario, if so back it out by 7 days
if (nth == 5)
{
DateTime outDate;
DateTime.TryParse(String.Format("{0}-{1}-{2}", now.Year, now.Month, returnDay), out outDate);
//if it was bad, minus 7 and go
if (outDate == DateTime.MinValue || outDate == null)
returnDay -= 7;
}
return returnDay;
}
NOTES:
There are no notes on this topic.
TODO:
Have you ever gotten the dreaded message [ 'xxx' is a 'namespace' but is used like a 'type' ], even though you are using the fully qualified namespace? For Example I have a Class named ProcessManager in the namespace ProcessManagerService.ProcessManager. When I create a Console app, I try creating my object by saying:
ProcessManagerService.ProcessManager.ProcessManager pManager = new ProcessManagerService.ProcessManager.ProcessManager()
This statement will give the error above, when really I shouldn't.
SOLUTION:
In this case, if you look at the Properties of your project, you will most likely see the "Target Framework" is set to ".Net Framework 4 Client Profile". Change that to ".Net Framework 4", and your build error will go away.
NOTES:
Information on the .Net Framework 4 Client Profile can be found at http://msdn.microsoft.com/en-us/library/cc656912.aspx
TODO:
Have you ever wanted to write to a seperate log file per class for instance? In my case, I was running a Start() method of a class in a thread, and I was ending up with log messages in the single log file in an order that was really hard to follow. I wanted to write each class to it's own log file, and also ensure it was Thread safe while doing so. I was a little shocked at the lack of example out there on this topic, so below I have included a log class that wraps the log4net calls, and allows you to do the above.
SOLUTION:
using System;
using System.Collections.Generic;
using System.Text;
using log4net;
using log4net.Core;
using log4net.Config;
using log4net.Layout;
using log4net.Repository;
using log4net.Appender;
using log4net.Repository.Hierarchy;
namespace DevelopersAlley.Logging
{
public class ThreadSafeLogger
{
private const string _LOGNAME = "LogName";
static readonly object _locker = new object();
private ILog _logger;
/// <summary>
/// Allow a log file name to be passed in
/// </summary>
/// <param name="className"></param>
/// <param name="LogFileName"></param>
public ThreadSafeLogger(string ClassName, string LogPath)
{
if (!String.IsNullOrEmpty(LogPath))
{
//clean up path
if (!LogPath.EndsWith("\\"))
LogPath += "\\";
}
else
LogPath = "";
//make the nice log path
LogPath = String.Format("{0}{1}.log", LogPath, ClassName);
lock (_locker)
{
log4net.ThreadContext.Properties[_LOGNAME] = ClassName;
_logger = LogManager.GetLogger("Root");
if (!_logger.Logger.Repository.Configured)
XmlConfigurator.Configure();
//add the appender and set the filter now...
AddAppender(ClassName, CreateFileAppender(ClassName, LogPath));
}
}
#region LOG4NET UTILITIES
/// <summary>
/// Add an appender
/// </summary>
/// <param name="LoggerName"></param>
/// <param name="Appender"></param>
private void AddAppender(string LoggerName, log4net.Appender.IAppender Appender)
{
log4net.ILog log = log4net.LogManager.GetLogger(LoggerName);
log4net.Repository.Hierarchy.Logger l = (log4net.Repository.Hierarchy.Logger)log.Logger;
l.AddAppender(Appender);
}
/// <summary>
/// Find a named appender already attached to a logger
/// </summary>
/// <param name="appenderName"></param>
/// <returns></returns>
public log4net.Appender.IAppender FindAppender(string AppenderName)
{
foreach (log4net.Appender.IAppender appender in log4net.LogManager.GetRepository().GetAppenders())
{
if (appender.Name == AppenderName)
return appender;
}
return null;
}
/// <summary>
/// Create an appender
/// </summary>
/// <param name="name"></param>
/// <param name="fileName"></param>
/// <returns></returns>
public log4net.Appender.IAppender CreateFileAppender(string ClassName, string FileName)
{
log4net.Appender.RollingFileAppender appender = (log4net.Appender.RollingFileAppender)FindAppender(ClassName);
if (appender != null)
return appender;
appender = new log4net.Appender.RollingFileAppender();
appender.Name = ClassName;
appender.File = FileName;
appender.AppendToFile = true;
appender.MaximumFileSize = "10MB";
appender.MaxSizeRollBackups = 5;
appender.RollingStyle = RollingFileAppender.RollingMode.Size;
appender.StaticLogFileName = true;
//// add the filter for the log source
log4net.Filter.PropertyFilter filter = new log4net.Filter.PropertyFilter();
filter.Key = _LOGNAME;
filter.StringToMatch = ClassName;
filter.AcceptOnMatch = true;
//add deny all filter
log4net.Filter.DenyAllFilter filterDeny = new log4net.Filter.DenyAllFilter();
appender.AddFilter(filter);
appender.AddFilter(filterDeny);
log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
log4net.Config.BasicConfigurator.Configure(appender);
return appender;
}
#endregion
#region INFO LOGGING
/// <summary>
/// Log a message to a particular log name
/// </summary>
/// <param name="messageFormat"></param>
/// <param name="classname"></param>
public void LogInfo(string MessageFormat, string ClassName)
{
lock (_locker)
{
log4net.ThreadContext.Properties[_LOGNAME] = ClassName;
if (_logger.IsInfoEnabled)
_logger.Info(MessageFormat);
}
}
#endregion
#region DEBUG LOGGING
/// <summary>
/// Log debug message to a file
/// </summary>
/// <param name="messageFormat"></param>
/// <param name="classname"></param>
public void LogDebug(string MessageFormat, string ClassName)
{
lock (_locker)
{
log4net.ThreadContext.Properties[_LOGNAME] = ClassName;
if (_logger.IsDebugEnabled)
_logger.Debug(MessageFormat);
}
}
#endregion
#region ERROR LOGGING
/// <summary>
/// Logs an error message to a specific log
/// </summary>
/// <param name="messageFormat"></param>
/// <param name="classname"></param>
public void LogError(string MessageFormat, string ClassName)
{
lock (_locker)
{
log4net.ThreadContext.Properties[_LOGNAME] = ClassName;
if (_logger.IsErrorEnabled)
_logger.Error(MessageFormat);
}
}
#endregion
}
}
NOTES:
- IMPORTANT** - in your app config, you now only need empty log4net node. Having any appenders in this node will throw things off, and you will end up with logs getting mixed up.
<log4net debug="true"></log4net>
- This creates appenders on the fly, and sets a PropertyFilter by the ClassName value that I passed in.
- Before the log event, you can see I set a property _LOGNAME, to ClassName. By setting this property, the filter will now only allow events to go to that Appender, because we applied a PropertyFilter to the Appender when we created it.
- I added locking to ensure Thread safety (may be overkill)
- To use, just call this code.
protected ThreadSafeLogger _Logger = null;
_Logger = new ThreadSafeLogger ("MyClassName", "C:\\logs");
- You will end up with a log file named C:\logs\MyClassName.log
- If you do #5 in each class with a different class name, you will end up with a log per class.
- Enjoy!
TODO:
Have you ever wanted to create a thread, and pass a parameter to it when it starts?
SOLUTION:
//This code creates the thread, and starts it with a parameter
Thread myThread = new Thread(new ParameterizedThreadStart(MyMethodtoCall)); //create our job thread
myThread.Start(jobStepsToRun); //start it now, passing in our parameter
//This method will be use in the ParameterizedThreadStart call
private void MyMethodtoCall(object myPassedParameter)
{
//here you can access your parameter and use it
}
NOTES:
There are no notes on this topic.
TODO:
Have you ever wanted to get the directory for the executing Console Application in C#? The following method will do so, and is the equivalent of Application.StartupPath when working with Windows Forms.
SOLUTION:
System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
NOTES:
There are no notes on this topic.
TODO:
Have you ever wanted to protect your web.config file, so that the appsettings and connectionstrings sections could not be read? Below are 2 methods and a class level variable you can add to your code to protect your app.config or web.config.
SOLUTION:
private string LastErrorMessage = "";
/// <summary>
/// Protect the App.Config
/// </summary>
public void ProtectApplicationConfig()
{
Configuration standardConfig = null;
ConnectionStringsSection standardConnectionStringsSection = null;
AppSettingsSection standardAppSettingsSection = null;
try
{
standardConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Get the connection strings section
standardConnectionStringsSection = standardConfig.ConnectionStrings;
standardAppSettingsSection = standardConfig.AppSettings;
// Protect this section by using the DpapiProtectedConfigurationProvider a.k.a. DataProtectionConfigurationProvider
if (!standardConnectionStringsSection.SectionInformation.IsProtected)
standardConnectionStringsSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
// Protect this section by using the DpapiProtectedConfigurationProvider a.k.a. DataProtectionConfigurationProvider
if (!standardAppSettingsSection.SectionInformation.IsProtected)
standardAppSettingsSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
// Save the configuration section within protected data
standardConnectionStringsSection.SectionInformation.ForceSave = true;
standardAppSettingsSection.SectionInformation.ForceSave = true;
standardConfig.Save();
}
catch (Exception x)
{
LastErrorMessage = x.Message;
}
finally
{
standardConfig = null;
standardConnectionStringsSection = null;
standardAppSettingsSection = null;
}
}
/// <summary>
/// Protect the Web.Config
/// </summary>
public void ProtectWebConfig()
{
Configuration standardConfig = null;
ConnectionStringsSection standardConnectionStringsSection = null;
AppSettingsSection standardAppSettingsSection = null;
try
{
standardConfig = WebConfigurationManager.OpenWebConfiguration("~");
// Get the connection strings section
standardConnectionStringsSection = (ConnectionStringsSection)standardConfig.GetSection("connectionStrings");
standardAppSettingsSection = (AppSettingsSection)standardConfig.GetSection("appSettings");
// Protect this section by using the DpapiProtectedConfigurationProvider a.k.a. DataProtectionConfigurationProvider
if (!standardConnectionStringsSection.SectionInformation.IsProtected)
standardConnectionStringsSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
// Protect this section by using the DpapiProtectedConfigurationProvider a.k.a. DataProtectionConfigurationProvider
if (!standardAppSettingsSection.SectionInformation.IsProtected)
standardAppSettingsSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
// Save the configuration section within protected data
standardConnectionStringsSection.SectionInformation.ForceSave = true;
standardAppSettingsSection.SectionInformation.ForceSave = true;
standardConfig.Save();
}
catch (Exception x)
{
LastErrorMessage = x.Message;
}
finally
{
standardConfig = null;
standardConnectionStringsSection = null;
standardAppSettingsSection = null;
}
}
NOTES:
The config file can ONLY be used on the machine it is protected on. Once a file is protected, trying to copy the protected file to another machine and use it will not work.
TODO:
Have you ever wanted a Guid and did not want the dashes?
SOLUTION:
string batchId = Guid.NewGuid().ToString("N");
NOTES:
There are no notes on this topic.
TODO:
Have you ever wanted to iterate a Hashtable?
SOLUTION:
Hashtable myHashTable = new Hashtable();
myHashTable.Add("ES", 1);
myHashTable.Add("EN", 2);
myHashTable.Add("FR", 4);
myHashTable.Add("RU", 3);
//now go through our hash
foreach (object obj in myHashTable.Keys)
{
//check for the value is 4
if ((int)myHashTable[obj] == 4)
{
//do something
}
Console.WriteLine(String.Format("Key: {0}, Value: {1}", obj, myHashTable[obj]));
}
NOTES:
The application of this example may not make sense, but it was to illustrate how to iterate a Hashtable, and analyse the value of a key. A real life applicaiton could be that I have a document that has 4 sections. A source delivers it in numerous languages, and each language may or may not have all of the sections populated. I need to keep track of which lanugage has populated sections, so that I can display the most populated version of the document. In this case I would store the language in the Hashtable as the Key, and then when I get a section, I can simply increment the Value for the Key (in this case the language). When my loading of the document is complete I can then get the Language for the most populated section, and then do things, like display a flag or somethine else.
TODO:
Have you ever wanted to Serialize an object using C#? The method I created below, will allow you to pass in an object and turn it into an XML Document.
SOLUTION:
/// <summary>
///
/// </summary>
/// <param name="myObject"></param>
/// <returns></returns>
public static XmlDocument MakeXmlDocumentFromObject(Object myObject)
{
UTF8Encoding encoding = new UTF8Encoding();
XmlDocument returnObject = new XmlDocument();
try
{
//create our serializer
XmlSerializer xmlSerial = new XmlSerializer(myObject.GetType());
//get it....
using (MemoryStream memStream = new MemoryStream())
{
//serialize the object
xmlSerial.Serialize(memStream, myObject);
//load the XML now, and we will return it....
returnObject.LoadXml(encoding.GetString(memStream.GetBuffer()));
}
return returnObject;
}
catch (Exception)
{
return null;
}
}
NOTES:
There are no notes on this subject.