Включение представления MVC или строки в пакет javascript с использованием среды связывания

Я пытаюсь объединить несколько файлов javascript вместе, но мне также нужно включить переменную из app.config в файл js.

Моя мысль заключалась в том, чтобы использовать контроллер для возврата строки для установки переменной, поэтому переход к ~/Javascript/Index вернет var foo = "bar"; Это прекрасно работает.

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

Я обновился до последней версии пакета, но не могу найти никакой информации о том, как получить сочетание статических файлов и файлов, созданных контроллером/представлением, для объединения. Думаю, я просто хочу использовать поставщика пути MVC?

Другая моя мысль заключалась в том, чтобы попытаться использовать механизм связывания для создания строки связанных статических файлов, а затем просто добавить мою строку и вернуть все это в браузер. Но я не могу найти метод, который позволяет мне использовать механизм связывания для возврата результата процесса связывания.


person Jeff S    schedule 13.12.2013    source источник
comment
аналогично stackoverflow.com/questions/21323373/   -  person drzaus    schedule 03.08.2014
comment
Это потрясающий ответ. Извините только за ссылку. blog.mariusschulz. ком/2015/10/25/   -  person Jess    schedule 28.11.2017


Ответы (1)


Для интеграции динамического контента в процесс объединения необходимо выполнить следующие шаги:

  1. Написание логики, которая запрашивает/строит требуемый контент. Генерация контента напрямую из контроллера требует немного работы:

    public static class ControllerActionHelper
    {
        public static string RenderControllerActionToString(string virtualPath)
        {
            HttpContext httpContext = CreateHttpContext(virtualPath);
            HttpContextWrapper httpContextWrapper = new HttpContextWrapper(httpContext);
    
            RequestContext httpResponse = new RequestContext()
            {
                HttpContext = httpContextWrapper,
                RouteData = RouteTable.Routes.GetRouteData(httpContextWrapper)
            };
    
            // Set HttpContext.Current if RenderActionToString is called outside of a request
            if (HttpContext.Current == null)
            {
                HttpContext.Current = httpContext;
            }
    
            IControllerFactory controllerFactory = ControllerBuilder.Current.GetControllerFactory();
            IController controller = controllerFactory.CreateController(httpResponse,
                httpResponse.RouteData.GetRequiredString("controller"));
            controller.Execute(httpResponse);
    
            return httpResponse.HttpContext.Response.Output.ToString();
        }
    
        private static HttpContext CreateHttpContext(string virtualPath)
        {
            HttpRequest httpRequest = new HttpRequest(string.Empty, ToDummyAbsoluteUrl(virtualPath), string.Empty);
            HttpResponse httpResponse = new HttpResponse(new StringWriter());
    
            return new HttpContext(httpRequest, httpResponse);
        }
    
        private static string ToDummyAbsoluteUrl(string virtualPath)
        {
            return string.Format("http://dummy.net{0}", VirtualPathUtility.ToAbsolute(virtualPath));
        }
    }
    
  2. Реализуйте поставщика виртуального пути, который является оболочкой существующего и перехватывает все виртуальные пути, которые должны доставлять динамическое содержимое.

    public class ControllerActionVirtualPathProvider : VirtualPathProvider
    {
        public ControllerActionVirtualPathProvider(VirtualPathProvider virtualPathProvider)
        {
            // Wrap an existing virtual path provider
            VirtualPathProvider = virtualPathProvider;
        }
    
        protected VirtualPathProvider VirtualPathProvider { get; set; }
    
        public override string CombineVirtualPaths(string basePath, string relativePath)
        {
            return VirtualPathProvider.CombineVirtualPaths(basePath, relativePath);
        }
    
        public override bool DirectoryExists(string virtualDir)
        {
            return VirtualPathProvider.DirectoryExists(virtualDir);
        }
    
        public override bool FileExists(string virtualPath)
        {
            if (ControllerActionHelper.IsControllerActionRoute(virtualPath))
            {
                return true;
            }
    
            return VirtualPathProvider.FileExists(virtualPath);
        }
    
        public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies,
            DateTime utcStart)
        {
            AggregateCacheDependency aggregateCacheDependency = new AggregateCacheDependency();
    
            List<string> virtualPathDependenciesCopy = virtualPathDependencies.Cast<string>().ToList();
    
            // Create CacheDependencies for our virtual Controller Action paths
            foreach (string virtualPathDependency in virtualPathDependenciesCopy.ToList())
            {
                if (ControllerActionHelper.IsControllerActionRoute(virtualPathDependency))
                {
                    aggregateCacheDependency.Add(new ControllerActionCacheDependency(virtualPathDependency));
                    virtualPathDependenciesCopy.Remove(virtualPathDependency);
                }
            }
    
            // Aggregate them with the base cache dependency for virtual file paths
            aggregateCacheDependency.Add(VirtualPathProvider.GetCacheDependency(virtualPath, virtualPathDependenciesCopy,
                utcStart));
    
            return aggregateCacheDependency;
        }
    
        public override string GetCacheKey(string virtualPath)
        {
            return VirtualPathProvider.GetCacheKey(virtualPath);
        }
    
        public override VirtualDirectory GetDirectory(string virtualDir)
        {
            return VirtualPathProvider.GetDirectory(virtualDir);
        }
    
        public override VirtualFile GetFile(string virtualPath)
        {
            if (ControllerActionHelper.IsControllerActionRoute(virtualPath))
            {
                return new ControllerActionVirtualFile(virtualPath,
                    new MemoryStream(Encoding.Default.GetBytes(ControllerActionHelper.RenderControllerActionToString(virtualPath))));
            }
    
            return VirtualPathProvider.GetFile(virtualPath);
        }
    
        public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
        {
            return VirtualPathProvider.GetFileHash(virtualPath, virtualPathDependencies);
        }
    
        public override object InitializeLifetimeService()
        {
            return VirtualPathProvider.InitializeLifetimeService();
        }
    }
    
    public class ControllerActionVirtualFile : VirtualFile
    {
        public CustomVirtualFile (string virtualPath, Stream stream)
            : base(virtualPath)
        {
            Stream = stream;
        }
    
        public Stream Stream { get; private set; }
    
        public override Stream Open()
        {
             return Stream;
        }
    }
    

    Вы также должны реализовать CacheDependency, если вам это нужно:

    public class ControllerActionCacheDependency : CacheDependency
    {
        public ControllerActionCacheDependency(string virtualPath, int actualizationTime = 10000)
        {
            VirtualPath = virtualPath;
            LastContent = GetContentFromControllerAction();
    
            Timer = new Timer(CheckDependencyCallback, this, actualizationTime, actualizationTime);
        }
    
        private string LastContent { get; set; }
    
        private Timer Timer { get; set; }
    
        private string VirtualPath { get; set; }
    
        protected override void DependencyDispose()
        {
            if (Timer != null)
            {
                Timer.Dispose();
            }
    
            base.DependencyDispose();
        }
    
        private void CheckDependencyCallback(object sender)
        {
            if (Monitor.TryEnter(Timer))
            {
                try
                {
                    string contentFromAction = GetContentFromControllerAction();
    
                    if (contentFromAction != LastContent)
                    {
                        LastContent = contentFromAction;
                        NotifyDependencyChanged(sender, EventArgs.Empty);
                    }
                }
                finally
                {
                    Monitor.Exit(Timer);
                }
            }
        }
    
        private string GetContentFromControllerAction()
        {
            return ControllerActionHelper.RenderControllerActionToString(VirtualPath);
        }
    }
    
  3. Зарегистрируйте поставщика виртуального пути:

    public static void RegisterBundles(BundleCollection bundles)
    {
        // Set the virtual path provider
        BundleTable.VirtualPathProvider = new ControllerActionVirtualPathProvider(BundleTable.VirtualPathProvider);
    
        bundles.Add(new Bundle("~/bundle")
            .Include("~/Content/static.js")
            .Include("~/JavaScript/Route1")
            .Include("~/JavaScript/Route2"));
    }
    
  4. Необязательно: добавьте поддержку Intellisense в свои представления. Используйте теги <script> в своем представлении и позвольте им быть удаленными пользовательским ViewResult:

    public class DynamicContentViewResult : ViewResult
    {
        public DynamicContentViewResult()
        {
            StripTags = false;
        }
    
        public string ContentType { get; set; }
    
        public bool StripTags { get; set; }
    
        public string TagName { get; set; }
    
        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
    
            if (string.IsNullOrEmpty(ViewName))
            {
                ViewName = context.RouteData.GetRequiredString("action");
            }
    
            ViewEngineResult result = null;
    
            if (View == null)
            {
                result = FindView(context);
                View = result.View;
            }
    
            string viewResult;
    
            using (StringWriter viewContentWriter = new StringWriter())
            {
                ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, viewContentWriter);
    
                View.Render(viewContext, viewContentWriter);
    
                if (result != null)
                {
                    result.ViewEngine.ReleaseView(context, View);
                }
    
                viewResult = viewContentWriter.ToString();
    
                // Strip Tags
                if (StripTags)
                {
                    string regex = string.Format("<{0}[^>]*>(.*?)</{0}>", TagName);
                    Match res = Regex.Match(viewResult, regex,
                        RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.Singleline);
    
                    if (res.Success && res.Groups.Count > 1)
                    {
                        viewResult = res.Groups[1].Value;
                    }
                    else
                    {
                        throw new InvalidProgramException(
                            string.Format("Dynamic content produced by View '{0}' expected to be wrapped in '{1}' tag.", ViewName, TagName));
                    }
                }
            }
    
            context.HttpContext.Response.ContentType = ContentType;
            context.HttpContext.Response.Output.Write(viewResult);
        }
    }
    

    Используйте метод расширения или добавьте вспомогательную функцию в свой контроллер:

    public static DynamicContentViewResult JavaScriptView(this Controller controller, string viewName, string masterName, object model)
    {
        if (model != null)
        {
            controller.ViewData.Model = model;
        }
    
        return new DynamicContentViewResult
        {
            ViewName = viewName,
            MasterName = masterName,
            ViewData = controller.ViewData,
            TempData = controller.TempData,
            ViewEngineCollection = controller.ViewEngineCollection,
            ContentType = "text/javascript",
            TagName = "script",
            StripTags = true
        };
    }
    

Шаги аналогичны для другого типа динамического содержимого. См. раздел Объединение и минификация и встроенные ресурсы. Например.

Я добавил тестовый репозиторий на GitHub, если вы хотите попробовать его.

person Dresel    schedule 16.12.2014