Ehsan Ghanbari

Experience, DotNet, Solutions

Using Middleware to handle exceptions in asp.net core

There are a few ways to handle exceptions in asp.net core 2.1. using Middleware is so straightforward, and it handles the application exceptions as well as exceptions from filters and you can have full control over. Look at the following class:

 

 public class MiddlewareExceptionHandler

    {

        private readonly RequestDelegate _requestDelegate;

 

        public MiddlewareExceptionHandler(RequestDelegate requestDelegate)

        {

            _requestDelegate = requestDelegate;

        }

 

        public async Task Invoke(HttpContext context)

        {

            try

            {

                await _requestDelegate(context);

            }

            catch (Exception ex)

            {

                await HandleExceptionAsync(context, ex);

            }

        }

 

        private static Task HandleExceptionAsync(HttpContext context, Exception exception)

        {

            var code = HttpStatusCode.InternalServerError;

            var result = JsonConvert.SerializeObject(new { error = exception.Message });

            context.Response.ContentType = "application/json";

            context.Response.StatusCode = (int)code;

            return context.Response.WriteAsync(result);

        }

    }

 

And register the class in Configure method of Startup class:

 

 

  public void Configure(IApplicationBuilder app, IHostingEnvironment env)

        {

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

            }

            else

            {

                app.UseExceptionHandler("/Home/Error");

                app.UseHsts();

            }

 

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseCookiePolicy();

 

            app.UseMiddleware(typeof(MiddlewareExceptionHandler));

 

            app.UseMvc(routes =>

            {

                routes.MapRoute(

                    name: "default",

                    template: "{controller=Home}/{action=Index}/{id?}");

            });

        }

 

Note that I'm returning the exception as JSON. In order to Invoke the exception in HTTP, you can change the MiddlewareExceptionHandler class like below:

 

  

 public class MiddlewareExceptionHandler

    {

        private readonly RequestDelegate _requestDelegate;

 

        public MiddlewareExceptionHandler(RequestDelegate requestDelegate)

        {

            _requestDelegate = requestDelegate;

        }

 

        public async Task Invoke(HttpContext context)

        {

            try

            {

                await _requestDelegate(context);

            }

            catch (Exception ex)

            {

                if (context.Response.HasStarted)

                {

                    throw;

                }

 

                await context.Response.WriteAsync(ex.Message);

 

                return;

            }

        }

    }

 



Enabling the CORS in Asp.net Core

As I'm talking with Asp.net core these days, so I'm supposed to be eager about that! In asp.net core, in order to enable the CORS, you should refer to application startup and ConfigureServices and add the following configuration:

 

 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;

            });


            services.AddCors(o => o.AddPolicy("MyPolicyName", builder =>

            {

                builder.AllowAnyOrigin()

                       .AllowAnyMethod()

                       .AllowAnyHeader();

            }));

 
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        }

 

 Now for applying the above policy in your controller or action, you just need to use it via attribute:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Cors;

using Microsoft.AspNetCore.Mvc;

 

namespace WebApplication3.Controllers

{

    [EnableCors(policyName: "MyPolicyName")]

    public class DefaultController : Controller

    {

        [EnableCors(policyName: "MyPolicyName")]

        public IActionResult Index()

        {

            return View();

        }

    }

}

 

And, in order to apply for every request, you can config it like below in startup class: 

 

 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)

        {

            app.UseCors("MyPolicyName");

 

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

            }

            else

            {

                app.UseExceptionHandler("/Error");

                app.UseHsts();

            }

 

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseCookiePolicy();

 

            app.UseMvc();

        }

 



HttpContext in asp.net core

Accessing to HttpContext in asp.net core application is just like before, for example:

 

 public class MyController : Controller

    {

        [HttpGet]

        public ActionResult Show()

        {

            var user = HttpContext.User;

            return View();

        }

    }

 

 But HttpContext is not available everywhere in your solution! For IHttpContextAccessor. If you are using the default dependency injection of Ap.net Core then you should example to access to HttpContext in layers rather than web, you should inject a new interface of asp.net core named firstly resolve the mentioned interface in it:

 

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;

            });

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        }

 

Now you can inject the interface wherever you are going to use HttpContext:

 

   public interface ISampleService

    {

    }

 

    public class SampleService : ISampleService

    {

        private readonly IHttpContextAccessor _httpContextAccessor;

 

        public SampleService(IHttpContextAccessor httpContextAccessor)

        {

            _httpContextAccessor = httpContextAccessor;

        }

    }

 

To tell the truth, I don't like this kind of using HttpContext in the outside scope of the controller. It's an antipattern in my point of view because HttpContext and every related thing to the web should live in the web project. By the way! Using HttpContext in Razor view engine is just like before!



Disable directory browsing in asp.net core

In asp.net applications, directory browsing has enabled some versions and you let the users see all of the content and structure of your application like the picture below:

To the best of my knowledge, in order to disable the directory browsing, there are two ways: by web.config and IIS. In web.config file you just need to add the following piece of code:

 

    <system.webServer>
      <directoryBrowse enabled="false" />
    </system.webServer>

 

and In IIS, you have to disable the configuration manually:

 

 

Actually, both of them are the same. But in asp.net core, as the structure has been changed, you can handle the mentioned feature by code. In web asp.net core, static files are located in a folder named wwwroot. In the configure method of Startup class you can call the UseFileServer() and set the enableDirectoryBrowsing as false:

 

      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseMvc();
            app.UseFileServer(enableDirectoryBrowsing: false);
        }



WCF replacement in .Net Core

As you know, WCF is Windows Communication Service and doesn't match the targets of .Net Core which is cross-platform. It was a just a question to know how can I handle the WCF services in .Net core. Reference the following Nuget Pacakges to your project:

  1. JKang.IpcServiceFramework.Client
  2. JKang.IpcServiceFramework.Server

 

And assume that your services are like below:

  

public interface IMyService

        {

        }

 

        public class MyService : IMyService

        {

        }

 

In order to register and use them in asp.net core add some piece of code to the ConfigureServices of Startup class:

 

 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;

            });

 

 

            services.AddIpc(serviceBuilder =>

                 {

                     serviceBuilder.AddNamedPipe(options =>

                         {

                             options.ThreadCount = 2;

                         }).AddService<IMyService, MyService>();

                 });

 

            new IpcServiceHostBuilder(services.BuildServiceProvider())

               .AddNamedPipeEndpoint<IMyService>(name: "endpointA", pipeName: "pipeName")

               .AddTcpEndpoint<IMyService>(name: "endpointB", ipEndpoint: IPAddress.Loopback, port: 564)

               .Build()

               .Run();

 

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        }

 



About Me

Ehsan Ghanbari

Hi! my name is Ehsan. I'm a developer, passionate technologist, and fan of clean code. I'm interested in enterprise and large-scale applications architecture and design patterns and I'm spending a lot of my time on architecture subject. Since 2008, I've been as a developer for companies and organizations and I've been focusing on Microsoft ecosystem all the time. During the&nb Read More

Post Tags
Pending Blog Posts
Strategic design
Factory Pattern
time out pattern in ajax
Selectors in Jquery
Peridic pattern
How to use PagedList In asp.net MVC
Redis as a cache server
How to query over Icollection<> of a type with linq
Domain driven design VS model driven architecture
What's the DDD-lite?