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

ASP.NET Core Hosting - HostForLIFE.eu :: Progressive Retry for Network Calls

clock March 18, 2020 11:55 by author Peter

In today's mobile world, many calls across the internet or network could fail for many reasons. Some of the reasons could be the service is busy, the network is slow and many more. For these types of calls, it’s advisable to retry the call if there is an error. The current code base I am working on connects to Salesforce to retrieve and update data. Salesforce is one of those backend services that could experience these types of issues.

To help with these types of network issues, I have added a new method to my open-source code called ProgressiveRetry(). This method will try the call a given number of times. If there is an error, it will wait for a given milliseconds that increases with each error. Below is the code for this call.

    /// <summary> 
    /// Progressive retry for a function call. 
    /// </summary> 
    /// <param name="operation">The operation to perform.</param> 
    /// <param name="retryCount">The retry count (default 3).</param> 
    /// <param name="retryWaitMilliseconds">The retry wait milliseconds (default 100).</param> 
    /// <returns>System.Int32.</returns> 
    public static int ProgressiveRetry(Action operation, byte retryCount = 3,  
                                       int retryWaitMilliseconds = 100) 
    { 
        Encapsulation.TryValidateParam<ArgumentNullException>(operation != null); 
        Encapsulation.TryValidateParam<ArgumentOutOfRangeException>(retryCount > 0); 
        Encapsulation.TryValidateParam<ArgumentOutOfRangeException>(retryWaitMilliseconds > 0); 
      
        var attempts = 0; 
      
        do 
        { 
            try 
            { 
                attempts++; 
     
                 operation(); 
                return attempts; 
     
            } 
            catch (Exception ex) 
            { 
                if (attempts == retryCount) 
                { 
                    throw; 
                } 
      
                Debug.WriteLine(ex.GetAllMessages()); 
      
                Task.Delay(retryWaitMilliseconds * attempts).Wait(); 
                   } 
            } while (true); 
        } 
    } 


Here is example code on how to use ProgressiveRetry().
    var result = false; 
    var count = ExecutionHelper.ProgressiveRetry(() => 
    { 
        result = NetworkHelper.IsHostAvailable("wordpress.com"); 
    } 
    , retryCount: 3, retryWaitMilliseconds: 225); 
    Console.WriteLine($"Host available {result}. Tried call {count} times.");

HostForLIFE.eu ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



ASP.NET Core Hosting - HostForLIFE.eu :: Using Redis To Delay Execution In ASP.NET Core

clock March 3, 2020 11:07 by author Peter

Due to some business requirements, many operations should not begin to execute right away;  they should begin after some seconds, minutes or hours. For example, say there is a task, and it contains two steps. When we finish the first step, the second step should begin after 5 minutes.
 

How can we solve this problem?
Thread.Sleep() and Task.Delay() is a very easy solution that we can use. But it may block our applictions.
 
And in this article, I will introduce a solution based on keyspace notifications of Redis.
 
Here we will use expired events to do it, but this solution also has some limitations , because it may have a significant delay. That means that delay of execution may have smoe error, and will not be very accurate!
 
Let's take a look at this solution.
 
Set Up Redis
Keyspace notifications is a feature available since 2.8.0, so the version of Redis should not be less than 2.8.0.
 
We should modify an important configuration so that we can enable this feature.
    ############################# Event notification ############################## 
    
    # Redis can notify Pub/Sub clients about events happening in the key space. 
    # This feature is documented at http://redis.io/topics/notifications 
    # 
    # ......... 
    # 
    #  By default all notifications are disabled because most users don't need 
    #  this feature and the feature has some overhead. Note that if you don't 
    #  specify at least one of K or E, no events will be delivered. 
    notify-keyspace-events "" 


The default value of notify-keyspace-events is empty, we should modify it to Ex.
    notify-keyspace-events "Ex" 

Then we can startup the Redis server.

Create Project
Create a new ASP.NET Core Web API project and install CSRedisCore.
    <Project Sdk="Microsoft.NET.Sdk.Web"> 
     
      <PropertyGroup> 
        <TargetFramework>netcoreapp3.1</TargetFramework> 
      </PropertyGroup> 
     
      <ItemGroup> 
        <PackageReference Include="CSRedisCore" Version="3.4.1" /> 
      </ItemGroup> 
     
    </Project> 

Add an interface named ITaskServices and a class named TaskServices.
    public interface ITaskServices 
    { 
        void SubscribeToDo(string keyPrefix); 
     
        Task DoTaskAsync(); 
    } 
     
    public class TaskServices : ITaskServices 
    { 
        public async Task DoTaskAsync() 
        { 
            // do something here 
            // ... 
     
            // this operation should be done after some min or sec 
            var taskId = new Random().Next(1, 10000); 
            int sec = new Random().Next(1, 5); 
     
            await RedisHelper.SetAsync($"task:{taskId}", "1", sec); 
            await RedisHelper.SetAsync($"other:{taskId + 10000}", "1", sec); 
        } 
     
        public void SubscribeToDo(string keyPrefix) 
        { 
            RedisHelper.Subscribe( 
                ("__keyevent@0__:expired", arg => 
                    { 
                        var msg = arg.Body; 
                        Console.WriteLine($"recive {msg}"); 
                        if (msg.StartsWith(keyPrefix)) 
                        { 
                            // read the task id from expired key 
                            var val = msg.Substring(keyPrefix.Length); 
                            Console.WriteLine($"Redis + Subscribe {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} begin to do task {val}"); 
                        } 
                    }) 
            ); 
        } 
    } 


As you can see, we set a redis key with expiration. The expiration is the delay time.
 
For the delay execution, we can find it in SubscribeToDo method. It subscribes a channel named __keyevent@0__:expired.
 
When a key is expired, redis server will publish a message to this channel, and subscribers will receive it.
 
After reciving the notification, the client will begin to do the job.
 
Before the client receives the notification, the delay job will not be executed, so that it can help us to do the job for a delay.
 
Here is the entry of this operation.
    [ApiController] 
    [Route("api/tasks")] 
    public class TaskController : ControllerBase 
    { 
        private readonly ITaskServices _svc; 
     
        public TaskController(ITaskServices svc) 
        { 
            _svc = svc; 
        } 
     
        [HttpGet] 
        public async Task<string> Get() 
        { 
            await _svc.DoTaskAsync(); 
            System.Console.WriteLine("done here"); 
            return "done"; 
        } 
    } 


Put the subscriber to a BackgroundService, so that it can run in the background.
    public class SubscribeTaskBgTask : BackgroundService 
    { 
        private readonly ILogger _logger; 
        private readonly ITaskServices _taskServices; 
     
        public SubscribeTaskBgTask(ILoggerFactory loggerFactory, ITaskServices taskServices) 
        { 
            this._logger = loggerFactory.CreateLogger<RefreshCachingBgTask>(); 
            this._taskServices = taskServices; 
        } 
     
        protected override Task ExecuteAsync(CancellationToken stoppingToken) 
        { 
            stoppingToken.ThrowIfCancellationRequested(); 
     
            _taskServices.SubscribeToDo("task:"); 
     
            return Task.CompletedTask; 
        } 
    } 


At last, we should register the above services in startup class.
    public class Startup 
    { 
        // ... 
         
        public void ConfigureServices(IServiceCollection services) 
        { 
            var csredis = new CSRedis.CSRedisClient("127.0.0.1:6379"); 
            RedisHelper.Initialization(csredis); 
     
            services.AddSingleton<ITaskServices, TaskServices>(); 
            services.AddHostedService<SubscribeTaskBgTask>(); 
     
            services.AddControllers(); 
        } 
    } 


Here is the result after running this application.

HostForLIFE.eu ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



ASP.NET Core Hosting - HostForLIFE.eu :: How to Steps To Generate Excel Using EPPlus?

clock February 25, 2020 08:01 by author Peter

My work is to create an excel file, which will contain 3 fields: Address, Latitude and longitude.The user will upload an Address in an excel file and after reading the addresses from an excel file, I have to retrieve Latitude and longitude, using Bing MAP API and build another excel file, which can contain Addresses beside the Latitude and longitude of that address and download the new excel file to the user's end.

Create a MVC Application and add EPPLUS from NuGet package manager to your solution.

Now, Add the code to your .cshtml page.

<h2>Upload File</h2> 
 
sing (Html.BeginForm("Upload", "Home", null, FormMethod.Post, new { enctype = "multipart/form-data" })) 
  { 
      @Html.AntiForgeryToken() 
      @Html.ValidationSummary() 
 
      <div class="form-group"> 
          <input type="file" id="dataFile" name="upload" /> 
      </div> 
 
      <div class="form-group"> 
          <input type="submit" value="Upload" class="btn btn-default" /> 
      </div> 
 
       
  } 


And then, add the code, mentioned below to your controller.

[HttpPost] 
        public ActionResult Upload(HttpPostedFileBase upload) 
        { 
            if (ModelState.IsValid) 
            { 
                if (Path.GetExtension(upload.FileName) == ".xlsx") 
                { 
                    ExcelPackage package = new ExcelPackage(upload.InputStream); 
            //From This part we will read excel file 
                    DataTable dt = ExcelPackageExtensions.ToDataTable(package); 
 
 
                    DataTable dtExcel = new DataTable(); 
                    dtExcel.Columns.Add("Address", typeof(String)); 
                    dtExcel.Columns.Add("LAT", typeof(Double)); 
                    dtExcel.Columns.Add("LONG", typeof(Double)); 
 
                    List<Coordinates> lstCor = new List<Coordinates>(); 
                    for (int i = 0; i < dt.Rows.Count; i++) 
                    { 
                        //Fill the new data Table to generate new excel file 
                    } 
            //This method will generate new excel and download the same 
                    generateExcel(dtExcel);                  
                } 
            } 
            return View(); 
        } 


“ExcelPackageExtensions.ToDataTable(package)” for this create a new class with the name ExcelPackageExtensions and create a static method with the name “ToDataTable()”. The code is mentioned below.

public static class ExcelPackageExtensions 
    { 
        public static DataTable ToDataTable(this ExcelPackage package) 
        { 
            ExcelWorksheet workSheet = package.Workbook.Worksheets.First(); 
            DataTable table = new DataTable(); 
            foreach (var firstRowCell in workSheet.Cells[1, 1, 1, workSheet.Dimension.End.Column]) 
            { 
                table.Columns.Add(firstRowCell.Text); 
            } 
 
            for (var rowNumber = 2; rowNumber <= workSheet.Dimension.End.Row; rowNumber++) 
            { 
                var row = workSheet.Cells[rowNumber, 1, rowNumber, workSheet.Dimension.End.Column]; 
                var newRow = table.NewRow(); 
                foreach (var cell in row) 
                { 
                    newRow[cell.Start.Column - 1] = cell.Text; 
                } 
                table.Rows.Add(newRow); 
            } 
            return table; 
        } 
    } 

Now, add the code part to generate and download an Excel file.
[NonAction] 
        public void generateExcel(DataTable Dtvalue) 
        { 
            string excelpath = ""; 
            excelpath = @"C:\Excels\abc.xlsx";//Server.MapPath("~/UploadExcel/" + DateTime.UtcNow.Date.ToString() + ".xlsx"); 
            FileInfo finame = new FileInfo(excelpath); 
            if (System.IO.File.Exists(excelpath)) 
            { 
                System.IO.File.Delete(excelpath); 
            } 
            if (!System.IO.File.Exists(excelpath)) 
            { 
                ExcelPackage excel = new ExcelPackage(finame); 
                var sheetcreate = excel.Workbook.Worksheets.Add(DateTime.UtcNow.Date.ToString()); 
                if (Dtvalue.Rows.Count > 0) 
                { 
                    for (int i = 0; i < Dtvalue.Rows.Count; ) 
                    { 
                        sheetcreate.Cells[i + 1, 1].Value = Dtvalue.Rows[i][0].ToString(); 
                        sheetcreate.Cells[i + 1, 2].Value = Dtvalue.Rows[i][1].ToString(); 
                        sheetcreate.Cells[i + 1, 3].Value = Dtvalue.Rows[i][2].ToString(); 
                        i++; 
                    } 
                } 
                //sheetcreate.Cells[1, 1, 1, 25].Style.Font.Bold = true; 
                //excel.Save(); 
 
                var workSheet = excel.Workbook.Worksheets.Add("Sheet1"); 
                //workSheet.Cells[1, 1].LoadFromCollection(data, true); 
                using (var memoryStream = new MemoryStream()) 
                { 
                    Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; 
                    Response.AddHeader("content-disposition", "attachment;  filename=Contact.xlsx"); 
                    excel.SaveAs(memoryStream); 
                    memoryStream.WriteTo(Response.OutputStream); 
                    Response.Flush(); 
                    Response.End(); 
                } 
            } 
 
        } 

HostForLIFE.eu ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting :: Add Custom Parameters In Swagger Using ASP.NET Core 3.1

clock February 18, 2020 10:54 by author Peter

Web APIs have some common parameters in a project, mabybe those paramters should be passed via header or query, etc.For example, there is a Web API url, https://yourdomain.com/api/values, and when we access this Web API, we should add timestamp, nonce and sign three parameters in the query.

It means that the url must be https://yourdomain.com/api/values?timestamp=xxx&nonce=yyy&sign=zzz

Most of the time, we will use Swagger as our document. How can we document those parameters in Swagger without adding them in each action?

Here I will use ASP.NET Core 3.1 to introduce the concept.

How to do this?
Create a new Web API project, and edit the csproj file, add the following content in it.
<ItemGroup> 
    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0" /> 
</ItemGroup> 
 
<PropertyGroup> 
    <GenerateDocumentationFile>true</GenerateDocumentationFile> 
    <NoWarn>$(NoWarn);1591</NoWarn> 
</PropertyGroup> 


Swashbuckle provides a feature named operation filter that can help us to do that job.

We can add those three additional parameters in our custom operation filter, so that we do not need to add them in each action.

Here is the sample code demonstration.
using Microsoft.AspNetCore.Mvc.Controllers; 
using Microsoft.OpenApi.Models; 
using Swashbuckle.AspNetCore.SwaggerGen; 
using System.Collections.Generic; 
 
public class AddCommonParameOperationFilter : IOperationFilter 

    public void Apply(OpenApiOperation operation, OperationFilterContext context) 
    { 
        if (operation.Parameters == null) operation.Parameters = new List<OpenApiParameter>(); 
 
        var descriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor; 
 
        if (descriptor != null && !descriptor.ControllerName.StartsWith("Weather")) 
        { 
            operation.Parameters.Add(new OpenApiParameter() 
            { 
                Name = "timestamp", 
                In = ParameterLocation.Query, 
                Description = "The timestamp of now", 
                Required = true 
            }); 
 
            operation.Parameters.Add(new OpenApiParameter() 
            { 
                Name = "nonce", 
                In = ParameterLocation.Query, 
                Description = "The random value", 
                Required = true 
            }); 
 
            operation.Parameters.Add(new OpenApiParameter() 
            { 
                Name = "sign", 
                In = ParameterLocation.Query, 
                Description = "The signature", 
                Required = true 
            }); 
        } 
    } 


NOTE
For showing the difference, we only add those parameters whose controller name does not start with Weather.

By the way, if you have any other parameters or conditions, add them yourself.

Then, we will configure Swagger in Startup class.
public class Startup 

    public void ConfigureServices(IServiceCollection services) 
    { 
        services.AddSwaggerGen(c => 
        { 
            // sepcify our operation filter here. 
            c.OperationFilter<AddCommonParameOperationFilter>(); 
 
            c.SwaggerDoc("v1", new OpenApiInfo 
            { 
                Version = "v1.0.0", 
                Title = $"v1 API", 
                Description = "v1 API", 
                TermsOfService = new Uri("https://www.c-sharpcorner.com/members/catcher-wong"), 
                Contact = new OpenApiContact 
                { 
                    Name = "Catcher Wong", 
                    Email = "catcher_hwq@outlook.com", 
                }, 
                License = new OpenApiLicense 
                { 
                    Name = "Apache-2.0", 
                    Url = new Uri("https://www.apache.org/licenses/LICENSE-2.0.html") 
                } 
            }); 
        }); 
 
        // other.... 
    } 

 
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
    { 
        app.UseSwagger(c => 
        { 
        }); 
        app.UseSwaggerUI(c => 
        { 
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1 API"); 
        }); 
 
        // other.... 
    } 


Here is the result.


The controller name that doesn't start with `Weather` will contain those three parameters.

This article showed you a sample of how to add custom request parameters in Swagger using ASP.NET Core 3.1 and Swashbuckle.AspNetCore 5.0.0.



European ASP.NET Core Hosting :: Label, TextArea and Image Tag Helper In ASP.NET Core 3.1

clock February 11, 2020 11:55 by author Peter

In this blog, we will discuss 3 tag helpers: Label, Textarea and Image Tag Helper. We will also discuss how to use them in application with an example.

Label Tag Helper: The label tag helper is used for text labels in an application. It renders as an HTML label tag.
Textarea Tag Helper: The Textarea tag helper is used for Textarea of description in the application. It renders as an HTML Textarea tag.
Image Tag Helper: The Image Tag Helper renders as an HTML img tag. It is used to display images in the core applications. It provides cache-busting behavior for static image files. It has scr and asp-append-version which is set to true.

Step 1 Create an ASP.NET web application project in Visual Studio 2019.
Step 2 Create a class employee under the Models folder.
using System.ComponentModel.DataAnnotations; 
 
namespace LabelTextareaImageTagHelper__Demo.Models 

    public class Employee 
    { 
        [Key] 
        public int Id { get; set; } 
 
        [Required] 
        public string Name { get; set; } 
 
        [Required] 
        public string Image { get; set; } 
 
        [Required] 
        [MinLength(10)] 
        [MaxLength(255)] 
        public string Description { get; set; } 
    } 


Step 3 Now open index view from views than Home folder.
Step 4 Add model on top of the view to retrieve property of model class.
@model LabelTextareaImageTagHelper__Demo.Models.Employee  
Step 5 Create images folder in wwwroot folder copy and paste some image to display it on browser.
<div class="form-group"> 
   <label asp-for="Name" class="control-label"></label> 
   <input asp-for="Name" class="form-control" /> 
</div> 

<div class="form-group"> 
   <label asp-for="Image" class="control-label"></label> 
   <img src="~/images/855211650_154321.jpg" asp-append-version="true" height="150" width="150" class="img-thumbnail" /> 
</div> 

<div class="form-group"> 
   <label asp-for="Description" class="control-label"></label> 
   <textarea asp-for="Description" class="form-control"></textarea> 
</div>


This is how it renders in browser:
<textarea class="form-control" data-val="true" data-val-maxlength="The field Description must be a string or array type with a maximum length of '255'." data-val-maxlength-max="255" data-val-minlength="The field Description must be a string or array type with a minimum length of '10'." data-val-minlength-min="10" data-val-required="The Description field is required." id="Description" maxlength="255" name="Description"></textarea> 




European ASP.NET 3.1 Core Hosting :: How to Only Allow Numbers in a Text Box using jQuery?

clock February 4, 2020 11:05 by author Peter

This tutorial explains how to only allow a number in textbox using jQuery.  If you simply add the 'numberonly' class to the text control, then it will only allow numbers.

Code
$(document).ready(function () {   
   
            $('.numberonly').keypress(function (e) {   
   
                var charCode = (e.which) ? e.which : event.keyCode   
   
                if (String.fromCharCode(charCode).match(/[^0-9]/g))   
   
                    return false;                       
   
            });   
   
        });  
 



European ASP.NET Core Hosting :: ViewComponent In ASP.NET Core

clock January 28, 2020 11:09 by author Peter

ViewComponent was introduced in ASP.NET Core MVC. It can do everything that a partial view can and can do even more. ViewComponents are completely self-contained objects that consistently render html from a razor view. ViewComponents are very powerful UI building blocks of the areas of application which are not directly accessible for controller actions. Let's suppose we have a page of social icons and we display icons dynamically. We have separate settings for color, urls and names of social icons and we have to render icons dynamically.
 
Previously this kind of thing was achieved by HtmlHelpers and child actions but now it is very easy to use ViewComponent for this purpose. It is very easy to create your dynamic elements in a ViewCompnent and render in a view.
 
Creating a ViewComponent?
Step 1
Create a new ASP.NET Core MVC application and run that application. You can see an empty page like the following,

Step 2
We have to display data dynamically. In real scenarios dynamic data mostly comes from the database but for our application we do not use a database and we will create a class to generate fome data. So let's create a class. Add a class with name SocialIcon and add the following fields and methods in it,
    public class SocialIcon 
        { 
            public int ID { get; set; } 
            public string IconName { get; set; } 
            public string IconBgColor { get; set; } 
            public string IconTargetUrl { get; set; } 
            public string IconClass { get; set; } 
     
            public static List<SocialIcon> AppSocialIcons() 
            { 
                List<SocialIcon> icons = new List<SocialIcon>(); 
                icons.Add(new SocialIcon { ID = 1, IconName = "Google", IconBgColor = "#dd4b39",IconTargetUrl="www.google.com", IconClass="fa fa-google" }); 
                icons.Add(new SocialIcon { ID = 2, IconName = "Facebook", IconBgColor = "#3B5998", IconTargetUrl="www.facebook.com", IconClass="fa fa-facebook" }); 
                icons.Add(new SocialIcon { ID = 3, IconName = "Linked In", IconBgColor = "#007bb5", IconTargetUrl = "www.linkedin.com", IconClass= "fa fa-fa-linkedin" }); 
                icons.Add(new SocialIcon { ID = 4, IconName = "YouTube", IconBgColor = "#007bb5", IconTargetUrl = "www.youtube.com", IconClass="fa fa-youtube" }); 
                icons.Add(new SocialIcon { ID = 5, IconName = "Twitter", IconBgColor = "#55acee", IconTargetUrl = "www.twitter.com",IconClass="fa fa-twitter" }); 
     
                return icons; 
            } 
        } 


Step 3
Add a ViewComponent class with name SocialLinksViewComponent. (Don't forget to add ViewComponent with name, in our application we will use it with name SocialLinks and by writing ViewComponent with its name system will understand that it is ViewComponent and will be handled accordingly).

Step 4
ViewComponents are generated from a C# class derived from a base class ViewComponent and are typically associated with a Razor files to generate markup. Just like controllers, ViewComponents also support constructor injection. To implement SocialLinksViewComponent add the following code in your class that you have just created:
    public class SocialLinksViewComponent : ViewComponent 
       { 
           List<SocialIcon> socialIcons = new List<SocialIcon>(); 
           public SocialLinksViewComponent() 
           { 
               socialIcons = SocialIcon.AppSocialIcons(); 
           } 
     
           public async Task<IViewComponentResult> InvokeAsync() 
           { 
               var model = socialIcons; 
               return await Task.FromResult((IViewComponentResult)View("SocialLinks", model)); 
           } 
     
       } 


We created a class and added a List of SocialIcon class. In constructor we loaded our list with data (it is not mandatory to add in constructor you can add data in InvokeAsync method as well and there will be no need of constructor). It will return data in our model object and will render markup in Razor View SocialLinks.
 
Step 5
We added a folder in Views > Shared with the name Components (it should have Components name). And will added a folder SocialLinks in this folder we created a Razor View with name SocialLinks.cshtml. Do the same and add the following code in Razor View,
    @model IList<ViewComponentApp.Models.SocialIcon>   
       
    <div class="col-md-12" style="padding-top:50px;">   
        @foreach (var icon in Model)   
        {   
            <a style="background:@icon.IconBgColor" href="@icon.IconTargetUrl">   
                <i class="@icon.IconClass"></i>   
                @icon.IconName   
            </a>   
        }   
    </div>    


Step 6
Now we have implemented our ViewComponent and added markup html in our coresponding Razor View. Now we will call this ViewComponent in our desired page where it is needed. I am calling it on Index.cshtml page you can use it anywhere in the application with just this following code,
    @(await Component.InvokeAsync("SocialLinks")) 

This above code snippet is the way we can call a ViewComponent in our Razor Views. It will render the desired markup. You can also pass parameters in ViewComponents as following,
    @(await Component.InvokeAsync("SocialLinks", new { IconsToShow = 5 })) 

This is how we can pass parameters. But in our application we are not passing any parameters so we will use the snippet above. So code in our Index.cshtml page will look like this,
    @{   
        ViewData["Title"] = "Home Page";   
    }   
    <style>   
        a {   
            padding: 5px;   
            margin: 5px;   
            color: white;   
        }   
       
        .main-div {   
            margin-bottom: 20px;   
            padding-bottom: 20px;   
        }   
    </style>   
       
    <div class="text-center main-div">   
        <h1 class="display-4">Welcome</h1>   
        <h3>View Component Example</h3>   
       
        @(await Component.InvokeAsync("SocialLinks", new { IconsToShow = 5 }))   
       
    </div>    

Step 7
Run the application. After successfully running the application you will see the following output,

You can see that our ViewComponent is rendered on our Index.cshtml page. Similarly this can be rendered on any page in application using the same call that we used on Index.cshtml page. 

 



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!



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