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 Core Hosting :: How to Create a Multi Tenant .NET Core Application

clock January 21, 2020 07:30 by author Scott

Introduction

In the final installment we will extend our multi-tenant solution to allow each tenant to have different ASP.NET Identity providers configured. This will allow each tenant to have different external identiy providers or different clients for the same identity provider.

This is important to allow consent screens on third party services reflect the branding of the particular tenant that the user is signing in to.

Tenant specific authentication features

In this post we will enable three features

Allow different tenants to configure different authentication options

This is useful if different tenants want to allow different ways of signing in, e.g. one tenant might want to allow Facebook and Instagram while another wants local logins only.

Make sure each tenant has their own authentication cookies

This is useful if tenants are sharing a domain, you don’t want the cookies of one tenant signing you in to all tenants.

Note: If you follow this post your tenants will be sharing decryption keys so one tenant’s cookie is a valid ticket on another tenant. Someone could send one tenant’s cookie to a second tenant, you will need to either also include a tenant Id claim or extend this further to have seperate keys to verify the cookie supplied is intended for the tenant.

Allow different tenants to use different configured clients on an external identity provider

With platforms such as Facebook if it’s the first time the user is signing in they will often be asked to grant access to the application for their account, it’s importannt that this grant access screen mentions the tenant that is requesting access. Otherwise the user might get confused and deny access if it’s from a shared app with a generic name.

Implementation

There are 3 main steps to our solution

1. Register the services depending on your tenant: Configure the authentication services depending on which tenant is in scope

2. Support dynamic registration of schemes: Move the scheme provider to be fetched at request time to reflect the current tenant context

3. Add an application builder extension: Make it nice for developers to enable the feature

This implementation is only compatible with ASP.NET Core 2.X. In 1.0 the Authentication was defined in the pipeline so you could use branching to configure services on a per-tenant basis, however this is no longer possible. The approach we’ve taken is to use our tenant specific container to register the different schemes/ options for each tenant.

This post on GitHub outlines all of the changes between 1.0 and 2.0.

1. Register the services depending on your tenant

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    ...

    return services.UseMultiTenantServiceProvider<Tenant>((t, c) =>
    {
        //Create a new service collection and register all services
        ServiceCollection tenantServices = new ServiceCollection();       

        var builder = tenantServices.AddAuthentication(o =>
            {
                //Support tenant specific schemes
                o.DefaultScheme = $"{t.Id}-{IdentityConstants.ApplicationScheme}";
            }).AddCookie($"{t.Id}-{IdentityConstants.ApplicationScheme}", o =>
            {
                ...
            });

        //Optionally add different handlers based on tenant
        if (t.FacebookEnabled)
                builder.AddFacebook(o => {
                    o.ClientId = t.FacebookClientId;
                    o.ClientSecret = t.FacebookSecret; });

        //Add services to the container
        c.Populate(tenantServices);

        ...
    });
}

Seems too easy right? It is. If you run it now your handlers aren’t registered using the default “.UseAuthentication” middleware. The schemes are registered in the middleware constructor before you have a valid tenant context. Since it doesn’t support registering schemes dynamically OOTB we will need to slightly modify it.

2. Update the authentication middleware to support dynamic registration of schemes

Disclaimer ahead! The ASP.NET framework was written by very smart people so I get super nervous about making any changes here - I’ve tried to limit the change but there could be unintended consequences! Proceed with caution

We’re going to take the existing middleware and just move the IAuthenticationSchemeProvider injection point from the constructor to the Invoke method. Since the invoke method is called after we’ve registered our tenant services it will have all the tenant specific authentication services available to it now.

/// <summary>
/// AuthenticationMiddleware.cs from framework with injection point moved
/// </summary>
public class TenantAuthMiddleware
{
    private readonly RequestDelegate _next;

    public TenantAuthMiddleware(RequestDelegate next)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
    }  

    public async Task Invoke(HttpContext context, IAuthenticationSchemeProvider Schemes)
    {
        context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
        {
            OriginalPath = context.Request.Path,
            OriginalPathBase = context.Request.PathBase
        });

        // Give any IAuthenticationRequestHandler schemes a chance to handle the request
        var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
        foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
        {
            var handler = await handlers.GetHandlerAsync(context, scheme.Name)
                as IAuthenticationRequestHandler;
            if (handler != null && await handler.HandleRequestAsync())
            {
                return;
            }
        }

        var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
        if (defaultAuthenticate != null)
        {
            var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
            if (result?.Principal != null)
            {
                context.User = result.Principal;
            }
        }       

        await _next(context);
    }
}

3. Add an application builder extension to register our slightly modified authentication middleware

This provides a nice way for the developer to quickly register the tenant aware authentication middleware

/// <summary>
/// Use the Teanant Auth to process the authentication handlers
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseMultiTenantAuthentication(this IApplicationBuilder builder)
    => builder.UseMiddleware<TenantAuthMiddleware>();

Now we can register the tenant aware authenticaion middleware like this

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...

    app.UseMultiTenancy()
        .UseMultiTenantContainer()
        .UseMultiTenantAuthentication();
}

Wrapping up

In this post we looked at how we can upgrade ASP.NET Core to support tenant specifc authentication, this means each tenant can have different external identify providers registered and connect to different clients for each of those providers.



European ASP.NET Core Hosting :: JWT Token Authentication

clock December 17, 2019 11:29 by author Peter

In web applications, security is essential. Say that the user wants to use the resources of our system. For that, we need to authenticate the user. Authentication means need to check whether the user is eligible to use the system or not. Generally, we do authentication via username (in the form of a unique user name or email ID) and a password. If the user is authenticated successfully, then we allow that user to use the resources of our system. But what about subsequent requests? If the user has been already identified then s/he does not need to provide credentials each time. Once authenticated, for a particular period s/he can use the system's resources. In a traditional approach, we used to save Username in Session. This session period is configurable, which means the session is valid for about 15 or 20 minutes. This session is stored in server's memory. After expiration of the session, the user needs to login again.

But here, there are couple of problems.

  1. The session can be hijacked.
  2. If we have multiple instances of server with load balancer, then if the request goes to a server other than the server which has authenticated the earlier request, then it will invalidate that session. Because the session is not distributed among all the servers, we have to use a 'Sticky' session; that is we need to send each subsequent request to the same server only. Here, we can also store session in database instead of the server's memory. In that case, we need to query the database each time, and that's extra work which may increase the overall latency.

To solve this problem, we can do authentication via JWT i.e. JSON web token. After successful authentication, the server will generate a security token and send it back to the client. This token can be generated using a symmetric key algorithm or an asymmetric key algorithm. On each subsequent request after a successful login, the client will send a generated token back to the server. The server will check whether the sent token is valid or not and also checks whether its expired or not. The client will send this token in Authentication Bearer header.

JWT token has a particular format. Header, Payload, and Signature.

  1. Header
    - We need to specify which token system we want to use and also need to specify the algorithm type.
  2. Payload
    - This is a token body. Basically, it contains expiry detail, claims details, issuer detail, etc.
  3. Signature
    - To create the signature part we have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

E.g. HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Benefits of using JWT

  1. JSON parser is common in programming languages.
  2. Secure. We can use a Symmetric or Asymmetric key algorithm.
  3. Less verbose in comparison to SAML.

I have created an ASP.Net Core web API sample application. JWTAuthService is responsible for the generation and validation of token. Feel free to download and contribute to the code on Github.



European ASP.NET Core Hosting :: How to Make Simple Chat Using Asp.net Core SignalR

clock December 12, 2019 07:54 by author Scott

This is tutorial about how to make simple chat with Asp.net Core SignalR. It only takes around 5-10 mins for someone who is familiar with Asp.net Core. Here we go

Creating the projects

We will create a new empty ASP.NET Core Web project. You can either do it with Visual Studio or execute dotnet new web in the command line.

I have Angular CLI installed on my machine. If you don’t either install it or create a new empty Angular application. I am using Angular CLI 1.5 and creating a new project with it – Angular 5 application.

I will just execute ng new CodingBlastChat in the command line, inside of solution folder. And now I have basic working Angular application. To start it, I just type in ng serve and I my application is running on localhost port 4200.

Installing dependencies

We need to install both server-side and client-side libraries for ASP.NET Core SignalR.

To install the server-side library we will use NuGet. You can either use Visual Studio or do it via command line. The package name is Microsoft.AspNetCore.SignalR

dotnet add package Microsoft.AspNetCore.SignalR

We will use npm to add client-side library:

npm install @aspnet/signalr-client

If you are using npm 4 or older you will need to add the –save argument, if you want it to be saved inside of your package.json as well. And that’s it for library dependencies. We are all set and we can now use SignalR.

Setting up server-side

We can now add the simple ChatHub class:

public class ChatHub : Hub
{
    public void SendToAll(string name, string message)
    {
        Clients.All.InvokeAsync("sendToAll", name, message);
    }
}

This will call the sendToAll client method for ALL clients.

For SignalR to work we have to add it to DI Container inside of ConfigureServices method in Startup class:

services.AddSignalR();

Also, we have to tell the middleware pipeline that we will be using SignalR. When the request comes to the /chat endpoint we want our ChatHub to take over and handle it.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseSignalR(routes =>
    {
        routes.MapHub<ChatHub>("chat");
    });
}

Enabling CORS

Since we will be serving the Angular application on a separate port, for it to be able to access the SignalR server we will need to enable CORS on the Server.

Add the following inside of ConfigureServices, just before the code that adds SignalR to DI container.

services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
    {
        builder
        .AllowAnyMethod()
        .AllowAnyHeader()
        .WithOrigins("http://localhost:4200");
    }));

We also have to tell the middleware to use this CORS policy. Add the following inside of Configure method, BEFORE SignalR:

app.UseCors("CorsPolicy");

Now your Configure method should look like this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseCors("CorsPolicy");

    app.UseSignalR(routes =>
    {
        routes.MapHub<ChatHub>("chat");
    });
}

Also, make sure to check your Properties/launchSettings.json file so you can know which port is your app running. You can also configure it to use any port you want. I will set it to 5000.

Client-side

You would ideally want to have a separate service for communicating with ChatHub on the server. Also, you would want to store your endpoints in some kind of Angular service for constants. But for the simplicity sake, we will skip that for now and add it after we make the chat functional.

I will use existing AppComponent that Angular CLI created, and extend it.

I will add properties for nick, message and list of messages. Also, I will add a property for HubConnection.

import { Component } from '@angular/core';
import { HubConnection } from '@aspnet/signalr-client';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  private hubConnection: HubConnection;
  nick = '';
  message = '';
  messages: string[] = [];
}

HubConnection is part of the signalr-client library built by ASP.NET team. And we will use it to establish the connection with the server and also to send messages and listen for messages from the server.

We will establish the connection before any other code runs in our component. Hence, we will use the OnInit event.

import { Component, OnInit } from '@angular/core';
import { HubConnection } from '@aspnet/signalr-client';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  private hubConnection: HubConnection;
  nick = '';
  message = '';
  messages: string[] = [];

  ngOnInit() {
    this.nick = window.prompt('Your name:', 'John');

    this.hubConnection = new HubConnection('http://localhost:5000/chat');

    this.hubConnection
      .start()
      .then(() => console.log('Connection started!'))
      .catch(err => console.log('Error while establishing connection :('));

    }
}

Notice the ngOnInit method. We are asking the user to enter his name and we store that inside of nick property that we created previously.

After that, we create the HubConnection object and try to establish the connection with the server.

Inside of that method, we will also add the listener for sendToAll event from the server:

this.hubConnection.on('sendToAll', (nick: string, receivedMessage: string) => {
  const text = `${nick}: ${receivedMessage}`;
  this.messages.push(text);
});

After the event is received, we get two parameters: nick and the message itself. Now we form the new string from these two parameters and we add it to our messages array on AppComponent.

Inside of AppComponent we also need a method for sending messages from client TO server. We will use it from our view and here is the code:

  public sendMessage(): void {
    this.hubConnection
      .invoke('sendToAll', this.nick, this.message)
      .catch(err => console.error(err));
  }

View

Now we need to set up the view. Since we plan to use the form element, we will import FormsModule in our AppModule. We will change the app.module.ts file.

We can now add the view to app.component.html:

<div id="main-container" style="text-align:center">
  <h1>
    <a href="https://dotnet4europeanhosting.hostforlife.eu/make-chat-using-as-net-core-signalr/" target="_new">
      Make Chat Using ASP.NET Core SignalR
    </a>
  </h1>

  <div class="container">
    <h2>Hello {{nick}}!</h2>
    <form (ngSubmit)="sendMessage()" #chatForm="ngForm">
      <div>
        <label for="message">Message</label>
        <input type="text" id="message" name="message" [(ngModel)]="message" required>
      </div>
      <button type="submit" id="sendmessage" [disabled]="!chatForm.valid">
        Send
      </button>
    </form>
  </div>

  <div class="container" *ngIf="messages.length > 0">
    <div *ngFor="let message of messages">
      <span>{{message}}</span>
    </div>
  </div>

</div>

The view has two main parts.

 

First is a container for sending messages with a form that consists of input and button for sending the message.

The second part is for listing the messages that we store inside of messages property on AppComponent. We push a new message to this array every time we get an event (message) from the ASP.NET Core SignalR server.

That’s all there is to it!



European ASP.NET Core Hosting :: How to Use AutoMapper in Asp.Net Core Application

clock December 10, 2019 11:46 by author Scott

This is only brief tutorial about how to use AutoMapper in Asp Net Core 3.0 application. Automapper is a very popular Object-to-Object mapping library that can be used to map objects.

How to use automapper in Asp.Net Core 3.0 application

Let’s see how to use automapper in Asp Net Core 3.0 application using a very simple example.

1. First step you need to do is please make sure you install Asp.net Core 3.0 application à Create a new project button à then choose “ASP.NET Core Web Application” template à click “Next” button and then enter your Project name. Please see the image below for further information

 

2. Install AutoMapper in Asp.Net Core 3.0 Application 

Now, in this step, we will install AutoMapper in our project. So, go to visual studio and then go to “Tools” from the menu and then select “NuGet Package Manager” and then choose “Manager NuGet Packages for Solution”. Now, go to “Browse” tab and then install this below package as you do see below in the screenshot.

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

3. Configure AutoMapper in Asp.net Core 3.0 Application

Go to project folder structure, and then go to Startup class and then add some changes as you do see below in the code file’s Line # 11 and Line # 26.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AutoMapper;
namespace AspNetCore3AutoMapper
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddAutoMapper(typeof(Startup));
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

        }
    }
}

4. Create a Model Class and Data Transfer Object Class

Now, in this step , we will create two classes. One is Model class and the other one is Dto(Data Transfer Object) class. So, go to Models’ folder and then right click on the folder name and then add a new class with the name of “Employee” and then write some properties as you do see below in the code.

public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Department { get; set; }
    }

Now, again add a new class with the name of “EmployeeDto” as you do see below in the file.

public class EmployeeDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Department { get; set; }
    }

5. Add relation of Employee class with EmployeeDto class

Now, in this step, we will see how to add relation between a domain class and a Dto class. So, again add a new class (E.g. AutoMapping.cs) and then write some code as you do see below in the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;

namespace AspNetCoreAutoMapper.Models
{
    public class AutoMapping : Profile
    {
        public AutoMapping()
        {
            CreateMap<Employee, EmployeeDto>();
        }
    }
}

Let’s understand the above code.

Line # 9: In this line, we are inheriting AutoMapping class from Profile.

Line # 13: In this line, we are mapping our Employee and EmployeeDto Classes.

6. Map Employee class with EmployeeDto Controller

We will see how to map Employee class with EmployeeDto class within the Home Controller. So, go to HomeController and then go to Index method and then write some code as you do see below in the file.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using AspNetCore3AutoMapper.Models;
using AutoMapper;

namespace AspNetCore3AutoMapper.Controllers
{
    public class HomeController : Controller
    {
        private readonly IMapper _mapper;
        public HomeController(IMapper mapper)
        {
            _mapper = mapper;
        }
        public IActionResult Index()
        {
            var empObj = new Employee();
            empObj.Id = 1;
            empObj.Name = "Scott";
            empObj.Department = "MM";
            var employeeDto = _mapper.Map<EmployeeDto>(empObj);
            return View(employeeDto);
        }
    }
}

Let’s understand the above code.

Line # 15 to 19: In this block of code, we are injecting IMapper interface. This will help us to use our configured mappings.

Line # 22 to 25: In this block of code, we are initializing Employee object.

Line # 26: In this line, we are using IMapper interface that we have injected into our constructor to call the Map method. And we are giving the type that we want to map and the object that we want to map from.

Line # 27: In this line, we are returning the EmployeeDto object to the view.

Now, go to Index view and access the returning values from the Index method as you do see below in the file.

@model EmployeeDto
@{
    ViewData["Title"] = "Home Page";
}
<div>
    <h1>ID: @Model.Id</h1>
    <h1>Name: @Model.Name</h1>
    <h1>Department: @Model.Department</h1>
</div>

Now, run your project by pressing f5 and then you will see the output

Or you can install this package by using this below command in Package Manager Console as you do see below in the screenshot.



European ASP.NET Core Hosting :: How to use AutoWrapper.Server?

clock December 4, 2019 11:16 by author Peter

If you are using AutoWrapper for generating a consistent Http response for your ASP.NET Core API's and you have some server-side applications (.NET Clients) that consume the Response, chances are you are forced to create a schema to properly deserialize the ApiResponse to your Model. The idea behind this project was based on community feedback by dazinator. It occurs to me as well that this might be a common scenario. Big thanks to dazinator!

AutoWrapper.Server is simple library that enables you unwrap the Result property of the AutoWrapper's ApiResponse object in your C# .NET Client code. The goal is to deserialize the Result object directly to your matching Model without having you to create the ApiResponse schema.

Installation
1) Download and Install the latest AutoWrapper.Server from NuGet or via CLI:
PM> Install-Package AutoWrapper.Server -Version 2.0.0 

2) Declare the following namespace in the class where you want to use it.
using AutoWrapper.Server; 

Sample Usage
[HttpGet] 
public async Task<IEnumerable<PersonDTO>> Get()   

    var client = HttpClientFactory.Create(); 
    var httpResponse = await client.GetAsync("https://localhost:5001/api/v1/persons"); 
 
    IEnumerable<PersonDTO> persons = null; 
    if (httpResponse.IsSuccessStatusCode) 
    { 
        var jsonString = await httpResponse.Content.ReadAsStringAsync(); 
        persons = Unwrapper.Unwrap<IEnumerable<PersonDTO>>(jsonString); 
    } 
 
    return persons; 


If you are using the [AutoWrapperPropertyMap] to replace the default Result property to something else like Payload, then you can use the following overload method below and pass the matching property:
Unwrapper.Unwrap<IEnumerable<PersonDTO>>(jsonString, "payload"); 


Using the UnwrappingResponseHandler

Alternatively you can use the UnwrappingResponseHandler like below:
[HttpGet] 
public async Task<IEnumerable<PersonDTO>> Get()   

    var client = HttpClientFactory.Create(new UnwrappingResponseHandler()); 
    var httpResponse = await client.GetAsync("https://localhost:5001/api/v1/persons"); 
 
    IEnumerable<PersonDTO> persons = null; 
    if (httpResponse.IsSuccessStatusCode) 
    { 
        var jsonString = await httpResponse.Content.ReadAsStringAsync(); 
        persons = JsonSerializer.Deserialize<IEnumerable<PersonDTO>>(jsonString); 
    } 
 
    return persons; 


You can also pass the matching property to the handler like in the following:

var client = HttpClientFactory.Create( new UnwrappingResponseHandler("payload")); 

That's it. If you used AutoWrapper or if you find this useful, please give it a star to show your support and share it to others.



European ASP.NET Core Hosting :: PopupBox For Debug Only

clock November 28, 2019 11:38 by author Peter

When debugging I feel a need to popup values from variables. I know that Visual Studio is cool but I feel the need to use it just typing. So I design an extension method to make it easy. You can add your custom objects, or Windows objects, and make a clause to show it or not. The message is shown only in DEBUG time.

See this sample,
using System; 
using System.Net.Mail; 
using System.Windows.Forms; 
 
namespace DebugPopup 

    public partial class FrmSample : Form 
    { 
        public FrmSample() => InitializeComponent(); 
 
        private void Form1_Load(object sender, EventArgs e) 
        { 
            var eml = new MailAddress("[email protected]", "test"); 
 
            eml.PopupBox(); 
 
            var n = 0; 
 
            n.PopupBox(); 
 
            Handle.PopupBox(); 
 
            decimal.Zero.PopupBox(n==0, "n is equals zero!"); 
         
        } 
 
        private void button1_Click(object sender, EventArgs e) 
        { 
            ((Button)sender).PopupBox(); 
        } 
    } 


It 's an extension method that you only need to add.PopupBox() from the Visual Studio property menu.
You can add custom types and the message will be shown only in DEBUG mode, I mean that in production there will be no message.

This is the main code,
using System.Windows.Forms; 
using System.Net.Mail; 
using System.Diagnostics; 
 
/// <summary> 
/// Author: Jefferson Saul G. Motta 
/// 10-24-2019 20:50 
/// Uses the System 
/// </summary> 
namespace System 

 
    /// <summary>   
    /// This is my real code that I make to debug easly 
    /// You can copy to .NET Core as Well 
    /// If you are debugging in a local IIS (ASP.NET WebForms) 
    /// The popup will raises too 
    /// C# 7.3 and C# 8.0 
    /// About extensions: http://www.c-sharpcorner.com/blogs/extension-method-in-c-sharp3 
    /// </summary> 
    public static class ExtensionMethodStrings 
    { 
 
         
        /// <summary> 
        /// Popup for int value 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="showIf"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this int value, in bool showIf = true, in string message = "") => PopupIt($"Value: {value}", showIf, message); 
         
        /// <summary> 
        /// Popup for decimal value 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="showIf"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this decimal value, in bool showIf = true, in string message = "") => PopupIt($"Value: {value}", showIf, message); 
         
        /// <summary> 
        /// Popup for IntPtr value 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="showIf"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this IntPtr value, in bool showIf = true, in string message = "") => PopupIt($"Value: {value}", showIf, message);         
         
        /// <summary> 
        /// Popup for double value 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="showIf"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this double value, in bool showIf = true, in string message = "") => PopupIt($"Value: {value}", showIf, message); 
         
        /// <summary> 
        /// Popup for long value 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="showIf"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this long value, in bool showIf = true, in string message = "") => PopupIt($"Value: {value}", showIf, message); 
         
        /// <summary> 
        /// Popup for string value 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="showIf"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this string value, in bool showIf = true, in string message = "") => PopupIt($"Value: {value}", showIf, message); 
         
         
        /// <summary> 
        /// Popup for string value if contem a string 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="contem"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this string value, in string contem, in string message = "") => PopupIt($"Value: {value}", value.ContemUpper(contem), message);         
         
        /// <summary> 
        /// Popup for bool value 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="showIf"></param> 
        /// <param name="message"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this bool value, in bool showIf = true, in string message = "") => PopupIt($"Value: {value}", showIf, message); 
 
        /// <summary> 
        /// Check if exist comparing uppper text 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="text"></param> 
        /// <returns></returns> 
        private static bool ContemUpper(this string value, string text) => string.IsNullOrEmpty(value) || string.IsNullOrEmpty(text) ? false : value.ToUpper().IndexOf(text.ToUpper()) != -1; 
 
 
        /// <summary> 
        /// Sample 
        /// You can add another controls or objects 
        /// </summary> 
        /// <param name="button"></param> 
        /// <param name="showIf"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this Button button, in bool showIf = true) => PopupIt(button.Text, showIf); 
 
        /// <summary> 
        /// Sample 
        /// You can add another controls or objects 
        /// Test with MailAddress 
        /// </summary> 
        /// <param name="eml"></param> 
        /// <param name="showIf"></param> 
        /// <returns></returns> 
        public static bool PopupBox(this MailAddress eml, in bool showIf = true) => PopupIt(eml.Address, showIf); 
 
        /// <summary> 
        /// Add the label if value not is empty 
        /// </summary> 
        /// <param name="value"></param> 
        /// <param name="label"></param> 
        /// <returns></returns> 
        private static string LabelIfNotEmpty(this string value, string label) => string.IsNullOrEmpty(value) ? "" : $"{label}:{value}"; 
 
        /// <summary> 
        /// Show popup only for DEBUG 
        /// </summary> 
        /// <param name="message"></param> 
        /// <param name="showIf"></param> 
        /// <param name="messageExtra"></param> 
        /// <returns></returns> 
        private static bool PopupIt(string message, in bool showIf = true, in string messageExtra = "") 
 
#if (DEBUG) 
        { 
            // Show popup if true 
            if (showIf) 
            { 
                Debug.WriteLine($"{messageExtra.LabelIfNotEmpty("Extra message:")}{message}"); 
             
                // Optional: 
                MessageBox.Show($"{messageExtra.LabelIfNotEmpty("Extra message:")}{message}"); 
             
            } 
            // showIf  
            return showIf; 
        } 
#else 
            // on Releases returns false 
            => false; 
 
#endif 
 
    } 
 
}



European ASP.NET Core Hosting :: AutoWrapper Version 2.1.0 Released

clock November 12, 2019 10:42 by author Peter

AutoWrapper 2.1.0 has been released with newly features added based on community feedback. Here are the newly features added:

  • Added [AutoWrapIgnore] action filter attribute.
  • Added support to override non-success message when using IActionResult return types.
  • Added EnableResponseLogging and EnableExceptionLogging options to turn off auto logging.
  • Added UnAuthorize and BadRequest message for HandleNotSucessAsync() method response.

Using IActionResult Return Types
AutoWrapper now supports IActionResult return types that allows you to return non successful requests such as BadRequest, NotFound, UnAuthorize and etc.
For example:
[Route("{id:long}")] 
[HttpGet] 
public async Task<IActionResult> Get(long id)   

    var person = await _personManager.GetByIdAsync(id); 
    if (person != null) 
    { 
        return Ok(person); 
    } 
    else 
        return NotFound($"Record with id: { id } does not exist."); 


Another example such as:
return Unauthorized("Access token is invalid.");   
return BadRequest("SomeField is null.");   


AutoWrapIgnore Attribute
You can now use the [AutoWrapIgnore] filter attribute for enpoints that you don't want to be wrapped.
For example:
[HttpGet] 
[AutoWrapIgnore] 
public async Task<IActionResult> Get()   

    var data = await _personManager.GetAllAsync(); 
    return Ok(data); 


or
[HttpGet] 
[AutoWrapIgnore] 
public async Task<IEnumerable<Person>> Get()   

    return await _personManager.GetAllAsync(); 


Turn-off Default Logging
You can now turn off Logging by setting EnableResponseLogging and EnableExceptionLogging options to false in AutoWrapper options.
For example:
app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions {   
              EnableResponseLogging = false,  
              EnableExceptionLogging = false  
}); 


That's it. Feel free to request an issue on github if you find bugs or request a new feature. Your valuable feedback is much appreciated to better improve this project. If you find this useful, please give it a star to show your support for this project.



European ASP.NET Core Hosting :: All About Sessions In ASP.NET Core

clock November 5, 2019 10:53 by author Peter

HTTP is a stateless protocol, so we need some mechanism to maintain our App State. Server Side Session has been a way to maintain our state on the server side. In this article we'll see what differences ASP.NET Core has introduced regarding SESSION.

We'll quickly discuss how we used to use Sessions before ASP.NET Core and then we'll see how to access Sessions in ASP.NET Core.

Session In Pre-ASP.NET Core era
You get Session functionality by default (without adding any package)
Previously, you would have accessed Session by -

    Session variable in your Controllers/Forms
    System.Web.HttpContext.Current.Session in places where you don't have direct access to the Session variable.

Anything you store in session is stored as Object. You store values in Key/Value format.

    Session["mydata"] = 10;  

Or to access on those places where Session is not available (e.g. Non-Controller classes)

    System.Web.HttpContext.Current.Session["mydata"] = 10;  

Quite difficult to mock Session Object for Unit Testing

Session in ASP.NET Core 2.2
Now, Session is not available by default.
You need to add the following package. Meta package by default provides you this.

    <PackageReference Include="Microsoft.AspNetCore.Session" Version="2.2.0" /> 
In Startup.ConfigureServices, you need to add the following to register services with DI Container.
    services.AddDistributedMemoryCache();//To Store session in Memory, This is default implementation of IDistributedCache   
    services.AddSession(); 

In Startup.Configure, you need to add the following (before UseMVC) to add Session Middleware.

    app.UseCookiePolicy();     
    app.UseSession();     
    app.UseMvc(routes =>   

Make sure the following is also there (It is added by default when you use ASP.NET Core MVC Template).

    app.UseCookiePolicy();  

ASP.NET Core 2.2 onwards adds Cookie Consent (true) in the Startup file. When an application runs, the user needs to accept Cookie Consent on screen. When the user accepts the policy on the page, it creates a consent cookie. It is to follow GDPR and to give control to the user if the user wants to store cookies from a site or not. If the user doesn't accept that, Session does not work because Session requires a cookie to send/receive session Id. You may face this issue while working with ASP.NET Core MVC default template.

How to access Session in Controller?

You will notice that you don't have "Session" variable available now. Controller now has a property "HttpContext" which has "Session" variable. So, you can access session in controller by using the following code.

var a = this.HttpContext.Session.GetString("login");   
HttpContext.Session.SetString("login", dto.Login); 


How to access Session in Non-Controller class?

Now, you don't have System.Web.HttpContext.Current.Session in ASP.NET Core. To access session in non-controller class -

First, register the following service in Startup.ConfigureServices;

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

Now, register a class (example - TestManager) where you want to access the Session in Startup.ConfigureServices;
    services.AddScoped<TestManager>(); 
Note
You may use AddTransient or AddSingleton according to your logic.

Now, in TestManager class, add the following code.
    private readonly IHttpContextAccessor _httpContextAccessor;   
    private readonly ISession _session;   
    public TestManager(IHttpContextAccessor httpContextAccessor)   
       {   
            _httpContextAccessor = httpContextAccessor;   
            _session = _httpContextAccessor.HttpContext.Session;   
        } 


The above code is receiving IHttpContextAccessor object through dependency injection and then, it is storing Sessions in a local variable.

How to access Session in View file?

Add the following at the top of your View file.
@using Microsoft.AspNetCore.Http   
@inject IHttpContextAccessor httpContextAccessor  


Then, you may access the Session variable in your View like following.
@httpContextAccessor.HttpContext.Session.GetString("login")  

What else is changed regarding Session?

Session is non-locking now.
A session is not created until you have at least one value in it
You need to use functions to get & set data. Array syntax is not supported now.
Now, ISession only provides Get & Set method which takes & returns data in Byte Array format.
If you want to store data in the String format, you may add the following in your file and use extension methods.
    using Microsoft.AspNetCore.Http;  
It exposes the new extension methods.
    SetInt32   
    GetInt32   
    SetString   
    GetString   
Under the hood, these covert the data into bytes.

You may also write your own extension methods. For example, the following Extension Methods help you store & retrieve any complex type.
    public static class SessionExtensions       
        {       
            public static void Set<T>(this ISession session, string key, T value)       
            {       
                session.Set<(key, JsonConvert.SerializeObject(value));       
            }       
           
            public static T GetObject<T>(this ISession session, string key)       
            {       
                var value = session.GetString(key);       
                return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);       
            }       
        }  


In the next article, we'll learn about SESSION Wrapper Design Pattern.

Summary

Session concepts are similar to what we've seen in earlier .NET Frameworks. The real difference is that now, it is cleaner & more flexible to use.

 



European ASP.NET Core Hosting :: Error When Published ASP.NET Core? See Below Tips!

clock November 5, 2019 05:38 by author Scott

At the past few years, we have discussed about common error that you can find when published .NET Core, the most common error is 502.5 – process failure error.

Startup errors with ASP.NET Core don’t provide much information either, at least not in a production environment. Here are 7 tips for understanding and fixing those errors.

1. There are two types of startup errors.

There are unhandled exceptions originating outside of the Startup class, and exceptions from inside of Startup. These two error types can produce different behavior and may require different troubleshooting techniques.

2. ASP.NET Core will handle exceptions from inside the Startup class.

If code in the ConfigureServices or Configure methods throw an exception, the framework will catch the exception and continue execution.

Although the process continues to run after the exception, every incoming request will generate a 500 response with the message “An error occurred while starting the application”.

Two additional pieces of information about this behavior:

- If you want the process to fail in this scenario, call CaptureStartupErrors on the web host builder and pass the value false.

- In a production environment, the “error occurred” message is all the information you’ll see in a web browser. The framework follows the practice of not giving away error details in a response because error details might give an attacker too much information. You can change the environment setting using the environment variable ASPNETCORE_ENVIRONMENT, but see the next two tips first. You don’t have to change the entire environment to see more error details.

3. Set detailedErrors in code to see a stack trace.

The following bit of code allows for detailed error message, even in production, so use with caution.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
           .CaptureStartupErrors(true) // the default
           .UseSetting("detailedErrors", "true")
           .UseStartup<Startup>();

4. Alternatively, set the ASPNETCORE_DETAILEDERRORS environment variable.

Set the value to true and you’ll also see a stack trace, even in production, so use with caution.

5. Unhandled exceptions outside of the Startup class will kill the process.

Perhaps you have code inside of Program.cs to run schema migrations or perform other initialization tasks which fail, or perhaps the application cannot bind to the desired ports. If you are running behind IIS, this is the scenario where you’ll see a generic 502.5 Process Failure error message.

These types of errors can be a bit more difficult to track down, but the following two tips should help.

6. For IIS, turn on standard output logging in web.config.

If you are carefully logging using other tools, you might be able to capture output there, too, but if all else fails, ASP.NET will write exception information to stdout by default. By turning the log flag to true, and creating the output directory, you’ll have a file with exception information and a stack trace inside to help track down the problem.

The following shows the web.config file created by dotnet publish and is typically the config file in use when hosting .NET Core in IIS. The attribute to change is the stdoutLogEnabled flag.

<system.webServer>
  <handlers>
    <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />

  </handlers>
  <aspNetCore processPath="dotnet" arguments=".\codes.dll"
              stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" />
</system.webServer>

Important: Make sure to create the logging output directory.

Important: Make sure to turn logging off after troubleshooting is complete.

7. Use the dotnet CLI to run the application on your server.

If you have access to the server, it is sometimes easier to go directly to the server and use dotnet to witness the exception in real time. There’s no need to turn on logging or set and unset environment variables.

Summary

Debugging startup errors in ASP.NET Core is a simple case of finding the exception. In many cases, #7 is the simplest approach that doesn’t require code or environment changes. FYI, we also have support latest ASP.NET Core on our hosting environment. Feel free to visit our site at https://www.hostforlife.eu.



European ASP.NET Core 3.1 Hosting - HostForLIFE.eu :: .NET Core Implementing .NET Core Health Checks

clock October 29, 2019 12:16 by author Peter

Generally, when we are using any uptime monitoring systems or load balancers, these systems will keep monitoring the health of the application and based on its health condition it will decide to send the request to serve it. For this earlier, we use to create a special endpoint where it will return any error message or code to indicate the health of the API/service.
 

Following is the sample, an endpoint /health where it verifying the database connection and returns the result accordingly.
    [Route("health")] 
    public ActionResult Health() 
    { 
        using (var connection = new SqlConnection(_connectionString)) 
        { 
            try 
            { 
                connection.Open(); 
            } 
            catch (SqlException) 
            { 
                return new HttpStatusCodeResult(503, "Database connection is unhealthy"); 
            } 
        } 
     
        return new EmptyResult(); 
    } 

When we ran the application with endpoint /health, it will display an empty message with 200 status code and 503 status code when there is any connectivity issue while connecting to the database.

Now, based on these resulted status codes, monitoring systems can take appropriate actions like removing this particular services instance from its list of healthy services so that no requests will be redirected to it until it becomes healthy (in our case, when database connectivity issue resolves).
 
We need to keep adding more external resource health checks accordingly.
 
Since .NET Core 2.2, we no need to add a special controller for health check endpoint, instead, the framework itself providing Health Check services as follows.
 
NuGet Package
You have to install following NuGet package
 
Install-Package Microsoft.Extensions.Diagnostics.HealthChecks
 
Once the package is installed, we need to add the following lines at ConfigureServices() and Configure() methods in Startup.cs file.
    public void ConfigureServices(IServiceCollection services) 
    { 
        services.AddHealthChecks(); 
    } 
      
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
    { 
        app.UseHealthChecks("/Health"); 
    } 


As observed, we are providing the endpoint name in Configure() method. These lines of code will enable a dynamic endpoint "/Health" and display either Healthy/UnHealthy results based on its health state.
 
But, where can we write our custom logic to replicate the above? Yes, we have many features to customize our needs from logic to display results.
 
Adding Custom Logic
 
We can perform in two ways the following are those.
 
Option 1
 
In ConfigureServices method,
    public void ConfigureServices(IServiceCollection services) { 
     services.AddHealthChecks() 
      .AddCheck("sql", () => { 
     
       using(var connection = new SqlConnection(_connectionString)) { 
        try { 
         connection.Open(); 
        } catch (SqlException) { 
         return HealthCheckResult.Unhealthy(); 
        } 
       } 
     
       return HealthCheckResult.Healthy(); 
     
      }); 
    } 


Here, we can use an anonymous method to write the custom logic using AddCheck() method. This will expect a HealthCheckResult object as a result. This object will contain 3 options,
    Healthy
    Unhealthy
    Degraded

Based on the result we need to return appropriately so that runtime will return the status code accordingly. For example, in the above code, if database connection passes it will return a 200 status code (Healthy) and 503 status code (Unhealthy) if failed.
 
Option 2 - In a separate class
The class should implement an IHealthCheck interface and implement CheckHealthAsync() method as follows,
    public class DatabaseHealthCheck: IHealthCheck { 
     public Task < HealthCheckResult > CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = 
      default) { 
      using(var connection = new SqlConnection(_connectionString)) { 
       try { 
        connection.Open(); 
       } catch (SqlException) { 
        return HealthCheckResult.Healthy(); 
       } 
      } 
     
      return HealthCheckResult.Healthy(); 
     
     } 
    } 


Once we created the class, we need to mention this class in ConfigureServices() method using AddTask<T> method as follows by giving some valid unique names.
    public void ConfigureServices(IServiceCollection services) 
    { 
         services.AddControllers(); 
     
         services.AddHealthChecks() 
              .AddCheck<DatabaseHealthCheck>("sql"); 
    } 


Now, our code is clean and we can add any number of Health Tasks as above and it will be run in the order how we declared here.
 
Custom Status Code

As discussed above, by default it will send 200 status code if we return Healthy and 503 for Unhealthy. The Healthcheck service even provides scope for us to change this default behavior by providing custom status code using its options object as follows.
    var options = new HealthCheckOptions(); 
    options.ResultStatusCodes[HealthStatus.Unhealthy] = 420; 
    app.UseHealthChecks("/Health", options); 


In this example, I replace the status code for the Unhealthy state with 420.
 
Custom Response
The beauty of this tool is, we can even customize our output for more clear detailed information about each Health check task. This will be very useful in case we have multiple health check tasks to analyze which task made the complete service heath status to Unhealthy.
 
We can achieve this via HealthCheckOptions ResponseWriter property.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { 
     app.UseHealthChecks("/Health", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions() { 
      ResponseWriter = CustomResponseWriter 
     }); 
    } 
     
    private static Task CustomResponseWriter(HttpContext context, HealthReport healthReport) { 
     context.Response.ContentType = "application/json"; 
     
     var result = JsonConvert.SerializeObject(new { 
      status = healthReport.Status.ToString(), 
       errors = healthReport.Entries.Select(e => new { 
        key = e.Key, value = e.Value.Status.ToString() 
       }) 
     }); 
     return context.Response.WriteAsync(result); 
     
    } 


Now, the above code will display the result in JSON format will all the tasks information. Here, Key represents the Task name we have given (in our case "sql") and value is either Healthy/Unhealthy.
 
Health Check UI
We can even see the health check results on-screen visually by installing the following NuGet package
Install-Package AspNetCore.HealthChecks.UI
 
Once installed need to call respective service methods in ConfigureServices() and Configure() methods accordingly.
    public void ConfigureServices(IServiceCollection services) 
    { 
        services.AddHealthChecksUI(); 
    } 
     
    public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
    { 
        app.UseHealthChecksUI(); 
    } 

Once configured, you can run the application and point to /healthchecks-ui endpoint which display a UI as follows,



About HostForLIFE

HostForLIFE 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 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Month List

Tag cloud

Sign in