Search code examples
c#asp.net-mvcdependenciesclass-library

Custom dependency injection in a class library file


I am working on a project(asp.net mvc-5 with jQuery) in which whole validation is happening in front-end and we are executing APIs using $.ajax call, now as there are no validations on API level or not even in stored procedures of sql server, a user can easily access the the APIs with wrong values, so we decided to add a logic layer in our application.

So before that our structure looks like the below

jQuery -> Api layer -> Db layer

Now I want to add a layer between Api layer and Db layer which will be called as Logic layer.

The new structure will look like below

jQuery -> Api layer -> Logic layer -> Db layer

Note:

  1. all the layers are different projects in same solution
  2. Logic layer and Db layer is a class library file
  3. Db layer is divided into 2 sub categories (interface and class)

So we have 4 class library 1 api and 1 front end. interfaces are inherited in the class files. The class library is like below

  • db.Interface (class library project)

  • db.Class (class library project)

  • Logic.Interface (class library project)

  • Logic.Class (class library project)

We have already added dependencies for db layer the code for which looks like below,

Set of code In global.asax.cs

//Helps to find all the classes of Dblayer
string dbName = ConfigurationManager.AppSettings["DB"];
string dbDAL = Path.Combine(Server.MapPath("./DAL"), "DocPro.DMS.BusinessLayer." + dbName + ".dll");
AssemblyName an = AssemblyName.GetAssemblyName(dbDAL);
Assembly assembly = Assembly.Load(an);
Type[] assemblyTypes = assembly.GetTypes();
DALFinder.Initialize(assemblyTypes);

class file in api project called DalFinder

public static class DALFinder
{
    private static List<Type> TypeList { get; set; } = new List<Type>();

    public static void Initialize(Type[] typelist)
    {
        TypeList.Clear();
        TypeList = typelist.ToList<Type>();
    }
    public static object GetInstance(Type plugin)
    {
        foreach (Type type in TypeList)
        {
            if (type.IsInterface || type.IsAbstract)
            {
                continue;
            }
            else
            {
                if (type.GetInterface(plugin.FullName) != null)
                {
                    return Activator.CreateInstance(type, new object[] { Program.GetConnectionString() });
                }
            }
        }
        return null;
    }
}

and while executing a particular function I needed to do the below in my Api layer

BusinessLayer.IAdmin.IFolderRole a = (BusinessLayer.IAdmin.IFolderRole)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IFolderRole));
response = a.SaveFolderRole(item);

now for my current scenario I want to call db layer from my logic layer but since it is a class library file I failed to understand what should I do, for now I did something like below

public class DocTemplateController : ApiController
{
    private LogicLayer.IAdmin.IDocTemplate _LogicLayer;
    private BusinessLayer.IAdmin.IDocTemplate _Businesslayer;
    public DocTemplateController()
    {
        _LogicLayer = (LogicLayer.IAdmin.IDocTemplate)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IDocTemplate));
        _Businesslayer = (BusinessLayer.IAdmin.IDocTemplate)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IDocTemplate));
    }
    [HttpPost]
    [Route("api/Admin/DocTemplate/GetDocTemplates")]
    [Authorize]
    [Filters.AuthorizeLoginApi()]
    public async Task<GetTemplatesList> GetDocTemplates(DocTemplate request)
    {
        var response = new GetTemplatesList() { LogicLayerValidation = false };
        try
        {
            response = _LogicLayer.GetDocTemplates(request);
            if (response.LogicLayerValidation != false)
                response.GetTemplates = await _Businesslayer.GetDocTemplates(request.TemplateName, request.AccountId);
        }
        catch (Exception ex)
        {
            Utils.Logger.Instance.LogException(ex);
            response.LogicLayerValidation = false;
            response.LogicLayerMessage = ex.Message;
        }
        return response;
    }
}

And as I understand (I might be wrong) that this is a bad way of coding, I want to follow the structure of

jQuery -> API layer -> Logic layer -> Db layer

How can I do this?

Edit

I think I need to edit this question and provide more details. All the answers are good and can be very helpful for many but unfortunately I have failed to get what I wanted.

This is how my controller looks like:

[RateLimitApi]
public class UserController : ApiController
{
    private readonly LogicLayer.IAdmin.IUsers _LogicLayer;//Logic layer
    private readonly LogicLayer.IGlobalValidation _CommonLogicLayer; //common logic layer
    private readonly BusinessLayer.IAdmin.IUsers _Businesslayer;// business layer
    private readonly BusinessLayer.IAccess.IUser _IAccessBusinesslayer;//business layer which is being used in another api

    private BusinessEntities.Response.LogicLayerValidationResult _Llv; //entity for logiclayer
    private SPResponse _Sp; //response entity for add/edit
    private readonly ErrorLogger _Er; error log class
    private readonly BusinessEntities.Response.Admin.GetUsersList _UserList; //user list
    private readonly BusinessEntities.Response.Admin.GetUsersSingle _UserSingle; //single user
    public UserController()
    {
        _LogicLayer = (LogicLayer.IAdmin.IUsers)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IUsers));
        _Businesslayer = (BusinessLayer.IAdmin.IUsers)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IUsers));
        _IAccessBusinesslayer = (BusinessLayer.IAccess.IUser)DALFinder.GetInstance(typeof(BusinessLayer.IAccess.IUser));
        _CommonLogicLayer = (LogicLayer.IGlobalValidation)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IGlobalValidation));

        _Llv = new BusinessEntities.Response.LogicLayerValidationResult() { LogicLayerValidation = false };
        _Sp = new SPResponse();
        _Er = new ErrorLogger();
        _UserList = new BusinessEntities.Response.Admin.GetUsersList();
        _UserSingle = new BusinessEntities.Response.Admin.GetUsersSingle();
    }

    // GET: Admin/Users
    [HttpPost]
    [Authorize]
    [ActionName("GetList")]
    [Filters.AuthorizeLoginApi()]
    public async Task<BusinessEntities.Response.Admin.GetUsersList> GetList(DocPro.DMS.BusinessEntities.Request.Admin.UsersRequest request)
    {
        try
        {
           // had to call logic layer and then call the business layer like below
            _Llv = _LogicLayer.GetList(request);
            if (_Llv.LogicLayerValidation)
            {
                _UserList.GetUsers = await _Businesslayer.GetList(request.LoginText, request.Name, request.Email, request.UserTypeId, request.IsActive, Convert.ToInt32(request.LoggedInUserId));
            }
        }
        catch (Exception ex)
        {
            _Llv = _Er.LogExceptionWithLogicLayerValidations(ex, _Llv);
        }
        _UserList.LogicLayerValidation = _Llv;
        return _UserList;
    }
}

Solution

  • how can I do this?

    is quite a general question (which is frown upon in this community).

    I don't see any issue with the structure:

    jQuery -> Api layer -> Logic layer -> Db layer

    It is very common structure: frontend -> api-> business (logic) layer-> db

    If it is a new project, I might recommend to do it with .net core and use the microsoft dependency injections or maybe use Autofac, since the topic is complex. If you really want to do it, then you can also browse their (ms or autofuc) code on github to familiarize yourself on the topic.