Як встановити маршрут за замовчуванням (до області) у MVC


122

Добре, про це вже просили, але твердого рішення там немає. Тож з метою себе та інших, хто може вважати це корисним.

У MVC2 (ASP.NET) я хочу, щоб коли хтось переходить на веб-сайт, вказана область за замовчуванням. Тому перехід на мій сайт повинен надіслати вас до ControllerX ActionY в AreaZ.

Використовуючи наступний маршрут у Global.asax

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

Тепер це працює, як і в ньому, намагаються обслуговувати правильну сторінку. Однак MVC продовжує шукати Перегляд у корені сайту, а не у папці Area.

Чи є спосіб вирішити це?

EDIT

Існує "Рішення", і це в 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. Я зробив це так, що якщо ви хочете створити вигляд Іскри замість (або будь-якого іншого), ви все одно можете використовувати цей клас як базовий тип.

Код, наведений нижче, є досить затятим, тому для швидкого підсумку того, що він насправді робить: він дозволяє вводити {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 (в ~ / Контролери /)

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

Очевидно, що нам потрібна структура каталогів і перегляд, щоб працювати з нею - це буде дуже просто:

TestView.aspx (у ~ / Області / ПлощаZ / Перегляди / за замовчуванням / або ~ / Області / ПлощаZ / Перегляди / Спільне /)

<%@ 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та створення структури вашого сайту.


Це, як правило, найкраще поточне рішення, але далеко не ідеальне. Як вище, як тільки ви додаєте Actionlink або існує така ж проблема.
LiamB

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

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

3
Я ненавиджу спростувати, але я не можу повірити, що наведена нижче відповідь від @Chris Олдерсон не отримала більше голосів. Це набагато простіше рішення, ніж це, і, здається, вирішує крайові випадки (ActionLinks тощо).
jdmcnair

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

100

Ось як я це зробив. Я не знаю, чому MapRoute () не дозволяє встановлювати область, але він повертає об’єкт маршруту, щоб ви могли продовжувати вносити будь-які додаткові зміни, які хотіли б. Я використовую це, тому що у мене є модульний сайт MVC, який продається корпоративним клієнтам, і їм потрібно мати можливість скидати dlls в папку 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, він може змінити ваші старі глобальні конфігурації.
Мерт Аккакая

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. Дякую!
Марк

2
Я використовую MVC4, і це було для мене найпростішим рішенням. Дозволяє програмі використовувати індексний вигляд у певній області як "домашню сторінку" сайту.
JTech

2
Це рішення не працюватиме в майбутньому (від Asp.Net MVC6 і вище).
Патрік Дешардінс

@PatrickDesjardins: Якась причина не підтримує вище рішення?
Акаш 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.


Варто зазначити, що це стосується лише RC MVC 2 - MVC 1 VirtualPathProviderViewEngineне має цієї властивості та не знає місцевості. І хоча це питання справді говорилося про MVC 2, багато людей все ще не користуються ним (і не буде деякий час). Отже, ваша відповідь простіша на конкретне питання, але моя єдина, яка буде працювати для користувачів MVC1, які натрапляють на це питання. Мені подобається надати відповіді, які не залежать від функцій перед випуском, які потенційно можуть бути змінені.
Aaronaught

Крім того, це не "двигун псевдоперегляду" - класи двигунів перегляду були навмисно розширені, щоб можна було використовувати різні види поглядів.
Aaronaught

Це не було для того, щоб образити вас, вибачте. Це "псевдо" в тому, що це не суттєво змінює спосіб обробки поглядів, а лише замінює деякі значення.
mnemosyn

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

2
Чудова порада про RegisterAreasпоїздку раніше RegisterRoutes. Цікаво, чому мій код раптом перестав працювати і помітив, що рефактор;)
webnoob

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 ви використовуєте? Від попереднього перегляду2 до RC відбулися значні зміни.

Якщо припустити, що ви використовуєте RC, я думаю, що картографування маршруту має виглядати інакше. У AreaRegistration.csвашому регіоні ви можете зареєструвати якийсь маршрут за замовчуванням, наприклад

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

Код, наведений вище, надішле користувача до MyRouteControllerнашого ShopAreaза замовчуванням.

Використання порожнього рядка як другого параметра повинно бути винятком, оскільки повинен бути вказаний контролер.

Звичайно, вам доведеться змінити маршрут за замовчуванням, Global.asaxщоб він не заважав цьому маршруту за замовчуванням, наприклад, використовуючи префікс для головного сайту.

Також дивіться цю тему та відповідь Хакка: Замовлення маршрутів MVC 2 AreaRegistration

Сподіваюся, це допомагає.


Дякую, але я не впевнений, що це вирішує питання, пояснене в питанні. І його 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" або його головного не знайдено. Шукали такі локації: ~ / Перегляди / 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 (), який запускається кожного разу, коли програма складена або перезапущений веб-сервер, реєструється таблиця маршрутів. Маршрут за замовчуванням називається Типовим і відповідає URL-адресі у формі http://www.example.com/ {контролер} / {дія} / {id}. Змінні між {і} заповнюються фактичними значеннями з URL-адреси запиту або зі значеннями за замовчуванням, якщо в URL-адресі немає переопределення. Цей маршрут за замовчуванням буде відображатись до контролера Home та методу дії Index відповідно до параметрів маршрутизації за замовчуванням. Ми не матимемо жодних інших дій з цією картою маршрутів.

За замовчуванням всі можливі URL-адреси можуть бути відображені через цей маршрут за замовчуванням. Також можливо створити власні маршрути. Наприклад, давайте відобразимо URL-адресу http://www.example.com/E zaposee/Maarten на контролері Employee, дії Show та параметру імені. Наступний фрагмент коду можна вставити у файл 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 Controller Class, розміщений під веб | Категорія MVC. Видаліть метод дії індексу та замініть його на метод або дію під назвою Показати. Цей метод приймає параметр імені та передає дані в словник ViewData. Цей словник буде використовуватися представленням для перегляду даних.

Клас EmployeeController передасть об’єкт Employee перегляду. Цей клас «Співробітник» слід додати в папку «Моделі» (клацніть правою кнопкою миші на цій папці та виберіть «Додати | клас» у контекстному меню). Ось код для класу Співробітник:

namespace MvcApplication1.Models {

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

} 

1
Дякую, я не зовсім впевнений, як це стосується встановлення за замовчуванням AREA. : - /
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

Прийняте рішення цього питання, хоча правильне підсумовувати, як створити користувацький механізм перегляду, не відповідає правильно на питання. Проблема тут полягає в тому, що Піно неправильно вказав свій маршрут за замовчуванням . Особливо його "область" визначення неправильне. "Зона" перевіряється за допомогою колекції 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 додано ключ "Простори імен", це потрібно лише в тому випадку, якщо у вас є кілька контролерів з одним іменем. Це рішення перевірено за допомогою 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.