MVC에서 기본 경로 (지역으로)를 설정하는 방법


122

좋아 이것은 이전에 요청되었지만 거기에는 고체 솔루션이 없습니다. 그래서 나 자신과 이것이 유용하다고 생각하는 다른 사람들을 위해.

MVC2 (ASP.NET)에서는 누군가가 웹 사이트를 탐색 할 때 기본 영역이 지정되기를 원합니다. 내 사이트로 이동하면 AreaZ의 ControllerX ActionY로 이동합니다.

Global.asax에서 다음 경로 사용

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

이제 이것은 올바른 페이지를 제공하려고 시도하는 것처럼 작동합니다. 그러나 MVC는 영역 폴더가 아닌 사이트의 루트에서보기를 계속 찾습니다.

이 문제를 해결할 방법이 있습니까?

편집하다

'솔루션'이 있으며 ControllerX에 있으며 ActionY는 뷰의 전체 경로를 반환합니다. 약간의 해킹이지만 작동합니다. 그러나 더 나은 해결책이 있기를 바랍니다.

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

편집하다:

페이지의 HTML ActionLink가있을 때도 문제가됩니다. 영역이 설정되지 않은 경우 액션 링크는 공백으로 출력됩니다.

이 모든 것이 디자인에 의한 것인지 결함입니까?

답변:


98

이것은 나에게 관심이 있었고 마침내 그것을 조사 할 기회가 생겼습니다. 다른 사람들은 이것이 라우팅 자체 의 문제가 아니라 찾는 문제라는 것을 분명히 이해 하지 못했습니다. 질문 제목이 라우팅에 관한 것임을 나타 내기 때문일 것입니다.

어쨌든 이것은 뷰 관련 문제이므로 원하는 것을 얻는 유일한 방법 은 기본 뷰 엔진재정의하는 것 입니다. 일반적으로이 작업을 수행 할 때 뷰 엔진을 전환하는 단순한 목적 (예 : Spark, NHaml 등)입니다. 이 경우 재정의해야하는 뷰 생성 논리가 아니라 클래스 의 FindPartialViewFindView메서드입니다 VirtualPathProviderViewEngine.

다른 모든이 (가)에 있기 때문에,이 방법은 실제로 가상 것을 당신에게 행운의 별을 감사 할 수 VirtualPathProviderViewEngine조차없는 접근 이 개인, 그리고 그게하게 - 아주 당신이 이미 코드의 기본적으로 재 작성 절반에 있기 때문에 짜증나 찾기 논리를 재정의 위치 캐시 및 위치 형식으로 멋지게 재생하려는 경우 작성되었습니다. Reflector를 파헤친 후 마침내 작동하는 해결책을 찾았습니다.

내가 여기서 한 일은 먼저 AreaAwareViewEngine.NET 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사이트 구조를 만드는 문제입니다 .


이것은 가장 좋은 현재 솔루션이지만 이상적이지는 않습니다. 위와 같이 Actionlink를 추가하면 동일한 문제가 발생합니다.
LiamB 2010

1
@Pino : .NET 의 "기본"경로 매핑에 ActionLink동일한 내용 area = "AreaZ"을 추가하여 문제 를 해결할 수 있어야한다고 생각합니다 global.asax.cs. 나는 긍정적이지 않다. 그것을 시도하고보십시오.
Aaronaught 2010

MVC4에서 "Default"경로 declaraton이 Global.asax에서 ~ / App_Start / RouteConfig.cs / RegisterRoutes ()
Andriy F.

3
나는 반대 투표를 싫어하지만 @Chris Alderson의 아래 답변이 더 많은 표를 얻지 못했다는 사실을 믿을 수 없습니다. 이것은 이것보다 훨씬 더 간단한 솔루션이며 엣지 케이스 (ActionLinks 등)를 해결하는 것 같습니다.
jdmcnair

여기에 버그가있는 것 같습니다. 예를 들어 "Re"라는 이름의 영역에 대한 뷰는 ~ / Areas / Re / Views / Ctrlr / blah.aspx에 있지만 여기의 코드는 ~ / {2} / {1} / {0}를 사용합니다. /Re/Ctrl/blah.aspx, 경로에 중요한 Areas 디렉터리가 없습니다. 그것은 "~ / 지역 / {2} / 조회 / {1} / {0}에서 .aspx"이어야합니다
크리스 Moschini

100

이것이 내가 한 방법입니다. MapRoute ()가 지역 설정을 허용하지 않는 이유를 모르겠지만 원하는 추가 변경을 계속할 수 있도록 경로 객체를 반환합니다. 엔터프라이즈 고객에게 판매되는 모듈 식 MVC 사이트가 있고 새 모듈을 추가하기 위해 dll을 bin 폴더에 놓을 수 있어야하기 때문에 이것을 사용합니다. AppSettings 구성에서 "HomeArea"를 변경할 수 있습니다.

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 파일에주의하십시오. 이전 전역 구성을 재정의 할 수 있습니다.
Mert Akcakaya

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 이상에서) 작동하지 않습니다.
Patrick Desjardins 2015 년

@PatrickDesjardins : 위의 솔루션을 지원하지 않는 이유는 무엇입니까?
Akash KC

@SeriousM 당신의 대답은 상록수입니다. 여전히 도움이됩니다. 당신은 날 밤을 구했습니다.
skpaul

16

뷰를 찾는 것에 관한 것이라고 지적한 Aaron 덕분에 나는 그것을 오해했다.

[업데이트] 방금 코드 나 조회 경로를 엉망으로 만들지 않고 기본적으로 사용자를 Area로 보내는 프로젝트를 만들었습니다.

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에서 VirtualPathProviderViewEngineMVC 2 RC에.


이것은 MVC 2 RC에서만 적용된다는 점에 주목할 가치가 있습니다. MVC 1 VirtualPathProviderViewEngine에는이 속성이 없으며 영역을 인식하지 않습니다. 이 질문은 실제로 MVC 2에 관한 것으로 언급되었지만 많은 사람들이 여전히 그것을 사용하지 않고 있습니다 (그리고 당분간 사용되지 않을 것입니다). 따라서 특정 질문에 대한 답변은 더 쉽지만이 질문을 우연히 발견 한 MVC1 사용자에게 적합한 유일한 답변은 제 것입니다. 잠재적으로 변경 될 수있는 시험판 기능에 의존하지 않는 답변을 제공하고 싶습니다.
Aaronaught

또한 이것은 "의사 뷰 엔진"이 아닙니다. 뷰 엔진 클래스는 의도적으로 확장 가능하도록 만들어져 다른 종류의 뷰를 사용할 수 있습니다.
Aaronaught

당신을 모욕하기위한 것이 아닙니다. 죄송합니다. 뷰가 처리되는 방식을 크게 변경하지 않고 일부 값을 대체한다는 점에서 '의사'입니다.
mnemosyn

나는 불쾌한 것이 아니라, 관련 메서드를 재정의 할 수 있다는 사실에서 알 수 있듯이 사용자 지정 뷰 엔진을 파생하는 특별한 이유가 아니라는 사실을 명확히하고 싶었습니다.
Aaronaught

2
RegisterAreas전에가는 좋은 팁 RegisterRoutes. 내 코드가 갑자기 작동을 멈추고 리팩터링을 발견 한 이유가 궁금했습니다.)
webnoob

6

사용자 ~/AreaZ~/URL 을 방문 하면 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 이 기본 경로를 방해하지 않도록 합니다 (예 : 기본 사이트에 접두사 사용).

또한이 스레드와 Haack의 답변을 참조하십시오. 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 프레임 워크에 요청을 처리하는 방법을 설명합니다. MvcApplication1 프로젝트에서 Global.asax 파일을 두 번 클릭하면 다음 코드가 표시됩니다.

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이며 http://www.example.com/ 형식의 URL에 응답합니다 . {controller} / {action} / {id} . {와} 사이의 변수는 요청 URL의 실제 값으로 채워지거나 URL에 재정의가없는 경우 기본값으로 채워집니다. 이 기본 경로는 기본 라우팅 매개 변수에 따라 홈 컨트롤러 및 색인 작업 방법에 매핑됩니다. 이 라우팅 맵에 대한 다른 조치는 없습니다.

기본적으로 가능한 모든 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 = "" 
   }  

);

이제이 경로에 필요한 구성 요소를 추가하겠습니다. 먼저 Controllers 폴더에 EmployeeController라는 클래스를 만듭니다. 프로젝트에 새 항목을 추가하고 Web | MVC 카테고리. Index 작업 메서드를 제거하고 Show라는 메서드 또는 작업으로 바꿉니다. 이 메서드는 firstname 매개 변수를 받아들이고 데이터를 ViewData 사전에 전달합니다. 이 사전은보기에서 데이터를 표시하는 데 사용됩니다.

EmployeeController 클래스는 Employee 개체를 뷰에 전달합니다. 이 Employee 클래스는 Models 폴더에 추가되어야합니다 (이 폴더를 마우스 오른쪽 버튼으로 클릭 한 다음 상황에 맞는 메뉴에서 추가 | 클래스 선택). 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 정의를 건드리지 않고 영역을 추가 / 제거 할 수 있어야합니다. 질문에 대한 접근 방식에서는 요청을 "인계"하는 [글로벌] 웹 사이트 대신 요청을 "인계"하는 영역을 선호합니다.
Tengiz

0

이 질문에 대한 해결책은 사용자 정의보기 엔진을 만드는 방법을 요약하면 정확하지만 질문에 올바르게 대답하지 않는다는 것입니다. 여기서 문제는 Pino가 기본 경로를 잘못 지정하고 있다는 것입니다 . 특히 그의 "영역"정의가 잘못되었습니다. "영역"은 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);

기본 개체에 지정된 "영역"은 무시 됩니다. 위의 코드는 사이트의 루트에 대한 요청을 포착 한 다음 관리 영역에서 기본 컨트롤러, 인덱스 작업을 호출하는 기본 경로를 만듭니다. 또한 "Namespaces"키가 DataToken에 추가된다는 점에 유의하십시오. 이는 동일한 이름을 가진 여러 컨트롤러가있는 경우에만 필요합니다. 이 솔루션은 Mvc2 및 Mvc3 .NET 3.5 / 4.0으로 검증되었습니다.


-1

음,이 모든 프로그래밍이 왜이 기본 경로를 지정하면 원래 문제가 쉽게 해결되는지 모르겠습니다.

routes.MapRoute("Default", "{*id}", 
                 new { controller = "Home"
                     , action = "Index"
                     , id = UrlParameter.Optional 
                     }
              );
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.