Требуется ли пользовательский ViewEngine? - PullRequest
1 голос
/ 26 октября 2009

У меня есть веб-сайт, который будет иметь индивидуальный дизайн, в зависимости от того, в каком "магазине" была нажата ...

Итак, у меня есть структура папок:

 + _default
    - Site.Master
    - Site.css
    + Views
      - main.ascx
      - xyz.ascx
      - zbf.aspx
 + custom_design_01
    - Site.Master
    - Site.css
    + Views
      - xyz.ascx
      - zbf.aspx
 + custom_design_02
    - Site.Master
    - Site.css
    + Views
      - xyz.ascx
      - zbf.aspx

В моем контроллере я приму решение, какую из папок использовать, в зависимости от параметра из запроса (папка по умолчанию должна использоваться, когда файл недоступен как настроенный) ..

Итак, контроллер должен сделать что-то вроде:

    public ActionResult Index(int id)
    {
        var newRouteParamThatWouldntFitIntoTheCurrentViewMethodLikeThis = DoSomeMagicalRoutingStuff(id);

        return View(newRouteParamThatWouldntFitIntoTheCurrentViewMethodLikeThis);
        //return View();
    }

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

У кого-нибудь есть идеи, как это реализовать (с помощью встроенных инструментов MVC)? Я действительно хочу продолжать использовать метод Html.RenderPartial и другие «преимущества» MVC ... вот почему я предпочел бы решить эту проблему с помощью методов / переопределений MVC / и т.д.

Обновление:

  • Сайты различаются по дизайну, содержанию, сами используют "RenderPartial" и т. Д.
  • Взгляды действительно разные .. не только шедевры ..
  • Параметр ID в контроллере определяет, какую «папку» следует использовать (например, custom_design_01)
  • URL будут выглядеть следующим образом: "/ Stores / {id_of_design} /", который вызывает метод примера контроллера. Затем ctonroller возвращает представление "/Stores/ndomid_of_design‹/Views/zbf.aspx", например

Спасибо!

Ответы [ 3 ]

2 голосов
/ 26 октября 2009

Я предлагаю вам использовать специализированный ViewEngine с некоторыми пользовательскими местами поиска. Поскольку вы все еще используете страницы WebForms, вы можете просто извлечь из встроенного WebFormViewEngine:

public class ThemedViewEngine : WebFormViewEngine {

    private static readonly string[] _emptyLocations = new string[0];

    //Format: {0} page name {1} controller {2} design
    string[] _masterLocations = new[] {
        "~/Views/{2}/{0}.master"
    };

    string[] _viewLocations = new[] {
        "~/Views/{2}/{1}/{0}.aspx",
        "~/Views/{2}/Shared/{0}.aspx",
    };

    #region View search

    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
        string[] viewLocationsSearched;
        string[] masterLocationsSearched;

        string viewPath = FindPath(controllerContext, _viewLocations, viewName, _cacheKeyPrefix_View, useCache, out viewLocationsSearched);
        string masterPath = FindPath(controllerContext, _masterLocations, masterName, _cacheKeyPrefix_Master, useCache, out masterLocationsSearched);

        //Check if one view missing
        if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName))) {
            return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
        }

        return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
    }

    //Same thing as above, but without master page
    public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
        string[] viewLocationsSearched;

        string viewPath = FindPath(controllerContext, _viewLocations, partialViewName, _cacheKeyPrefix_Partial, useCache, out viewLocationsSearched);

        if (String.IsNullOrEmpty(viewPath)) {
            return new ViewEngineResult(viewLocationsSearched);
        }

        return new ViewEngineResult(CreatePartialView(controllerContext, viewPath), this);  
    }

    protected string FindPath(ControllerContext context, string[] locations, string viewName, string prefix, bool useCache, out string[] searched) {
        searched = _emptyLocations;

        if (string.IsNullOrEmpty(viewName))
            return string.Empty;

        //Prepare your data here
        string controllerName = context.RouteData.GetRequiredString("controller");
        string designName = /* YOUR WAY OF GETTING THE DESIGN */;

        string result = FindPathGeneral(context, locations, viewName, controllerName, designName, out searched);

        return result;
    }

    /// <summary>
    /// Finds the complete path for a general view page.
    /// </summary>
    private string FindPathGeneral(ControllerContext context, string[] locations, string viewName, string controllerName, string designName, out string[] searched) {
        string result = string.Empty;
        searched = new string[locations.Length];

        for (int i = 0; i < locations.Length; i++) {
            //Build virtual path from the locations defined on top
            string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i],
                viewName, controllerName, designName);

            if (FileExists(context, virtualPath)) {
                searched = _emptyLocations;
                return virtualPath;
            }

            searched[i] = virtualPath;
        }

        return result;
    }
    #endregion
}

Это должно работать для вашего случая, при условии, что вы нашли способ найти нужное имя дизайна в методе FindPath.

В приведенном выше примере не реализовано кэширование представлений для простоты. Вы можете проверить код WebFormViewEngine с отражателем (или из исходного кода), чтобы увидеть, как это делается фреймворком.

0 голосов
/ 26 октября 2009

Это звучит очень похоже на области, отметьте здесь и здесь , а также для общих областей asp.net mvc Я не уверен только в области «по умолчанию», но думаю, что это можно сделать. Обратите внимание, что ASP.NET MVC v2 (который сейчас находится в бета-версии) имеет поддержку нативных областей.

0 голосов
/ 26 октября 2009

Один из способов решения этой проблемы - создать подкласс Controller в качестве общего базового класса для ваших контроллеров. Вы можете определить альтернативную функцию действия, такую ​​как View(), которая использует данные маршрута и параметры метода, чтобы решить, какое представление следует использовать, а затем просто вернуть стандартный экземпляр ViewResult. (Вы можете извлечь информацию из URL в маршруте, который не используется напрямую для сопоставления с контроллером или его параметрами.)

Однако, может быть, лучше создать пользовательский подкласс WebFormViewEngine (поскольку именно здесь люди могут ожидать найти такой код). Опять же, если не все ваши контроллеры имеют такое поведение, первый подход может быть лучше.

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