A typicaly Singleton implementation in C# looks like below:
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
[MSDN]This approach ensures that only one instance is created and only when the instance is needed. Also, the variable is declared to be volatile to ensure that assignment to the instance variable completes before the instance variable can be accessed. Lastly, this approach uses a syncRoot instance to lock on, rather than locking on the type itself, to avoid deadlocks. This double-check locking approach solves the thread concurrency problems while avoiding an exclusive lock in every call to the Instance property method. It also allows you to delay instantiation until the object is first accessed.
Above solution looks perfect, however, actually the ‘Double-Checked Locking’ can be still broken under certain multi-processor machine. A recommended way to implement Singleton correctly is below:
public sealed class Singleton
{
Singleton(){}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
static class Nested
{
internal static readonly Singleton instance = new Singleton();
}
}
Above code looks weird, but correct. It leverages .Net’s Class Loader to achieve thread-safe.
It is very common that you need to run some commands on a remote server. For example, you may want to config your source control server to start a build process on a dedicated build machine once it receives any checkins. To achieve this, you can leverage the WMI scripting APIs.
The steps are:
- Use SWbemLocator to create Locator object
- Use the Locator object to connect to the remote server and get back a Service object
- Use the Service object to get a Win32 process object
- Finally, use the Process object to issue your command
WMI WbemScripting script sample:
Function RemoteExecute(strServer, strUser, strPassword, CmdLine)
Const Impersonate = 3
RemoteExecute = -1
Set Locator = CreateObject("WbemScripting.SWbemLocator")
Set Service = Locator.ConnectServer(strServer, "root\cimv2", strUser, strPassword)
Service.Security_.ImpersonationLevel = Impersonate
Set Process = Service.Get("Win32_Process")
result = Process.Create(CmdLine, , , ProcessId)
If (result <> 0) Then
WScript.Echo "Creating Remote Process Failed: " & result
Wscript.Quit
End If
RemoteExecute = ProcessId
End Function
NAnt is very popular in the .Net development community. You may want to write a C# extension for NAnt scripts to achieve some build automations on remote servers. You can achieve that easily too. I am posting a WMI C# sample below for your reference too.
WMI C# sample:
using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
namespace WMISample
{
class Program
{
static void Main(string[] args)
{
string remoteMachine = "localhost";
ConnectionOptions connOptions = new ConnectionOptions();
connOptions.Impersonation = ImpersonationLevel.Impersonate;
connOptions.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope(
String.Format(@"\\{0}\ROOT\CIMV2", remoteMachine), connOptions);
manScope.Connect();
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ManagementPath managementPath = new ManagementPath("Win32_Process");
ManagementClass processClass = new ManagementClass(
manScope, managementPath, objectGetOptions);
ManagementBaseObject inParams = processClass.GetMethodParameters("Create");
inParams["CommandLine"] = @"notepad.exe";
ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null);
Console.WriteLine("Creation of the process returned: " + outParams["returnValue"]);
Console.WriteLine("Process ID: " + outParams["processId"]);
Console.ReadLine();
}
}
}
An ASP.Net applicatin may return an “Access Denied” error when it is accessing the Eventlog.
If it is not a GPO permission issue from your domain controller, you may need to check the SDDL string specified in the registry for the EventLog.
For example, if the identity of the App pool is the “Network service” account, “impersonation” in the web.config is true and authentication is enabled, you may need to add a WRITE access (A;;0×2;;;AU) for the authenticated users to the following registry key.
HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\Application\CustomSD
(A;;0x2;;;AU) Note: AU means "Authenticated Users"
Similarly, you can grant permissions for the “Network service” account.
(A;;0x2;;;NS) Note: NS means "Network service" account
What (A;;0×2;;;AU) is? You can check out Microsoft’s SDDL (Security Descriptor Definition Language) on MSDN.
Windows 2008 is much easier as long as you are ok giving the user/group read access to all event logs. If that is the case just add them to the Built in Event Log Readers group.
The location on the SDDL has changed in Windows 2008 and is no longer set it via the CustomSD in the registry. You now have to use the command line wevtutil utility.
Lean Software Development - An Agile Toolkit By Mary Poppendieck and Tom Poppendieck
This book contains seven chapters devoted to seven lean principles and thinking tools for translating each principle into agile practices.
- Eliminate waste. Waste is anything that does not add value to a product, value as perceived by the customer.
- Amplify learning. Development is an exercise in discovery. Take your most difficult problem and devise a way to increase feedback. Start iterations with a negotiation session between customers and developers. Post a progress chart for your current project in a common area so the team can see what needs to be done and everyone can see the project is converging. Find your toughest outstanding development problem and have the development team come up with three options on how to solve it. Instead of choosing one of the solutions, have the team explore all three options at the same time.
- Decide as late as possible. Development practices that provide for late decision making are effective in domains that involve uncertainty, because they provide any options-based approach.
- Deliver as fast as possible.
- Empower the team.
- Build integrity.
- See the whole. Finding and removing the limits of growth. Avoid the pattern called “Shifting the burden”. Ask “five whys” to counter the tendency to the burden to symptoms rather than addressing the root cause of a problem. Avoid “Suboptimization”. Local management tends to create local measuremens of performance. These local measurements often create systemwide effects that decrease overall performance.
The code is very simple. You just need to use DirectoryEntry object to locate the local group and the domain user. Then invoke an “Add” operation on the local group object.
public class AdUtil
{
public static void AddDomainUserToLocalGroup(
String domain,
String userName,
String groupName)
{
String groupPath = String.Format("WinNT://{0}/{1},group",
Environment.MachineName, groupName);
DirectoryEntry theGroup = new DirectoryEntry(groupPath);
if (theGroup.SchemaClassName != "Group")
{
throw new ArgumentException("The local group specified doesn't exist.");
}
String userPath = String.Format("WinNT://{0}/{1},user", domain, userName);
theGroup.Invoke("Add", new object[] { userPath });
theGroup.CommitChanges();
}
}
Following code doesn’t compile:
class GenericFactory where T : new()
{
public T Create(object a, object b)
{
return new T(a, b);
}
}
The compiler will give you following error message: “‘T’: cannot provide arguments when creating an instance of a variable type.”. Well, there are a couple ways to solve this issue.
Use reflection
class GenericFactory
{
public T Create(object a, object b)
{
return (T) typeof(T).GetConstructor(
new System.Type[] { typeof(object), typeof(object) }).Invoke(new object[] {a, b});
}
}
Use intialization
Following code uses an initialization interface to solve this issue. You can also use properties instead of a method.
interface I
{
void Initialize(object a, object b);
}
class GenericFactory where T : I, new()
{
public T Create(object a, object b)
{
T t = new T();
t.Initialize(a, b);
return t;
}
}
In case you see following error, you can bypass the .Net Strong name verification.
Unhandled Exception: System.IO.FileLoadException: Could not load file
or assembly 'FunkyProg, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089' or one of its dependencies.
Strong name validation failed. (Exception from HRESULT: 0x8013141A)
File name: 'FunkyProg, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089' ---> System.Security.SecurityException:
Strong name validation failed. (Exception from HRESULT: 0x8013141A)
The Zone of the assembly that failed was:
MyComputer
You can use sn.exe to register <assembly> for verification skipping.
sn -Vr <assembly> [<userlist>] [<infile>]
Or you can add following entry to the registry(you need to put the right public key token value).
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\*,b77a5c561934e089]
b77a5c561934e08 is the PublicKeyToken for the assembly.