Something To Code

All about programming and information security

Why interface for decoupled system? A note on how to design decoupled system in ASP.NET MVC

An Interface:

At first interfaces are come in the focus because of there is no multiple inheritance supported by C#, meaning you cannot inherit from multiple classes but you can implement multiple interfaces. The interfaces are grouping of object in terms of behavior.

An interface contains only signatures there is no implementation, only the signatures of the functionality the interface provides. An interface can contain signatures of methods, properties, indexers & events.

Interface doesn't do anything like classes and abstract classes, it just defines what the class will performs if some class inherits it. An interface also be inherit from another interface.

If we take an example of USB (Universal Serial Bus), Its an interface which has signature of Connection functionality. The USB interface only know I have to connect with Desktop Computer or laptop or anything, but it does not know what implementation will come to connection. It may be Pen drive(mass storage), It may be Printer(COM Ports)

Lets see the concept by programmatic way. Using the code.

An USB Interface:

public interface IUSB
{
    public void MakeConnection();
}

The Pendrive Class:

public class Pendrive: IUSB
{
    public void MakeConnection()
    {
        //The code for connecting pen drive to desktop, laptop or other
        throw new NotImplementedException();
    }
}

The Printer Class:

public class Printer: IUSB
{
    public void MakeConnection()
    {
        //The code for connecting printer to desktop, laptop or other
        throw new NotImplementedException();
    }
}

Decoupled System:

Now the decoupled system means the way of defining the architecture of project that one module can not be depend on another module. The system should be depends on abstraction rather than implementation.  

In realistic way suppose, I am currently designing the MVC project with MS SQL Server but if in future I have to change the database to MySQL. In this case I just need to change the Repository Implementation not a Controller. 

So my Controller should be implementing the abstraction/interfaces of Repository. When I change the implementation of Repository I just have to change it to new implementation rest nothing will be change.

private readonly IRepository _repository;
public ActionResult Index()
{
    _repository = new MSSQLRepository();
    //or
    //_repository = new MySQLRepository();
}

Decoupled system using interface by realistic example:

As I am developer I got one requirement from client. The requirement is I have to get current exchange rate by currency. So I have to Pass USD and Get current INR Rate or Current EURO rate. There are various web services can offers this functionality.

So consider provider ABC, DEF & PQR provides this web services but they charging different money. So my client said me at first we will try ABC's Service, but if we found its not reliable then we have to change it later stage.

So lets consider the dirty code first:

public class ProductController : Controller
{
    public async Task<ActionResult> DisplayProduct()
    {
        Product p = new Product();
        p.Name = "Test Product";
        p.Type = "USD";
        p.Price = 5;
        
        //All ABC Service code which returns USD to INR 
        double INR = <RETURN FROM WEB SERVICE>
        p.Price = p.Price * INR;
        return View(p);
    }
}

Now lets assume I am going to use this dirty code implementation directly in controller. It has some disadvantages.

  1. If I implement service code directly to controller I have to change it in all controller which needs currency conversion functionality. For this demo I have only 1 Controller and 1 Action but in real world application we may have lots or Controllers and Actions.
  2. To change the code in each every controller which need conversion functionality its very frustrated, and its opposite of Good Programming Standard. As per Programming Standard we have to reduce repetitive efforts.

Now I have to make design some logic decoupled way, So when client say we have to go with another service provider I don't have to change much in my Controller, But the problem is how to design the decoupled logic and then Interface comes in focus.

The design as follows.

  • What is important here is, I have get current exchange rate by passing currency.
  • So I created one ICurrencyExchangeService Interface.
  • Then I Just defined the function signatures in interface. e.g. GetCurrentINR(string currency); GetCurrentEURO(string currency);

ICurrencyExchangeService Interface:

public interface ICurrencyExchangeService
{
    double GetCurrentINR(string type);
    double GetCurrentEURO(string type);
} 
  • Now I created ABCCurrencyExchangeService class which inherited from ICurrencyExchangeService
  • All functions [defined in interface] will be implemented here as per the ABC Service documentation.

ABCCurrencyExchangeService Class:

public class ABCCurrencyExchangeService : ICurrencyExchangeService
{
    public double GetCurrentINR(string type)
    {
        double exchangeRate = 0.0;

        //Call the ABC web service with appropriate parameters as per the  documentation. 
        //Assign converted rate to exchangeRate variable

        return exchangeRate;
    }

    public double GetCurrentEURO(string type)
    {
        double exchangeRate = 0.0;

        //Call the ABC web service with appropriate parameters as per the  documentation. 
        //Assign converted rate to exchangeRate variable

        return exchangeRate;
    }    
}
  • Now I am using ICurrencyExchangeService in my Controller

ProductController Controller [MVC]

public class ProductController : Controller
{
    ICurrencyExchangeService  _currencyService = new ABCCurrencyExchangeService();

    public async Task<ActionResult> DisplayProduct()
    {
        Product p = new Product();
        p.Name = "Test Product";
        p.Type = "USD";
        p.Price = 5;
        //But we have to show INR prices
        double INR = _currencyService.GetCurrentINR(p.Type);
        p.Price = p.Price * INR;
        return View(p);
    }
}

  • All my code is going well but after few days client says the service is not reliable. We have to migrate it to another service i.e. DEF Service.
  • Now what to do? I have 2 options:
  1. A. Change the ABCCurrencyExchangeService Class implementation as per the DEF Service documentation, But it's against the name standard because we are implementing the DEF service under the class name ABCCurrencyExchangeService.
    B. Also one more disadvantage is suppose after some days if client say we have to revert our old service that is ABC then we have to again implement ABC service.
  2. The second and good option is we will create new class DEFCurrencyExchangeService which inherited from ICurrencyExchangeService Interface and I implement all the methods as per the DEF Service.
public class DEFCurrencyExchangeService : ICurrencyExchangeService
{
    public double GetCurrentINR(string type)
    {
        double exchangeRate = 0.0;

        //Call the DEF web service with appropriate parameters as per the  documentation. 
        //Assign converted rate to exchangeRate variable

        return exchangeRate;
    }

    public double GetCurrentEURO(string type)
    {
        double exchangeRate = 0.0;

        //Call the DEF web service with appropriate parameters as per the  documentation. 
        //Assign converted rate to exchangeRate variable

        return exchangeRate;
    }
    
}
  • Now I just have to change the the one line in my controller. The repository is now pointing to DEFCurrencyExchangeService Class. So my new Product Controller look like.
public class ProductController : Controller
{
    //ICurrencyExchangeService  _currencyService = new ABCCurrencyExchangeService();

    ICurrencyExchangeService  _currencyService = new DEFCurrencyExchangeService();

    public async Task<ActionResult> DisplayProduct()
    {
        Product p = new Product();
        p.Name = "Test Product";
        p.Type = "USD";
        p.Price = 5;
        //But we have to show INR prices
        double INR = _currencyService.GetCurrentINR(p.Type);
        p.Price = p.Price * INR;
        return View(p);
    }
}

  •  I just change one line and our new service is started also after some days if my client asks me to revert back to ABC service. Again I have to change only 1 Line.
  • If you are plan to use it with Dependency Injection container so it gives us flexibility at whole new level. You don't have to change anything in Controller. We have to just change in dependency injection container and its done.

Using Unity as Dependency Injection Container

If you don't know about DI or how to use it, Please check following link.

  1. http://www.codeproject.com/Articles/786332/ASP-NET-MVC-with-Unity-Dependency-Injection
  2. http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection

Using the code. UnityConfig.cs Class Configuration. (Located in App_Start\UnityConfig.cs)

public static class UnityConfig
    {
        public static void RegisterComponents()
        {
            var container = new UnityContainer();

            // register all your components with the container here
            // it is NOT necessary to register your controllers

            // e.g. container.RegisterType<ITestService, TestService>();
            //container.RegisterType<ICurrencyExchangeService , ABCCurrencyExchangeService>();
            container.RegisterType<ICurrencyExchangeService , DEFCurrencyExchangeService >();

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }
    }
  • The above code is using unity DI container and we have just change mapping, Previously ICurrencyExchangeService Interface pointing to ABCCurrencyExchangeService Class and Now its pointing to DEFCurrencyExchangeService Class. The dynamic object creation is done by UNITY DI.
  • Now our new Product Controller will look like:

ProductController Class:

public class ProductController : Controller
{
    private readonly ICurrencyExchangeService  _currencyService;

    public ProductController(ICurrencyExchangeService  currencyService)
    {
        _currencyService = currencyService;
    }

    public async Task<ActionResult> DisplayProduct()
    {
        Product p = new Product();
        p.Name = "Test Product";
        p.Type = "USD";
        p.Price = 5;
        //But we have to show INR prices
        double INR = _currencyService.GetCurrentINR(p.Type);
        p.Price = p.Price * INR;
        return View(p);
    }
}

 

About Author

Author Mayur Lohite
Mayur Lohite

My name is Mayur Lohite. I am Programmer and Web Developer also I am Interested in Web Application Security and penetration testing. I have more than 4+ Years of experience in Microsoft Technologies such as C#, ASP.NET Webforms, ASP.NET MVC, Visual Basic, Entity Framework, SQL SERVER.

Loading