Friday, February 16, 2018

All About Appsettings.json in ASP.NET Core 2.0

As most of you are aware that in ASP.Net Core, we don't have anything called Web.Config, where we use to write our connection strings or application specific settings. Rather, here we have the file named appsettings.json to store similar sort of information. There are few very common use cases where we need to maintain multiple appsettings.json file in a single solution. For example:
  • Multiple application settings per application - When we need to maintain different-different application specific settings based on the application environment. Say, one can have one type of application settings for Development, another type of application settings for Production, another one for Staging, and so on. Needless to mention, all the appsettings file will have different names.
  • To implement inheritance – If there are some common settings between multiple application settings file, in that case developer can come up with a base application settings file and on top of that specific file can be created. In that case, common information need not to be repeated in all the files.
If you are aware about the ASP.NET Core architecture, then you must agree on the point that, such scenarios can also be handled very easily in the ASP.Net Core as plugging multiple sources is very straight forward.
So, coming to the point. My this article is all about how to inherit or say read data from appsettings.json file which is outside my project. This scenario usually comes into the picture, when we are maintaining different project for holding all the shared resources, that has to be consumed across many projects in a given solution file. So, in the real world, one project can have its project specific settings as well as some common (or say global) settings which is placed outside its boundary.
Let me first tell something about my project structure. Here goes my solution structure:





















As you can see in the above figure that 'CommonSettings.json' is the file which is kept outside of the main project named 'AllAboutConfigurations' and here is how my both the JSON files look like:

appsettings.json:

{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" }
},
"MySettings": { "PersonalizedSettings": " It's just for me" }
}


CommonSettings.json:
{
  "MySettings": { "CommonSettings": "Hi, I'm common setting. Anyone can use me." }
}       
 
Now in order to read 'CommonSettings.json' in 'AllAboutConfigurations' project, I have to update the application configuration while constructing the web host as shown below:
 public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((webHostBuilderContext, configurationbuilder) =>
                {
                    var environment = webHostBuilderContext.HostingEnvironment;
                    string pathOfCommonSettingsFile = Path.Combine(environment.ContentRootPath,"..","Common");
                    configurationbuilder
                            .AddJsonFile("appSettings.json", optional: true)
                            .AddJsonFile(Path.Combine(pathOfCommonSettingsFile, "CommonSettings.json"), optional: true);

                    configurationbuilder.AddEnvironmentVariables();
                })
                .UseStartup()
                .Build();

Now if we want to see something on our web page, we have to update UI code too. Let's make it simple with just few lines of code as shown below:
@using Microsoft.Extensions.Configuration; @inject IConfiguration configuration; @{ Layout = null; }
<html> <head>         <title>Settings</title> </head> <body>     Personalized Settings: @configuration.GetSection("MySettings")["PersonalizedSettings"]<br />
    Common Settings: @configuration.GetSection("MySettings")["CommonSettings"]<br />
</body> </html>  

Now if you will run your application, you will be able to see that both the settings are considered as part of single project.











Happy Learning!

Tuesday, February 13, 2018

Application Initialization and Configuration in ASP.Net Versions

Most of us might have worked upon various versions of ASP.NET and few of you must be aware about the major changes happened in application initialization and configuration phase. In this article, I'll be outlining few of those major changes starting from ASP.NET MVC, ASP.NET Core 1.x and ASP.NET 2.x.
In ASP.NET:
In an era of ASP.NET (prior to ASP.NET Core releases), loading of the application was handled by IIS or say Inetmgr was the one who use to call web application's entry point wherein Global.asax.cs use to provide the Application_Start()method.Below is the sample code snippet take from Global.asax.cx file:

       public class MvcApplication : System.Web.HttpApplication   {        protected void Application_Start()        {               AreaRegistration.RegisterAllAreas();               FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);               RouteConfig.RegisterRoutes(RouteTable.Routes);               BundleConfig.RegisterBundles(BundleTable.Bundles);         }  
}

In ASP.NET Core 1.x:
Moving on to ASP.NET Core, Global.asax.cs doesn't exusts anymore as the applicaiton initialization process itself has changed a lot. In case of Core, almost all the application initialization and configuration related changed are tale care by two important files named Program.cs and Startup.cs.

Program.cs - This file takes care of web hosting part. Below is the sample code snippet:
public class Program   {           public static void Main(string[] args)           {               var host = new WebHostBuilder()                   .UseKestrel()                   .UseContentRoot(Directory.GetCurrentDirectory())                   .UseIISIntegration()                   .UseStartup<Startup>()                   .Build();                  host.Run();           }  
}

Startup.cs -  This file takes care of dependency injection and configuration related stuff. Below is the sample code snippet:
public class Startup   {           public Startup()           {           }                // This method gets called by the runtime. Use this method to add services to the container.                  public void ConfigureServices(IServiceCollection services)           {               services.AddMvc();               services.AddScoped<IStudentRepository, StudentRepository>();               services.AddDbContext<ApplicationDbContext>          (c=>c.UserSqlServer(Configuraiton.GetConnectionString("PrimaryConnection")));
        }              // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.           public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)           {               loggerFactory.AddConsole();               if (env.IsDevelopment())               {                   app.UseDeveloperExceptionPage();               }                                 app.UseMvc(configureRoutes);               app.Run(async (context) =>               {                   await context.Response.WriteAsync("Hi There!");               });           }              private void configureRoutes(IRouteBuilder routeBuilder)           {                        }   }         

In ASP.NET Core 2.x:
In this version, application initialization and configuration still evolves around these two files named Startup.cs and Program.cs but in much more simplified and with reduced lines of code. Let's have a look at this new Program.cs file:
public class Program   {       public static void Main(string[] args)       {             BuildWebHost(args).Run();       }     
    public static IWebHost BuildWebHost(string[] args) =>               WebHost.CreateDefaultBuilder(args)                   .UseStartup<Startup>()                   .Build();   }   

If you will notice above snippet, it would look very compact. Just three lines, isn't it? Where that entire configuration went which we use to specify in Core 1.x? 

Well, that entire thing is wrapped up in single line via CreateDefaultBuilder method. This method has hide lot many things in itself as: 
- configured the Kestrel along with integration with IIS
- set the current project directory as the root content 
- configured the logging system to make it read from appsettings.json file
- configured reading of environment variables from  appsettings.json file, etc.

Isn't it a cleaner way? 
Happy learning!  

Thursday, February 8, 2018

Tip on MVC URL Routing

Recently, one of my colleague asked me a question, in which his routing was not working as expected. Let me mention the exact URL he was giving:

URL 1:
http://localhost:port/StudentEnquiries/StudentEnquiries/44

URL 2:
http://localhost:port/StudentEnquiries/StudentEnquiries/?StudentID=44 

And his code snippet was as below:
      
    public class RouteConfig 
    { 
        public static void RegisterRoutes(RouteCollection routes) 
        { 
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
            routes.MapRoute( 
                name: "Default", 
                url: "{controller}/{action}/{id}", 
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
            ); 
        } 
    }    

Where he claimed that he didn’t change anything in his Route.Config file and his Controller looks something like this:
  public ActionResult StudentEnquiries(string StudentID) 
  { 
        return Content(StudentID); 
  }     

Now his question was, when he is giving URL 1, he is not getting the expected output, which is 44 whereas in URL 2 everything was working as expected.
Problem statement looks very straightforward. Any guesses, what went wrong with his code?
I’m sure most of you might have already figured out the solution. But for the sake of rest of the readers, I’ll elaborate more on it.
The route mentioned in Route.Config file outlines variables in the URL and the action parameter maps those URL variables to input parameters.


So, basically id has to be replaced with StudentId in routing parameter and we are done.
Hope you enjoyed this small tip. Happy troubleshooting.