SORU
26 Ocak 2010, Salı


Nasıl MVC Varsayılan bir Yol (bir Alana)

Tamam, bu daha önce de soruldu ama dışarıda sağlam bir çözümü yok. Kendime bir amaç ve bu yararlı olabilir diğerleri için.

Birisi web sitesine gittiğinde MVC2 (ASP.NET) istiyorum, varsayılan bir uygulamadır. Çok sitem için navigasyon AreaZ içinde ActionY ControllerX göndermek gerekir.

Genel olarak aşağıdaki yolu kullanarak.asax

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

Şimdi bu doğru sayfayı sunmak için deneyin gibi çalışır. Ancak gelirleri Alan klasörde sitenin kök ve Görünüm aramak için MVC.

Bu sorunu çözmek için bir yol var mı?

EDİT

Bir 'Çözüm' ve görünümü ControllerX, ActionY tam dönüş yolunda. Biraz ama çalışır hack. Ancak daha iyi bir çözüm olduğunu umuyorum.

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

Düzenleme:

Bu da sayfanın HTML ActionLink sahip olduğunda bir sorun haline gelir. Eğer alanını ayarlamak ise Eylem Link boş çıktı.

Tüm bu tasarım ya da bir kusur mu?

CEVAP
31 Ocak 2010, Pazar


Bu ilgimi, ve sonunda içine bakmak için bir şans vardı. Diğer arkadaşlar görünüşe göre bu bir sorun olduğunu anlamıyorgörünüm bulmasorun değilyönlendirmekendisi - ve muhtemelen soru başlık yönlendirme olduğunu gösterir çünkü.

Bu Görünüm ile ilgili bir sorun var çünkü herhangi bir durumda, istediğini almak için tek yol olduğunuvarsayılan görünümü motoru geçersiz kılar. Bunu yaptığınızda normalde, görüntülemek motoru (Spark, NHaml için, vb.) geçiş basit bir amaç için. Bu durumda, geçersiz kılmak gerekir Görünüm oluşturma mantığı değil, ama VirtualPathProviderViewEngine sınıf FindPartialView FindView yöntemleri.

VirtualPathProviderViewEngine Her şey bile değildir, çünkü bu yöntemler aslında sanal olduğu için şükreterişilebilir- özel bir şey, ve o yaparçokgeçersiz kılmak için can sıkıcı temelde zaten eğer konum önbelleği ve konum biçimleri ile güzel oynamak istiyorsan yazılmış kodu yarısını yeniden yazmak zorunda çünkü mantık bulmak. Reflektör bazı kazma sonra nihayet çalışan bir çözüm ile gelip başardı.

Burada yaptığım ilk doğrudan WebFormViewEngine yerine VirtualPathProviderViewEngine türetildiği AreaAwareViewEngine soyut oluşturmaktır. Eğer görüş yerine (ya da her neyse) Kıvılcım oluşturmak istiyorsanız, hala temel tür olarak bu sınıfı kullanabilmek için böyle yaptım.

Aşağıdaki kod oldukça uzun soluklu, çok verip, hızlı bir özet ne olduğu: sağlar put {2} konuma biçimi, karşılık gelen alan adı, aynı şekilde {1} karşılık denetleyicisi adı. İşte bu! Bu kod yazmak için yaptık.

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 de belirtildiği gibi, bu somut bir motor değil, bunu oluşturmak için de var. Bu bölüm, neyse kiçokkolay, tek yapmamız gereken varsayılan biçimleri ayarlanır ve aslında görünümler oluşturun:

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

21* *standart birkaç girişleri ekledik unutmayın. Bu {2} RouteData koyduk area eşleştirilir nerede {2} yeni girişleri. Yalnız MasterLocationFormats bıraktım ama açıkçası Eğer isterseniz bunu değiştirebilirsiniz.

Şimdi global.asax bu görüşe motoru kaydı değiştirmek için:

Global.asax.cs

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

...ve varsayılan rota kaydı:

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 sadece başvurulan AreaController Oluşturun:

DefaultController.cs (~/Kontrolörleri/)

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

Açıkça ve dizin yapısını görüntülemek ihtiyacımız var - bu süper basit tutacağız:

TestView.SEO (~/Alanlar/AreaZ/Görüş/Default/ veya ~/Alanlar/AreaZ/Görüş/Shared/)

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

Ve işte bu kadar.Sonunda bitti.

Çoğunlukla gerekir sadece al BaseAreaAwareViewEngine AreaAwareViewEngine ve bırak içine herhangi bir MVC projesi, çok bile sürdü bir sürü kod almak bu iş, sadece yazmaya devam et. Bundan sonra, sadece global.asax.cs birkaç satır düzenleme ve site yapısını oluşturma meselesi.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Eddie Bravo

    Eddie Bravo

    17 EKİM 2006
  • SaMmM123

    SaMmM123

    3 Mayıs 2006
  • Sergio Fernandez

    Sergio Ferna

    1 EKİM 2009