简体   繁体   中英

Routing from one view to another controller's action method and passing a parameter to that controller's constructor

I'm creating my first C# MVC site and quite early on I've hit a roadblock where I'm not sure if I'm going about things entirely the wrong way and I can't find an example similar to my own online but it seems like what I'm trying to do should be straightforward.

Basically, I have my initial controller (called ClientController) that sets up a list of clients and then displays them in my list view:

public class ClientController : Controller
{

    private readonly IClientManagerRepository _clientManagerRepository;

    public ClientController()
        : this(new EntityClientManagerRepository())
    {
    }

    public ClientController(IClientManagerRepository repository)
    {
        _clientManagerRepository = repository;
    }

    //
    // GET: /Client/
    public ViewResult List()
    {

        return View(_clientManagerRepository.GetAllClients());

    }
}

Then in my view I have an action link where I want to route to my UserController, passing it the client name, so that it can build the list of users for that particular client.

@Html.ActionLink("View Admin Users","Index","User",new {clientName = item.ClientName},null)

This works with the following code:

public class UserController : Controller
{     
    private IUserManagerRepository _userManagerRepository;

    //
    // GET: /User/
    public ActionResult Index(string clientName)
    {
        _userManagerRepository = new EntityUserManagerRepository(clientName);
        return View(_userManagerRepository.GetAllUsers());
    }

}

And my list of users is displayed correctly in my view.

However, when I then add in my details action method it doesn't work because the _userManagerRepository isn't instantiated:

//
// GET: /User/Details/5
public ActionResult Details(int contactId)
{
    return View(_userManagerRepository.GetUser(contactId));
}

I would have to I guess pass in the clientname each time and re-instantiate my _userManagerRepository. That doesn't feel like a very good way though.

Ideally I'd like to create my _userManagerRepository in the constructor of my UserController. I've been looking into how I would do this so I'd have something like:

public class UserController : Controller
{


    private IUserManagerRepository _userManagerRepository;

    public UserController(string clientname)
        : this(new EntityUserManagerRepository(clientname))
    {
    }

    public UserController(IUserManagerRepository repository)
    {
        _userManagerRepository = repository;
    }

I've researched that I can create my own controller factory so that I can have a parameter in my userController constructor however I still don't understand how I would pass my clientname parameter form a view to my UserController.

If you want to instantiate Repository class in controller's constructor,you can use NInject , it's really nice approach to do it.

1-Install Ninject from Nuget 2-Create Repository Abstract for example ICustomerRepository

public abstract ICustomerRepository
{
   string GetCustomerName();
}

3-Create Repository for example CustomerRepository

public class CustomerRepository:ICustomerRepository
{
    string GetCustomerName()
    {
       return ("John");
    }

}

4-create CustomerControllerFactory Class

public class CustomControllerFactory : DefaultControllerFactory
    {
        private static IKernel ninjectKernel;
        public CustomControllerFactory()
        {
            ninjectKernel = new StandardKernel();
            AddBindings(ninjectKernel);
        }

        protected override IController GetControllerInstance
            (System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            if (controllerType == null)
            {
                return (new Controllers.MessageController());
            }
            else
            {
                return ((IController)ninjectKernel.Get(controllerType));
            }
        }

        public static void AddBindings(IKernel ninjectKernel)
        {
            Common.DependencyInjection.DependencyManager.GetDependencyInjections().ForEach(current =>
            {
                if (current.Abstract != null && current.Implementation != null)
                {
                    ninjectKernel.Bind(current.Abstract).To(current.Implementation);
                }
            });

            ninjectKernel.Bind<ICustomerRepository>().To(typeof(CustomerRepository));
        }
    }

ninjectKernel.Bind().To(typeof(CustomerRepository));

I bind ICustomerRepository to CustomerRepository in upper code

5- Add below code to Application_Start

ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());

6-Create New Controller

public class CustomerController:Controller
{
    public CustomerController(ICustomerRepository customerRepository)
   {
       //customerRepository instantiate to CustomerRepostory Class automatically
   }
}

it's Dependency Injection that i think useful for you

Regards

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