2 частичных просмотра бритвы с одинаковыми именами в разных проектах с использованием razorgenerator - PullRequest
2 голосов
/ 11 октября 2011

В нашем проекте мы используем разоргенератор Дэвида Эббо . Это позволило нам переместить некоторые из наших файлов cshtml в библиотеку классов.

То, чего мы хотели бы достичь сейчас, это:

  • MyCommonViews имеет "MyView.cshtml" в своей папке Views.
  • MyWebProject ТАКЖЕ имеет «MyView.cshtml» в своей папке Views.
  • MyOtherWebProject НЕ имеет «MyView.cshtml» в своей папке Views.

Когда MyOtherWebProject необходимо загрузить MyView.cshtml, он выберет тот, который находится в скомпилированном проекте MyCommonViews. Это то, что мы хотим.
НО, когда MyWebProject необходимо загрузить MyView.cshtml, мы бы хотели, чтобы он взял «переопределенный» файл MyView.cshtml, который находится в самом MyWebProject.

Возможно ли то, что мы хотим, и как?

Мана.

Ответы [ 3 ]

2 голосов
/ 07 июня 2013

Вы также можете попробовать CompositePrecompiledMvcEngine из RazorGenerator.Mvc 2.1.0. Он был разработан для правильной поддержки переопределения вида в нескольких сборках. Код:

var engine = new CompositePrecompiledMvcEngine(
/*1*/ PrecompiledViewAssembly.OfType<MyCommonViewsSomeClass>(),
/*2*/ PrecompiledViewAssembly.OfType<MyWebProjectSomeClass>(
        usePhysicalViewsIfNewer: HttpContext.Current.IsDebuggingEnabled));

ViewEngines.Engines.Insert(0, engine);
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);

В первой строке будут зарегистрированы все виды из сборки MyCommonViews (~ / Views / MyView.cshtml), во второй строке будут зарегистрированы все виды из сборки MyWebProject или MyOtherWebProject.

Когда он встречает виртуальный путь, который уже был зарегистрирован (~ / Views / MyView.cshtml из сборки MyWebProject), он переопределяет старое отображение новым отображением типа представления.

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

2 голосов
/ 11 октября 2011

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

Обсуждение дешево, покажите мне код:

    private static void HackRazorGeneratorToAllowViewOverriding()
    {
        // first we search for the PrecompiledMvcEngine
        var razorGeneratorViewEngine = ViewEngines.Engines.ToList().FirstOrDefault(ve => ve.GetType().Name.Contains("PrecompiledMvcEngine"));
        if (razorGeneratorViewEngine == null)
            return;

        // retrieve the dictionary where it keeps the mapping between a view path and the (view object) type to instantiate
        var razorMappings = (IDictionary<string, Type>)ReflectionUtils.GetPrivateReadonly("_mappings", razorGeneratorViewEngine);

        // retrieve a list of all our cshtml files in our 'concrete' web project
        var files = Directory.GetFiles(Path.Combine(WebConfigSettings.RootPath, "Views"), "*.cshtml", SearchOption.AllDirectories);

        // do some kungfu on those file paths so that they are in the same format as in the razor mapping dictionary
        var concreteViewPaths = files.Select(fp => string.Format("~{0}", fp.Replace(WebConfigSettings.RootPath, "").Replace(@"\", "/"))).ToList();

        // loop through each of the cshtml paths (of our 'concrete' project) and remove it from the razor mappings if it's there
        concreteViewPaths.ForEach(vp =>
                                      {
                                          if (razorMappings.ContainsKey(vp))
                                              razorMappings.Remove(vp);
                                      });
    }

WebConfigSettings.RootPath содержит путь на HD к корню нашего веб-приложения.

Это частьнашего статического класса ReflectionUtils:

/// <summary>
/// Get a field that is 'private readonly'.
/// </summary>
public static object GetPrivateReadonly(string readonlyPropName, object instance)
{
    var field = instance.GetType().GetField(readonlyPropName, BindingFlags.Instance | BindingFlags.NonPublic);
    if (field == null)
        throw new NullReferenceException(string.Format("private readonly field '{0}' not found in '{1}'", readonlyPropName, instance));
    return field.GetValue(instance);
}

Это помогло.Мы в основном заставляем PrecompiledMvcEngine «забыть» любое представление, которое мы имеем в нашем конкретном проекте.

1 голос
/ 18 февраля 2013

Существует флаг PreemptPhysicalFiles = false, который совершает магию.

Полный образец:

[assembly: WebActivator.PostApplicationStartMethod(typeof(Application.Web.Common.App_Start.RazorGeneratorMvcStart), "Start")]

namespace Application.Web.Common.App_Start
{
    public static class RazorGeneratorMvcStart
    {
        public static void Start()
        {
            var engine = new PrecompiledMvcEngine2(typeof (RazorGeneratorMvcStart).Assembly)
                             {
                                 UsePhysicalViewsIfNewer = true, //compile if file changed
                                 PreemptPhysicalFiles = false //use local file if exist
                             };

            ViewEngines.Engines.Add(engine);//Insert(0,engine) ignores local partial views

            // StartPage lookups are done by WebPages. 
            VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
        }
    }
}

Однако, возможно, есть небольшая ошибка: http://razorgenerator.codeplex.com/workitem/100

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