How can we enable caching for Bundles in MVC5 - asp.net-mvc-4

I have created 2 bundles in my mvc project as given below:
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/Scripts/BaseScripts").Include(
"~/Content/js/jquery-{version}.js",
"~/Content/js/jquery-ui-{version}.js",
"~/Scripts/jquery.unobtrusive-ajax.min.js",
"~/Content/js/bootstrap.js",
"~/Content/js/bootstrap-datepicker.js",
"~/Scripts/jquery.validate.min.js",
"~/Scripts/jquery.validate.unobtrusive.js",
"~/Scripts/customvalidation.js"
)
);
bundles.Add(new ScriptBundle("~/Scripts/CustomScripts").Include(
"~/Content/js/customscripts/commonscript.js",
"~/Content/js/customscripts/registration.js"
));
bundles.Add(new StyleBundle("~/Styles/Css").Include(
"~/Content/css/bootstrap.min.css",
"~/Content/css/ymobiz.css",
"~/Content/css/Style.css",
"~/Content/css/datepicker3.css",
"~/Content/font-awesome-4.1.0/css/font-awesome.min.css",
"~/Content/css/css.css"
));
//To enable bundling and minification
BundleTable.EnableOptimizations = true;
}
Now i need to enable caching for these files as well. Is there any way by which we can control caching duration for these bundles files

MVC bundles are returned as a single static file to browsers whose cache time is set to 1 year by default. ASP.NET MVC takes care of change tracking of your bundle files and changes bundle url if content of any file is changed or a file is being added / removed from bundle.
As bundles are already cached and change tracking is maintained by asp.net mvc framework, what else cache control do you want on those bundles?
EDIT (in response to comment)
Unfortunately you can not alter that limit. Cache limit is handles by ProcessRequest method of BundleHandler class and this is internal sealed so there is no chance that you can inherit \ override these requests.
For further details you can refer this question.

Add a key in webconfig
<appSettings>
<add key="Version" value="sa291988" />
</appSettings>
Create a class, where we define the format for both JavaScript and styles.
using System.Configuration;
namespace BundlingSample
{
public class SiteKeys {
public static string StyleVersion {
get {
return "<link href=\"{0}?v=" +
ConfigurationManager.AppSettings["version"] + "\" rel=\"stylesheet\"/>";
}
}
public static string ScriptVersion {
get {
return "<script src=\"{0}?v=" +
ConfigurationManager.AppSettings["version"] + "\"></script>";
}
}
}
}
#Styles.RenderFormat(SiteKeys.StyleVersion,"~/Content/css")
#Scripts.RenderFormat(SiteKeys.ScriptVersion,"~/bundles/jquery")

Related

Force the usage of a bin folder

I have a larger ASP.NET Core project which means that a lot of DLLs are included in the publish.
Since all of the DLLs are placed in the root folder it's cumbersome to navigate the folder structure (to mange configs etc) due to the sheer amount of files.
Is it possible to tell ASP.NET Core that it should load all assemblies from another folder (bin\)?
I would do it in opposite side. If your problem is just config files then relocate them into config folder and keep them there. As of now dotnet will publish your project + framework (if you use self contained flag).
You can configure aspnetcore to use files
config.AddJsonFile("config/appsettings.json", optional: false, reloadOnChange: false);
So then that folder will be on top and better accessible
Yes in root folder there still be web.config but in my project that file usually is same for all environments. But again it depends where you deploy, because if you deploy to non IIS environment then you don't even need it
Hi How about the Managed Extensibility Framework , It allows you load assemblies dynamically.
Use BuildManager to load assemblies dynamically,
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
foreach (string f in Directory.GetDirectories(pluginPath))
{
string binPath = Path.Combine(f, "bin");
if (Directory.Exists(binPath))
{
foreach (String file in Directory.GetFiles(binPath, "*.dll"))
{
Assembly a = Assembly.LoadFrom(file);
BuildManager.AddReferencedAssembly(a);
}
}
Resolve assemblies using below code,
protected virtual void Application_Start(object sender, EventArgs e)
{
//...
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in currentAssemblies)
{
if (assembly.FullName == args.Name || assembly.GetName().Name == args.Name)
{
return assembly;
}
}
return null;
}

EF Core in class library and use from API project - How to pass config information to class library?

Ive setup a solution with a .net core class library project and an asp.net core web api project. To use my class library I added the interface via ConfigureServices, where DataRepo is a class in the class library.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IDataRepo, DataRepo>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
This class library needs to get the environment-specific connection string that will be in the API project file appsettings.json. How can I pass config settings over to it? Also, I wan to add an EF core datamodel in the library project and Id rather not register a DbContext with the API project, but rather in the constructor of my library, use the connection info to pass along with the config in the DbContext. First things first, How can I get the config settings from the appsettings.json to my class library?
namespace DataLib
{
public class DataRepo : IDataRepo
{
public DataRepo()
{
}
public string GetHello()
{
return "hello from lib";
}
}
}
If your class needs a connection string, then simply give it the connection string. You can utilize the overload for AddScoped that takes an Action<T>.
First, add a constructor that takes your connection string:
public class DataRepo : IDataRepo
{
private readonly string _connectionString;
public DataRepo(string connectionString)
{
_connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
}
}
Then, in Startup.cs:
services.AddScoped<IDataRepo>(p => new DataRepo(Configuration.GetConnectionString("Foo")));
Your class should not know or care where the connection string actually comes from, which is why other approaches, such as injecting IConfiguration are wrong here.
If you only wants to share configuration between a lib project and a website project , you'd better use dependency injection to do that .
A lib project should not care about the location of the configuration file . Anytime we need a configuration in our lib project , let's say a ConnectionString , we should just ask for it .
The first to do is to add a package reference in the lib project :
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.1" />
And then inject an IConfiguration when we need it . For example , we should have a IConfiguration object injected in DataLib:
namespace DataLib
{
public class DataLib: IDataRepo
{
private readonly IConfiguration _configuration ;
public DataLib(IConfiguration config ){
this._configuration=config;
}
public string ConnectionString{
get{
return _configuration.GetConnectionString("DefaultConnection");
}
}
}
}
The IConfiguration doesn't care where is the configuration file or which kinds of arguments are passed by command-line when started . Actually , it doesn't care about anything . The DataLib just uses a simple POCO .
When we need the class lib in main project , we can simply add the service to DI container by :
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddScoped<DataLib.DataLib>(); // if you want to use DbContext , just use AddScoped<TService>()
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
That's all we have to do . The appsettings.json and other configurations will be built into an instance of IConfiguration and then be injected to the lib project automatically.
There're also other solutions , such as using linked files and so on . However , the approach above keeps the DataLib a plain POCO . This is great . As a lib is always used by a main project , we don't need to care about the configuration or how it is created . The main project will take care of it .

Override razor views in asp.net core razor pages

In asp.net core mvc, I had multiple locations specified for the views. so, if view was missing in one location, it gets fetched from the other location.
I have a CMS with asp.net core mvc where controllers and views comes in a compiled library. If I don't want to use the view from the library, it's easy to add a new one e.g. /Views/ControllerName/Index.cshtml and then the application will use this view instead of fetching from the library.
How can it be done in razor pages? Basically, I want to have an option to override the razor view of any page by adding a .cshtml file in a location.
Use an IViewLocationExpander, adding your custom location(s) before the default ones.
Here's an example that would look into an "Override" folder:
public class MyViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(
ViewLocationExpanderContext context,
IEnumerable<string> viewLocations)
{
// {2} = Area
// {1} = Controller
// {0} = Action
var locations = new string[] { "/Views/Override/{2}/{1}/{0}.cshtml" };
return locations.Union(viewLocations);
}
public void PopulateValues(ViewLocationExpanderContext context)
{
}
}
Then register it in your Startup class:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new MyViewLocationExpander());
});
}
I didn't get this to work in ASP.NET Core 2.2 using the other solutions suggested here (IViewLocationExpander or PageViewLocationFormats). What worked for me was using a PageRouteModelConvention in combination with an ActionConstraint.
Here's a similar solution where this has been used for localization:
PageRouteModelConvention and ActionConstraint
Configuration in Startup

How to get compile time errors in views using ASP.NET CORE

How can we get compile time errors in views and view components in Mvc6?
In MVC 5, it was simple to edit the .csproj file. How do we do it now?
Answer for RC-1
Create the following RazorPreCompilation class:
namespace YourApp.Compiler.Preprocess
{
public sealed class RazorPreCompilation : RazorPreCompileModule
{
protected override bool EnablePreCompilation(BeforeCompileContext context) => true;
}
}
Places this class in {root}/Compiler/Preprocess.
Add a call to AddPrecompiledRazorViews in your ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
// ... other code ...
services
.AddMvc()
.AddPrecompiledRazorViews(GetType().GetTypeInfo().Assembly);
// ... other code ...
}
As noted in other answers, when views are precompiled you lose the ability to change them while the application is running. Additionally, it seems that sometimes you have to do a rebuild on your project (as opposed to just a build) in order for new code changes to take effect. For example, correcting a typo in a Razor method call may still trigger a compilation error until you rebuild the project.
Update on Directives
If you'd like to have this run with preprocess directives, wrap them around the AddPrecompiledRazorViews call like this:
public void ConfigureServices(IServiceCollection services)
{
// ... other code ...
var mvcBuilder = services.AddMvc()
#if !DEBUG
mvcBuilder.AddPrecompiledRazorViews(GetType().GetTypeInfo().Assembly);
#endif
// ... other code ...
}
You can use pre-compiled views by adding the following class to your project. However, doing this stops you from being able to edit the views at runtime. Therefore, I have added the #if !DEBUG pre-processor directive so that the views are only pre-compiled in release mode.
#if !DEBUG
namespace MvcBoilerplate.Compiler.Preprocess
{
using System;
using Microsoft.AspNet.Mvc;
/// <summary>
/// Enable pre-compilation of Razor views, so that errors in your .cshtml files are caught and displayed
/// in the Visual Studio errors window at compile time, rather than your sites users receiving a runtime 500
/// internal server error. Pre-compilation may reduce the time it takes to build and launch your project but will
/// cause the build time to increase. It will also stop edit and continue working for .cshtml files.
/// </summary>
public class RazorPreCompilation : RazorPreCompileModule
{
}
}
#endif
Secondly, in Startup.cs you need to actually use the pre-compiled views which you can do like so:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddPrecompiledRazorViews(GetType().GetTypeInfo().Assembly);
}
Pre-compiled views give quicker application startup performance.
You must add a class
public class RazorPreCompilation : RazorPreCompileModule
{
public RazorPreCompilation(IServiceProvider provider) : base(provider)
{
this.GenerateSymbols = true;
}
}
and Add AddPrecompiledRazorViews to your mvc setup in your startup class
see this question

Use of AuthConfig, BundleConfig, FilterConfig , RouteConfig and WebApiConfig in App_Start() folder in MVC

Can you please explain in detail, the use of App_Start() folder in MVC4?
I see that this folder is actually not available in previous versions of MVC.
There are 5 files in this folder.
AuthConfig
BundleConfig,
FilterConfig,
RouteConfig,
WebApiConfig.
App_Start is just another folder that groups together ASP.NET MVC configuration, which in previous versions of ASP.NET MVC was done in Global.asax.
ASP.NET MVC introduces more and more configuration elements, and this folder is ideal to place this configuration. For example, MVC 5's new auth. configuration, such as for third-party login providers, are also placed within this folder (in Startup.Auth.cs).
App_Start is not a ASP.NET special folder recognized by ASP.NET/IIS. You can rename the folder if you want. The name is just a convention, like App_GlobalResouces etc.
Update:
Below are some information and reference points for each file. The use of these files are pretty straightforward. I have included few online references that might help your to understand more.
AuthConfig — registers external authentication providers.
See ASP.NET MVC external authentication providers for more information.
BundleConfig — registers your CSS and JS so they can be bundled and minified. See also ASP.NET MVC: Guidance: Bundling and Minification.
WebApiConfig — only applicable if you are using Web API. It can be used to configure Web API-specific routes, any Web API settings and Web API services. See also configuring ASP.NET MVC Web API 2
FilterConfig — registered global filters. These filters are applied to all actions and controllers. See also ASP.NET MVC 3: Global action filters
RouteConfig — you already found information.
App_start folder has been introduced in Mvc4. It contains various configurations files like:
BundleConnfig.cs
FilterConfig.cs
RouteConfig.cs
WebApiConfig.cs
AuthConfig.cs
App_start is not a special folder in MVC nor the class files inside this, these are just normal class files with different application
configurations(filtering, bundling, routing etc.) and all these settings gets registered within Application_Start method of Global.asax.cs file.
BundleConfig.cs:
This is used to create and register bundles for CSS and JS files. for
eg. jQuery,jQueryUI,jQuery validation,Modernizr and Site CSS..
Bundling and minification are two techniques to improve request load time by
reducing the number of requests to the server and reducing the size of
requested assets (such as CSS and JavaScript.)
Microsoft provides assembly Microsoft.Web.Optimization for the same
for eg.
Lets create two Bundles. one for style(css) and another for script(javascript)
You can create bundle for css and javascripts respectively by calling
BundleCollection class Add() method within BundleConfig.cs file.
STEP 1:
Creating Style Bundle
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
"~/Content/mystyle.min.css"));
Creating Script Bundle
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery-1.7.1.min.js",
"~/Scripts/jquery.validate.min.js"));
STEP 2:
Above bundles are defined in BundleConfig class as:
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
//Adding StyleBundle to BundleCollection
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
"~/Content/mystyle.min.css"));
//Adding ScriptBundle to BundleCollection
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery-1.7.1.min.js",
"~/Scripts/jquery.validate.min.js"));
}
}
STEP 3:
Registering Bundle
All bundles are registered in the Application_Start event of Global.asax:
protected void Application_Start()
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Minification is a technique for removing unnecessary characters (like
white space, newline, tab) and comments from the JavaScript and CSS
files to reduce the size, in turn improve load time of a web page. for
eg. jquery-1.7.1.min.js is the minified js file for jquery-1.7.1,
mostly used for production environment, for non-prod you can better use non-
minified js to have better readability.
for eg.
A Jquery function in uncompressed js may look something like:
( function( global, factory ) {
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
// For CommonJS and CommonJS-like environments where a proper `window`
// is present, execute the factory and get jQuery.
// For environments that do not have a `window` with a `document`
// (such as Node.js), expose a factory as module.exports.
// This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
// See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
same above function in compressed or minified js will look like:
!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}
FilterConfig.cs:
This is used to create and register global MVC filter:
for eg.
Authentication filters (Executed First)
Authorization filters
Action filters
Result filters
Exception filters (Executed Last)
Note: As mentioned above Filters are executed in an order.
for eg. Authentication Filters introduced with MVC5:
public interface IAuthenticationFilter
{
void OnAuthentication(AuthenticationContext filterContext);
void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
}
You can create your CustomAuthentication filter attribute by implementing
IAuthenticationFilter as shown below-
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
//logic goes here
}
Runs after the OnAuthentication method
public void OnAuthenticationChallenge(AuthenticationChallengeContext
filterContext)
{
{
//logic goes here
}
}
Configuring Filters
You can configure your own custom filter into your application at
following three levels:
Global level
By registering your filter into Application_Start event of
Global.asax.cs file:
protected void Application_Start()
{
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
Controller level
By putting your filter on the top of the controller name:
[Authorize(Roles="Admin")]
public class AdminController : Controller
{
// Logic goes here
}
Action level
By putting your filter on the top of the action name:
public class UserController : Controller
{
[Authorize(Users="User1,User2")]
public ActionResult LinkLogin(string provider)
{
// Logic goes here
return View();
}
}
RouteConfig.cs:
This is used to register various route patterns for your Asp.Net MVC
application. Routing plays an important role in an ASP.NET MVC Application
execution flow, it maps request URL to a specific controller action using a
Routing Table. We can define Routing Rules for the engine, so that it can map > incoming URLs to appropriate controller. Routing Engine uses routing rules
that are defined in Global.asax file in order to parse the URL and find out
the path of corresponding controller. We can find the following piece of code > in Application_Start() method of Global.asax file.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
We can find RouteConfig.cs file under App_Start folder. If we follow
this method in RouteConfig class, we will find one default configured
route as follows. Line 3 to 7 is configuring one default route.
public static void RegisterRoutes(RouteCollection routes)
{
1. routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);
2.
3. routes.MapRoute(
4. name: “Default”,
5. url: “{controller}/{action}/{id}”,
6. defaults: new { controller = “Home”, action = “Index”, id = UrlParameter.Optional }
7. );
}
Line 4 : Name for the route. Line 5 : represent URL : Controller,
action followed by id (if any). Line 6 : default controller will be
Home, default action will be Index and Id is optional.
WebApiConfig.cs:
This is used to register various WEB API routes like as Asp.Net MVC, as well as set any addtional WEB API configurations settings.
AuthConfig.cs:
Used to register external authentication providers
for eg. if you want to enable users to log in with credentials from an external provider, such as Facebook, Twitter, Microsoft, or Google, and then integrate some of the functionality from those providers into your web application.
App_start folder has been introduced in Mvc4. It contains various configurations files like as :
BundleConnfig.cs,
FilterConfig.cs,
RouteConfig.cs,
WebApiConfig.cs
for you application.All those settings are registered within App_Start method of Global.asax.cs file
BundleConfig.cs:
This is used to create and register bundles for CS and JS files.By default various bundles are added in this file including jQuery,jQueryUI,jQuery validation,Modernizer and Site Css..
FilterConfig.cs-
This is used to create and register global MVC filter error filter,action filter etc.By default it contains HandleErrorAttribute filter.
RouteConfig.cs-
This is used to register various route patterns for your Asp.Net MVC application. By default,one route is registered here named as Default Route.
WebApiConfig.cs-
This is used to register various WEB API routes like as Asp.Net MVC,as well as set any additional WEB API configurations settings.
In the previous versions of MVC, we just have RegisterRoutes() method in global.asax file to configure the routing. MVC 4 has built in templates to develop mobile web applications, web apis(restful http services).so to configure the routings for all those template driven development ,we will be using the
AuthConfig.cs(Authorization),BundleConfig.cs(web potimization),,FilterConfig.cs,RouteConfig.cs,WebApiConfig.cs(WEB API) files and they will be mainteained in App_start folder.
Lets have a look at each those config.cs files.
AuthConfig.cs - settings in this file allows you to login to ASP.NET MVC site using third party client credentials like fb account,google account,yahoo account etc..or you can register also.
BundleConfig.cs: settings in this file allows to improve the performance of an applications using bundling...
WebApiConfig: sets the routing settings for WEB API (Note:No action needed in url)
AuthConfi g.cs: Used to confi gure security settings, including sites for OAuth login.
BundleConfi g.cs: Used to register bundles used by the bundling and minifi cation
system. Several bundles are added by default, including jQuery, jQueryUI, jQuery
validation, Modernizr, and default CSS references.
FilterConfi g.cs: Unsurprisingly, this is used to register global MVC fi lters. The only
fi lter registered by default is the HandleErrorAttribute, but this is a great place to put
other fi lter registrations.
RouteConfi g.cs: Holds the granddaddy of the MVC confi g statements, Route confi
guration.
WebApiConfi g.cs: Used to register Web API routes, as well as set any additional Web
API confi guration settings.
All those settings are registered within the App_Start method of Global.asax.cs file
BundleConfig.cs:
This is used to create and register bundles for CS and JS files that we have in the template.
FilterConfig.cs-
This is used to create and register global MVC filter error filter
RouteConfig.cs-
This is used to register various route patterns for your Asp.Net MVC application.
WebApiConfig.cs-
This is used to register various WEB API routes like want login with credentials from an external provider, such as Facebook, Twitter, Microsoft, or Google,