简体   繁体   中英

c# MVC dependency injection based on route param

What I'm trying to do is to instantiate a service using NInject and a route param.

I have something like this:

DAL

public interface IDALContract
{
  object GetById(int id);
}

public class DALPeopleContract : IDALContract
{
  public object GetById(int id)
  {
    //get person
    return null;
  }
}

public class DALAnimalsContract : IDALContract
{
  public object GetById(int id)
  {
    //get animal
    return null;
  }
}

public static class DALContractFactory
{
  public static IDALContract GetContract(int discriminator)
  {
    switch(discriminator)
    {
      case 1: return new DALPeopleContract();
      case 2: return new DALAnimalsContract();
      default: throw new NotSupportedException();
    }
  }
}

Business Layer

public interface IMyService
{
  object GetById(int id);
}

public class MyService : IMyService
{
  private IDALContract _contract;

  public MyService(int discriminator)
  {
    _contract = DALContractFactory.GetContract(discriminator)
  }

  public object GetById(int id)
  {
    return _contract.GetById(id);
  }
}

Controller

public class MyController
{
  private IMyService _myService;

  public MyController()
  {
    //how do I get the discriminator here? (the discriminator should be a route param)
    IParameter param = new Parameter("MyParam", discriminator, true);
    _myService = NInjectKernel.TryGet<IMyService>(param);
  }

  ActionResult Index(id)
  {
    _myService.GetById(id);
    return View(model);
  }
}

So the issue that I'm having is how to get the param, or is there a better approach to this. Basicaly what I'm trying to do is to have one controller that handles the same actions for different models, but I'm having an issue with the Data Access Layer (DAL).

Would it be a good idea to get the value on OnActionExecuting and instantiate there the service?

I found a clean (in my opinion) solution to my issue.

So now I have a fairly easy way to deal with simple operation on related classes.

I replaced the DALContractFactory with some NInject binding. And I have a custom route defined for my controller that requires a "type" that is read in OnActionExecuting on my controller.

For the models, I have a factory defined and a custom mapper (I haven't posted them here because they were not relevant to the question). If anybody is interested, I can post a sample sln with this approach.

So now I have something like:

DAL

public interface IDALContract
{
  object GetById(int id);
}

public class DALPeopleContract : IDALContract
{
  public object GetById(int id)
  {
    //get person
    return null;
  }
}

public class DALAnimalsContract : IDALContract
{
  public object GetById(int id)
  {
    //get animal
    return null;
  }
}

Business Layer

public enum Discriminator
{
    Animal,
    Person
}

public interface IMyService
{
  object GetById(int id);
}

public class MyService : IMyService
{
  private IDALContract _contract;

  public MyService(IDALContract contract)
  {
    _contract = contract;
  }

  public object GetById(int id)
  {
    return _contract.GetById(id);
  }
}

Controller

public class MyController : Controller
{
  private IMyService _myService;

  protected override void OnActionExecuting(ActionExecutingContext ctx)
  {
    base.OnActionExecuting(ctx);
    int type;
    var routeValue = ControllerContext.RouteData.Values["type"];

    Discriminator type;

    if(!Enum.TryParse<Discriminator>(routeValue.ToString(), out type))
    {
        //set a default value
        type = Discriminator.Animal;
    }

    _myService = NInjectKernel.Instance.GetService<IMyService>("type", type);
  }

  public ActionResult Index(id)
  {
    _myService.GetById(id);
    return View(model);
  }
}

NInjectConfiguration

public class NInjectKernel
{
  private readonly IKernel _kernel;
  private NInjectKernel()
  {
    _kernel = new StandardKernel();
  }

  private static volatile Irr2NInjectKernel _instance;
  private static readonly object SyncRoot = new object();
  public static Irr2NInjectKernel Instance
  {
        get
        {
            if (_instance == null)
            {
                lock (SyncRoot)
                {
                    if (_instance == null)
                    {
                        var temp = new Irr2NInjectKernel();
                        temp.BindAllDependencies();
                        _instance = temp;
                    }
                }
            }

            return _instance;
        }
    }

    private void BindAllDependencies()
    {
        _kernel.Bind<IMyService>().To<MyService>();
        _kernel.Bind<IDALContract>().ToMethod(x =>
        {
            IParameter parameter = x.Parameters.SingleOrDefault(p => p.Name == "type");
            if (parameter != null)
            {
                var recordType = (Discriminator)parameter.GetValue(x, x.Request.Target);

                switch (recordType)
                {
                    case RecordType.Animal:
                        return new DALAnimalsContract();
                    case RecordType.Person:
                        return new DALPeopleContract();
                    default:
                        throw new NotSupportedException("DQS type is not suppported.");
                }
            }
            throw new NotSupportedException();
        });
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM