2010-10-15 19 views
0

J'ai un peu de problème. J'ai une zone appelée Framed. Cette zone a un contrôleur de la maison. La valeur par défaut pour le site a également un contrôleur de la maison. Ce que j'essaye de faire avec ceci est d'avoir une version de chaque contrôleur/action qui convient à un IFrame, et une version qui est le site normal. Je le fais à travers les pages maîtres, et la page maître du site a de nombreux détenteurs de contenu différent de la version encadrée. Pour cette raison, je ne peux pas échanger la page maître. Par exemple, http://example.com/Framed/Account/Index affichera une version très basique avec uniquement les informations de votre compte pour une utilisation sur un site externe. http://example.com/Account/Index affichera les mêmes données, mais à l'intérieur du site par défaut.MVC 2.0, StructureMap, zones et noms de contrôleurs en double

Mon conteneur IoC est structemap. Donc, j'ai trouvé http://odetocode.com/Blogs/scott/archive/2009/10/19/mvc-2-areas-and-containers.aspx et http://odetocode.com/Blogs/scott/archive/2009/10/13/asp-net-mvc2-preview-2-areas-and-routes.aspx. Voici ma configuration actuelle.

StructureMap Init

ObjectFactory.Initialize(x => 
      { 
       x.AddRegistry(new ApplicationRegistry()); 
       x.Scan(s => 
       { 
        s.AssembliesFromPath(HttpRuntime.BinDirectory); 
        s.AddAllTypesOf<IController>() 
         .NameBy(type => type.Namespace + "." + type.Name.Replace("Controller", "")); 
       }); 
      }); 

Le problème que j'ai trouvé à travers le débogage est que parce que les contrôleurs ont le même nom (HomeController), il enregistre seul le premier, qui est le contrôleur d'accueil par défaut. J'ai été créatif et j'ai ajouté l'espace de noms afin qu'il enregistre tous mes contrôleurs.

Default Route

routes.MapRoute(
       "Default", // Route name 
       "{controller}/{action}/{id}", // URL with parameters 
       new { area = "", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults 
       new[] { "MySite.Controllers" } 
       ); 

itinéraire Zone

context.MapRoute(
       "Framed_default", 
       "Framed/{controller}/{action}/{id}", 
       new { area = "Framed", controller = "Home", action = "Index", id = UrlParameter.Optional }, 
       new string[] { "MySite.Areas.Framed.Controllers" } 
      ); 

Comme recommandé par Phil Haack, j'utilise les espaces de noms comme le 4ème paramètre

application début, juste pour prouver l'ordre d'initialisation

protected void Application_Start() 
     { 
      InitializeControllerFactory(); 

      AreaRegistration.RegisterAllAreas(); 

      RouteConfiguration.RegisterRoutes(); 
     } 

Controller usine

protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
     { 
      IController result = null; 
      if (controllerType != null) 
      { 
       result = ObjectFactory.GetInstance(controllerType) 
        as IController; 
      } 
      return result; 
     } 

Alors, quand je frappe/Accueil/Index, il passe dans le type de contrôleur correct. Lorsque je clique sur/Framed/Home/Index, controllerType est null, erreurs qui ne sont pas renvoyées.

C'est comme si MVC ignorait complètement ma zone. Que se passe t-il ici? Qu'est-ce que je fais mal?

Répondre

0

Au cas où quelqu'un essaye de faire quelque chose de similaire, j'ai utilisé l'idée de ce post: Categories of controllers in MVC Routing? (Duplicate Controller names in separate Namespaces) J'ai dû déverser des zones complètement et implémenter quelque chose moi-même.

J'ai Contrôleurs/HomeController.cs et contrôleurs/Framed/HomeController.cs

J'ai un ControllerBase de classe que tous les contrôleurs/contrôleurs héritent. J'ai AreaController qui hérite de ControllerBase à partir de laquelle tous les contrôleurs dans/Controllers/Framed s'étendent.

Voici ma zone de classe contrôleur

public class AreaController : ControllerBase 
    { 
     private string Area 
     { 
      get 
      { 
       return this.GetType().Namespace.Replace("MySite.Controllers.", ""); 
      } 
     } 
     protected override ViewResult View(string viewName, string masterName, object model) 
     { 
      string controller = this.ControllerContext.RequestContext.RouteData.Values["controller"].ToString(); 

      if (String.IsNullOrEmpty(viewName)) 
       viewName = this.ControllerContext.RequestContext.RouteData.Values["action"].ToString(); 

      return base.View(String.Format("~/Views/{0}/{1}/{2}.aspx", Area, controller, viewName), masterName, model); 
     } 

     protected override PartialViewResult PartialView(string viewName, object model) 
     { 
      string controller = this.ControllerContext.RequestContext.RouteData.Values["controller"].ToString(); 

      if (String.IsNullOrEmpty(viewName)) 
       viewName = this.ControllerContext.RequestContext.RouteData.Values["action"].ToString(); 

      PartialViewResult result = null; 

      result = base.PartialView(String.Format("~/Views/{0}/{1}/{2}.aspx", Area, controller, viewName), model); 

      if (result != null) 
       return result; 

      result = base.PartialView(String.Format("~/Views/{0}/{1}/{2}.ascx", Area, controller, viewName), model); 

      if (result != null) 
       return result; 

      result = base.PartialView(viewName, model); 

      return result; 
     } 
    } 

je devais passer outre les méthodes d'affichage et PartialView. De cette façon, les contrôleurs dans ma "zone" peuvent utiliser les méthodes par défaut pour les vues et partiels et supporter les structures de dossiers ajoutées.Comme pour les vues, j'ai Views/Home/Index.aspx et Views/Framed/Home/Index.aspx. J'utilise le routage comme indiqué dans le poste, mais voici comment le mien ressemble de référence:

var testNamespace = new RouteValueDictionary(); 
      testNamespace.Add("namespaces", new HashSet<string>(new string[] 
      { 
       "MySite.Controllers.Framed" 
      })); 

      //for some reason we need to delare the empty version to support /framed when it does not have a controller or action 
      routes.Add("FramedEmpty", new Route("Framed", new MvcRouteHandler()) 
      { 
       Defaults = new RouteValueDictionary(new 
       { 
        controller = "Home", 
        action = "Index", 
        id = UrlParameter.Optional 
       }), 
       DataTokens = testNamespace 
      }); 

      routes.Add("FramedDefault", new Route("Framed/{controller}/{action}/{id}", new MvcRouteHandler()) 
      { 
       Defaults = new RouteValueDictionary(new 
       { 
        //controller = "Home", 
        action = "Index", 
        id = UrlParameter.Optional 
       }), 
       DataTokens = testNamespace 
      }); 

var defaultNamespace = new RouteValueDictionary(); 
      defaultNamespace.Add("namespaces", new HashSet<string>(new string[] 
      { 
       "MySite.Controllers" 
      })); 

routes.Add("Default", new Route("{controller}/{action}/{id}", new MvcRouteHandler()) 
       { 
        Defaults = new RouteValueDictionary(new 
        { 
         controller = "Home", 
         action = "Index", 
         id = UrlParameter.Optional 
        }), 
        DataTokens = defaultNamespace 
       }); 

Maintenant, je peux aller/Accueil/Index ou/Framed/Accueil/Index sur le même site et obtenir deux points de vue différents avec un contrôle partagé. Idéalement, j'aimerais que l'un des contrôleurs renvoie une des deux vues, mais je n'ai aucune idée de la façon de le faire sans deux contrôleurs.

0

J'ai eu un problème similaire en utilisant Structuremap avec Areas. J'avais une zone nommée Admin et chaque fois que vous essayiez d'aller dans/admin, elle arrivait à l'usine de contrôleur StructureMap avec un type de contrôleur nul.

Je fixe en suivant ce blog: http://stephenwalther.com/blog/archive/2008/08/07/asp-net-mvc-tip-30-create-custom-route-constraints.aspx

Had pour ajouter une contrainte sur la route par défaut pour correspondre pas si le contrôleur était administrateur.

Voilà ma définition d'itinéraire par défaut:

routes.MapRoute(
    "Default", 
    "{controller}/{action}/{id}", 
    new { controller = "MyController", action = "AnAction", id = UrlParameter.Optional }, 
    new { controller = new NotEqualConstraint("Admin")}, 
    new string[] {"DailyDealsHQ.WebUI.Controllers"} 
); 

et est ici la mise en œuvre du NotEqualConstraint:

public class NotEqualConstraint : IRouteConstraint 
{ 
    private string match = String.Empty; 

    public NotEqualConstraint(string match) 
    { 
     this.match = match; 
    } 

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     return String.Compare(values[parameterName].ToString(), match, true) != 0; 
    } 
} 

Il y a probablement d'autres façons de résoudre ce problème, mais il fixe pour moi :)