65.9K
CodeProject is changing. Read more.
Home

Implementing C# Factory Pattern with Dynamic Class Loading

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.67/5 (3 votes)

Dec 6, 2017

CPOL

1 min read

viewsIcon

27108

Guide on creating a C# Factory Pattern with Dynamic Class Loading

Introduction

The Factory pattern is frequently used to de-couple service implementations. In C#, you can easily create a factory for dynamic class loading. I used this article as a basis, however, this factory is for Service, rather than for domain layer.

Background

In this example, unlike the example above, we will create a service factory. Service layer is the most frequent layer which will need tweaking, seeing as how database layers are often swapped. For example, you coded the software using stored procedures for insertion, but later need to switch to Entity Framework. This allows you to easily do so, by recoding implementation, and then "swapping" the said implementation.

Using the Code

First, you will need your Factory Class. This is the class which will be instantiated in order to lookup the key in the configuration file, and subsequently, it will be used to return the correct service implementation for that application version. In this application, we will be using service implementations.

using System;
using System.Linq;
using System.Configuration;

namespace MyProject.Factory
{
    public class Factory
    {
        public static Factory GetInstance()
        {
            return new Factory();
        }

        public IService GetImpl(string svcName)
        {
            string implName = GetImplName(svcName);
            Console.WriteLine(implName);
            Type type = Type.GetType(implName, true);
            IService newInstance = (IService)Activator.CreateInstance(type);
            return newInstance; 
        }

        public string GetImplName(string typeName)
        {
            string implName=ConfigurationManager.AppSettings[typeName];
            return implName;
        }
    }
}

You will need a parent Service Interface. This interface will be inherited by all child service interfaces. The child service interfaces will then be implemented by concrete classes.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyProject.Service
{
    public interface IService //top level for use by factory pattern
    {
 
    }
}

Now, we create the Service Interfaces. Decide on what the service will do, and inherit from the parent Service Interface.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyProject.Service
{
    public interface IMyService: IService
    {
		public bool MyMethod1();
		public bool MyMethod2(string input);

    }
} 

Let's implement the service interface. For now, we will just code it "TDD" style. YOu will need to provide proper implementations.

using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;
using System.Security;
using FileCopier.Service;
using System.Configuration;

namespace FileCopier.Service
{
    public class ImpersonationSvcImpl : IImpersonationSvc
    {
		public bool MyMethod1(){
			throw new NotImplementedException();			
		}
		
		public bool MyMethod2(string input);
		{
			throw new NotImplementedException();
		}
	}
} 

Next, you will need an app.Config file which lists your services and implementation classes.

 <?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
 <appSettings>
  <!-- service implementations-->
  <add key="IMyService" value="MyProject.Service.IMyServiceImpl"/>
 </appSettings>
</configuration>

Build your test classes:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FileCopier.Service.Factory;
using FileCopier.Service;
using System.Configuration;

namespace MyFactoryDemoTest
{
    [TestClass]
    public class FactoryTest
    {
        [TestMethod]
        public void TesFactory1()
        {
            string svcName = "IMyService";
            Factory f = Factory.GetInstance();
            string implName = f.GetImplName(svcName);
            Console.WriteLine(implName);
            Assert.IsNotNull(implName);
        }

        [TestMethod]
        public void TesFactory2()
        {
            string svcName = "IMyService";
            Factory f = Factory.GetInstance();
            IGetSettingsSvc setSvc = (IGetSettingsSvc)f.GetImpl(svcName);
            Assert.IsNotNull(setSvc);
        }

        [TestMethod]
        public void TestFactoryIMyServiceg()
        {
            string svcName = "IMyService";
            Factory f = Factory.GetInstance();
            IGetSettingsSvc setSvc = (IGetSettingsSvc)f.GetImpl(svcName);             
        }

        public string GetImplName(string typeName)
        {
            string implName = ConfigurationManager.AppSettings[typeName];
            return implName;
        }     
    }
}