MVC Custom RouteHandler not firing for files - vb.net

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;

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 4 Areas not working properly

I have created a sample VB project in VS2010 to add Areas to the web UI but when I run it gives the following error:
The resource cannot be found. Description: HTTP 404. The resource you
are looking for (or one of its dependencies) could have been removed,
had its name changed, or is temporarily unavailable. Please review
the following URL and make sure that it is spelled correctly.
I also added AreaRegistration.RegisterAllAreas() to the global.asax file and also tried to manually register the route in the route.config but nothing is working.
routes.MapRoute( _
"Admin_default", _
"Admin/{controller}/{action}/{id}", _
New With {.action = "Index", .id = UrlParameter.Optional} _
)
It looks like it only finds the root views but not the Area specific view. Any ideas??
Found an answer on another site so posting the solution here:
The same project in C# works perfectly fine but fails in VB.
The reason: The controllers namespace is wrong in VB.net
Solution: Change the namespace of the controller in the vb project to MyApplication.Areas.MyArea.Controllers and then run it, will be fine.
Make sure you add AreaRegistration.RegisterAllAreas() as first line in Global.asax. Because areas should be registered before registering other routes.
Also in the route you mentioned, there is no default value for controller. So, make sure you provide controller value in url or provide default controller parameter in route.

make asp.net MVC 4 views compiled / give errors on compilation, not only on first access

I have a Asp.Net MVC 4 View (Razor), which includes a model like below:
#model Project.Models.TestModel
The problem is that if I go the project, and rename TestModel to TestModel2, and I click on rebuild project, no errors are given. If I open up the .cshtml file directly, then I do get the error there.
Can you enforce such errors to be given immediately at compile time?
Open *.Web.csproj file and change this:
<MvcBuildViews>false</MvcBuildViews>
to true

ASP.NET MVC 4 ScriptBundle returns empty

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);
}