How can I add the result of an ASP.NET MVC controller action to a Bundle?

后端 未结 3 1622
南方客
南方客 2021-02-04 12:26

I have a controller action that returns Javascript file. I can reference this file from my view and it works fine. I\'d like to put it in a System.Web.Optimization.Bundle with t

3条回答
  •  孤独总比滥情好
    2021-02-04 12:57

    I think this is quite doable - but before I get into my solution - Remember that the bundle is created on the first hit and is reused - this means that any 'dynamic' script still has to be global (ie it cannot be dependant on a specific user etc). This is why generally it only allows static js files. Saying that... I could imagine a situation where you might want to stick variables like version number or something like that in your js (though in that case I personally would just use Ajax/JSON to get it).

    I think the way to go about it is to create an derived type from Bundle. In it you would overwrite the EnumerateFiles method. Initially you would enumerate over the base.EnumerateFiles and then include your own virtual file.

    Something like (Note: not tested code):

    public class VirtualMethodBundle : Bundle
    {
        private List _virtualContent = new List();
    
        public override IEnumerable EnumerateFiles(BundleContext context)
        {
            foreach(var file in base.EnumerateFiles(context))
            {
                yield return file;
            }
    
            foreach(var virtual in _virtualContent)
            {
                yield return virtual;
            }
        }
    
        public void AddCustomFile(VirtualFile file)
        {
            _virtualContent.Add(method);
        }
    }
    

    Then you would have a special VirtualFile defined type that overrides the Open/Name method and returns your dynamic content there... Something like.

    public class MethodBasedVirtualFile : VirtualFile
    {
        private readonly Func _contentFactory;
        private readonly string _path;
    
        public MethodBasedVirtualFile(string path, Func contentFactory)
        {
            _path = path;
            _contentFactory = contentFactory;
        }
    
        public override string Name { get { return _path; } }
    
        public override Stream Open()
        {
            MemoryStream stream = new MemoryStream();
            StreamWriter writer = new StreamWriter(stream);
            writer.Write(_contentFactory());
            writer.Flush();
            stream.Position = 0;
            return stream;
        }
    }
    

    So then to use it all you would have...

    var bundle = new VirtualMethodBundle();
    bundle.Include(... real files ...);
    bundle.AddCustomFile(
        new MethodBasedVirtualFile("~/DynamicScript/UrlDictionary",
        ... the method that creates the content of that script...)
    );
    

    If you were clever you could just make a UrlVirtualFile that takes the url path and uses MVC to automatically get the content when required.

提交回复
热议问题