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 :: Common Practices In .NET Project Structure

clock June 10, 2022 07:58 by author Peter

The topic of properly organizing the code inside a project is often a critical issue for developers who are just starting to learn .NET. Often in the early development stages too much time is wasted trying to figure out where a new class should be created, or when a new project should be added to a solution, or even when to put code in a  specific subfolder.

The truth is that there isn't actually a single correct way to organize your code.

After years of developing in .NET, I've never actually worked on two projects where code was organized in the same way. The same goes for my personal projects: with the progress of my learning path in .NET, I have always tried to progressively move towards a "standard" way of organizing the code inside a repository.

Despite the differences, the analysis of the structure of numerous open source repositories shows that they actually share some common patterns and practices when it comes to organizing the code.

This article illustrates some of these common practices in organizing .NET projects, to help you structure your applications in a cleaner and easily understandable way.
Folder structure

.NET is actually very flexible in how you can organize the folder structure for an application. However, having a clear folder structure helps new contributors understand where to find the code they need. Even people who have never worked on your application would know where to look to find the documentation, or unit tests, or source code.

While there is no official standard on how to organize files and folders in a .NET application, many repositories follow a structure similar to the one outlined by David Fowler. A simplified version of the structure can be represented as follows:

$/
  artifacts/
  build/
  docs/
  packages/
  samples/
  src/
  tests/
  .editorconfig
  .gitignore
  .gitattributes
  LICENSE
  NuGet.Config
  README.md
  {solution}.sln
  ...

Files such as the solution file, README or LICENSE are put on the root folder, while the rest of the content is organized inside some main subfolders:
    src - Contains the actual source code for the application (the various projects with their classes etc.)
    tests - Contains unit test projects
    docs - Contains documentation files
    samples - This is where you would place files that provide examples to users on how to use your code or library
    artifacts - Build outputs go here
    packages - Contains NuGet packages
    build - Contains build customization scripts

Notice that in some cases the same structure could be recursively applied to the individual projects of the solution (for instance, you could have a src and test folder for each project).

Naming conventions for projects and namespaces

From the name of a project it should be easy to understand the functionality of the code it contains. For instance, if a project contains math related operations, it would probably contain Math in its name.

Talking about naming conventions, there isn't an actual standard; some common practices include:

    CompanyName.ProductName.Component (eg. MyCompany.MyApplication.DataAccess)
    CompanyName.Component (eg. MyCompany.Math)
    ProductName.Component (eg. MyApplication.Models)

Once you've chosen your particular naming convention, it's important to remain consistent with it.

In the case of subfolders within the same project, the namespaces of the files within the subfolders reflect the same hierarchical structure. For example, in a MyApplication.DataAccess project, classes within a SqlServer folder would belong to a MyApplication.DataAccess.SqlServer namespace.
Use multiple projects to separate macro functionality or layers

A common mistake is to put too many different functionalities inside the same project in a .NET solution. This often leads, for instance, to situations where data access logic is mixed up with UI functionalities, and there isn't a clear separation between the two areas. Instead, separating the code into multiple projects within the same solution helps you keep the code cleanly sorted in multiple distinct logical groupings; think of this like putting your dishes in a separate compartment from the cutlery. This makes it easier to understand where to look for what you need, and where the new class you're writing should be created.

One way to group code into multiple projects is by major functionality. For example, everything related to math operations in an application could go in its own project, separate from UI or data access components.

Another common approach is to divide the application into layers, creating a separate project for each layer. This helps you manage dependencies and avoid circular references, so that each layer is visible only to the correct projects. As an example, think of creating a project for the UI layer, that references the Business Logic layer, that in turn references the Data access layer; this creates a clear separation between those different areas of the application.

Within the same project it is then possible to create additional groupings, putting classes and components with similar functionalities into subfolders. Returning to the previous analogy, it would be like dividing forks and spoons into separate sections within the same compartment. For example, a data access project might have a subfolder containing all implementations related to SQL databases, a subfolder for mock implementations, and so on.

The resulting folder structure could look like this:
$/
  MyApplication.sln
  src/
    MyApplication.UI/
      MyApplication.UI.csproj

    MyApplication.Math/
      MyApplication.Math.csproj

    MyApplication.Business/
      MyApplication.Business.csproj

    MyApplication.DataAccess/
      SqlServer/
        SqlServerRepository.cs
      Mock/
        MockRepository.cs
      IRepository.cs
      MyApplication.DataAccess.csproj


Unit tests organization
The structure and naming convention of unit test projects should reflect those of the source code that it's being tested, usually with an addition of a Tests suffix to the names of projects and classes.

For instance, the MyApplication.Math project would be tested by a unit test project called MyApplication.Math.Tests; the unit tests for a class called Calculator would be found in a test class named CalculatorTests.

$/
  MyApplication.sln
  src/
    MyApplication.Math/
      Calculator.cs
      MyApplication.Math.csproj
      Utilities/
        MathUtilities.cs

  tests/
    MyApplication.Math.Tests/
      CalculatorTests.cs
      MyApplication.Math.Tests.csproj
      Utilities/
        MathUtilitiesTests.cs


This article covered some common practices in organizing code for .NET projects. While there is no single true correct approach and every project is unique, these guidelines can help you clear up some confusion when starting to build a new application in .NET.

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 :: Cookie Sharing Authentication

clock June 7, 2022 08:31 by author Peter

Usually, web applications work together to integrate different functionalities in a single login. So, if web applications (eg: - multiple modules) can host within a primary application, it is easier to use ASP.NET Core cookie sharing mechanisms over a single sign-on (SSO) experience.

For example, we can start with two MVC applications in .Net core and share the cookie for authentication. Let’s consider the primary application name is “PrimarySite” and secondary application “Subsite”.

Initially both applications have similar startup.cs file.

public void ConfigureServices(IServiceCollection services) {
    services.AddControllersWithViews();
}
// 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?}");
    });
}


Step 1
First, we can make a login/register page in Primarysite. For that we need to add authentication middleware in configure method above UseAuthorization middleware.
app.UseAuthentication();


Steps 2
Set up a cookie sharing configuration with a key storage location in Configureservices method of startup.cs. The application name “SharedCookieApp” should be common in other applications/modules. (available namespace:- using Microsoft.AspNetCore.DataProtection;)

Then apply cookie policy configurations.

services.AddDataProtection().PersistKeysToFileSystem(GetKyRingDirectoryInfo()).SetApplicationName("SharedCookieApp");
services.Configure < CookiePolicyOptions > (options => {
    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
});


We are using different applications/solutions set samesite policy to “None”

GetKyRingDirectoryInfo is a custom method to retrieve common path directory.

private DirectoryInfo GetKyRingDirectoryInfo() {
    string applicationBasePath = System.AppContext.BaseDirectory;
    DirectoryInfo directoryInof = new DirectoryInfo(applicationBasePath);
    string keyRingPath = Configuration.GetSection("AppKeys").GetValue < string > ("keyRingPath");
    do {
        directoryInof = directoryInof.Parent;
        DirectoryInfo keyRingDirectoryInfo = new DirectoryInfo($ "{directoryInof.FullName}{keyRingPath}");
        if (keyRingDirectoryInfo.Exists) {
            return keyRingDirectoryInfo;
        }
    }
    while (directoryInof.Parent != null);
    throw new Exception($ "key ring path not found");
}


Common path can be set in appsettings.json
"keyRingPath": "\\PrimarySite\\wwwroot\\Ring"

 

 

We are using different applications/solutions set samesite policy to “None”

GetKyRingDirectoryInfo is a custom method to retrieve common path directory.
private DirectoryInfo GetKyRingDirectoryInfo() {
    string applicationBasePath = System.AppContext.BaseDirectory;
    DirectoryInfo directoryInof = new DirectoryInfo(applicationBasePath);
    string keyRingPath = Configuration.GetSection("AppKeys").GetValue < string > ("keyRingPath");
    do {
        directoryInof = directoryInof.Parent;
        DirectoryInfo keyRingDirectoryInfo = new DirectoryInfo($ "{directoryInof.FullName}{keyRingPath}");
        if (keyRingDirectoryInfo.Exists) {
            return keyRingDirectoryInfo;
        }
    }
    while (directoryInof.Parent != null);
    throw new Exception($ "key ring path not found");
}


Common path can be set in appsettings.json
"keyRingPath": "\\PrimarySite\\wwwroot\\Ring"


Step 3
For testing the register/login functionality, we can use in-memory database (data storing in memory not in real database). For that we need to install the below NuGet packages (entity framework core Identity and In-memory). This step is optional and used for testing register and login. Real entity framework can be used if it exists in the original application.

Then create a context class which inherits from IdentityDBContext

public class AppDbContext: IdentityDbContext {
    public AppDbContext(DbContextOptions < AppDbContext > options): base(options) {}
}


And Inject AddDbcontext with UseInmemmoryDatabase in Configureservice method.
#region DB
services.AddDbContext < AppDbContext > (config => {
    config.UseInMemoryDatabase("Memory");
});
#endregion


Configure Identity specification and EntityFramework core with AppDbContext.

services.Configure < CookiePolicyOptions > (options => {
    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddIdentity < IdentityUser, IdentityRole > (config => {
    config.Password.RequiredLength = 4;
    config.Password.RequireDigit = false;
    config.Password.RequireNonAlphanumeric = false;
    config.Password.RequireUppercase = false;
}).AddEntityFrameworkStores < AppDbContext > ().AddDefaultTokenProviders();

Step 4
Set authentication type set to Identity.Application and a common cookie name (.AspNet.SharedCookie) which should be same among different applications those shares cookie authentication.

services.AddAuthentication("Identity.Application");
services.ConfigureApplicationCookie(config => {
    config.Cookie.Name = ".AspNet.SharedCookie";
    config.LoginPath = "/Home/Login";
    //config.Cookie.Domain = ".test.com";
});

Step 6
This step is also optional. This is to show a simple authentication (If it already has a  different authentication setup, it would be good to use that.)

Creating a user registration and authentication within memory database.
[HttpPost]
public async Task < IActionResult > Register(string username, string password) {
    var user = new IdentityUser {
        UserName = username,
            Email = ""
    };
    var result = await _userManager.CreateAsync(user, password);
    if (result.Succeeded) {
        var signInResult = await _signInManager.PasswordSignInAsync(user, password, false, false);
        if (signInResult.Succeeded) {
            return RedirectToAction("LoginSuccess");
        }
    }
    return RedirectToAction("Login");
}


Step 7
Now the primarysite will get logged in after entering values in register/login. Now we need to configure Startup.cs of SubSite/ Sub module as below.

ConfigureServices Method.
public void ConfigureServices(IServiceCollection services) {
    services.AddDataProtection().PersistKeysToFileSystem(GetKyRingDirectoryInfo()).SetApplicationName("SharedCookieApp");
    services.Configure < CookiePolicyOptions > (options => {
        // This lambda determines whether user consent for nonessential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });
    services.AddAuthentication("Identity.Application").AddCookie("Identity.Application", option => {
        option.Cookie.Name = ".AspNet.SharedCookie";
        option.Events.OnRedirectToLogin = (context) => {
            context.Response.StatusCode = 401;
            return Task.CompletedTask;
        };
    });
    services.AddControllersWithViews();
}

option.Events.OnRedirectToLogin can be configured to redirect in case of not authorized/authenticated scenario.

Configure Method.
Add UsecookiePolicy middleware above UseRouting
app.UseCookiePolicy();

Add UseAuthentication middleware below UseRouting.
app.UseAuthentication();


Then Add common key path in appsettings.json
"keyRingPath": "\\PrimarySite\\wwwroot\\Ring"

Step 8
Run both application and login to Primary site and redirect to the subsite authorize method(add[Authorize] attribute for methods or controller for which authentication is mandatory).


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 :: AJAX In .NET Core

clock May 30, 2022 07:39 by author Peter

What is Ajax?
Ajax stands for Asynchronous JavaScript and XML, the data transmitted can be JSON, XML, HTML, JavaScript, plain text, etc. Regardless of the type of data, Ajax can send and receive it. Ajax uses a built-in object of all modern browsers called XMLHttpRequest. This object is used to exchange data back and forth between your Web page and a Web server, as shown below.

Types of AJAX Call

Ajax Methods Description
get() Sends HTTP GET request to load the data from the server.
Post() Sends HTTP POST request to submit or load the data to the server.
Put() Sends HTTP PUT request to update data on the server.
Delete() Sends HTTP DELETE request to delete data on the server.

STEP 1
Open VS 2022 click on create project as shown below,


 

Step 2
Choose the below mentioned template


 

Step 3
Now open the Model folder and add the 2 classes

    JsonResponseViewModel
    Student Model

This model will be used to communicate during ajax request. Below is the source code defination for both the models

[Serializable]
public class JsonResponseViewModel
{
    public int ResponseCode { get; set; }

    public string ResponseMessage { get; set; } = string.Empty;
}

public class StudentModel
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}

Step 4
Now add the GET|POST|PUT|DELETE function for the server so that we can perform operations

public class HomeController: Controller {
    private readonly ILogger < HomeController > _logger;
    public static List < StudentModel > students = new List < StudentModel > ();
    public HomeController(ILogger < HomeController > logger) {
        _logger = logger;
        students = new List < StudentModel > ();
        students.Add(new StudentModel() {
            Id = 1, Email = "[email protected]", Name = "Ankush"
        });
        students.Add(new StudentModel() {
            Id = 2, Email = "[email protected]", Name = "Rohit"
        });
        students.Add(new StudentModel() {
            Id = 3, Email = "[email protected]", Name = "Sunny"
        });
        students.Add(new StudentModel() {
            Id = 4, Email = "[email protected]", Name = "Amit"
        });
    }
    public IActionResult Index() {
        return View(students);
    }
    [HttpGet]
    public JsonResult GetDetailsById(int id) {
        var student = students.Where(d => d.Id.Equals(id)).FirstOrDefault();
        JsonResponseViewModel model = new JsonResponseViewModel();
        if (student != null) {
            model.ResponseCode = 0;
            model.ResponseMessage = JsonConvert.SerializeObject(student);
        } else {
            model.ResponseCode = 1;
            model.ResponseMessage = "No record available";
        }
        return Json(model);
    }
    [HttpPost]
    public JsonResult InsertStudent(IFormCollection formcollection) {
        StudentModel student = new StudentModel();
        student.Email = formcollection["email"];
        student.Name = formcollection["name"];
        JsonResponseViewModel model = new JsonResponseViewModel();
        //MAKE DB CALL and handle the response
        if (student != null) {
            model.ResponseCode = 0;
            model.ResponseMessage = JsonConvert.SerializeObject(student);
        } else {
            model.ResponseCode = 1;
            model.ResponseMessage = "No record available";
        }
        return Json(model);
    }
    [HttpPut]
    public JsonResult UpdateStudent(IFormCollection formcollection) {
        StudentModel student = new StudentModel();
        student.Id = int.Parse(formcollection["id"]);
        student.Email = formcollection["email"];
        student.Name = formcollection["name"];
        JsonResponseViewModel model = new JsonResponseViewModel();
        //MAKE DB CALL and handle the response
        if (student != null) {
            model.ResponseCode = 0;
            model.ResponseMessage = JsonConvert.SerializeObject(student);
        } else {
            model.ResponseCode = 1;
            model.ResponseMessage = "No record available";
        }
        return Json(model);
    }
    [HttpDelete]
    public JsonResult DeleteStudent(IFormCollection formcollection) {
        StudentModel student = new StudentModel();
        student.Id = int.Parse(formcollection["id"]);
        JsonResponseViewModel model = new JsonResponseViewModel();
        //MAKE DB CALL and handle the response
        if (student != null) {
            model.ResponseCode = 0;
            model.ResponseMessage = JsonConvert.SerializeObject(student);
        } else {
            model.ResponseCode = 1;
            model.ResponseMessage = "No record available";
        }
        return Json(model);
    }
}

Step 5
Switch to the view and add the AJAX Calls functions

@model IEnumerable<ajaxSample.Models.StudentModel>

@{
    ViewData["Title"] = "Home Page";
}
@section Scripts{
    <script>
        $(document).ready(function() {
            // GET BY ID
            $(".btn-get-student").on("click", function() {
                var formData = new FormData();
                var studentid = $(this).attr("data-studentid");
                var url = '@Url.Action("GetDetailsById", "Home")' + '/' + studentid;
                $.ajax({
                    type: 'GET',
                    url: url,
                    contentType: false,
                    processData: false,
                    cache: false,
                    data: formData,
                    success: function(response) {
                        if (response.responseCode == 0) {
                            var student = JSON.parse(response.responseMessage);
                            $("#email").val(student.Email);
                            $("#name").val(student.Name);
                            $("#hdn-student-id").val(student.Id);

                        }
                        else {
                            bootbox.alert(response.ResponseMessage);
                        }
                    },
                    error: errorCallback
                });
            });
            //SAVE
            $("#btn-insert-student").on("click", function() {
                var formData = new FormData();
                formData.append("name", $("#name").val());
                formData.append("email", $("#email").val());
                $.ajax({
                    type: 'POST',
                    url: '@Url.Action("InsertStudent", "Home")',
                    contentType: false,
                    processData: false,
                    cache: false,
                    data: formData,
                    success: successCallback,
                    error: errorCallback
                });
            });
            // UPDATE
            $("#btn-update-student").on("click", function() {
                var formData = new FormData();
                formData.append("id", $("#hdn-student-id").val());
                formData.append("name", $("#name").val());
                formData.append("email", $("#email").val());
                $.ajax({
                    type: 'PUT',
                    url: '@Url.Action("UpdateStudent", "Home")',
                    contentType: false,
                    processData: false,
                    cache: false,
                    data: formData,
                    success: successCallback,
                    error: errorCallback
                });
            });
            //DELETE
            $("#btn-delete-student").on("click", function() {
                var formData = new FormData();
                formData.append("id", $("#hdn-student-id").val());
                $.ajax({
                    type: 'DELETE',
                    url: '@Url.Action("DeleteStudent", "Home")',
                    contentType: false,
                    processData: false,
                    cache: false,
                    data: formData,
                    success: successCallback,
                    error: errorCallback
                });
            });
            function resetForm() {
                $("#hdn-student-id").val("");
                $("#name").val("");
                $("#email").val("");
            }
            function errorCallback() {
                bootbox.alert("Something went wrong please contact admin.");
            }
            function successCallback(response) {
                if (response.responseCode == 0) {
                    resetForm();
                    bootbox.alert(response.responseMessage, function() {

                        //PERFORM REMAINING LOGIC
                    });
                }
                else {
                    bootbox.alert(response.ResponseMessage);
                }
            };
        });
    </script>
}
    <div class="text-center">
        <h1 class="display-4">Welcome To ASP.NET CORE AJAX Demo</h1>
        <hr />
    </div>
    <div class="row">
        <div class="col-sm-12">
            <form>
                <input type="hidden" id="hdn-student-id" />
                <div class="row g-3">
                    <div class="col-sm-6">
                        <label for="email" class="form-label">Email</label>
                        <input type="email" class="form-control" id="email" placeholder="Enter your email">
                        <div class="invalid-feedback">
                            Please enter a valid email address for shipping updates.
                        </div>
                    </div>

                    <div class="col-sm-6">
                        <label for="lastName" class="form-label">Name</label>
                        <input type="text" class="form-control" id="name" placeholder="Enter Your Name" value="" required="">
                        <div class="invalid-feedback">
                            Name is required.
                        </div>
                    </div>

                </div>
                <table class="table">
                    <tbody>
                        <tr>
                            <td>  <a href="javascript:void(0)" class="btn btn-primary" id="btn-insert-student">Save Student</a></td>
                            <td>
                                <a href="javascript:void(0)" class="btn btn-info" id="btn-update-student">Update Student</a>
                            </td>
                            <td>
                                <a href="javascript:void(0)" class="btn btn-danger" id="btn-delete-student">Delete Student</a>
                            </td>
                        </tr>
                    </tbody>

                </table>
            </form>

        </div>
        <br />
    </div>
    <div class="row">
        <div class="col-md-12">
            <table class="table table-bordered">
                <thead>
                    <tr>
                        <td>#</td>
                        <td>Name</td>
                        <td>Email</td>
                        <td>Action</td>
                    </tr>
                </thead>
                <tbody id="student-list">
                    @{

                    foreach (var student in Model)
                    {
                        <tr>
                            <td>@student.Id</td>
                            <td>@student.Name</td>
                            <td>@student.Email</td>
                            <td>
                                <a href="javascript:void(0)" data-studentid="@student.Id" class="btn btn-success btn-get-student">Get Student</a>
                            </td>
                        </tr>
                    }
                }
            </tbody>
        </table>
    </div>
</div>

RUN the code and you will see the below mentioned O/P,

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 :: Populating Dropdown Menu Using AJAX In ASP.NET Core

clock May 27, 2022 10:46 by author Peter

In this blog, we will study how to populate the dropdown menu using ajax call in asp.net net core step by step.

Step 1 - Add the jQuery CDN to your application
First of all, you need to add the jQuery CDN to your application that helps us to run the jQuery Code smoothly in the application.

Step 2 - Write the Ajax Call
The second step is to write the ajax call that is used to handle the asp.net Controller for bringing the data from the database in the form of JSON Object.

Add this Ajax call where you want to get the data from the database using the Asp.net Core Controller.
<script type = "text/javascript" > $(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "/Bookings/FromLocation",
        data: "{}",
        success: function(data) {
            var s = '<option value="-1">Pickup Location</option>';
            for (var i = 0; i < data.length; i++) {
                console.log(data[i])
                s += '<option value="' + data[i].id + '">' + data[i].name + " " + data[i].address + '</option>';
            }
            $("#PickUpLocation").html(s);
        }
    });
});
</script>


Step 3 - Write the Asp.net Core Controller
The third step is to write the controller that is used to handle the HTTP request and bring the data from the database.

Note: the name of the controller should be the same as in the ajax call.
public Object FromLocation()
{
    return (_context.Locations.Select(x => new
    {
        Id = x.Id,
        Name = x.Name,
        Address = x.Address
    }).ToList().Where(x => x.Name != null && x.Address != null));
}


Step 4 - Pass the Data to Dropdown Menu

One thing that should be in your mind  is that the id of the select option should be the same as in the Ajax call.
<div class="form-group">
    <label asp-for="PickUpLocation" class="control-label"></label>
        <div class="form-group">
            <select class="form-control" asp-for="PickUpLocation" id="PickUpLocation" name="PickUpLocation"></select>
            <span asp-validation-for="PickUpLocation" class="text-danger"></span>
        </div>
</div>


Output
Now you can see that our data is now populated in the dropdown menu

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 :: Minimal APIs In .NET 6

clock May 24, 2022 07:50 by author Peter

Today we will look at minimal APIs, a new feature in .NET 6. In the past, we created controllers in order to create an API which could be consumed by our clients. In .NET 6, a new feature called Minimal APIs has been introduced. This allows us to create an API with minimum code and plumbing. In fact, it is created directly in the Program.cs file. In .NET 6, the Startup.cs file is also not required anymore, and all initial plumbing is done inside the Program.cs file. We will create a simple Minimal API. So, let us begin.
Creating Minimal APIs

Let us start by opening Visual Studio 2022. I use the community edition which is free to download and use.

Select “Create a new project”.


Select “ASP.NET Core Web API”.


 

Remember to uncheck the highlighted option to use minimal APIs


Open the “Program.cs” file and update as below,

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var summaries = new [] {
    "Freezing",
    "Bracing",
    "Chilly",
    "Cool",
    "Mild",
    "Warm",
    "Balmy",
    "Hot",
    "Sweltering",
    "Scorching"
};
app.MapGet("/weatherforecast", () => {
    var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast(DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)])).ToArray();
    return forecast;
}).WithName("GetWeatherForecast");
app.MapGet("/welcomemessage", () => {
    return "Welcome to Minimal APIs";
}).WithName("GetWelcomeMessage");
app.Run();
internal record WeatherForecast(DateTime Date, int TemperatureC, string ? Summary) {
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Running the application
We now run the application and see the swagger page as below,

Here, we can try both the minimal APIs we have in our code.


 

In this article, we looked at creating a minimal API, a new feature in .NET 6. The example here was a simple one but it gives an idea of the concept and more complex APIs can be added. Probably for more complex APIs, refactoring into a separate file is a good idea. Happy coding!

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 :: Log Correlation In Microservices

clock May 17, 2022 07:45 by author Peter

Logging is one of the most important factors to trace any issue in the system. Multiple requests will reach the system at the same time. Each request will have its own way. In Microservices architecture the complexity will be more. The same request will get forwarded to multiple systems. Each layer in each system will add some logs to trace the issue. But we need to link all the logs belonging to the request. Then only we identify how the request is behaving on each system. To Link all the logs into a single link, that is why correlation is required.

There are multiple frameworks available to correlate all the logs.

Azure is providing azure app insights to link and showcase all the requests into a single pipeline. Kibana and Serilog also provide to link the logs. Here we are going to see to link the logs without any third-party components.
Setup the CorrelationId

The request will originate from any client application or any subsystem. Each request can be identified by its reuestId. So the origin system can send its requestId or we can create the Id in case the origin didn't send it.

public class CorrelationHeaderMiddleware {
    private readonly RequestDelegate _next;
    public CorrelationHeaderMiddleware(RequestDelegate next) {
        _next = next;
    }
    public async Task InvokeAsync(HttpContext context) {
        var correlationHeaders = context.Request.Headers["CorrelationId"];
        string correlationId;
        if (correlationHeaders.Any()) {
            correlationId = correlationHeaders[0];
        } else {
            correlationId = Guid.NewGuid().ToString();
            context.Request.Headers.Add("CorrelationId", correlationId);
        }
        context.Items["CorrelationId"] = correlationId;
        await _next(context);
    }
}

We have created new middleware that will fetch the correlation from the httpcontext or it will create the new id and set it into the request. Middleware is added into the request pipeline. All the requests will be processed and they will be added with CorrelationId.
Setup Logs

The request will get into multiple flows and add its logs. While adding the logs it will send the information alone to the log. While saving the logs we are fetching the CorrelationId from the request and adding it with the logs. So all the logs will get added with CorrelationId. After that, we can store the logs based on our format.

public class Logger: ILogType {
    private readonly ILogger < Logger > _logger;
    private readonly IHttpContextAccessor _httpContextAccessor;
    public Logger(ILogger < Logger > logger, IHttpContextAccessor httpContextAccessor) {
        _logger = logger;
        _httpContextAccessor = httpContextAccessor;
    }
    private string GetCorrelationId() {
        return _httpContextAccessor.HttpContext.Items["CorrelationId"] as string;
    }
    public void ProcessError(string message) {
        _logger.LogError(GetCorrelationId() + ": " + message);
    }
    public void ProcessLogs(string message) {
        _logger.LogInformation(GetCorrelationId() + ": " + message);
    }
    public void ProcessWarning(string message) {
        _logger.LogWarning(GetCorrelationId() + ": " + message);
    }
}


The request needs to be forwarded to multiple systems to complete it. To send the request to multiple subsystems, we need to use any protocol like HTTP or AMQP. In this case, we need to attach the CorrelationId as a header with the corresponding protocol. The corresponding subsystem will read the id and logs the stuff.

All the log data will be get stored in the same or multiple systems. But CorrelationId will be the key to linking all the logs. Using this id we can fetch the request flow order. It will help to understand the system's flow as well as to trace any issue in the system's behavior. Adding more logs will increase the system space. We need to ensure the log type on each log also.

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 :: How To Migrate From .NET Core 3.1 To .NET 6.0?

clock May 9, 2022 07:54 by author Peter


.Net 6 is an LTS (Long Tern Support) Version. It will be supported for three years. It is the latest long-term support release. The previous version, .Net Core 3.1 support will be finalized in December 2022, and support for .Net 5 will be ended May 2022. This article describes how to upgrade the solution from .Net Core 3.1 to .NET 6.0 with an example of Console application and .Net Core 3.1 class library project. Upgrading console applications and class library project is almost similar. However, there is some difference between Upgrading ASP.NET Core Web app.

Prerequisites
    Visual Studio 2022

Step 1 - Upgrade the Target Framework
Right-click on the project then go to properties and change the target.

Then select the target framework to .NET 6.0 as depicted below and save it.

Alternatively from project.csproj file you can change the target Framework from netcore3.1 to net 6.0 as shown below.

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

Step 2 - Updating Package references
Update Package references if there are any. Go to Project.csproj file and upgrade packages as shown below.


For an instance upgrade the package Microsoft.AspNetCore.JsonPatch and Microsoft.EntityFrameworkCore.Tools and so on from version 3.1.6 to 6.0.0 as illustrated below.

<ItemGroup>
-    <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="3.1.6" />
-    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.6" />
-    <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" />
-    <PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
+    <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="6.0.0" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
+    <PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
</ItemGroup>

Step 3 - Delete obj and bin folder

You may need to delete the existing bin and obj folder. Go to the respective project directory and delete those folders. Additionally, you can delete the NuGet cache by running the below command.
dotnet nuget locals --clear all

Step 4 - Build the solution

Then build the solution and see whether there are errors or your app is built successfully. If there are errors based on an error message correct the code and rebuild the solution. On successful build of the application, your app is upgraded to the .NET 6.0.

The above three steps are required to follow to upgrade the class library and console application to migrate from .NET Core 3.1 to .NET 6.0.

On the other hand, to update the Asp.NET Core 3.1 and Blazor application you need to follow more steps in addition to the above three.

Following are some changes you need to consider for upgrading ASP.NET Core 3.1 web application to .NET6

    Minimal hosting and statup.cs file changes
    Note that minimal hosting unifies the Startup.cs and Program.cs to a single Program.cs file. Moreover, the ConfigureServices and Configure are no longer used in .NET6.0.
    Model Binding
    Datetime values are model bound as UTC timezone. For applications build on ASP .NET Core 5 and later, model binding binds the DateTime as UTC timezone whereas, in applications built using ASP.NET Core 3.1 and earlier, Datetime values were model bound as local time and the timezone was determined by the server.
    Docker Image
    If your app uses docker then you need to pull a Docker image that consists of ASP.NET Core 6.0 runtime as well. The below command can be used for that.

docker pull mcr.microsoft.com/dotnet/aspnet:6.0

You can check the details on the below document.

In this article, we have learned how to upgrade the project from .NET Core 3.1 to .NET 6.0 with an example of a console application. This article will be useful while migrating your application from .NET Core 3.1 to .NET 6.0 without encountering any issues. Best of luck to migrate your application before the end of support.

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 :: Introduction To Postman

clock April 26, 2022 09:43 by author Peter

In this step-by-step article series, we are going to learn about the Postman. This article covers the following topics:
    What is Postman?
    Features
    How to make a first GET API request?

What is Postman?
It is an API platform to build and use APIs. You can create better or faster APIs with the help of an API repository, tools, intelligence, workspace, and integrations. It is built on open-source technologies.
    API repository – Using the central platform you can easily store, catalog, and collaborate all your API-related stuff like test cases, specifications, documentation, etc.
    Tools – It provides various sets of API tools to accelerate the API lifecycle like design, testing, mocking, documentation, etc.
    Intelligence – It provides an advanced level of intelligence and insights about the API operations alerts, search, security warnings, reporting, etc.
    Workspace – It helps you to organize your API work and collaborate across the world. There are three different workspaces – personal, team and public.
    Integrations – It is a most important tool in the software development pipeline to go with API-first practices. You can integrate postman into the code repositories, CI/CD pipeline, you can build your integrations using the postman API, etc.

So, what are you waiting for go and download the Postman, start designing, testing, and documenting API - https://www.postman.com/downloads/
It comes in two types of versions desktop app and a web version.

Features
It provides a bunch of cool features some are as below:

Request
    Create, send and save REST, SOAP, or GraphQL requests.
    Save request to collections.
    Send a request through a proxy server, etc.

Response

    View status code, response time, headers, and size.
    View response body in raw and pretty view.
    Save response as an example, etc.

Variables
    Built-in support for variables.
    Create and set variables for collections, environments, and global.
    Dynamic variables for dummy data, etc.

Scripts and Postman sandbox

    Write scripts at the collection, folder, or request level.
    Write pre or post-request scripts for after or before the request.
    Use scripts to send the request, etc.

Collaboration
    Create unlimited personal or team workspaces.
    Create a private workspace(Enterprise only).
    You can set roles, and invite members, etc.

Collections
    They are executable API descriptions.
    You can organize and keep track of related requests.
    You can share collections to workspaces, etc.

How to make a first GET API request?
I hope you have installed any one of the postman versions on your system desktop, or web version, follow the below steps to make your first request in postman:

Step 1

Open the Postman app.(Using the desktop version)

Once you open the Postman, you will see the output as above screenshot. This is what the postman UI looks like and you can see the various options such as Sign-in, Create Account, Home, Workspace, Reports, Explore, Collections, API, Environments, etc. these options we are going learn in upcoming articles.

Step 2

Click on the plus icon button as shown below screenshot:

It will open the request pop-up in the same window like the below screenshot:


Step 3
Next, enter the URL for our first GET request as ‘https://api.github.com/users/jsgund’ and click on send button as below screenshot:

Step 4
Once you click on send button you will get the response as below screenshot:

In this example, we are accessing the GitHub to get users to request by id and at the end, you can see my GitHub login id as “jsgund”. In the response, you will get the details of the GitHub login id “jsgund”, properties such as name, id, imageUrl, followers URL, etc.

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 :: How To Handle Nullable Reference In .NET 6?

clock April 20, 2022 09:08 by author Peter

As we know there are so many changes in .Net 6 and C# 10. In this article, we will explore one of the changes in C#10 on the writing properties and objects of a class. More details on new features or changes in .NET 6 can be found in the previous article Features of .NET 6.

In .NET 5 and lower versions, we can write properties and objects of class like below.
public class Person {
    public string Name;
    public string Sex;
    public string Address;
    public string Email;
}


However, it has been changed in C# 10. If we write like earlier, the compiler shows a warning like below.

So, to handle this there are different ways. In this article, we will learn those methods to handle the warnings.

Let’s create a console application in .NET6
Create Console Application in .NET 6

Step 1
Open Visual Studio 2022 and click Create a new project.

Step 2
Select Console App and click Next.

Step 3
Give the project name and location of the project.

Step 4
Select framework: .NET 6.0 (Long-term support).

This creates the console app which looks like below.

Default Program.cs file is listed below.

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");


Now, let’s compile and run the program. when you run it, it will display the “Hello, World!” message. Now, we will move to the main point of this write-up.
Add a New Class

Right-click on project -> add class and give the name of the class as Person.

Person class contains the following properties. Write the below code.

public class Person {
    public string Name;
    public string Sex;
    public string Address;
    public string Email;
    public string Description {
        get;
        set;
    }
}

Then, you will get the warning as depicted below.

Let’s jump to different ways to handle the compiler warning.

Method 1
Changing the project file(project.csproj). You disable or remove the nullable in csproj file so that it will not show the warning message. Right-click on the project and Edit the project as shown below.

Then project file will be opened, and you can simply disable Nullable as illustrated below.

Inside the PropertyGroup change Nullable to disable as shown below or remove that line.
<Nullable>disable</Nullable>

Method 2: Giving default value

You can assign it in different ways:
    a default value
    reasonable default value as a string.Empty or
    “”

as illustrated in the below code.

public class Person {
    public string Name = "Default Value";
    public string Sex = "";
    public string Address = "";
    public string Email = string.Empty;
    public string Description {
        get;
        set;
    } = string.Empty;
}


Method 3
Another way to handle it is to make properties nullable reference type by simply using "?" as demonstrated below.
public class Person {
    public string ? Name;
    public string ? Sex;
    public string ? Address;
    public string ? Email;
    public string ? Description {
        get;
        set;
    }
}


Overall, in .NET 6 we should define the variable, properties, or field explicitly as either nullable or non-nullable with a reference type.

Summary

In this article, I have created a console application in .NET 6 and demonstrated issues with fields or properties if we code as in .NET 5 or lower. Additionally, the article has provided the different methods to handle such situations in .NET 6. Hence, these are the three ways to handle the nullable, non-nullable field and properties in .NET 6. I hope you have got an idea about it.

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 ::How To Add KendoUI Grid In Angular With .NET Core API With Multilayer Architecture

clock April 19, 2022 08:42 by author Peter

In this part of the article, we learn how to create .Net Core API for the KendoUI Curd Operations. Also here we learn the multilayer architecture of .Net Core API.

Preconditions
    Basic knowledge of Angular CLI
    Basic knowledge of Dot Net core
    Basic knowledge of SQL server
    Bootstrap
    Node.js
    V.S. Code,Visual Studio

We cover the below things

    Create Dot Net Core API
    Create Angular application
    Angular Routing
    Kendo UI setup
    Bind KendoUI grid

Add this script to the database to create table.

Create Database KendoUIDb
CREATE TABLE [dbo].[Users](
    [UserId] [int] primary key IDENTITY(1,1) NOT NULL,
    [UserName] [nvarchar](56) NOT NULL,
    [FullName] [nvarchar](200) NULL,
    [EmailId] [nvarchar](200) NULL,
    [Contactno] [nvarchar](10) NULL,
    [Password] [nvarchar](200) NULL,
    [Createdby] [int] NULL,
    [CreatedDate] [datetime] NULL,
    [Status] [bit] NULL,
    [imagename] [varchar](100) NULL
)


Now let's create a .Net API Project in visual studio using the following steps.

We have to create four libraries mentioned in the below image.

Now we add the references of project for interconnect.


Now we will create the following files according to the below images.


Now add the following packages from nuget package manager.

Now add the below code in the Custom.cs file.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using KendoApi.ViewModels;
namespace KendoApi.Common {
    public class Custom {
        public static string UploadImage(UsersViewModel users, IHostingEnvironment _environment, string routePath = "") {
            string filesName = "";
            if (users.file != null) {
                //Getting FileName
                var fileName = Path.GetFileName(users.file.FileName);
                //Assigning Unique Filename (Guid)
                var myUniqueFileName = Convert.ToString(Guid.NewGuid());
                //Getting file Extension
                var fileExtension = Path.GetExtension(fileName);
                // concatenating  FileName + FileExtension
                var newFileName = String.Concat(myUniqueFileName, fileExtension);
                filesName = newFileName;
                // Combines two strings into a path.
                var filepath = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Images")).Root + $ @ "\{newFileName}";
                using(FileStream fs = System.IO.File.Create(filepath)) {
                    users.file.CopyTo(fs);
                    fs.Flush();
                }
            } else {
                if (users.imagename == null) {
                    filesName = "";
                } else {
                    filesName = users.imagename != "" ? users.imagename.Replace("http://" + routePath + "/images/", "") : null;
                }
            }
            return filesName;
        }
    }
}

Now add the below code in the CustomExceptionFilterAttribute.cs file.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
namespace KendoApi.Common {
    public class CustomExceptionFilterAttribute: ExceptionFilterAttribute {
        private readonly IHostingEnvironment _hostingEnvironment;
        public CustomExceptionFilterAttribute(IHostingEnvironment hostingEnvironment) {
            _hostingEnvironment = hostingEnvironment;
        }
        public override void OnException(ExceptionContext context) {
            string strLogText = "";
            Exception ex = context.Exception;
            context.ExceptionHandled = true;
            var objClass = context;
            strLogText += "Message ---\n{0}" + ex.Message;
            if (context.HttpContext.Request.Headers["x-requested-with"] == "XMLHttpRequest") {
                strLogText += Environment.NewLine + ".Net Error ---\n{0}" + "Check MVC Ajax Code For Error";
            }
            strLogText += Environment.NewLine + "Source ---\n{0}" + ex.Source;
            strLogText += Environment.NewLine + "StackTrace ---\n{0}" + ex.StackTrace;
            strLogText += Environment.NewLine + "TargetSite ---\n{0}" + ex.TargetSite;
            if (ex.InnerException != null) {
                strLogText += Environment.NewLine + "Inner Exception is {0}" + ex.InnerException;
                //error prone
            }
            if (ex.HelpLink != null) {
                strLogText += Environment.NewLine + "HelpLink ---\n{0}" + ex.HelpLink; //error prone
            }
            StreamWriter log;
            string timestamp = DateTime.Now.ToString("d-MMMM-yyyy", new CultureInfo("en-GB"));
            string errorFolder = Path.Combine(_hostingEnvironment.WebRootPath, "ErrorLog");
            if (!System.IO.Directory.Exists(errorFolder)) {
                System.IO.Directory.CreateDirectory(errorFolder);
            }
            // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
            if (!File.Exists($ @ "{errorFolder}\Log_{timestamp}.txt")) {
                log = new StreamWriter($ @ "{errorFolder}\Log_{timestamp}.txt");
            } else {
                log = File.AppendText($ @ "{errorFolder}\Log_{timestamp}.txt");
            }
            var controllerName = (string) context.RouteData.Values["controller"];
            var actionName = (string) context.RouteData.Values["action"];
            // Write to the file:
            log.WriteLine(Environment.NewLine + DateTime.Now);
            log.WriteLine("------------------------------------------------------------------------------------------------");
            log.WriteLine("Controller Name :- " + controllerName);
            log.WriteLine("Action Method Name :- " + actionName);
            log.WriteLine("------------------------------------------------------------------------------------------------");
            log.WriteLine(objClass);
            log.WriteLine(strLogText);
            log.WriteLine();
            // Close the stream:
            log.Close();
            if (!_hostingEnvironment.IsDevelopment()) {
                // do nothing
                return;
            }
            var result = new RedirectToRouteResult(new RouteValueDictionary {
                {
                    "controller",
                    "Errorview"
                }, {
                    "action",
                    "Error"
                }
            });
            // TODO: Pass additional detailed data via ViewData
            context.Result = result;
        }
    }
}

Now add the below code in the UserController.cs file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using KendoApi.Common;
using KendoApi.Interface;
using KendoApi.Models;
using KendoApi.ViewModels;
using System.Web;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using AutoMapper;
namespace KendoApi.Controllers {
    //[Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class UserController: ControllerBase {
        private readonly IUsers _users;
        private readonly IHostingEnvironment _environment;
        private readonly IHttpContextAccessor _httpContextAccessor;
        public UserController(IUsers users, IHostingEnvironment environment, IHttpContextAccessor httpContextAccessor) {
            _users = users;
            _environment = environment;
            _httpContextAccessor = httpContextAccessor;
        }
        // GET: api/User
        [HttpGet]
        public IEnumerable < Users > Get() {
            var path = _httpContextAccessor.HttpContext.Request.Host.ToString();
            var UserData = _users.GetAllUsers(path);
            return UserData;
        }
        // GET: api/User/5
        [HttpGet]
        [Route("GetByUserName")]
        public Users GetByUserName(string username = "") {
            var path = _httpContextAccessor.HttpContext.Request.Host.ToString();
            var UserData = _users.GetByUserName(username, path);
            return UserData;
        }
        // GET: api/User/5
        [HttpGet("{id}", Name = "GetUsers")]
        public Users Get(int id) {
                var UserData = _users.GetUsersbyId(id);
                var password = EncryptionLibrary.DecryptText(UserData.Password);
                return UserData;
            }
            [HttpPost]
        public IActionResult Post([FromForm] UsersViewModel users) {
            var path = _httpContextAccessor.HttpContext.Request.Host.ToString();
            var Result = Custom.UploadImage(users, _environment, path);
            string imagepath = "http://" + path + "/images/";
            var _rootPath = _environment.WebRootPath;
            if (ModelState.IsValid) {
                if (_users.CheckUsersExits(users.UserName)) {
                    var response = new HttpResponseModel() {
                        StatusCode = (int) HttpStatusCode.Conflict,
                            data = ""
                    };
                    return Ok(response);
                } else {
                    var userId = this.User.FindFirstValue(ClaimTypes.Name);
                    var tempUsers = AutoMapper.Mapper.Map < Users > (users);
                    tempUsers.UserName = users.UserName;
                    tempUsers.imagename = users.file != null ? users.file.FileName : "";
                    tempUsers.CreatedDate = DateTime.Now;
                    tempUsers.imagename = Result;
                    tempUsers.Createdby = Convert.ToInt32(userId);
                    tempUsers.Password = EncryptionLibrary.EncryptText(users.Password);
                    _users.InsertUsers(tempUsers);
                    var response = new HttpResponseModel() {
                        StatusCode = (int) HttpStatusCode.OK,
                            data = imagepath + tempUsers.imagename
                    };
                    return Ok(response);
                }
            } else {
                var Results = ModelState.Values.ToList()[0].Errors.Count().ToString();
                var response = new HttpResponseModel() {
                    StatusCode = (int) HttpStatusCode.BadRequest,
                        data = ""
                };
                return Ok(Results);
            }
        }
        // PUT: api/User/5
        [HttpPut("{id}")]
        public IActionResult Put(int id, [FromForm] UsersViewModel users) {
            if (ModelState.IsValid) {
                var path = _httpContextAccessor.HttpContext.Request.Host.ToString();
                string imagepath = "http://" + path + "/images/";
                var Result = Custom.UploadImage(users, _environment, path);
                users.Password = EncryptionLibrary.EncryptText(users.Password);
                var tempUsers = AutoMapper.Mapper.Map < Users > (users);
                tempUsers.UserId = id;
                tempUsers.CreatedDate = DateTime.Now;
                tempUsers.imagename = Result;
                _users.UpdateUsers(tempUsers);
                var response = new HttpResponseModel() {
                    StatusCode = (int)(HttpStatusCode.OK),
                        data = imagepath + tempUsers.imagename
                };
                return Ok(response);
            } else {
                var response = new HttpResponseModel() {
                    StatusCode = (int) HttpStatusCode.BadRequest,
                        data = ""
                };
                return Ok(response);
            }
        }
        // DELETE: api/ApiWithActions/5
        [HttpDelete("{id}")]
        public HttpResponseMessage Delete(int id) {
            var result = _users.DeleteUsers(id);
            if (result) {
                var response = new HttpResponseMessage() {
                    StatusCode = HttpStatusCode.OK
                };
                return response;
            } else {
                var response = new HttpResponseMessage() {
                    StatusCode = HttpStatusCode.BadRequest
                };
                return response;
            }
        }
    }
}

Now add the below code in the MappingProfile.cs file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using KendoApi.Models;
using KendoApi.ViewModels;

namespace KendoApi.Mappings
{
    public class MappingProfile : Profile
    {
        public MappingProfile()
        {

            CreateMap<UsersViewModel, Users>()
                .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.UserName))
                .ForMember(dest => dest.Contactno, opt => opt.MapFrom(src => src.Contactno))
                .ForMember(dest => dest.EmailId, opt => opt.MapFrom(src => src.EmailId))
                .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.FullName))
                .ForMember(dest => dest.Password, opt => opt.MapFrom(src => src.Password))
                .ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.Id))
                .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status));
        }
    }
}

Now add the below code in the AppSettings.cs file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace KendoApi.Models {
    public class AppSettings {
        public string Secret {
            get;
            set;
        }
    }
}

Now add the below code in the AppSettings.cs file.

{
    "AppSettings": {
        "Secret": "6XJCIEJO41PQZNWJC4RR"
    },
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },
    "AllowedHosts": "*",
    "ConnectionStrings": {
        "DatabaseConnection": "Data Source=DESKTOP-13P092J\\SA; UID=sa; Password=sa123;Database=KendoUIDb;"
    }
}

Now add the below code in the Startup.cs file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using KendoApi.Common;
using KendoApi.Concrete;
using KendoApi.Interface;
using KendoApi.Mappings;
using KendoApi.Models;
namespace KendoApi {
    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.Configure < CookiePolicyOptions > (options => {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            #region MyRegion
            var connection = Configuration.GetConnectionString("DatabaseConnection");
            services.AddDbContext < DatabaseContext > (options => options.UseSqlServer(connection, b => b.UseRowNumberForPaging()));
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure < AppSettings > (appSettingsSection);
            // configure jwt authentication
            var appSettings = appSettingsSection.Get < AppSettings > ();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x => {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(x => {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters {
                    ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(key),
                        ValidateIssuer = false,
                        ValidateAudience = false
                };
            });
            services.AddSingleton < IConfiguration > (Configuration);
            services.AddTransient < IUsers, UsersConcrete > ();
            services.AddSingleton < IActionContextAccessor, ActionContextAccessor > ();
            services.AddScoped < IUrlHelper > (implementationFactory => {
                var actionContext = implementationFactory.GetService < IActionContextAccessor > ().ActionContext;
                return new UrlHelper(actionContext);
            });
            #endregion
            services.AddSingleton < IHttpContextAccessor, HttpContextAccessor > ();
            services.AddHttpContextAccessor();
            // Start Registering and Initializing AutoMapper
            Mapper.Initialize(cfg => cfg.AddProfile < MappingProfile > ());
            services.AddAutoMapper();
            // End Registering and Initializing AutoMapper
            services.Configure < FormOptions > (options => {
                options.ValueCountLimit = 200; //default 1024
                options.ValueLengthLimit = 1024 * 1024 * 100; //not recommended value
                options.MultipartBodyLengthLimit = long.MaxValue; //not recommended value
            });
            services.AddMvc(options => {
                options.Filters.Add(typeof(CustomExceptionFilterAttribute));
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddJsonOptions(options => {
                options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
            });
            services.AddCors(options => {
                options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials().WithExposedHeaders("X-Pagination"));
            });
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            } else {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseAuthentication();
            app.UseCors("CorsPolicy");
            app.UseMvc(routes => {
                routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Now add the below code in the DatabaseContext.cs file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using KendoApi.Models;
namespace KendoApi.Concrete {
    public class DatabaseContext: DbContext {
        public DatabaseContext(DbContextOptions < DatabaseContext > options): base(options) {}
        public DbSet < Users > Users {
            get;
            set;
        }
    }
}

Now add the below code in the UsersConcrete.cs file.

using System;
using System.Collections.Generic;
using KendoApi.Models;
using KendoApi.ViewModels;
namespace KendoApi.Interface {
    public interface IUsers {
        bool InsertUsers(Users user);
        bool CheckUsersExits(string username);
        Users GetUsersbyId(int userid);
        bool DeleteUsers(int userid);
        bool UpdateUsers(Users role);
        List < Users > GetAllUsers(string rootpath = "");
        bool AuthenticateUsers(string username, string password);
        Users GetByUserName(string username, string rootpath);
    }
}

Now add the below code in the Users.cs file.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KendoApi.Models {
    [Table("Users")]
    public class Users {
        [Key]
        public int UserId {
            get;
            set;
        }
        public string UserName {
            get;
            set;
        }
        public string FullName {
            get;
            set;
        }
        public string EmailId {
            get;
            set;
        }
        public string Contactno {
            get;
            set;
        }
        public string Password {
            get;
            set;
        }
        public int ? Createdby {
            get;
            set;
        }
        public string imagename {
            get;
            set;
        }
        public DateTime ? CreatedDate {
            get;
            set;
        }
        public bool Status {
            get;
            set;
        }
    }
}

Now add the below code in the HttpResponseModel.cs file.

using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KendoApi.ViewModels {
    public class HttpResponseModel {
        public string data {
            get;
            set;
        }
        public int StatusCode {
            get;
            set;
        }
    }
}

Now add the below code in the UsersViewModel.cs file.

using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KendoApi.ViewModels {
    public class UsersViewModel {
        public int Id {
            get;
            set;
        }
        public int UserId {
            get;
            set;
        }
        //[Required]
        public string UserName {
            get;
            set;
        }
        // [Required]
        public string FullName {
            get;
            set;
        }
        // [Required]
        public string EmailId {
            get;
            set;
        }
        // [Required]
        public string Contactno {
            get;
            set;
        }
        //   [Required]
        public string Password {
            get;
            set;
        }
        public bool Status {
            get;
            set;
        }
        [NotMapped]
        public IFormFile file {
            get;
            set;
        }
        public string imagename {
            get;
            set;
        }
        //     public List<IFormFile> files { get; set; }
    }
}

We have completed the API part, now in the next part we will work on binding the KendoUI Grid with API.

Summary
In this article, we learned how to create .Net core multilayer architecture for API with curd operations.



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