:::: MENU ::::

Monday, July 25, 2016

Logging is a critical feature in any piece of software. Logging is really so boring but it is so important to have logging in place when starting a new solution, it will save you so much time and be a significant help in the investigation of the essence of problems. With ASP.NET Core 1.0, we don't need another third party library to log our application. It is out of the box! Since ASP.NET Core is modular so all we need is to install the following extension: 
Microsoft.Extensions.Logging
 
2016.07.22: Updated to ASP.NET Core RTM
It has been summarized in the following official documents of the fundamentals : . 
Around here, because I want to firmly understand before actually performing the development, I'm going try to touch one way. Because before you can use the examples Logging, it is necessary to add a service to the DI, you keep calling the AddLogging method. This ILoggerFactory and ILogger will be handled via the DI.
C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;

namespace EmptyWebApplication
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

            builder.AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddLogging();
        }

        public void Configure(IApplicationBuilder app,
                              IHostingEnvironment env,
                              ILoggerFactory loggerFactory)
        {
            var log = Configuration.GetSection("Logging");
            loggerFactory.AddConsole(log);
            loggerFactory.AddDebug();
        }
    }
}
We have carried out the additional provider for Configure : ILoggerFactory.
When made from templates, and providers to be output to the console, it has been added to the provider to be output to the debug window in Visual Studio. By implementing the ILoggerProvider, you can implement your own provider.
Providers that are provided by default are as follows.
  • Console
  • Debug
  • TraceSource
  • Windows EventLog
If you use Visual Studio and Azure Web Apps you might be good in about Console and Debug, but you might be better that had been taken into consideration also to implement the TraceSource and proprietary provider.
Logging of settings in the appsettings.json is something like the following, setting of LogLevel have been made to be output.
JSON
{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}
Making settings in the Startup class, rest if to receive the ILogger in the class such as a controller, it will be easier to make the logging.
If this does not specify the type parameters when, you must be careful because it is not resolved in the DI.
Because the type parameter is no problem if you specify the class to use the logger, I think the most simple controller will make you feel like following.
C#
public class HomeController : Controller
{
    public HomeController(ILogger logger)
    {
        _logger = logger;
    }

    private ILogger _logger;

    public IActionResult Index()
    {
        _logger.LogInformation("loulou");
        _logger.LogError("loulou");

        return View();
    }
}
Because for the ILogger it is prepared the extension method, so that it outputs a log with the appropriate LogLevel.
When you receive a ILoggerFactory instead ILogger in the constructor at this time, you can create any number of any ILogger.
C#
public class HomeController : Controller
{
    public HomeController(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger("HomeController");
    }

    private ILogger _logger;

    public IActionResult Index()
    {
        _logger.LogInformation("loulou");
        _logger.LogError("loulou");

        return View();
    }
}
When I do this, it is output log in the debug window in Visual Studio. Since the default setting of LogLevel that AddDebug outputs is a more Information, in the case of Trace / Debug not output.
When you start in the console, the log is filtered as the settings made in AddConsole is output.
The logging around to the other there is a function, such as Scope and EventId, but omitted because it is not an essential part of the logging. Function as a provider is poor by default, but because there is a scalable or combine the existing framework, I think that there is a need to take advantage of TraceListener.
Because we want as yourself go by pouring log in Azure EventHubs, I want to play and write the appropriate provider leveraging ILoggerProvider.

Thursday, July 21, 2016

Recently, a question was asked on Stack Overflow regarding how to go about extending an existing ASP.NET MVC Controller that was present within another assembly or project (i.e. external to the "main" MVC application), so I thought I would take a bit of time to cover how one might handle this scenario.

The Basic Idea

Let's say you have two projects :
  • ProjectA - Your main MVC application.
  • ProjectB - Just a simple class library.
What you want to do is extend an existing controller that is present in ProjectA with additional controller actions or functionality. These additional actions will not be present in your main application, but instead will come from a different project / assembly. This could be useful for implementing client-specific functionality (i.e. a client wants certain behavior that may not be relevant in the main application).
So for instance, your controller definition in ProjectA might look something like this:
namespace ProjectA.Controllers  
{
    // This is the primary controller that we want to extend
    public class FooController : ApplicationController
    {
          public ActionResult Index()
          {
              return Content("Foo");
          }
    }
}
And you might have a similar class in ProjectB that resembles this:
namespace ProjectB.Controllers  
{
    // You want to essentially add the Bar action to the existing controller
    public class CustomFooController : FooController
    {
        public ActionResult Bar()
        {
            return Content("Bar");
        }
    }
}
You want to allow all of the different clients to access Foo, but perhaps only a certain client to be exposed to Foo/Bar.

Breaking Down The Steps

This process requires a few different steps that will need to be done to get everything working as expected, which I'll review over below:
  1. Inheritance - The custom controller will inherit from the controller in our main application to streamline extension.
  2. Routing - Routing can be a tricky business, so using attribute routing might ease some of the burden of fighting with route tables or conflicting controller names.
  3. Build Events - Build events are just one simple approach to actually getting the necessary .dll files from your custom project into your main application so they can be used.

Taking Advantage of Inheritance

If you actually want to extend the functionality of an existing controller, then inheritance might be the way to go. Inheriting from the controller within your main application will allow you to take advantage of any existing attributes, overridden methods, or underlying base controllers that might already place.
You'll just want to add a reference to your ProjectA project in ProjectB and then target the appropriate controller you wish to inherit from:
// Other references omitted for brevity
using ProjectA.Controllers;

namespace ProjectB.Controllers  
{
    public class CustomFooController : FooController
    {
        public ActionResult Bar()
        {
            return Content("Bar");
        }
    }
}

Leverage Attribute Routing

Doing this kind of thing can get a bit dicey with regards to routing. When you attempt to create this new controller within your current application, it'll attempt to use the existing routes defined in that application, which can lead to naming conflicts and ambiguity if you aren't careful.
Based on the code provided, this means you could easily access /CustomFoo/Bar, but not /Foo/Bar like you might prefer. Thankfully, attribute routing can help with this.
Simply decorate your custom controller action with a [Route] attribute that indicates how you wish to access it :
[Route("Foo/Bar")]
public ActionResult Bar()  
{
     return new Content("Bar");
}
This will let MVC know to use map this action to the Foo/Bar URL before taking a look at some of the other routes. In order for attribute routing to work as expected, you'll need to ensure to call the MapMvcAttributeRoutes() method within the RouteConfig.cs file of your main application :
public static void RegisterRoutes(RouteCollection routes)  
{
    // This is important to write up your Route Attributes
    routes.MapMvcAttributeRoutes();

    // Route declarations omitted for brevity
}
Note: If you were extending a controller that was present within an MVC Area, you would do the same thing within the RegisterArea() method in your AreaRegistration.cs file :
public override void RegisterArea(AreaRegistrationContext context)  
{
    // Wire up any attribute based routing
    context.Routes.MapMvcAttributeRoutes();

    // Area routing omitted for brevity
}

Properly Scoping Routes

One additional change that will need to be made within your main application will be to prioritize routes within its own namespace. The MapRoute() method supports an overload to handle this via the namespaces parameter.
Set the namespaces parameter to point to the namespaces that you wish to prioritize, namely those in your main application (i.e. "ProjectA.Controllers").
routes.MapRoute(  
   name: "Default",
   url: "{controller}/{action}/{id}",
   defaults: new { controller = "Foo", action = "Index", id = UrlParameter.Optional },
   // This will prioritize routes within your main application
   namespaces: new[] { "ProjectA.Controllers"}
);

Putting It All Together

At this point, code-wise, everything should be in place. The only thing left to do is actually get the code from your ProjectB into ProjectA so that you can run it.
There are a variety of ways to handle this and configure this entire process, but a very simple one might be through a Build Event. Build Events allow you to execute a bit of code during various stages of the build process.
We are interested in defining a Post-Build event that will move our ProjectB.dll file into the bin directory of ProjectA, which might look like this :
xcopy /E /Y /S  "$(ProjectName).dll" "$(SolutionDir)\ProjectA\Bin\"
This would be defined under ProjectB > Properties > Build Events > Post-Build Event Command Line as seen below:
Now if you perform a Rebuild Solution, you should see that all of the proper files have been added to your bin directory as expected:
Now if you were to navigate to /Foo within your application, you would see the content that you might expect:
And likewise, /Foo/Bar should now hit your custom code and do exactly what you'd imagine: