Как установить маршрут по умолчанию (в область) в MVC


122

Хорошо, об этом уже спрашивали, но твердого решения нет. Так что для меня и других, кто может найти это полезным.

В MVC2 (ASP.NET) я хочу, чтобы при переходе на веб-сайт была указана область по умолчанию. Поэтому переход на мой сайт должен отправить вас на ControllerX ActionY в AreaZ.

Используя следующий маршрут в Global.asax

routes.MapRoute(
                "Area",
                "",
                new { area = "AreaZ", controller = "ControllerX ", action = "ActionY " }
            );

Теперь это работает, поскольку он пытается обслуживать правильную страницу. Однако MVC продолжает искать представление в корне сайта, а не в папке Area.

Есть ли способ решить эту проблему?

РЕДАКТИРОВАТЬ

Существует «Решение», которое находится в ControllerX, ActionY возвращает полный путь к представлению. Немного взлома, но он работает. Однако я надеюсь, что есть лучшее решение.

         public ActionResult ActionY()
        {
            return View("~/Areas/AreaZ/views/ActionY.aspx");
        }

Редактировать:

Это также становится проблемой при наличии HTML ActionLink страницы. Если область не задана, ссылка на действие будет пустой.

Все это задумано или ошибочно?

Ответы:


98

Это меня заинтересовало, и у меня наконец-то появилась возможность изучить его. Другие люди, по-видимому, не поняли, что это проблема с поиском представления , а не проблема с самой маршрутизацией - и это, вероятно, потому, что заголовок вашего вопроса указывает, что он касается маршрутизации.

В любом случае, поскольку это проблема, связанная с представлением, единственный способ получить то, что вы хотите, - это переопределить механизм представления по умолчанию . Обычно, когда вы делаете это, просто переключите свой движок просмотра (например, на Spark, NHaml и т. Д.). В этом случае, это не логика показов создания нам нужно переопределить, но FindPartialViewи FindViewметоды в VirtualPathProviderViewEngineклассе.

Вы можете поблагодарить своих счастливчиков за то, что эти методы на самом деле виртуальные, потому что все остальное в VirtualPathProviderViewEngineних даже недоступно - оно частное, и поэтому очень раздражает переопределение логики поиска, потому что вам нужно в основном переписать половину кода, который уже был написан, если вы хотите, чтобы он хорошо работал с кешем местоположения и форматами местоположения. Покопавшись в Reflector, я наконец нашел рабочее решение.

То , что я сделал здесь , чтобы сначала создать аннотацию , AreaAwareViewEngineкоторая непосредственно вытекает из VirtualPathProviderViewEngineвместо WebFormViewEngine. Я сделал это для того, чтобы, если вы хотите вместо этого создавать представления Spark (или что-то еще), вы все равно можете использовать этот класс в качестве базового типа.

Приведенный ниже код довольно многословен, поэтому, чтобы дать вам краткое описание того, что он на самом деле делает: он позволяет вам поместить {2}в формат местоположения, который соответствует имени области, точно так же, как {1}имя контроллера. Это оно! Вот для чего нам пришлось написать весь этот код:

BaseAreaAwareViewEngine.cs

public abstract class BaseAreaAwareViewEngine : VirtualPathProviderViewEngine
{
    private static readonly string[] EmptyLocations = { };

    public override ViewEngineResult FindView(
        ControllerContext controllerContext, string viewName,
        string masterName, bool useCache)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (string.IsNullOrEmpty(viewName))
        {
            throw new ArgumentNullException(viewName,
                "Value cannot be null or empty.");
        }

        string area = getArea(controllerContext);
        return FindAreaView(controllerContext, area, viewName,
            masterName, useCache);
    }

    public override ViewEngineResult FindPartialView(
        ControllerContext controllerContext, string partialViewName,
        bool useCache)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (string.IsNullOrEmpty(partialViewName))
        {
            throw new ArgumentNullException(partialViewName,
                "Value cannot be null or empty.");
        }

        string area = getArea(controllerContext);
        return FindAreaPartialView(controllerContext, area,
            partialViewName, useCache);
    }

    protected virtual ViewEngineResult FindAreaView(
        ControllerContext controllerContext, string areaName, string viewName,
        string masterName, bool useCache)
    {
        string controllerName =
            controllerContext.RouteData.GetRequiredString("controller");
        string[] searchedViewPaths;
        string viewPath = GetPath(controllerContext, ViewLocationFormats,
            "ViewLocationFormats", viewName, controllerName, areaName, "View",
            useCache, out searchedViewPaths);
        string[] searchedMasterPaths;
        string masterPath = GetPath(controllerContext, MasterLocationFormats,
            "MasterLocationFormats", masterName, controllerName, areaName,
            "Master", useCache, out searchedMasterPaths);
        if (!string.IsNullOrEmpty(viewPath) &&
            (!string.IsNullOrEmpty(masterPath) || 
              string.IsNullOrEmpty(masterName)))
        {
            return new ViewEngineResult(CreateView(controllerContext, viewPath,
                masterPath), this);
        }
        return new ViewEngineResult(
            searchedViewPaths.Union<string>(searchedMasterPaths));
    }

    protected virtual ViewEngineResult FindAreaPartialView(
        ControllerContext controllerContext, string areaName,
        string viewName, bool useCache)
    {
        string controllerName =
            controllerContext.RouteData.GetRequiredString("controller");
        string[] searchedViewPaths;
        string partialViewPath = GetPath(controllerContext,
            ViewLocationFormats, "PartialViewLocationFormats", viewName,
            controllerName, areaName, "Partial", useCache,
            out searchedViewPaths);
        if (!string.IsNullOrEmpty(partialViewPath))
        {
            return new ViewEngineResult(CreatePartialView(controllerContext,
                partialViewPath), this);
        }
        return new ViewEngineResult(searchedViewPaths);
    }

    protected string CreateCacheKey(string prefix, string name,
        string controller, string area)
    {
        return string.Format(CultureInfo.InvariantCulture,
            ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:",
            base.GetType().AssemblyQualifiedName,
            prefix, name, controller, area);
    }

    protected string GetPath(ControllerContext controllerContext,
        string[] locations, string locationsPropertyName, string name,
        string controllerName, string areaName, string cacheKeyPrefix,
        bool useCache, out string[] searchedLocations)
    {
        searchedLocations = EmptyLocations;
        if (string.IsNullOrEmpty(name))
        {
            return string.Empty;
        }
        if ((locations == null) || (locations.Length == 0))
        {
            throw new InvalidOperationException(string.Format("The property " +
                "'{0}' cannot be null or empty.", locationsPropertyName));
        }
        bool isSpecificPath = IsSpecificPath(name);
        string key = CreateCacheKey(cacheKeyPrefix, name,
            isSpecificPath ? string.Empty : controllerName,
            isSpecificPath ? string.Empty : areaName);
        if (useCache)
        {
            string viewLocation = ViewLocationCache.GetViewLocation(
                controllerContext.HttpContext, key);
            if (viewLocation != null)
            {
                return viewLocation;
            }
        }
        if (!isSpecificPath)
        {
            return GetPathFromGeneralName(controllerContext, locations, name,
                controllerName, areaName, key, ref searchedLocations);
        }
        return GetPathFromSpecificName(controllerContext, name, key,
            ref searchedLocations);
    }

    protected string GetPathFromGeneralName(ControllerContext controllerContext,
        string[] locations, string name, string controllerName,
        string areaName, string cacheKey, ref string[] searchedLocations)
    {
        string virtualPath = string.Empty;
        searchedLocations = new string[locations.Length];
        for (int i = 0; i < locations.Length; i++)
        {
            if (string.IsNullOrEmpty(areaName) && locations[i].Contains("{2}"))
            {
                continue;
            }
            string testPath = string.Format(CultureInfo.InvariantCulture,
                locations[i], name, controllerName, areaName);
            if (FileExists(controllerContext, testPath))
            {
                searchedLocations = EmptyLocations;
                virtualPath = testPath;
                ViewLocationCache.InsertViewLocation(
                    controllerContext.HttpContext, cacheKey, virtualPath);
                return virtualPath;
            }
            searchedLocations[i] = testPath;
        }
        return virtualPath;
    }

    protected string GetPathFromSpecificName(
        ControllerContext controllerContext, string name, string cacheKey,
        ref string[] searchedLocations)
    {
        string virtualPath = name;
        if (!FileExists(controllerContext, name))
        {
            virtualPath = string.Empty;
            searchedLocations = new string[] { name };
        }
        ViewLocationCache.InsertViewLocation(controllerContext.HttpContext,
            cacheKey, virtualPath);
        return virtualPath;
    }


    protected string getArea(ControllerContext controllerContext)
    {
        // First try to get area from a RouteValue override, like one specified in the Defaults arg to a Route.
        object areaO;
        controllerContext.RouteData.Values.TryGetValue("area", out areaO);

        // If not specified, try to get it from the Controller's namespace
        if (areaO != null)
            return (string)areaO;

        string namespa = controllerContext.Controller.GetType().Namespace;
        int areaStart = namespa.IndexOf("Areas.");
        if (areaStart == -1)
            return null;

        areaStart += 6;
        int areaEnd = namespa.IndexOf('.', areaStart + 1);
        string area = namespa.Substring(areaStart, areaEnd - areaStart);
        return area;
    }

    protected static bool IsSpecificPath(string name)
    {
        char ch = name[0];
        if (ch != '~')
        {
            return (ch == '/');
        }
        return true;
    }
}

Как уже говорилось, это не конкретный движок, поэтому вы должны его создать. Эта часть, к счастью, намного проще, все, что нам нужно сделать, это установить форматы по умолчанию и фактически создать представления:

AreaAwareViewEngine.cs

public class AreaAwareViewEngine : BaseAreaAwareViewEngine
{
    public AreaAwareViewEngine()
    {
        MasterLocationFormats = new string[]
        {
            "~/Areas/{2}/Views/{1}/{0}.master",
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.master",
            "~/Areas/{2}/Views/Shared/{0}.cshtml",
            "~/Views/{1}/{0}.master",
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.master"
            "~/Views/Shared/{0}.cshtml"
        };
        ViewLocationFormats = new string[]
        {
            "~/Areas/{2}/Views/{1}/{0}.aspx",
            "~/Areas/{2}/Views/{1}/{0}.ascx",
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.aspx",
            "~/Areas/{2}/Views/Shared/{0}.ascx",
            "~/Areas/{2}/Views/Shared/{0}.cshtml",
            "~/Views/{1}/{0}.aspx",
            "~/Views/{1}/{0}.ascx",
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.aspx"
            "~/Views/Shared/{0}.ascx"
            "~/Views/Shared/{0}.cshtml"
        };
        PartialViewLocationFormats = ViewLocationFormats;
    }

    protected override IView CreatePartialView(
        ControllerContext controllerContext, string partialPath)
    {
        if (partialPath.EndsWith(".cshtml"))
            return new System.Web.Mvc.RazorView(controllerContext, partialPath, null, false, null);
        else
            return new WebFormView(controllerContext, partialPath);
    }

    protected override IView CreateView(ControllerContext controllerContext,
        string viewPath, string masterPath)
    {
        if (viewPath.EndsWith(".cshtml"))
            return new RazorView(controllerContext, viewPath, masterPath, false, null);
        else
            return new WebFormView(controllerContext, viewPath, masterPath);
    }
}

Обратите внимание, что мы добавили несколько записей в стандарт ViewLocationFormats. Это новые {2}записи, где {2}они будут сопоставлены с тем, что areaмы добавили в RouteData. Я оставил в MasterLocationFormatsпокое, но, очевидно, вы можете изменить это, если хотите.

Теперь измените ваш, global.asaxчтобы зарегистрировать этот механизм просмотра:

Global.asax.cs

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new AreaAwareViewEngine());
}

... и зарегистрируйте маршрут по умолчанию:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapRoute(
        "Area",
        "",
        new { area = "AreaZ", controller = "Default", action = "ActionY" }
    );
    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = "" }
    );
}

Теперь создайте AreaControllerтолько что упомянутый:

DefaultController.cs (в ~ / Controllers /)

public class DefaultController : Controller
{
    public ActionResult ActionY()
    {
        return View("TestView");
    }
}

Очевидно, нам нужна структура каталогов и представление, чтобы работать с ними - мы будем делать это очень просто:

TestView.aspx (в ~ / Areas / AreaZ / Views / Default / или ~ / Areas / AreaZ / Views / Shared /)

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<h2>TestView</h2>
This is a test view in AreaZ.

И это все. Наконец, мы закончили .

По большей части вы должны иметь возможность просто взять BaseAreaAwareViewEngineи AreaAwareViewEngineи поместить его в любой проект MVC, поэтому, хотя для этого потребовалось много кода, вам нужно написать его только один раз. После этого остается лишь отредактировать несколько строк global.asax.csи создать структуру вашего сайта.


Скорее всего, это лучшее из существующих решений, но далеко от идеала. Как указано выше, после добавления ссылки действия или существует такая же проблема.
LiamB

1
@Pino: Я думаю, вы сможете решить эту ActionLinkпроблему, добавив то же самое area = "AreaZ"в сопоставление маршрутов "Default" в global.asax.cs. Хотя я не уверен; попробуйте и посмотрите.
Aaronaught

В MVC4 "Default" декларатор маршрута перемещен из Global.asax в ~ / App_Start / RouteConfig.cs / RegisterRoutes ()
Андрей Ф.

3
Ненавижу отрицать, но я действительно не могу поверить, что ответ @Chris Alderson ниже не получил больше голосов. Это гораздо более простое решение, чем это, и, кажется, решает крайние случаи (ActionLinks и т. Д.).
jdmcnair

Похоже, здесь есть ошибка. Представления для области с именем «Re», например, будут в ~ / Areas / Re / Views / Ctrlr / blah.aspx, но код здесь использует ~ / {2} / {1} / {0}, который будет ~ /Re/Ctrl/blah.aspx, в пути отсутствует каталог критических областей. Это должно быть "~ / Areas / {2} / Views / {1} / {0} .aspx"
Крис Москини

100

Вот как я это сделал. Я не знаю, почему MapRoute () не позволяет вам установить область, но он возвращает объект маршрута, поэтому вы можете продолжать вносить любые дополнительные изменения, которые хотите. Я использую это, потому что у меня есть модульный сайт MVC, который продается корпоративным клиентам, и они должны иметь возможность помещать библиотеки DLL в папку bin для добавления новых модулей. Я разрешаю им изменить "HomeArea" в конфигурации AppSettings.

var route = routes.MapRoute(
                "Home_Default", 
                "", 
                new {controller = "Home", action = "index" },
                new[] { "IPC.Web.Core.Controllers" }
               );
route.DataTokens["area"] = area;

Изменить: вы также можете попробовать это в своей AreaRegistration.RegisterArea для области, в которую пользователь по умолчанию переходит. Я не тестировал его, но AreaRegistrationContext.MapRoute делает route.DataTokens["area"] = this.AreaName;для вас наборы .

context.MapRoute(
                    "Home_Default", 
                    "", 
                    new {controller = "Home", action = "index" },
                    new[] { "IPC.Web.Core.Controllers" }
                   );

Оно работает. Остерегайтесь нового файла web.config, он может переопределить ваши старые глобальные конфигурации.
Мерт Акчакая 01

56

даже на него уже ответили - это короткий синтаксис (ASP.net 3, 4, 5):

routes.MapRoute("redirect all other requests", "{*url}",
    new {
        controller = "UnderConstruction",
        action = "Index"
        }).DataTokens = new RouteValueDictionary(new { area = "Shop" });

6
Это отлично работает для меня. У меня нет контроллеров в корне, и я использую только области. Для MVC 4 это заменяет значение по умолчанию в RouteConfig.cs. Спасибо!
Marc

2
Я использую MVC4, и это было для меня самым простым решением. Позволяет приложению использовать представление индекса в определенной области в качестве «домашней страницы» сайта.
JTech

2
Это решение не будет работать в будущем (от Asp.Net MVC6 и выше).
Патрик Дежарден,

@PatrickDesjardins: Есть ли причина не поддерживать вышеуказанное решение?
Akash KC

@SeriousM Ваш ответ вечнозеленый. Это все еще полезно. Ты спас мне ночь.
skpaul

16

Спасибо Аарону за то, что он указал, что речь идет о поиске просмотров, я неправильно это понял.

[ОБНОВЛЕНИЕ] Я только что создал проект, который по умолчанию отправляет пользователя в область, не вмешиваясь ни в какой код или пути поиска:

В global.asax зарегистрируйтесь как обычно:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = ""}  // Parameter defaults,
        );
    }

в Application_Start()убедитесь, что используется следующий порядок;

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        RegisterRoutes(RouteTable.Routes);
    }

в вашей области регистрации, используйте

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "ShopArea_default",
            "{controller}/{action}/{id}",
            new { action = "Index", id = "", controller = "MyRoute" },
            new { controller = "MyRoute" }
        );
    }

Пример можно найти на http://www.emphess.net/2010/01/31/areas-routes-and-defaults-in-mvc-2-rc/

Я очень надеюсь, что это то, о чем вы просили ...

////

Не думаю, что написание псевдонима ViewEngine- лучшее решение в данном случае. (Отсутствие репутации, не могу комментировать). WebFormsViewEngineЯвляется Область известно и содержит AreaViewLocationFormats, определенный по умолчанию , так как

AreaViewLocationFormats = new[] {
        "~/Areas/{2}/Views/{1}/{0}.aspx",
        "~/Areas/{2}/Views/{1}/{0}.ascx",
        "~/Areas/{2}/Views/Shared/{0}.aspx",
        "~/Areas/{2}/Views/Shared/{0}.ascx",
    };

Я считаю, что вы не придерживаетесь этой конвенции. Вы опубликовали

public ActionResult ActionY() 
{ 
    return View("~/Areas/AreaZ/views/ActionY.aspx"); 
} 

как рабочий хак, но это должно быть

   return View("~/Areas/AreaZ/views/ControllerX/ActionY.aspx"); 

ЕСЛИ вы не хотите следовать соглашению, однако, вы можете выбрать короткий путь, производный от WebFormViewEngine(например, в MvcContrib), где вы можете установить пути поиска в конструкторе, или -a маленький хакер - указав свое соглашение следующим образом Application_Start:

((VirtualPathProviderViewEngine)ViewEngines.Engines[0]).AreaViewLocationFormats = ...;

Конечно, это следует делать немного осторожнее, но я думаю, что это показывает идею. Эти поля publicв VirtualPathProviderViewEngineв MVC 2 RC.


Стоит отметить, что это применимо только в MVC 2 RC - MVC 1 VirtualPathProviderViewEngineне имеет этого свойства и не зависит от области. И хотя этот вопрос действительно был заявлен о MVC 2, многие люди до сих пор его не используют (и не будут использовать в течение некоторого времени). Итак, ваш ответ на конкретный вопрос проще, но мой - единственный, который подойдет пользователям MVC1, которые наткнулись на этот вопрос. Мне нравится давать ответы, не зависящие от предварительных версий функций, которые могут быть изменены.
Aaronaught

Кроме того, это не «механизм псевдо-представления» - классы механизма представления были намеренно сделаны расширяемыми, чтобы можно было использовать различные виды представлений.
Aaronaught

Мне очень жаль, что я не хотел вас оскорбить. Это «псевдо» в том смысле, что он существенно не меняет способ обработки представлений, а просто заменяет некоторые значения.
mnemosyn

Я не обиделся, я просто хотел прояснить тот факт, что нет ничего необычного в том, чтобы создать собственный движок представления, о чем свидетельствует тот факт, что соответствующие методы можно переопределить.
Aaronaught

2
Отличный совет о том, чтобы RegisterAreasпойти раньше RegisterRoutes. Интересно, почему мой код внезапно перестал работать, и заметил этот рефакторинг;)
webnoob 01

6

Я предполагаю, что вы хотите, чтобы пользователь был перенаправлен на ~/AreaZURL-адрес после того, как он посетил ~/URL-адрес. Я бы добился этого с помощью следующего кода в вашем корне HomeController.

public class HomeController
{
    public ActionResult Index()
    {
        return RedirectToAction("ActionY", "ControllerX", new { Area = "AreaZ" });
    }
}

И следующий маршрут в Global.asax.

routes.MapRoute(
    "Redirection to AreaZ",
    String.Empty,
    new { controller = "Home ", action = "Index" }
);

Это работает, но изменяется на URL-адрес в браузере пользователя. На самом деле не идеально.
LiamB

2

Во-первых, какую версию MVC2 вы используете? От preview2 до RC произошли значительные изменения.

Предполагая, что вы используете RC, я думаю, что отображение маршрутов должно выглядеть иначе. В AreaRegistration.csвашем районе вы можете зарегистрировать какой-нибудь маршрут по умолчанию, например

        context.MapRoute(
            "ShopArea_default",
            "{controller}/{action}/{id}",
            new { action = "Index", id = "", controller="MyRoute" }
        );

Приведенный выше код отправит пользователя MyRouteControllerв наш ShopAreaпо умолчанию.

Использование пустой строки в качестве второго параметра должно вызывать исключение, поскольку необходимо указать контроллер.

Конечно, вам придется изменить маршрут по умолчанию, Global.asaxчтобы он не мешал этому маршруту по умолчанию, например, используя префикс для основного сайта.

Также см. Эту ветку и ответ Хаака: MVC 2 AreaRegistration Routes Order

Надеюсь это поможет.


Спасибо, но я не уверен, что это решит проблему, описанную в вопросе. И его MVC RC
LiamB

2

Добавление следующего в мой Application_Start работает для меня, хотя я не уверен, есть ли у вас этот параметр в RC:

var engine = (WebFormViewEngine)ViewEngines.Engines.First();

// These additions allow me to route default requests for "/" to the home area
engine.ViewLocationFormats = new string[] { 
    "~/Views/{1}/{0}.aspx",
    "~/Views/{1}/{0}.ascx",
    "~/Areas/{1}/Views/{1}/{0}.aspx", // new
    "~/Areas/{1}/Views/{1}/{0}.ascx", // new
    "~/Areas/{1}/Views/{0}.aspx", // new
    "~/Areas/{1}/Views/{0}.ascx", // new
    "~/Views/{1}/{0}.ascx",
    "~/Views/Shared/{0}.aspx",
    "~/Views/Shared/{0}.ascx"
};

1

Чтобы заставить это работать, я сделал следующее:

  1. Я создал контроллер по умолчанию в папке root / Controllers. Я назвал свой контроллер DefaultController.
  2. В контроллер я добавил следующий код:

    namespace MyNameSpace.Controllers {
    public class DefaultController : Controller {
        // GET: Default
        public ActionResult Index() {
            return RedirectToAction("Index", "ControllerName", new {area = "FolderName"});
        }
    } }
  3. В моем RouterConfig.cs я добавил следующее:

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new {controller = "Default", action = "Index", id = UrlParameter.Optional});

Уловка всего этого заключается в том, что я создал конструктор по умолчанию, который всегда будет контроллером запуска при каждом запуске моего приложения. Когда он попадает в этот контроллер по умолчанию, он перенаправляется на любой контроллер, который я укажу в действии индекса по умолчанию. Что в моем случае

www.myurl.com/FolderName/ControllerName

,


0
routes.MapRoute(
                "Area",
                "{area}/",
                new { area = "AreaZ", controller = "ControlerX ", action = "ActionY " }
            );

Вы пробовали это?


Да, проблема в том, что теперь сайт ищет просмотры в корне. Представление ActionY или его мастер не найдены. Был произведен поиск в следующих местах: ~ / Views / ActionY / ActionY.aspx ~ / Views / ActionY / ActionY.ascx ~ / Views / Shared / ActionY.aspx ~ / Views / Shared / ActionY.ascx
LiamB

2
Я понимаю. Я постараюсь найти решение. +1 за вопрос
Barbaros Alp

0

Поиск различных строительных блоков выполняется в жизненном цикле запроса. Один из первых шагов в жизненном цикле запроса ASP.NET MVC - сопоставление запрошенного URL-адреса с правильным методом действия контроллера. Этот процесс называется маршрутизацией. Маршрут по умолчанию инициализируется в файле Global.asax и описывает для платформы ASP.NET MVC, как обрабатывать запрос. Двойной щелчок по файлу Global.asax в проекте MvcApplication1 отобразит следующий код:

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing;

namespace MvcApplication1 {

   public class GlobalApplication : System.Web.HttpApplication
   {
       public static void RegisterRoutes(RouteCollection routes)
       {
           routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

           routes.MapRoute(
               "Default",                                          // Route name
               "{controller}/{action}/{id}",                       // URL with parameters
               new { controller = "Home", action = "Index",
                     id = "" }  // Parameter defaults
           );

       }

       protected void Application_Start()
       {
           RegisterRoutes(RouteTable.Routes);
       }
   }

}

В обработчике событий Application_Start (), который запускается при компиляции приложения или перезапуске веб-сервера, регистрируется таблица маршрутов. Маршрут по умолчанию называется Default и отвечает на URL-адрес в форме http://www.example.com/ {controller} / {action} / {id}. Переменные между {и} заполняются фактическими значениями из URL-адреса запроса или значениями по умолчанию, если в URL-адресе нет переопределения. Этот маршрут по умолчанию будет отображаться на контроллер Home и метод действия Index в соответствии с параметрами маршрутизации по умолчанию. У нас не будет никаких других действий с этой картой маршрутизации.

По умолчанию все возможные URL-адреса могут быть сопоставлены через этот маршрут по умолчанию. Также возможно создание собственных маршрутов. Например, сопоставим URL http://www.example.com/Employee/Maarten с контроллером Employee, действием Show и параметром firstname. Следующий фрагмент кода можно вставить в только что открытый файл Global.asax. Поскольку платформа ASP.NET MVC использует первый совпадающий маршрут, этот фрагмент кода следует вставить над маршрутом по умолчанию; в противном случае маршрут никогда не будет использоваться.

routes.MapRoute(

   "EmployeeShow",                    // Route name
   "Employee/{firstname}",            // URL with parameters
    new {                             // Parameter defaults
       controller = "Employee",
       action = "Show", 
       firstname = "" 
   }  

);

Теперь добавим необходимые компоненты для этого маршрута. Прежде всего, создайте класс с именем EmployeeController в папке Controllers. Вы можете сделать это, добавив новый элемент в проект и выбрав шаблон класса контроллера MVC, расположенный в Web | Категория MVC. Удалите метод действия Index и замените его методом или действием с именем Show. Этот метод принимает параметр firstname и передает данные в словарь ViewData. Этот словарь будет использоваться представлением для отображения данных.

Класс EmployeeController передаст в представление объект Employee. Этот класс Employee должен быть добавлен в папку Models (щелкните эту папку правой кнопкой мыши и выберите в контекстном меню Добавить | Class). Вот код для класса Employee:

namespace MvcApplication1.Models {

   public class Employee
   {
       public string FirstName { get; set; }
       public string LastName { get; set; }
       public string Email { get; set; }
   }

} 

1
Спасибо, я не совсем понимаю, как это связано с установкой ОБЛАСТИ по умолчанию. : - /
LiamB

0

Что ж, хотя создание пользовательского механизма просмотра может работать для этого, у вас все же может быть альтернатива:

  • Решите, что вам нужно показывать по умолчанию.
  • У этого чего-то есть контроллер и действие (и область), верно?
  • Откройте эту область регистрации и добавьте что-то вроде этого:
public override void RegisterArea(AreaRegistrationContext context)
{
    //this makes it work for the empty url (just domain) to act as current Area.
    context.MapRoute(
        "Area_empty",
        "",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces: new string[] { "Area controller namespace" }
    );
        //other routes of the area
}

Ура!


Согласовано. Хотя я думаю, что более подходящее место для этого определения маршрута находится в файле Global.asax.
nuhusky2003

В таком случае ваши определения global.asax будут знать о существовании пространства имен контроллера области, что, на мой взгляд, неверно. Области - это дополнительная функция, что означает, что вы должны иметь возможность добавлять / удалять их, не касаясь определений global.asax. В моем подходе к этому вопросу я предпочитаю область, которая «принимает» запрос, а не [глобальный] веб-сайт для «передачи» запроса.
Тенгиз

0

Принятое решение этого вопроса, хотя и верно в изложении того, как создать настраиваемый механизм представления, не дает правильного ответа на этот вопрос. Проблема здесь в том, что Пино неправильно указывает свой маршрут по умолчанию . В частности, его определение «площади» неверно. "Area" проверяется с помощью коллекции DataTokens и должна быть добавлена ​​как таковая:

var defaultRoute = new Route("",new RouteValueDictionary(){{"controller","Default"},{"action","Index"}},null/*constraints*/,new RouteValueDictionary(){{"area","Admin"}},new MvcRouteHandler());
defaultRoute.DataTokens.Add("Namespaces","MyProject.Web.Admin.Controller"); 
routes.Add(defaultRoute);

Указанная «область» в объекте по умолчанию будет проигнорирована . Приведенный выше код создает маршрут по умолчанию, который перехватывает запросы к корню вашего сайта, а затем вызывает контроллер по умолчанию, действие индекса в области администратора. Также обратите внимание, что к DataTokens добавляется ключ «Namespaces», это требуется только в том случае, если у вас несколько контроллеров с одинаковым именем. Это решение проверено с Mvc2 и Mvc3 .NET 3.5 / 4.0


-1

ммм, я не знаю, зачем все это программирование, я думаю, что исходная проблема легко решается указанием этого маршрута по умолчанию ...

routes.MapRoute("Default", "{*id}", 
                 new { controller = "Home"
                     , action = "Index"
                     , id = UrlParameter.Optional 
                     }
              );
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.