ASP.NET MVC 4 ScriptBundle returns empty - asp.net-mvc-4

Specifically, I am trying to create a ScriptBundle in MVC 4 with already minified scripts, and return this same Bundle whether the project is in Debug or not.
My web project references the MVC Telerik Grid NuGet package. In that package, Telerik only provides the minified JS files. Bundling code is below.
// telerik scripts
bundles.Add(new ScriptBundle("~/scripts/bundles/telerik").Include(
"~/Scripts/2012.1.214/telerik.common.min.js",
"~/Scripts/2012.1.214/telerik.textbox.min.js",
"~/Scripts/2012.1.214/telerik.calendar.min.js",
"~/Scripts/2012.1.214/telerik.datepicker.min.js",
"~/Scripts/2012.1.214/telerik.grid.min.js",
"~/Scripts/2012.1.214/telerik.grid.filtering.min.js"));
Other ScriptBundles run fine, but when my project attempts to reference this bundle, the request appears as: scripts/bundles/telerik?v= Returning nothing.
If I set BundleTable.EnableOptimizations = true, then it DOES return the ScriptBundle and references a specific version, however this solution is unacceptable.
I do not want to forcibly set BundleTable.EnableOptimizations = true, since I want all other Bundles to return the non-minified versions when appropriate.
Anyone have a similar experience and if so, what was the solution?

I think you have the same problem, please look at this link: mvc4 bundler not including .min files
Either rename .min.js to .js or do something like:
public static void AddDefaultIgnorePatterns(IgnoreList ignoreList)
{
if (ignoreList == null)
throw new ArgumentNullException("ignoreList");
ignoreList.Clear();
ignoreList.Ignore("*.intellisense.js");
ignoreList.Ignore("*-vsdoc.js");
ignoreList.Ignore("*.debug.js", OptimizationMode.WhenEnabled);
//ignoreList.Ignore("*.min.js", OptimizationMode.WhenDisabled);
ignoreList.Ignore("*.min.css", OptimizationMode.WhenDisabled);
}

Related

ASP.NET Core 6 MVC - access a view (.cshtml) page from a different class library project

We have a scenario where we have to move couple of our view pages away from our Web API project to a separate class library. Where this class library will be be consumed by different Web API projects that needs to load these shared View pages as part of the functionality. I have been looking for a day now but cannot find a way how to do it.
The view pages work with no problems when accessed from within the Web API project but we have now moved these View pages into our existing common library (a class library) and added it as a reference to the Web API project. Basically when we build the application with the common class library containing the views (we changed the property to Content so it gets added on build time), it gets built and copied into the bin folder. So from this, we could say that the view files should be reachable as its just within the project assembly bin folder.
What happens now is that even if setting the web application builder to specify the Content directory to point to this, it still cannot see the View pages and I get an error
The view was not found
Code:
var builder = WebApplication.CreateBuilder(new WebApplicationOptions {
Args = args,
ContentRootPath = PlatformServices.Default.Application.ApplicationBasePath
});
What bugs me is that the same /Views folder is generated when we put back the View pages back to the Web API project. Same structure and files. Only when put to another project, it now cannot recognize it. Having the view pages on the Web API works while putting it to another project does not.
This is a required structure that we need to implement without the use of a RCL but would still work when referenced by different Web APIs. This may seem odd but this is what we need to do and if possible with only minimal changes.
Your help is very much appreciated!
After a few tries, we we're able to do this by setting the resource object to Embedded Resource and implementing the ManifestEmbeddedFileProvider in the common library to virtually map the location when it gets published as a NuGet. In this case, say like we have a folder named /StaticResources in our common lib. In the sample code below, Program refers to your program assembly or any class object within your application.
Code:
// Get embedded file assembly path to allow our static files to be read by the consuming apps
var manifestEmbeddedProvider = new ManifestEmbeddedFileProvider(
typeof(Program).Assembly,
"/StaticResources");
// Sets the `/StaticResources` folder to be servable like a wwwroot folder
app.UseStaticFiles(new StaticFileOptions {
FileProvider = manifestEmbeddedProvider,
RequestPath = "/Resources"
});
// Use it like this
<script src="/Resources/MyScrtipt.js"></script>
For the View() to work, assuming your views are in /StaticResources folder.
var viewsFileProvider = new ManifestEmbeddedFileProvider(
typeof(Program).Assembly,
"/StaticResources");
app.UseStaticFiles(new StaticFileOptions {
FileProvider = viewsFileProvider,
RequestPath = "/Views/Shared"
});
Hope this helps anyone who comes across this issue. Thank you for all of you who have shared their answers.

Dynamically include precompiled (Razor) views in .NET Core 2.1

Idea
I'm trying to build a modular .NET Core MVC application, were I can add 'modules' (extensions) just by copying the required libraries to a predefined folder. The application defines a set of dependencies (DI), error handling and basic layout; the modules provide the actual application or page logic.
We've build a proof of concept, using ExtCore - the concept works great, Controllers are added automatically and the 'plain' Views are recognized easily (the ones set as 'Embedded Resource').
Challenge
However, I don't like the fact that Views are set to 'Embedded Resource', as it will be a small performance hit as the Razor page is now build at runtime.
What we've tried
As .NET Core 2.1 now has the ability to create Reusable Razor UI, I've created a project with a reference to <Project Sdk="Microsoft.NET.Sdk.Razor"> and compiled it to a Razor library (*.Views.dll).
When I link the Razor View library as project dependency in (main) application, everything works fine. However, the goal still is to make the application fully plug-and-play and allow libraries to be included just by deploying them to a folder.
I've tried to achieve this extending the Razor View Engine using a PhysicalFileProvider, but it won't recognize the views in the library.
services.Configure<RazorViewEngineOptions>(opt =>
{
opt.FileProviders.Add(new PhysicalFileProvider("path/to/extension"));
});
The result always is an exception telling me that /Views/[controller]/[action].cshtml is not found.
Searching other answers I came across this project, which creates a ViewLocationExpander. I tried implementing various versions of this idea without luck - most likely because this is an older concept based on .NET Core 1.x which still uses a project dependency; although the Razor View engine now searches the namespace of the assembly.
services.Configure<RazorViewEngineOptions>(opt =>
{
opt.FileProviders.Add(new PhysicalFileProvider("path/to/extension");
opt.ViewLocationExpanders.Add(new DynamicLocationExpander());
});
Where DynamicLocationExpander looks like:
public class DynamicLocationExpander: IViewLocationExpander
{
public DynamicLocationExpander()
{
}
public void PopulateValues(ViewLocationExpanderContext context)
{
}
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
string assembly = ((ControllerActionDescriptor)context.ActionContext.ActionDescriptor)
.ControllerTypeInfo.AsType().Assembly.GetName().Name;
foreach (var viewLocation in viewLocations)
yield return $"{assembly}/{viewLocation}";
}
}
Question
How can we dynamically link a Razor View library, containing precompiled views, to the Razor Engine in a (parent) application?

MVC Custom RouteHandler not firing for files

I have the following code to register a route with my custom routehandler:
routes.Add(New Route(path & "/{assembly}/{*resource}", New RouteValueDictionary(), New RouteValueDictionary(New With { _
Key .assembly = AssemblyName _
}), New EmbeddedContentRouteHandler(PluginAssembly, AssemblyName & "." & path)))
This allows me to access embedded resources in a compiled DLL for example: /Content/PluginAssemblyName/File.name
In MVC 3 and 4 the ProcessRequest function fires each time, but from MVC 5 it doesn't, it only fires when I specify a directory, which will obviously give me a null reference exception because I am looking for files, not directories (denominated, obviously, by . as a file should)
I've tried excluding .css and .js to try and see if my custom routehandler will fire, nothing. Testing this in the MVC 4 project, works perfectly.
Starting to tear my hair out.
Any ideas why the RouteHandler won't fire in MVC 5, but does in MVC 4 and 3?
(This is a Pluggable MVC project using MEF that I've brought to MVC 5 piece by piece since the upgrade path didn't pan out too well)
Starting ASP.net 4, it will not intercept URLs that end with an extension.
Follow the solution here to revert to the old behaviour.
and don't forgot to add this line in your route configuration if you want to intercept existing files.
routes.RouteExistingFiles = true;

Referencing other bundles in BundleConfig.cs in ASP.NET MVC4 app

I am working on an MVC4 application where I'm using WebOptimization to do all of my resource handling (cat and min). I have a few pages which are very similar, but need a few varying styles on a page by page basis.
So, I am trying to reference one bundle (base styles) within another bundle (page specific styles) and I'm not having much luck. Here's what I have in my bundle config:
bundles.Add(new StyleBundle("~/bundles/css/search").Include(
"~/Content/css/partials/grid-controls.css",
"~/Content/css/partials/grid.css",
"~/Content/css/views/search.css"));
bundles.Add(new StyleBundle("~/bundles/css/searchtrees").Include(
"~/bundles/css/search",
"~/Content/css/views/search/trees.css"));
On the search trees page I get the trees.css but nothing from the base search CSS bundle.
How can I go about referencing the first bundle in the second? I'm sure there's a way, just not too familiar with bundling yet.
You can reuse the file references instead of referencing another bundle. Something like this:
var baseIncludes = new string [] { "~/Content/css/partials/grid-controls.css", "~/Content/css/partials/grid.css", "~/Content/css/views/search.css" };
// 'base' bundle references the base includes
bundles.Add (new StyleBUndle ("~/bundles/css/search").Include (baseIncludes));
// other bundle references the base includes and some extras
bundles.Add (new StyleBundle ("~/bundles/css/searchtrees").Include(baseIncludes).Include ("~/Content/css/views/search/trees.css"));

ScriptBundle dependencies

I'm having difficulties getting the ScriptBundle to work properly (if this is supposed to work at all). What I'm trying to do is add another bundle (jQuery) as a dependency to my bundle, like so:
bundles.Add(new ScriptBundle("~/js/myscripts")
.Include("~/js/jquery",
"~/Content/scripts/myscript.js"));
~/js/jquery is the "name" (virtual path) of the jQuery bundle, registered as so (before my dependent bundle):
bundles.Add(new ScriptBundle("~/js/jquery")
.Include("~/Content/scripts/jquery-{version}.js"));
When I do #Scripts.Render("~/js/myscripts") in my view, only myscript.js is rendered to the HTML. If I change the virtual path to jQuery from the one in the name of the bundle to the physical, existing one, it works:
bundles.Add(new ScriptBundle("~/js/myscripts")
.Include("~/Content/scripts/jquery-{version}.js",
"~/Content/scripts/myscript.js"));
Also, doing #Scripts.Render("~/js/jquery") in the view, works. It's just referencing the non-existing virtual path (name) of another ScriptBundle that doesn't work. Is this supposed to work at all? If not, I would like to know where I can post a bug report saying that this scenario should throw an exception if it's not supported. If it is supported, where does it say and why doesn't it work?
Going by what your dependency all you have to put in your layout (view) is
#Scripts.Render("~/js/jquery")
#Scripts.Render("~/js/myscripts")
Update after your comment:
You cannot nest bundles, that is you can't Include a bundle within a bundle, that virtual path is most likely not available while the parent bundle is being created.
Typically I have a separate jquery bundle (including some other infrequently changing js) anyway and then one other js bundle for everything else. works well for browser caching.
On a side note, have you looked at requireJS, which is not really needed if you are bundling everything but it does make your js files better documented as it makes the dependencies explicit
It's not supported, but you could come up with your own solution to this, right? Something like:
var jquery = new[] { "~/Content/scripts/jquery-{version}.js" };
var myScripts = jquery.Concat(new[] { "~/Content/scripts/myscript.js" }).ToArray();
var myOtherScripts = myScripts.Concat(new[] { "~/Content/scripts/otherscript.js").ToArray();
bundles.Add(new ScriptBundle("~/js/jquery").Include(jquery));
bundles.Add(new ScriptBundle("~/js/myscripts").Include(myScripts));
bundles.Add(new ScriptBundle("~/js/other").Include(myOtherScripts));
Seems like this is an unsupported feature, so I've reported an issue for it.