gpt4 book ai didi

asp.net-mvc - ASP.NET 捆绑/缩小 : including dynamically generated Javascript

转载 作者:行者123 更新时间:2023-12-04 03:29:28 24 4
gpt4 key购买 nike

我有一个动态生成 Javascript 的网站。生成的代码描述了类型元数据和一些服务器端常量,以便客户端可以轻松地使用服务器的服务——因此它是非常可缓存的。

生成的 Javascript 由 ASP.NET MVC Controller 提供服务;所以它有一个 Uri;说~/MyGeneratedJs .

我想将此 Javascript 包含在与其他静态 Javascript 文件(例如 jQuery 等)的 Javascript 包中:所以就像静态文件一样,我希望它在 Debug模式下单独引用,并以与其他文件捆绑的缩小形式在非 Debug模式。

如何在捆绑包中包含动态生成的 Javascript?

最佳答案

VirtualPathProviders现在这是可能的。将动态内容集成到捆绑过程中需要以下步骤:

  • 编写请求/构建所需内容的逻辑。直接从 Controller 生成内容需要一些工作:
    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));
    }
    }
  • 实现一个虚拟路径提供者,它包装现有的并拦截所有应该传递动态内容的虚拟路径。
    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);
    }
    }
  • 注册您的虚拟路径提供程序:
    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"));
    }
  • 可选:将 Intellisense 支持添加到您的 View 中。使用<script>您的 View 中的标签,并让它们被自定义 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);
    }
    }

    使用扩展方法或向 Controller 添加辅助函数:
    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
    };
    }

  • 其他类型的动态内容的步骤与此类似。见 Bundling and Minification and Embedded Resources例如。

    我向 GitHub 添加了一个概念证明库如果你想尝试一下。

    关于asp.net-mvc - ASP.NET 捆绑/缩小 : including dynamically generated Javascript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12018429/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com