2016-06-06 20 views
8

Attualmente sto lavorando a un progetto MVC e sto cercando di capire come potrei andare ad estendere i percorsi di un controller esistente all'interno di un'area, in particolare da un altro progetto.Override/Estensione di un controller MVC/Area

Per esempio, ho un controller con una superficie che appare come il seguente:

namespace MyProject.Areas.Foo.Controllers 
{ 
    [Authorize] 
    public class FooController : ApplicationController 
    { 
      //code 
    } 
} 

E quello che vorrei fare, è in grado di definire un altro controller, all'interno di un progetto separato che potrebbe estendere questo modo:

namespace MyOtherProject.Areas.Foo.Custom.Controllers 
{ 
    public class FooController : ApplicationController 
    { 
      public string Bar() 
      { 
       return "Bar"; 
      } 
    } 
} 

in sostanza, vorrei i controllori a quasi la funzione come se stavo usando la parola partial (in modo che potessi chiamare qualsiasi delle azioni in originale o quello nuovo).

Il principale problema

Quello che sto davvero cercando di realizzare è che ho un progetto principale con diverse aree e un'altra zona della mia soluzione con varie cartelle del cliente. Voglio essere in grado di estendere sostanzialmente i controller di base per il mio progetto principale e aggiungere azioni specifiche del client all'interno di queste cartelle client in modo che possano essere utilizzate nel progetto principale. Lo sto già facendo con determinate MVC Views, ma speravo di poterlo realizzare anche con i controller.

Quello che ho provato

  • Ho provato ad utilizzare la parola chiave partial su entrambe le dichiarazioni della classe, ma dal momento che sono in diversi progetti/assemblee, non credo che le opere.
  • Ho definito un evento di build che spostava la DLL personalizzata nella directory bin del progetto MVC principale, ma non sembrava funzionare come previsto.
  • Ho provato vari approcci per l'ereditarietà, sperando che la nuova classe venisse rilevata, ma quelli non funzionavano (ha ricevuto l'errore di dichiarazione del controller duplicato).
  • Ho letto di provare a utilizzare un numero personalizzato ControllerFactory ma non ero sicuro di come implementarlo.
  • Ho provato a definire i parametri di routing del namespace personalizzati nella sezione AreaRegistration per prelevare il nuovo controller come nell'esempio seguente.

Routing Esempio (AreaRegistration)

context.MapRoute(
    AreaName, 
    String.Format("{0}/{{action}}/{{id}}", AreaName), 
    new { controller = AreaName, action = "Index", id = UrlParameter.Optional }, 
    new[] { 
     String.Format("MyProject.Areas.{0}.Controllers", AreaName), 
     String.Format("MyOtherProject.Areas.{0}.Custom.Controllers", AreaName) 
    } 
); 

Aggiornamento

ho tentato un approccio seen here come per alcune delle discussioni commenti che ha coinvolto semplicemente la manipolazione di questo attraverso l'ereditarietà:

// Main Project 
namespace MyProject.Areas.Foo.Controllers 
{ 
    [Authorize] 
    public class FooController : ApplicationController 
    { 
      public ActionResult Index() 
      { 
       return View(); 
      } 
    } 
} 

// This is in another project/namespace/assembly 
namespace MyOtherProject.Foo.Controllers 
{ 
    public class CustomFooController : MyProject.Areas.Foo.Controllers.FooController 
    { 
     [Route("Foo/Bar")] 
     public string Bar() 
     { 
      return "Bar"; 
     } 
    } 
} 

Così i miei passi attuali sono i seguenti:

  • ereditati dalla base FooController nel progetto principale all'interno di un altro progetto/soluzione.
  • Impostare il routing degli attributi per accedere al controller personalizzato per evitare percorsi in conflitto dal progetto principale.
  • Creato un evento di build che sposta la DLL personalizzata nel progetto principale una volta creato (quindi sarà accessibile) dal nuovo progetto personalizzato.

Questo non sembra fare alcuna differenza. Ho provato ad andare sull'URL Foo/Bar ma ho appena lanciato un 404 come se non lo vedesse affatto. Il file CustomFooController.cs si trova nel proprio progetto separato ed è solo un file di classe e non un progetto MVC. È corretto? Devo impostare le regole di routing nel progetto principale?

+0

Cosa c'è di sbagliato con l'utilizzo di eredità? Nel progetto B, includere un riferimento a project-main, quindi controller-B ereditato da controller-main. In alternativa, utilizzare una classe comune come base e configurare di conseguenza i percorsi. –

+0

Quindi dovrei ereditare il mio controller Project B da 'FooController' nel Progetto A? In tal caso, in che modo ciò influenzerebbe il mio routing, dal momento che voglio essere in grado di utilizzare lo stesso routing di base, ovvero "Foo/ProjectAAction" o "Foo/ProjectBAction". Funzionerebbe ancora? –

+0

Tutte le rotte verso il controllore-B otterrebbero anche azioni main controller perché fanno parte del controller-B per ereditarietà. cioè i tuoi percorsi non sarebbero a conoscenza dei controller principali del progetto –

risposta

6

controller Inheritance

Utilizzando l'ereditarietà come Chris menzionato nella sezione commenti sarà probabilmente il modo migliore per andare su questo pure. Ciò è particolarmente vero se si è già derivanti da un'altra classe controller di base come ApplicationController nel tuo esempio:

// ProjectA is assumed to be your "main" MVC application 
public class CustomFooController : ProjectA.Controllers.FooController 
{ 
    [Route("Foo/Bar")] 
    public ActionResult Bar() 
    { 
     return Content("Bar"); 
    } 
} 

L'attributo di routing qui è estremamente importante in quanto non si vuole che le rotte esistenti per confondere i due controller o si affacciano loro.

Registrazione Itinerari attributi

Dal momento che si sta utilizzando l'attributo di routing tramite l'attributo [Route] all'interno della vostra sezione ProjectB, ti consigliamo di assicurarsi che si imposta in modo esplicito all'interno del RouteConfig.cs del progetto ProjectA in modo che possa correttamente identificarlo attraverso il metodo Routes.MapMvcAttributeRoutes() come si vede qui sotto:

public static void RegisterRoutes(RouteCollection routes) 
{ 
    // This is important to set up your Route Attributes 
    routes.MapMvcAttributeRoutes(); 

    // Route declarations omitted for brevity 
} 

Allo stesso modo, se si utilizza Aree, ti consigliamo di configurare questo all'interno del rispettivo file come AreaRegistration.cs bene:

public override void RegisterArea(AreaRegistrationContext context) 
{ 
    // Wire up any attribute based routing 
    context.Routes.MapMvcAttributeRoutes(); 

    // Area routing omitted for brevity 
} 

di ambito Itinerari

Infine, l'ultima cosa che si vuole fare in modo di fare è propriamente "scope" i percorsi per dare priorità spazio dei nomi principale all'interno del RouteConfig.cs del vostro principale ProjectA applicazione:

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    routes.MapMvcAttributeRoutes(); 
    routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Foo", action = "Index", id = UrlParameter.Optional }, 
     // This will prioritize your existing Controllers so they work as expected 
     namespaces: new[] { "ProjectA.Controllers"} 
    ); 
} 

Ottenere riferimenti Across

Hai menzionato l'utilizzo di un evento di build per copiare la DLL dal progetto ProjectB nel progetto ProjectA principale, che in questo caso dovrebbe essere corretto. Sarà fondamentalmente bisogno qualche modo per accedervi e semplicemente xcopy come la seguente dovrebbe andare bene nella maggior parte degli scenari:

xcopy /E /Y /S "$(ProjectName).dll" "$(SolutionDir)\ProjectA\Bin\" 

Mettere tutto insieme

Se è stato cablato il backup di tutti questi passi correttamente, dovresti essere in grado di pulire/ricostruire la tua soluzione esistente.Dopo questo modo, doppio controllo per assicurarsi di avere la DLL appropriata all'interno del vostro ProjectA bin directory:

enter image description here

Se questo è lì, allora siete sulla strada giusta e dovrebbe essere in grado di eseguire il principale applicazione e passare alla ~/Foo per visualizzare i seguenti:

enter image description here

Allo stesso modo, la navigazione verso ~/Foo/Bar dovrebbe prendere il percorso attributo appropriato che è stato definito nel vostro altro controller e servire il contenuto corretto:

enter image description here

+0

Grazie mille! Questo ha funzionato esattamente come avevo immaginato. Grazie per aver capito cosa stavo cercando di fare! –

Problemi correlati