A simple C# factory class
I have a project that is pretty small. Despite the small size, it is well-designed, using multiple layers, and interfaces, dependency injection, and unit tests. I need to create a production object at runtime and a mocked object at test time. I could easily use an IOC container. The problem with that is that most IOC containers (Autoface, Castle Windsor, Unity, etc.) are larger than my entire project. While I am a proponent of using IOC containers in large projects, I’m not a big proponent of using them in very small projects.
To make my code more unit testable, I am using a project called SystemWrapper that wraps standard system calls in an Interface and a Wrapper. Again, because my project is small, I didn’t bring in the SystemInterfaces and SystemWrapper dlls. This wrapper includes an ISmtpClient and an SmtpClientWrap object and I only brought in those two class files. The business logic uses the interface, ISmtpWrapper. This allows for me to unit test it by injecting a mock ISmtpClient.
I needed a simple factory that creates a new SmptClient in production runtime but allows for my unit test to create and use a mock ISmptClient during unit test time.
Here is what my factory should do:
Production
- Create a new SmptClientWrap object (which wraps an System.Net.SmptClient oject).
- Use setting from the app.config or web.config for the mail server, domain, user, and password.
Unit Test
- Create an mock of ISmptClient (using Moq).
Here is the simple factory class that I wrote:
using System.Configuration;
using System.Net;
using SystemInterface.Net.Mail;
using SystemWrapper.Net.Mail;
namespace Rhyous.System.Factory
{
public class SmtpClientFactory
{
public ISmtpClient GetNewSmtpClient()
{
return CreateCredentialsMethod();
}
public delegate ISmtpClient CreateCredentialsDelegate();
public CreateCredentialsDelegate CreateCredentialsMethod = () => new SmtpClientWrap(ConfigurationManager.AppSettings["SmtpServer"])
{
Credentials = new NetworkCredential
{
Domain = ConfigurationManager.AppSettings["SmtpDomain"],
UserName = ConfigurationManager.AppSettings["SmtpUser"],
Password = ConfigurationManager.AppSettings["SmtpPassword"]
}
};
}
}
In the above class, the GetNewSmptClient returns an ISmtpClient. I use a delegate to create a concrete ISmtpClient called SmtpClienWrap. The default delegate implementation gets the data from the app.config or web.config.
Now I can inject a concrete ISmtpClient into my code:
using (var smtpClient = SmtpClientFactory.GetNewSmtpClient())
{
var mailer = new Mailer(smtpClient);
}
Note: I could make SmptClientFactory static or make it a singleton. I’m thinking about both.
Now in a test, I am able to create a mock ISmtpClient. Here is an example.
[TestMethod]
public void ReplacingTheCreateCredentialsDelegateWorks()
{
var factory = new SmtpClientFactory();
bool _wasCalled = false;
factory.CreateCredentialsMethod = () =>
{
_wasCalled = true;
return new Mock<ISmtpClient>().Object;
};
var client = factory.GetNewSmtpClient();
Assert.IsTrue(_wasCalled);
}
The one problem with my factory is that it is pretty specific to one class. It might be interesting to make it more generic.
using System;
namespace Rhyous.Factory
{
public class ObjectFactory<TInterface, TObject>
where TInterface : class
where TObject : TInterface, new()
{
public TInterface GetNewObject()
{
if (!typeof(TInterface).IsInterface)
{
throw new Exception("The first generic, TInterface, must be an interface.");
}
return CreateObjectMethod();
}
public delegate TInterface CreateObjectDelegate();
public virtual CreateObjectDelegate CreateObjectMethod
{
get
{
return _CreateObjectMethod ?? (_CreateObjectMethod = () => Activator.CreateInstance<TObject>());
}
set { _CreateObjectMethod = value; }
}
public CreateObjectDelegate _CreateObjectMethod;
}
}
Now I move my delegate (which is creation method of the factory) upstream to where I instantiate the factory.
var smtpClientFactory = smtpClientFactory = new ObjectFactory<ISmtpClient, SmtpClientWrap>
{
CreateObjectMethod = () => new SmtpClientWrap(ConfigurationManager.AppSettings["SmtpServer"])
{
Credentials = new NetworkCredential
{
Domain = ConfigurationManager.AppSettings["SmtpDomain"],
UserName = ConfigurationManager.AppSettings["SmtpUser"],
Password = ConfigurationManager.AppSettings["SmtpPassword"]
}
}
};
// Then later use the factory...
using (var smtpClient = smtpClientFactory.GetNewSmtpClient())
{
var mailer = new Mailer(smtpClient);
}
Anyway, have fun with this mini-factory. It might be useful on small projects where you don’t want an entire IOC container.

