European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET Hosting - HostForLIFE.eu :: jQuery PJAX Implementation In ASP.NET Core

clock February 26, 2019 11:15 by author Peter

PJAX is a jQuery plugin that uses AJAX and pushState to deliver a fast browsing experience with real permalinks, page titles, and a working back button. It is available to download from GitHub.

In all websites, the header and footer remain the same for all pages. Only the page contents (the content in the middle area between the header and footer) are changed for each page. PJAX uses this concept to fetch only the page contents while the header and footer remains the same for each page. In short, you can also say PJAX is the brother of the Update Panel of Web Forms that works for ASP.NET Core.

With PJAX, you get the following advantages.

    The website becomes fast since the header and footer are not loaded for different pages.
    You website behaves like a SPA (Single Page Application), and you don’t need to employ Angular framework in your ASP.NET Core Application.
    If you have worked with Update Panel of ASP.NET Web Forms then it is quite similar to it.

This is how PJAX will work.
See the below video which illustrates the working of PJAX.

PJAX Implementation in ASP.NET Core

Integration of PJAX in ASP.NET Core involves the following things.

Layout.cshtml View
In your application _Layout.cshml View, add jQuery and PJAX script links. You do this inside the head section:
    <script src="https://code.jquery.com/jquery-2.2.4.js"></script> 
    <script src="~/js/jquery.pjax.js"></script> 
    Also call PJAX on all anchors inside the #main element.  
    <script type="text/javascript"> 
        $(function () { 
            // call pjax 
            $(document).pjax('#menu li a', '#main', { timeout: 10000 }); 
     
        }); 
    </script> 


Loading Image
If you want to show the loading image when a new page contents are being fetched then add the following code inside the script section of Layout:
    $(document).ajaxStart(function () { 
        $("#loadingDiv").show(); 
    }); 
     
    $(document).ajaxComplete(function (event, jqxhr, settings) { 
        $("#loadingDiv").hide(); 
    }); 


Also, place the loading image somewhere in your layout.
    <div id="loadingDiv" style="display:none;"> 
        <img src="~/loading.gif" /> 
    </div> 


Do not worry as the source code contains all the loading image codes. Do check it.

Add some links to your _Layout.cshtml View. On these links, PJAX will work so when these links are clicked then their page’s contents are loaded by PJAX (but the header and footer area are not loaded).
    <ul> 
        <li><a href="/Home/Index">Index</a></li> 
        <li><a href="/Home/About">About</a></li> 
        <li><a href="/Home/Contact">Contact</a></li> 
    </ul> 


Don’t forget to add the #main element on the Layout so that PJAX only fetches the contents inside this #main element with AJAX.
    <div id="main"> 
        @RenderBody()  
    </div> 

Controller
Add a controller called Home with the following 3 action methods:

    public IActionResult Index() 
    { 
        if (string.IsNullOrEmpty(Request.Headers["X-PJAX"])) 
            return View(); 
        else 
            return PartialView("/Views/Home/Index.cshtml"); 
    } 
     
    public IActionResult About() 
    { 
        if (string.IsNullOrEmpty(Request.Headers["X-PJAX"])) 
            return View(); 
        else 
            return PartialView("/Views/Home/About.cshtml"); 
    } 
     
    public IActionResult Contact() 
    { 
        if (string.IsNullOrEmpty(Request.Headers["X-PJAX"])) 
            return View(); 
        else 
            return PartialView("/Views/Home/Contact.cshtml"); 
    }  


Make sure that the Action methods that are called by PJAX (i.e. clicking on menu links in my case) return PartialViews. Since PJAX sends ‘X-PJAX’ request in the HTTP Header therefore I can easily make a selection of View or Partial View by checking the HTTP header.

The condition applied in each action method that does this work is:
    if (string.IsNullOrEmpty(Request.Headers["X-PJAX"])) 
        return View(); 
    else 
        return PartialView("/Views/Home/Index.cshtml");  


Views

Add the 3 Views called ‘Index.cshtml’, ‘About.cshtml’ and ‘Contact.cshtml’ inside the ‘Views/Home’ folder:

Index.cshtml
    <div class="templatemo_content_area"> 
        <h1>WELCOME TO Index Page</h1> 
    </div> 


About.cshtml
    <div class="templatemo_content_area"> 
        <h1>WELCOME TO About Page</h1> 
    </div> 


Contact.cshtml
    <div class="templatemo_content_area"> 
        <h1>WELCOME TO Contact Page</h1> 
    </div> 


Also add _ViewStart.cshtml View inside the ‘Views’ folder:
    @{ 
        Layout = "_Layout"; 
    }



European ASP.NET Hosting :: Overriding ASP.NET Core Framework

clock February 20, 2019 10:57 by author Scott

OVERVIEW

In .NET it’s really easy to create your own interfaces and implementations. Likewise, it’s seemingly effortless to register them for dependency injection. But it is not always obvious how to override existing implementations. Let’s discuss various aspects of “dependency injection” and how you can override the “framework-provided services”.

As an example, let’s take a recent story on our product backlog for building a security audit of login attempts. The story involved the capture of attempted usernames along with their corresponding IP addresses. This would allow system administrators to monitor for potential attackers. This would require our ASP.NET Core application to have custom logging implemented.

LOGGING

Luckily ASP.NET Core Logging is simple to use and is a first-class citizen within ASP.NET Core.

In the Logging repository there is an extension method namely AddLogging, here is what it looks like:

public static IServiceCollection AddLogging(this IServiceCollection services)
{
    if (services == null)
    {
        throw new ArgumentNullException(nameof(services));
    }

    services.TryAdd(ServiceDescriptor.Singleton<ILoggerFactory, LoggerFactory>());
    services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>)));

    return services;
}

As you can see, it is rather simple. It adds two ServiceDescriptor instances to the IServiceCollection, effectively registering the given service type to the corresponding implementation type.

FOLLOWING THE RABBIT DOWN THE HOLE

When you create a new ASP.NET Core project from Visual Studio, all the templates follow the same pattern. They have the Program.cs file with a Main method that looks very similar to this:

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .UseStartup<Startup>()
        .UseApplicationInsights()
        .Build();

    host.Run();
}

TEMPLATES 

One thing that is concerning about a template like this is that the IWebHost is an IDisposable, so why then is this statement not wrapped in a using you ask? The answer is that the Run extension method internally wraps itself in a using. If you were wondering where the AddLogging occurs, it is a result of invoking the Build function.

[ Microsoft.AspNetCore.Hosting.WebHostBuilder ]
    public IWebHost Build() ...
        private IServiceCollection BuildCommonServices() ...
            creates services then invokes services.AddLogging()

A FEW WORDS ON THE SERVICE DESCRIPTOR

The ServiceDescriptor class is an object that describes a service, and this is used by dependency injection. In other words, instances of the ServiceDescriptor are descriptions of services. The ServiceDescriptor class exposes several static methods that allow its instantiation.

The ILoggerFactory interface is registered as a ServiceLifetime.Singleton and its implementation is mapped to the LoggerFactory. Likewise, the generic type typeof(ILogger<>) is mapped to typeof(Logger<>). This is just one of the several key “Framework-Provided Services” that are registered.

PUTTING IT TOGETHER

Now we know that the framework is providing all implementations of ILogger<T>, and resolving them as their Logger<T>. We also know that we could write our own implementation of the ILogger<T>interface. Being that this is open-source we can look to their implementation for inspiration.

public class RequestDetailLogger<T> : ILogger<T>
{
    private readonly ILogger _logger;

    public RequestDetailLogger(ILoggerFactory factory,
                               IRequestCategoryProvider requestCategoryProvider)
    {
        if (factory == null)
        {
            throw new ArgumentNullException(nameof(factory));
        }
        if (requestCategoryProvider == null)
        {
            throw new ArgumentNullException(nameof(requestCategoryProvider));
        }

        var category = requestDetailCategoryProvider.CreateCategory<T>();
        _logger = factory.CreateLogger(category);
    }

    IDisposable ILogger.BeginScope<TState>(TState state)
        => _logger.BeginScope(state);

    bool ILogger.IsEnabled(LogLevel logLevel)
        => _logger.IsEnabled(logLevel);

    void ILogger.Log<TState>(LogLevel logLevel,
                             EventId eventId,
                             TState state,
                             Exception exception,
                             Func<TState, Exception, string> formatter)
        => _logger.Log(logLevel, eventId, state, exception, formatter);
}

The IRequestCategoryProvider is defined and implemented as follows:

using static Microsoft.Extensions.Logging.Abstractions.Internal.TypeNameHelper;

public interface IRequestCategoryProvider
{
    string CreateCategory<T>();
}

public class RequestCategoryProvider : IRequestCategoryProvider
{
    private readonly IPrincipal _principal;
    private readonly IPAddress _ipAddress;

    public RequestCategoryProvider(IPrincipal principal,
                                   IPAddress ipAddress)
    {
        _principal = principal;
        _ipAddress = ipAddress;
    }

    public string CreateCategory<T>()
    {
        var typeDisplayName = GetTypeDisplayName(typeof(T));

        if (_principal == null || _ipAddress == null)
        {
            return typeDisplayName;
        }

        var username = _principal?.Identity?.Name;
        return $"User: {username}, IP: {_ipAddress} {typeDisplayName}";
    }
}

If you’re curious how to get the IPrincipal and IPAddress into this implementation (with DI). It is pretty straight-forward. In the Startup.ConfigureServices method do the following:

public void ConfigureServices(IServiceCollection services)
{
    // ... omitted for brevity

    services.AddTransient<IRequestCategoryProvider, RequestCategoryProvider>();
    services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
    services.AddTransient<IPrincipal>(
        provider => provider.GetService<IHttpContextAccessor>()
                           ?.HttpContext
                           ?.User);
    services.AddTransient<IPAddress>(
        provider => provider.GetService<IHttpContextAccessor>()
                           ?.HttpContext
                           ?.Connection
                           ?.RemoteIpAddress);
}

Finally, we can Replace the implementations for the ILogger<T> by using the following:

public void ConfigureServices(IServiceCollection services)
{
    // ... omitted for brevity
    services.Replace(ServiceDescriptor.Transient(typeof(ILogger<>),
                                                 typeof(RequestDetailLogger<>)));
}

Notice that we replace the framework-provided service as a ServiceLifetime.Transient. Opposed to the default ServiceLifetime.Singleton. This is more or less an extra precaution. We know that with each request we get the HttpContext from the IHttpContextAccessor, and from this we have the User. This is what is passed to each ILogger<T>.

CONCLUSION

This approach is valid for overriding any of the various framework-provided service implementations. It is simply a matter of knowing the correct ServiceLifetime for your specific needs. Likewise, it is a good idea to leverage the open-source libraries of the framework for inspiration. With this you can take finite control of your web-stack.



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in