MVC'de Varsayılan Rota (Bir Bölgeye) nasıl ayarlanır


122

Tamam, bu daha önce sorulmuştu ama ortada sağlam bir çözüm yok. Bu yüzden kendim ve bunu yararlı bulabilecek başkaları için.

MVC2'de (ASP.NET), birisi web sitesine gittiğinde, belirtilen varsayılan bir alan olmasını istiyorum. Bu yüzden siteme gitmek sizi AreaZ'deki ControllerX ActionY'ye göndermelidir.

Global.asax'ta aşağıdaki rotayı kullanma

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

Şimdi bu, olduğu gibi çalışır, doğru sayfayı sunmaya çalışır. Ancak MVC, Görünümü Alan klasöründe değil sitenin kökünde aramaya devam eder.

Bunu çözmenin bir yolu var mı?

DÜZENLE

Bir 'Çözüm' vardır ve bu ControllerX'te, ActionY görünümün tam yolunu döndürür. Biraz hack ama işe yarıyor. Ancak daha iyi bir çözüm olduğunu umuyorum.

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

Düzenle:

Bu, sayfanın bir HTML ActionLink'i olduğunda da bir sorun haline gelir. Alan ayarlanmadıysa, Eylem Bağlantısı boştur.

Bunların hepsi tasarım gereği mi yoksa kusur mu?

Yanıtlar:


98

Bu benim ilgimi çekti ve sonunda onu inceleme şansım oldu. Görünüşe göre diğer insanlar bunun yönlendirmeyle ilgili bir sorun değil , görünümü bulmakla ilgili bir sorun olduğunu anlamadılar. kendisiyle - ve bunun nedeni muhtemelen soru başlığınızın bunun yönlendirme ile ilgili olduğunu belirtmesidir.

Her durumda, bu Görünüm ile ilgili bir sorun olduğu için, istediğinizi elde etmenin tek yolu varsayılan görünüm motorunu geçersiz kılmaktır . Normalde, bunu yaptığınızda, görünüm motorunuzu (yani Spark, NHaml, vb.) Değiştirmek basit bir amaç içindir. Bu durumda, geçersiz kılmamız gereken Görünüm oluşturma mantığı değil , sınıftaki FindPartialViewve FindViewyöntemleri VirtualPathProviderViewEngine.

Şanslı yıldızlarınıza, bu yöntemlerin aslında sanal olduğu için teşekkür edebilirsiniz, çünkü içindeki diğer her şey VirtualPathProviderViewEnginebile erişilebilir değildir - özeldir ve bu , bulma mantığını geçersiz kılmak çok can sıkıcı hale getirir çünkü temelde zaten olan kodun yarısını yeniden yazmanız gerekir. konum önbelleği ve konum biçimleriyle iyi oynamasını istiyorsanız yazılmıştır. Reflektörde biraz kazı yaptıktan sonra nihayet çalışan bir çözüm bulmayı başardım.

Burada yaptığım şey, önce AreaAwareViewEnginedoğrudan VirtualPathProviderViewEngineyerine doğrudan türetilen bir soyut oluşturmaktır WebFormViewEngine. Bunu, bunun yerine (veya her neyse) Spark görünümleri oluşturmak istiyorsanız, bu sınıfı temel tür olarak kullanmaya devam edebilmeniz için yaptım.

Aşağıdaki kod oldukça uzun solukludur, bu yüzden size gerçekte ne yaptığının hızlı bir özetini vermek {2}için: Aynı şekilde alan adına karşılık gelen konum biçimine bir eklemenizi sağlar{1} denetleyici adına karşılık gelir. Bu kadar! Tüm bu kodu bunun için yazmamız gerekti:

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;
    }
}

Şimdi belirtildiği gibi, bu somut bir motor değil, bu yüzden onu da yaratmalısınız. Bu kısım, neyse ki, çok daha kolay, tek yapmamız gereken varsayılan formatları ayarlamak ve aslında görünümleri oluşturmak:

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);
    }
}

Standarda birkaç girdi eklediğimizi unutmayın ViewLocationFormats. Bunlar yeni {2}girişler, {2}eşlenir areabiz koymakRouteData . Ben MasterLocationFormatsyalnız bıraktım , ama tabii ki isterseniz bunu değiştirebilirsiniz.

Şimdi değiştirin global.asax bu görünüm motorunu kaydetmek :

Global.asax.cs

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

... ve varsayılan rotayı kaydedin:

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 = "" }
    );
}

Şimdi Oluştur AreaController az önce referans verdiğimizi :

DefaultController.cs (~ / Controllers / içinde)

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

Açıkçası, bunun için dizin yapısına ve görünüme ihtiyacımız var - bunu çok basit tutacağız:

TestView.aspx (~ / Alanlar / AlanZ / Görünümler / Varsayılan / veya ~ / Alanlar / AlanZ / Görünümler / Paylaşılan /)

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

Ve bu kadar. Sonunda bitirdik .

Çoğunlukla, sadece almak gerekir BaseAreaAwareViewEngineve AreaAwareViewEnginebunun yapılması için bir sürü kod aldı rağmen ve herhangi bir MVC proje haline bırakın, sadece bir kez yazmak zorunda. Bundan sonra, sadece birkaç satırı düzenleme global.asax.csve site yapınızı oluşturma meselesi .


Bu, büyük olasılıkla mevcut en iyi çözümdür ancak ideal olmaktan uzaktır. Yukarıdaki gibi bir kez bir Actionlink eklediğinizde veya aynı sorun var.
LiamB

1
@Pino: Bence ActionLinksorunu area = "AreaZ""Varsayılan" yol eşlemesine ekleyerek çözebilmelisiniz global.asax.cs. Yine de pozitif değilim; deneyin ve görün.
Aaronaught

MVC4'te "Varsayılan" yol açıklaması Global.asax'tan ~ / App_Start / RouteConfig.cs / RegisterRoutes ()
Andriy F.

3
Olumsuz oy vermekten nefret ediyorum, ancak @Chris Alderson'ın aşağıdaki cevabının daha fazla oy almadığına gerçekten inanamıyorum. Bu, bundan çok daha basit bir çözüm ve uç durumları (ActionLinks, vb.) Çözüyor gibi görünüyor.
jdmcnair

Görünüşe göre burada bir hata var. Örneğin "Re" adlı bir Alanın Görünümleri, ~ / Alanlar / Re / Görünümler / Ctrlr / blah.aspx içinde olabilir, ancak buradaki kod ~ / {2} / {1} / {0} kullanır ve bu da ~ /Re/Ctrl/blah.aspx, yolda kritik Alanlar dizini eksik. "~ / Alanlar / {2} / Görünümler / {1} / {0} .aspx" olmalıdır
Chris Moschini

100

Ben böyle yaptım. MapRoute () neden alanı ayarlamanıza izin vermiyor bilmiyorum, ancak rota nesnesini döndürür, böylece istediğiniz ek değişiklikleri yapmaya devam edebilirsiniz. Bunu kullanıyorum çünkü kurumsal müşterilere satılan modüler bir MVC sitem var ve yeni modüller eklemek için dll'leri bin klasörüne bırakabilmeleri gerekiyor. AppSettings yapılandırmasında "HomeArea" öğesini değiştirmelerine izin veriyorum.

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

Düzenleme: Bunu, kullanıcının varsayılan olarak gitmesini istediğiniz alan için AreaRegistration.RegisterArea içinde deneyebilirsiniz. Test etmedim ama AreaRegistrationContext.MapRoute route.DataTokens["area"] = this.AreaName;sizin için setler yapıyor.

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

İşe yarıyor. Yeni web.config dosyasına dikkat edin, eski genel yapılandırmalarınızı geçersiz kılabilir.
Mert Akçakaya

56

zaten cevaplanmış olsa bile - bu kısa sözdizimidir (ASP.net 3, 4, 5):

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

6
Bu benim için harika çalışıyor. Kökte herhangi bir denetleyicim yok ve yalnızca Alanları kullanıyorum. MVC 4 için RouteConfig.cs'deki varsayılanı değiştirdim. Teşekkürler!
Marc

2
MVC4 kullanıyorum ve bu benim için en basit çözümdü. Uygulamaya, sitenin 'ana sayfası' olarak belirli bir Alan içinde Dizin görünümünü kullanma izni verir.
JTech

2
Bu çözüm gelecekte çalışmayacaktır (Asp.Net MVC6 ve üzeri).
Patrick Desjardins

@PatrickDesjardins: Yukarıdaki çözümü desteklememek için herhangi bir neden var mı?
Akash KC

@SeriousM Cevabınız her zaman yeşildir. Yine de yardımcı oluyor. Beni bir geceden kurtardın.
skpaul

16

Aaron'a görüşlerin yerini bulmakla ilgili olduğuna işaret ettiği için teşekkürler, bunu yanlış anladım.

[GÜNCELLEME] Az önce, kullanıcıyı herhangi bir kod veya arama yoluyla uğraşmadan varsayılan olarak bir Alana gönderen bir proje oluşturdum:

Global.asax'ta her zamanki gibi kayıt olun:

    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,
        );
    }

içinde Application_Start(), aşağıdaki sırayı kullandığınızdan emin olun;

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

alan kaydınızda kullanın

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

Bir örnek http://www.emphess.net/2010/01/31/areas-routes-and-defaults-in-mvc-2-rc/ adresinde bulunabilir.

Umarım istediğin budur ...

////

ViewEngineBu durumda sözde yazmanın en iyi çözüm olduğunu düşünmüyorum . (İtibar eksikliği, yorum yapamam). WebFormsViewEngineAlan farkındadır ve içerdiği AreaViewLocationFormatsolarak varsayılan başına tanımlanan

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",
    };

Bu sözleşmeye uymadığına inanıyorum. Gönderdin

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

çalışan bir hack olarak, ancak bu olmalıdır

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

Bununla birlikte, kuralı izlemek istemiyorsanız WebFormViewEngine, yapıcıda arama yollarını ayarlayabileceğiniz (örneğin MvcContrib'de yapılan) veya -a'dan türeterek kısa bir yol izlemek isteyebilirsiniz. ufak tefek- konvansiyonunuzu şu şekilde belirterek Application_Start:

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

Tabi bu biraz daha dikkatli yapılmalı ama bence bu fikri gösteriyor. Bu alanlar publiciçinde VirtualPathProviderViewEngineMVC 2 RC.


Bunun yalnızca MVC 2 RC'de geçerli olduğunu belirtmek gerekir - MVC 1 VirtualPathProviderViewEnginebu özelliğe sahip değildir ve alan farkında değildir. Ve bu sorunun gerçekten MVC 2 ile ilgili olduğu belirtilirken, birçok insan hala onu kullanmıyor (ve bir süre için olmayacak). Yani, cevabınız belirli bir soru için daha kolay, ancak benimki bu soruya rastlayan MVC1 kullanıcıları için işe yarayacak tek soru. Potansiyel olarak değişime tabi olan yayın öncesi işlevselliğe bağlı olmayan yanıtlar vermeyi seviyorum.
Aaronaught

Ayrıca bu bir "sözde görünüm motoru" değildir - görünüm motoru sınıfları, farklı görünüm türlerinin kullanılabilmesi için bilinçli olarak genişletilebilir hale getirilmiştir.
Aaronaught

Bu size hakaret etmek anlamına gelmedi, üzgünüm. Görünümlerin işlenme şeklini önemli ölçüde değiştirmemesi, yalnızca bazı değerleri değiştirmesi açısından "sözde" dir.
mnemosyn

Gücenmedim, sadece özel bir görünüm motoru türetmenin alışılmadık bir neden olmadığı gerçeğini açıklığa kavuşturmak istedim, çünkü ilgili yöntemlerin geçersiz kılınabileceği gerçeğiyle kanıtlandı.
Aaronaught

2
Daha RegisterAreasönce gitmeyle ilgili harika bir ipucu RegisterRoutes.
Kodumun

6

Sanırım kullanıcının ~/AreaZURL'yi ziyaret ettikten sonra URL'ye yeniden yönlendirilmesini istiyorsunuz ~/. Kökünüzde bulunan aşağıdaki kod aracılığıyla başarırdım HomeController.

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

Ve aşağıdaki rota Global.asax.

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

Bu çalışır, ancak kullanıcıların tarayıcısındaki URL olarak değişir. Gerçekten ideal değil.
LiamB

2

İlk olarak, MVC2'nin hangi sürümünü kullanıyorsunuz? Preview2'den RC'ye önemli değişiklikler oldu.

RC kullandığınızı varsayarsak, rota haritalamanın farklı görünmesi gerektiğini düşünüyorum. In AreaRegistration.csBölgenizde, varsayılan yolun, örneğin çeşit kayıt olabilirsiniz

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

Yukarıdaki kod kullanıcıyı gönderir MyRouteControllerbizim de ShopAreabaşına varsayılan.

İkinci parametre olarak boş bir dizenin kullanılması bir istisna oluşturmalıdır, çünkü bir denetleyici belirtilmelidir.

Elbette, varsayılan rotayı Global.asaxbu varsayılan rotaya müdahale etmemesi için değiştirmeniz gerekecektir , örneğin ana site için bir önek kullanarak.

Ayrıca bu konuya ve Haack'ın cevabına bakın: MVC 2 AreaRegistration Routes Order

Bu yardımcı olur umarım.


Teşekkürler, ancak bunun soruda açıklanan sorunu çözdüğünden emin değilim. Ve MVC RC
LiamB

2

RC'de bu ayarın sizde olup olmadığından emin olmasam da, Application_Start'ıma aşağıdakileri eklemek benim için çalışıyor:

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

Bunun işe yaraması için yaptığım şey şudur:

  1. Kök / Denetleyiciler klasöründe varsayılan bir denetleyici oluşturdum. Denetleyicime DefaultController adını verdim.
  2. Denetleyicide aşağıdaki kodu ekledim:

    namespace MyNameSpace.Controllers {
    public class DefaultController : Controller {
        // GET: Default
        public ActionResult Index() {
            return RedirectToAction("Index", "ControllerName", new {area = "FolderName"});
        }
    } }
  3. RouterConfig.cs dosyamda şunları ekledim:

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

Tüm bunların arkasındaki püf noktası, uygulamam her başladığında her zaman başlangıç ​​denetleyicisi olacak varsayılan bir kurucu yapmamdır. Bu varsayılan denetleyiciye ulaştığında, varsayılan Dizin Eyleminde belirttiğim herhangi bir denetleyiciye yönlendirecektir. Hangisi benim durumumda

www.myurl.com/FolderName/ControllerName

.


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

Bunu denedin mi?


Evet, sorun, sitenin artık görünümleri kökte araması gerçeğinden kaynaklanıyor. "ActionY" görünümü veya ana görünümü bulunamadı. Aşağıdaki konumlar arandı: ~ / Views / ActionY / ActionY.aspx ~ / Views / ActionY / ActionY.ascx ~ / Views / Shared / ActionY.aspx ~ / Views / Shared / ActionY.ascx
LiamB

2
Anlıyorum. Bir çözüm bulmaya çalışacağım. Soru için +1
Barbaros Alp

0

Farklı yapı taşlarını bulmak, istek yaşam döngüsünde yapılır. ASP.NET MVC istek yaşam döngüsündeki ilk adımlardan biri, istenen URL'yi doğru denetleyici eylem yöntemiyle eşlemektir. Bu işlem, yönlendirme olarak adlandırılır. Varsayılan bir yol Global.asax dosyasında başlatılır ve ASP.NET MVC çerçevesine bir isteğin nasıl işleneceğini açıklar. MvcApplication1 projesinde Global.asax dosyasına çift tıklandığında aşağıdaki kod görüntülenir:

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);
       }
   }

}

Uygulama her derlendiğinde veya web sunucusu yeniden başlatıldığında ateşlenen Application_Start () olay işleyicisinde, bir yönlendirme tablosu kaydedilir. Varsayılan yol Varsayılan olarak adlandırılır ve http://www.example.com/ şeklinde bir URL'ye yanıt verir. {denetleyici} / {eylem} / {id} . {Ve} arasındaki değişkenler, istek URL'sindeki gerçek değerlerle veya URL'de geçersiz kılma yoksa varsayılan değerlerle doldurulur. Bu varsayılan yol, varsayılan yönlendirme parametrelerine göre Ev denetleyicisine ve Dizin eylem yöntemine eşlenecektir. Bu yönlendirme haritasıyla başka bir işlem yapmayacağız.

Varsayılan olarak, tüm olası URL'ler bu varsayılan yol üzerinden eşlenebilir. Kendi rotalarımızı oluşturmak da mümkün. Örneğin, http://www.example.com/Employee/Maarten URL'sini Employee controller, Show eylemi ve firstname parametresine eşleyelim. Aşağıdaki kod parçacığı, az önce açtığımız Global.asax dosyasına eklenebilir. ASP.NET MVC çerçevesi ilk eşleşen yolu kullandığından, bu kod parçacığı varsayılan yolun üzerine eklenmelidir; aksi takdirde rota asla kullanılmayacaktır.

routes.MapRoute(

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

);

Şimdi bu rota için gerekli bileşenleri ekleyelim. Öncelikle, Controllers klasöründe EmployeeController adlı bir sınıf oluşturun. Bunu projeye yeni bir öğe ekleyerek ve Web | altında bulunan MVC Denetleyici Sınıfı şablonunu seçerek yapabilirsiniz. MVC kategorisi. Dizin eylem yöntemini kaldırın ve bunu Göster adlı bir yöntem veya eylemle değiştirin. Bu yöntem bir ilk ad parametresini kabul eder ve verileri ViewData sözlüğüne iletir. Bu sözlük, görünüm tarafından verileri görüntülemek için kullanılacaktır.

EmployeeController sınıfı, bir Employee nesnesini görünüme iletir. Bu Employee sınıfı Modeller klasörüne eklenmelidir (bu klasöre sağ tıklayın ve ardından bağlam menüsünden Ekle | Sınıfı seçin). Employee sınıfının kodu şöyledir:

namespace MvcApplication1.Models {

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

} 

1
Teşekkürler, bunun varsayılan bir ALAN ayarlamakla nasıl bir ilgisi olduğundan emin değilim. : - /
LiamB

0

Özel bir görünüm motoru oluşturmak bunun için işe yarayabilir, ancak yine de bir alternatifiniz olabilir:

  • Varsayılan olarak neyi göstermeniz gerektiğine karar verin.
  • Bir şeyin denetleyicisi ve eylemi (ve Alanı) vardır, değil mi?
  • Bu Alan kaydını açın ve şuna benzer bir şey ekleyin:
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
}

Şerefe!


Kabul. Bu rota tanımı için daha uygun bir yerin Global.asax dosyasında olduğunu düşünmeme rağmen.
nuhusky2003

Böyle bir durumda, global.asax tanımlarınız bir alan denetleyicisi ad alanı varlığından haberdar olur, ki bence bu doğru değildir. Alanlar ek bir işlevdir, yani global.asax tanımlarına dokunmadan bir tane ekleyebilmeniz / kaldırabilmeniz gerektiği anlamına gelir. Soruya yaklaşımımda, talebi "devretmek" için [global] bir web sitesi yerine, talebi "devralacak" bir alanı tercih ediyorum.
Tengiz

0

Bu soruya kabul edilen çözüm, özel bir görünüm motorunun nasıl oluşturulacağını özetlemek doğru olsa da, soruya doğru cevap vermiyor. Buradaki sorun, Pino'nun yanlış bir şekilde varsayılan rotasını belirlemesidir . Özellikle "alan" tanımı yanlıştır. "Alan" DataTokens koleksiyonu yoluyla kontrol edilir ve şu şekilde eklenmelidir:

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);

Varsayılan nesnede belirtilen "alan" göz ardı edilecektir . Yukarıdaki kod, sitenizin köküne gelen istekleri yakalayan ve ardından Yönetici alanında Varsayılan denetleyici, Dizin eylemini çağıran varsayılan bir yol oluşturur. Ayrıca DataTokens'a eklenen "Namespaces" anahtarına da dikkat edin, bu yalnızca aynı ada sahip birden çok denetleyiciniz varsa gereklidir. Bu çözüm, Mvc2 ve Mvc3 .NET 3.5 / 4.0 ile doğrulanmıştır.


-1

ummm, tüm bu programlamanın nedenini bilmiyorum, bence bu varsayılan yol belirtilerek orijinal sorun kolayca çözülür ...

routes.MapRoute("Default", "{*id}", 
                 new { controller = "Home"
                     , action = "Index"
                     , id = UrlParameter.Optional 
                     }
              );
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.