1
\$\begingroup\$

I am working on a very simplified proof of concept (POC).

Separation of concerns should be achieved in this project, so that in the future we have flexibility in respect of what data source we use (hence no UI in this POC) .

  • The BLL has a POCO Fruit class, the repository interface it expects its data sources to implement, and a FruitService class, whose responsibility is to return a string that will be used to label the fruit.
  • The DAL returns a fruit when a key is supplied via a repository.

I want check that the code applies the SOLID principle of Dependency Inversion (DIP), so that the higher order BLL does not depend on the DAL - but rather DAL depends on BLL.

Solution structure:

enter image description here

BLL classes:

1.Fruit POCO:

namespace DapperRepository_SingleProject.BusinessLogicLayer
{
    public class Fruit
    {
        public int FruitKey { get; set; }
        public string Name { get; set; }
        public string Color { get; set; }
        public decimal Price { get; set; }
    }
}

2.Generalised repository interface:

namespace DapperRepository_SingleProject.BusinessLogicLayer
{
    public interface IRepository<T> where T : class
    {
        T GetByKey(int key);
    }
}

3.FruitService class with a single method to return a string, for a label - here I have attempted to implement constructor injection:

class FruitService
{

    private IRepository<Fruit> FruitRepo = null;

    public FruitService(IRepository<Fruit> fruitRepo)
    {
        FruitRepo = fruitRepo;
    }

    public string PrintLabel(int fruitKey)
    {
        Fruit f = FruitRepo.GetByKey(fruitKey);
        return string.Concat(f.Name.ToString(), " priced at ", f.Price.ToString());
    }

}

DAL has a Repository class that implements the repository interface specified in the BLL:

using System.Linq;
using Dapper;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using DapperRepository_SingleProject.BusinessLogicLayer;

namespace DapperRepository_SingleProject.DataAccessLayer
{

    public class FruitRepository : IRepository<Fruit>
    {
        private IDbConnection dbConnection = null;

        public FruitRepository()
        {
            dbConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["xxx"].ConnectionString);
        }

        public Fruit GetByKey(int key)
        {
            Fruit fruit = null;

            string sql = "SELECT * FROM FruitInfo.dbo.tb_Fruit WHERE FruitKey=@Key";
            var queryResult = dbConnection.Query<Fruit>(sql, new { Key = key });

            if (queryResult != null)
            {
                fruit = queryResult.FirstOrDefault();
            }
            return fruit;
        }
    }
}

Data is as follows:

USE FruitInfo;
CREATE TABLE dbo.tb_Fruit
(
    FruitKey    int not null,
    Name        varchar(25),
    Color       varchar(25),
    Price       money
);
ALTER TABLE dbo.tb_Fruit  
ADD CONSTRAINT PK_tb_Fruit_FruitKey PRIMARY KEY CLUSTERED (FruitKey);

INSERT INTO FruitInfo.dbo.tb_Fruit
    values
    (1, 'Apple', 'Red', 10),
    (2, 'Orange','Orange', 20),
    (3, 'Pear',  'Green', 15);

Program.cs I use both the namespaces of DAL and BLL with a method Orchestrator that is my attempt at the injection:

using System;
using DapperRepository_SingleProject.DataAccessLayer;
using DapperRepository_SingleProject.BusinessLogicLayer;


namespace DapperRepository_SingleProject
{
    class Program
    {

        FruitRepository fruitRepository = null;

        static void Main(string[] args)
        {
            Program p = new Program();
            p.Orchestrator();
        }

        public void Orchestrator()
        {

            fruitRepository = new FruitRepository();
            FruitService fs = new FruitService(fruitRepository);   //<<attempt at constructor injection
            Console.WriteLine(fs.PrintLabel(1));


            Console.WriteLine("press a key");
            Console.ReadKey();
        }

    }
}

Two questions for review:

  1. Does the above comply with the Dependency-Inversion Principle? I am using the BLL namespace in the DAL classes, but not the DAL namespace in the BLL so I am assuming it complies? If it does not comply with this principle then what changes are required so it does?

  2. In the Orchestration.cs and FruitService.cs classes I've tried to use Dependency Injection - is my implementation correct?

\$\endgroup\$
  • \$\begingroup\$ You have discribed only the architecture. Please add also a few sentencs about what this code is supposed to accomplish. \$\endgroup\$ – t3chb0t Jun 29 at 15:30
  • 1
    \$\begingroup\$ @t3chb0t ok - will do. It is the very beginning of a bigger project. \$\endgroup\$ – whytheq Jun 29 at 15:32
  • \$\begingroup\$ @t3chb0t .... ok I added some more detail - is that the sort of information that helps? Basically I want to use a Repository pattern in the DAL, have the DAL dependent on the BLL << and apply these techniques in the correct way. \$\endgroup\$ – whytheq Jun 29 at 15:39
  • \$\begingroup\$ The kind of description that we expect is something like this: the purpose of this code is to get fruits from a database and do something with it etc... it'd be great if you could explain the code on this level. In other words, what is each layer supposed to do exactly. \$\endgroup\$ – t3chb0t Jun 29 at 15:40
  • 2
    \$\begingroup\$ @dfhwze I'll edit and add a FruitService class. It will have a single method PrintLabel which will return a string saying "<FruitName> priced at <Price>" \$\endgroup\$ – whytheq Jun 29 at 18:43
2
\$\begingroup\$

Does the above comply with the Dependency-Inversion Principle? I am ..

Yes, because:

  • BLL defines domain classes and interfaces for DAL to implement
  • BLL does not depend on DAL
  • DAL implements BLL-provided interface and uses its domain classes

In the Orchestration.cs and FruitService.cs classes I've tried to use Dependency Injection - is my implementation correct?

You have coded in the dependency.

FruitService fs = new FruitService(fruitRepository);

Dependency 'Injection' means you don't have to code it in. Instead, you should use a Inversion-of-Control (IoC) container to resolve registered classes with their dependencies.

A pseudo usage of an IoC container:

register types

container.Register<FruitService>().AsSingleInstance();
container.Register<FruitRepository>().AsImplementedInterfaces();

get the repository (if you need to work directly with a repository)

var repository = container.Resolve<IRepository<Fruit>>();

get the service (the repository is injected because it got registered)

var service = container.Resolve<FruitService>(); 
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for the answer. DI is possible without an IoC container...no? \$\endgroup\$ – whytheq Jun 30 at 17:05
  • \$\begingroup\$ Check out autofac.org as a container. \$\endgroup\$ – dfhwze Jun 30 at 17:06
  • \$\begingroup\$ Cheers - how do I implement IoC and DI without using a container such as autofac? I assume DI is just a pattern which something like autofac helps to simplify? \$\endgroup\$ – whytheq Jul 2 at 10:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.