All About ASP.NET and ASP.NET Core 2 Hosting BLOG

Tutorial and Articles about ASP.NET and the latest ASP.NET Core

ASP.NET Core Hosting - ASPHostPortal :: API Project ASP.NET Core

clock September 25, 2018 09:26 by author Jervis

In this post, we are going to write about what we consider to be the best practices while developing the .NET Core Web API project. How we can make it better and how to make it more maintainable.

Startup Class and the Service Configuration

In the Startup class, there are two methods: the ConfigureServices method for registering the services and the Configure method for adding the middleware components to the application’s pipeline.

So, the best practice is to keep the ConfigureServices method clean and readable as much as possible. Of course, we need to write the code inside that method to register the services, but we can do that in more readable and maintainable way by using the Extension methods.

For example, let’s look at the wrong way to register CORS:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());
    });
}    

Even though this way will work just fine, and will register CORS without any problem, imagine the size of this method after registering dozens of services.

That’s not readable at all.

The better way is to create an extension class with the static method: 

public static class ServiceExtensions
{
    public static void ConfigureCors(this IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        });
    }
}

And then just to call this extended method upon the IServiceCollection type:

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

Project Organization

We should always try to split our application into smaller projects. That way we are getting the best project organization and separation of concerns (SoC). The business logic related to our entities, contracts, accessing the database, logging messages or sending an email message should always be in a separate .NET Core Class Library project.

Every small project inside our application should contain a number of folders to organize the business logic.

Here is just one simple example how a complete project should look like: 

Environment Based Settings

While we develop our application, that application is in the development environment. But as soon as we publish our application it is going to be in the production environment. Therefore having a separate configuration for each environment is always a good practice.

In .NET Core, this is very easy to accomplish.

As soon as we create the project, we are going to get the appsettings.json file and when we expand it we are going to see the appsetings.Development.json file:

All the settings inside this file are going to be used for the development environment.

We should add another file appsettings.Production.json, to use it in a production environment:

The production file is going to be placed right beneath the development one.

Data Access Layer

In many examples and different tutorials, we may see the DAL implemented inside the main project and instantiated in every controller. This is something we shouldn’t do.

When we work with DAL we should always create it as a separate service. This is very important in the .NET Core project because when we have DAL as a separate service we can register it inside the IOC (Inversion of Control) container. The IOC is the .NET Core’s built-in feature and by registering a DAL as a service inside the IOC we are able to use it in any controller by simple constructor injection:

public class OwnerController: Controller
{
    private IRepository _repository;
 
    public OwnerController(IRepository repository)
    {
        _repository = repository;
    }
}

Controllers

The controllers should always be as clean as possible. We shouldn’t place any business logic inside it.

So, our controllers should be responsible for accepting the service instances through the constructor injection and for organizing HTTP action methods (GET, POST, PUT, DELETE, PATCH…): 

public class OwnerController: Controller
{
    private ILoggerManager _logger;
    private IRepository _repository;
 
    public OwnerController(ILoggerManager logger, IRepository repository)
    {
        _logger = logger;
        _repository = repository;
    }
 
    [HttpGet]
    public IActionResult GetAllOwners()
    {           
    }
 
    [HttpGet("{id}", Name = "OwnerById")]
    public IActionResult GetOwnerById(Guid id)
    {          
    }
 
    [HttpGet("{id}/account")]
    public IActionResult GetOwnerWithDetails(Guid id)
    {
    }
 
    [HttpPost]
    public IActionResult CreateOwner([FromBody]Owner owner)
    {       
    }
 
    [HttpPut("{id}")]
    public IActionResult UpdateOwner(Guid id, [FromBody]Owner owner)
    {         
    }
 
    [HttpDelete("{id}")]
    public IActionResult DeleteOwner(Guid id)
    {        
    }
}

Actions

Our actions should always be clean and simple. Their responsibilities include handling HTTP requests, validating models, catching errors and returning responses: 

[HttpPost]
public IActionResult CreateOwner([FromBody]Owner owner)
{
    try
    {
        if (owner.IsObjectNull())
        {
            return BadRequest("Owner object is null");
        }
 
        if (!ModelState.IsValid)
        {
            return BadRequest("Invalid model object");
        }
 
        _repository.Owner.CreateOwner(owner);
 
        return CreatedAtRoute("OwnerById", new { id = owner.Id }, owner);
    }
    catch (Exception ex)
    {
        _logger.LogError($"Something went wrong inside the CreateOwner action: {ex}");
        return StatusCode(500, "Internal server error");
    }
}

Our actions should have IActionResult as a return type in most of the cases (sometimes we want to return a specific type or a JsonResult…). That way we can use all the methods inside .NET Core which returns results and the status codes as well.

The most used methods are:

  • OK => returns the 200 status code
  • NotFound => returns the 404 status code
  • BadRequest => returns the 400 status code
  • NoContent => returns the 204 status code
  • Created, CreatedAtRoute, CreatedAtAction => returns the 201 status code
  • Unauthorized => returns the 401 status code
  • Forbid => returns the 403 status code
  • StatusCode => returns the status code we provide as input 

Handling Errors Globally

In the example above, our action has its own try-catch block. This is very important because we need to handle all the errors (that in another way would be unhandled) in our action method. Many developers are using try-catch blocks in their actions and there is absolutely nothing wrong with that approach. But, we want our actions to be clean and simple, therefore, removing try-catch blocks from our actions and placing them in one centralized place would be an even better approach.

.NET Core gives us an opportunity to implement exception handling globally with a little effort by using built-in and ready to use middleware. All we have to do is to add that middleware in the Startup class by modifying the Configure method:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
     app.UseExceptionHandler(config =>
     {
         config.Run(async context =>
         {
             context.Response.StatusCode = 500;
             context.Response.ContentType = "application/json";
 
             var error = context.Features.Get<IExceptionHandlerFeature>();
             if (error != null)
             {
                 var ex = error.Error;
 
                 await context.Response.WriteAsync(new ErrorModel()
                 {
                     StatusCode = 500,
                     ErrorMessage = ex.Message
                 }.ToString(); //ToString() is overridden to Serialize object
             }
         });
     });
 
     app.UseMvc();
}

We can even write our own custom error handlers by creating custom middleware: 

public class CustomExceptionMiddleware
{
    //constructor and service injection
 
    public async Task Invoke(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (Exception ex)
        {
            _logger.LogError("Unhandled exception ...", ex);
            await HandleExceptionAsync(httpContext, ex);
        }
    }
   
    //additional methods
}

After that we need to register it and add it to applications pipeline: 

public static IApplicationBuilder UseCustomExceptionMiddleware(this IApplicationBuilder builder)
{
    return builder.UseMiddleware<CustomExceptionMiddleware>();
}

Using ActionFilters to Remove Duplicated Code

Filters in ASP.NET Core allows us to run some code prior to or after the specific stage in a request pipeline. Therefore, we can use them to execute validation actions that we need to repeat in our action methods.

When we handle a PUT or POST request in our action methods, we need to validate our model object as we did in the Actions part of this article. As a result, that would cause the repetition of our validation code, and we want to avoid that (Basically we want to avoid any code repetition as much as we can).

We can do that by using the ActionFilters. Instead of validation code in our action: 

if (!ModelState.IsValid)
{
  // bad request and logging logic
}

We can create our filter: 

public class ModelValidationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState); // returns 400 with error
        }
    }
}

And register it in the Startup class in the ConfigureServices method: 

services.AddScoped<ModelValidationAttribute>();

Now, we can use that filter with our action methods.

Microsoft.AspNetCore.All Meta-Package

This meta-package contains all of the AspNetCore packages, EntityFrameworkCore packages, SignalR package (from version 2.1) and the supporting packages required for running the framework. It is pretty convenient when starting a new project because we don’t have to manually install and reference all the packages we might need.

Of course, your machine needs to have the .NET Core runtime installed on it in order to use the AspNetCore meta-package.

Routing

In the .NET Core Web API projects, we should use Attribute Routing instead of Conventional Routing. That’s because Attribute Routing helps us match the route parameter names with the actual parameters inside the action methods. Another reason is the description of the route parameters. It is more readable when we see the parameter with the name “ownerId” than just “id”.

We can use the [Route] attribute on top of the controller and on top of the action itself: 

[Route("api/[controller]")]
public class OwnerController: Controller
{
     [Route("{id}")]
     [HttpGet]
     public IActionResult GetOwnerById(Guid id)
     {
           
     } 
}

There is another way to create routes for the controller and actions: 

[Route("api/owner")]
public class OwnerController: Controller
{
     [HttpGet("{id}")]
     public IActionResult GetOwnerById(Guid id)
     {
           
     } 
}

There are different opinions which way is better, but we would always recommend the second way, and this is something we always use in our projects.

When we talk about the routing we need to mention the route naming convention. We can use descriptive names for our actions, but for the routes/endpoints, we should use NOUNS and not VERBS.

The few wrong examples: 

[Route("api/owner")]
public class OwnerController : Controller
{
    [HttpGet("getAllOwners")]
    public IActionResult GetAllOwners()
    {
    }
 
    [HttpGet("getOwnerById/{id}"]
    public IActionResult GetOwnerById(Guid id)
    {       
    }
}

The good examples: 

[Route("api/owner")]
public class OwnerController : Controller
{
    [HttpGet]
    public IActionResult GetAllOwners()
    {
    }
 
    [HttpGet("{id}"]
    public IActionResult GetOwnerById(Guid id)
    {         
    }
}

Logging

If we plan to publish our application to production, we should have a logging mechanism in place. Log messages are very helpful when figuring out how our software behaves in a production.

.NET Core has its own logging implementation by using the ILoggerinterface. It is very easy to implement it by using Dependency Injection feature: 

public class TestController: Controller
{
    private readonly ILogger _logger;
 
    public TestController(ILogger<TestController> logger)
    {
        _logger = logger;
    }
}

Then in our actions, we can utilize various logging levels by using the _logger object.

.NET Core supports logging API that works with a variety of logging providers. Therefore, we may use different logging providers to implement our own logging logic inside our project.

The NLog is the great library to use for implementing our own custom logging logic. It is extensible, supports structured logging and very easy to configure. We can log our messages in the console window, files or even database. 

CryptoHelper

We won’t talk about how we shouldn’t store the passwords in a database as a plain text and how we need to hash them due to security reasons. That’s out of the scope of this article. There are various hashing algorithms all over the internet, and there are many different and great ways to hash a password.

But if need the library that provides support to the .NET Core’s application and that is easy to use, the CryptoHelper is quite a good library.

This library is available for installation through the NuGet and its usage is quite simple:

using CryptoHelper;
 
// Method for hashing the password
public string HashPassword(string password)
{
    return Crypto.HashPassword(password);
}
 
// Method to verify the password hash against the given password
public bool VerifyPassword(string hash, string password)
{
    return Crypto.VerifyHashedPassword(hash, password);
}

Content Negotiation

By default .NET Core Web API returns a JSON formatted result. In most of the cases, that’s all we need.

But what if the consumer of our Web API wants another response format, like XML for example?

For that, we need to create a server configuration to format our response in the desired way: 

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(config =>
    {
        // Add XML Content Negotiation
        config.RespectBrowserAcceptHeader = true;
        config.InputFormatters.Add(new XmlSerializerInputFormatter());
        config.OutputFormatters.Add(new XmlSerializerOutputFormatter());
    });
}

Sometimes the client may request a format that is not supported by our Web API and then the best practice is to respond with the status code 406 Not Acceptable. That can be configured inside our ConfigureServices method as well: 

config.ReturnHttpNotAcceptable = true;

We can create our own custom format rules as well.

Using JWT

JSON Web Tokens (JWT) are becoming more popular by the day in the web development. It is very easy to implement JWT Authentication is very easy to implement due to the .NET Core’s built-in support. JWT is an open standard and it allows us to transmit the data between a client and a server as a JSON object in a secure way.

We can configure the JWT Authentication in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
     services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
       .AddJwtBearer(options =>
       {
          options.TokenValidationParameters = new TokenValidationParameters
          {
             //Configuration in here
          };
       });
}

In order to use it inside the application, we need to invoke this code in the Configure method:

app.UseAuthentication();

We may use JWT for the Authorization part as well, by simply adding the role claims to the JWT configuration 

Conclusion

In this article, our main goal was to familiarize you with the best practices when developing a Web API project in .NET Core. Some of those could be used in other frameworks as well, therefore, having them in mind is always helpful.

If you find that something is missing from the list, don’t hesitate to add it in a comment section.

Thank you for reading the article and I hope you found something useful in it.



ASP.NET Core 2 Hosting - How to Publish ASP.NET Core 2

clock February 13, 2018 07:34 by author Jervis

This tutorial will show you how to publish ASP.NET Core on IIS. The following is steps by steps to deploy .net Core.

Program class in asp.net core 2.0 contains a method that is called “CreateDefaultBuilder”. It is responsible for setting up everything for your application related to hosting, manage server, IIS integration, create directory etc.

public class Program {  
    public static void Main(string[] args) {  
        BuildWebHost(args).Run();  
    }  
    public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args).UseStartup < Startup > ().Build();  
}

Just go through with CreateDefaultBuilder method's actual definition using F12 in Visual Studio, you can read the comment which specifies its tasks.

The deployment is not the same as Asp.Net, there are a few more components required to host your asp.net core 2.0 application on IIS. Before deploying, you have to install a bundle which is required to host Asp.Net Core 2.0 application on IIS and that is .Net Core Windows Server Hosting. This bundle will install .Net Core Runtime which provides all the required libraries on runtime, .Net Core Library and Asp.Net Core Module.

If you are still using Asp.Net Core 1.x then you can find out the “.Net Core Windows Server Hosting” bundle using the following link and install it.

Here we are using Asp.Net Core 2.0 application to deploy it on IIS, so we are going to download .Net Core Windows Server Hosting bundle from following link and install it with our system.

When it is in progress, you can see it is installing three main components: .Net Core Runtime, .Net Core Library and Asp.Net Core Module. As you can see in the following image, Microsoft .Net Core Runtime is being installed.

Warning

Please make sure you have restarted your system before moving to the next step after the installation of “Microsoft .Net Core Windows Server Hosting” bundles.

For this demonstration, we are using the same Asp.Net Core 2.0 application which we have created in previous article. To learn how to create First application in Asp.Net Core 2, please refer to following article.

First Application In ASP.NET Core MVC 2.0

Let’s move to Visual Studio 2017 version 15.3 which provides .Net Core 2 features.  Open the Asp.Net Core 2.0 application which we have created in last article. Open the solution explorer and right click to project and choose Publish option for publishing this web application.

It will open a new windows as following, which provide us three different options to publish our web application and these options are “Azure”, “IIS,FTP” and “Folder”. So, here are choosing “Folder” to publish our web content”. You have to provide the destination path where you would like to publish web application and then click to “Publish”.

It will start publishing content on selected folder as following image shown. Once everything will fine, it will show Publish Successes message.

Now it’s time to create a new website inside the IIS Manager, to open IIS Manager, just type “inetmgr” in “Search Program and files” in start menu. It will open IIS Manager for you as following image shown where you can manage you application.

Just right click to “Sites” and choose “Add Web Site..”.

In next window, you have to define you “Site Name”, physical path where you have published you application earlier and host name to find on web browser as below image. Don’t change Port and anything else and just click to OK.

Now we are almost done but need to change the “Application Pools” for this site. Click to application pools from the left panel and choose you pools as “asp.netcore2.com” and double click on that. Now you can edit you “Application Pool” for this website. From this window, you have to changes “.Net Framework  version” or “.Net CLR version” with “No Managed Code” and OK. 

Last thing, what you need to do, just make one entry about your application inside the host file, which is located on the following location. You have to add one more entry as we have done for asp.netcore2.com which directly points to localhost IP address.

C:\Windows\System32\drivers\etc

The time has come to run the application on the browser, so open any browser and just type asp.netcore2.com and press enter. Wow… you will get the following screen, which means the application has successfully hosted on IIS.



ASP.NET Core 1.0 Hosting - ASPHostPortal :: Publish Your First ASP.NET Core Project

clock October 7, 2016 20:37 by author Jervis

Here are simple tutorial how to build your ASP.NET Core application. It’s just simple steps and you can follow it easily.

Install .NET Core First

First, please make sure you install .NET Core SDK for Windows

With that installed, it’s time to build your first application.

Open up a command prompt (or use the in-built terminal in Visual Studio Code) and start by creating a folder for your application, then initialising it.

mkdir CoreApp
cd CoreApp
dotnet new

When you run the dotnet command for the first time you’ll see some information about how .NET Core collects usage data and initially populates a local package cache. Once you’ve seen this message you won’t see it again on the same machine.

Project.json and Program.cs File

One of the most striking things about getting started with .NET Core is that you don’t end up with lots of files and dependencies right out of the gate, just the minimum you need for an empty web site.

In fact, all you’ll be left with is a project.json and Program.cs file.

At this point, this is just a .net Core app (not web) which prints “Hello World” to the console.

If you take a look at project.json you’ll see the minimum dependencies your new .net core app needs to run.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        }
      },
      "imports": "dnxcore50"
    }
  }
}

When you create a new .net core application like this, it’s dependencies are not downloaded automatically. To do that, you simply need to issue a new command to restore the dependencies and then to run the app.

dotnet restore
dotnet run

Launch the Application

So your app just compiled and launched. It looks suspiciously like a console application, because it is a console application.

Up until now, everything you’ve done has resulted in a minimal .net core console application.

So how do you turn it into a web site?

Well you need to update project.json to tell it to add the Kestrel HTTP server as a dependency.

Kestrel is a lightning fast cross-platform web server which can be used to self-host your web application. In other words, you can tell your new web app that Kestrel is a dependency and then run your site on it without relying on IIS or IIS Express.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        },
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0"
      },
      "imports": "dnxcore50"
    }
  }
}

You’ve added a dependency so now you need to download that dependency using the restore command.

dotnet restore

Incidentally, in case you’re wondering where donet restore is restoring packages to, the default location is %userprofile%\.nuget\packages

Next up, you’ll need to create a Startup.cs file. This will define how incoming web requests should be handled.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; 

namespace ConsoleApplication {
    public class Startup{
        public void Configure(IApplicationBuilder app){
            app.Run(context => {
                return context.Response.WriteAsync("Hello world");
            });
        }
    }
}

This is about as simple as it comes, you simply tell your app to always return a response and write the text “Hello world” to it (for any request to your web application).

At this point, you haven’t told your app to start Kestrel (to start accepting web requests). You can do that by updating Program.cs.

using System;
using Microsoft.AspNetCore.Hosting; 

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!"); 

            var host = new WebHostBuilder()
            .UseKestrel()
            .UseStartup<Startup>()
            .Build(); 

            host.Run();
        }
    }
}

Should you wish, you can happily delete Console.WriteLine("Hello World!") as you’ve replaced it with something far more useful, you’ve told Core to launch Kestrel using the Startup class you just created.

Go ahead and run your app.

dotnet run

You’ll see a message telling you that your app is up and running and where you can access it.

Hosting environment: Development
Content root path: C:\Users\Jervis\CoreApp\bin\Debug\netcoreapp1.0
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Hit http://localhost:5000 in a browser!

 



Cheap ASP.NET 4.5 Hosting

We’re a company that works differently to most. Value is what we output and help our customers achieve, not how much money we put in the bank. It’s not because we are altruistic. It’s based on an even simpler principle. "Do good things, and good things will come to you".

Success for us is something that is continually experienced, not something that is reached. For us it is all about the experience – more than the journey. Life is a continual experience. We see the Internet as being an incredible amplifier to the experience of life for all of us. It can help humanity come together to explode in knowledge exploration and discussion. It is continual enlightenment of new ideas, experiences, and passions


Author Link

 photo ahp banner aspnet-01_zps87l92lcl.png

 

Corporate Address (Location)

ASPHostPortal
170 W 56th Street, Suite 121
New York, NY 10019
United States

Tag cloud

Sign in