405 ошибка asp net core

The transition from the traditional ASP.NET to ASP.NET Core brought several improvements, but it also presented developers with a new set of challenges. Among these challenges, encountering a “405 Method Not Allowed” error when issuing PUT or DELETE requests to an ASP.NET Core application hosted on IIS can be particularly vexing. In this article, we’ll deep dive into understanding the reasons behind this error and how to resolve it.

Understanding the Error 405

Before diving into the specifics of the ASP.NET Core scenario, it’s crucial to understand what the “405 Method Not Allowed” error generally implies. The error is an HTTP response status code indicating that the web server has recognized the request method, but the target resource does not support it for the given URI.

Common Causes of Error 405 in ASP.NET Core on IIS

  • WebDAV Module: When hosting ASP.NET Core applications on IIS, the WebDAV module is frequently the culprit. This module is designed for authoring on the web and uses both the PUT and DELETE requests. If not configured correctly, it can interfere with applications that rely on these methods.
  • Missing or Incorrect Verb Handlers: IIS uses verb handlers to process requests. If these handlers aren’t correctly configured for PUT or DELETE, you’ll face a 405 error.

Solution

If your application does not require WebDAV, you can resolve many issues by simply disabling the WebDAV module. Add the following code to your web.config file:


<system.webServer>
    <modules runAllManagedModulesForAllRequests="false">
        <remove name="WebDAVModule"/>
    </modules>
    <handlers>
        <remove name="WebDAV" />
    </handlers>
</system.webServer>

Additional Tips

  • Enable Detailed Error Messages: To get a clearer picture of the root cause, ensure your IIS server is configured to show detailed error messages. This will provide more context and possibly point directly to the offending module or handler.
  • Logging: Incorporate logging within your ASP.NET Core application. Tools like Serilog or the built-in ILogger can capture detailed logs that can offer insights into any potential issues.
  • Check Route Configurations: Ensure that your ASP.NET Core routing configurations support the methods you’re trying to invoke.

Conclusion

The “405 Method Not Allowed” error in an ASP.NET Core application hosted on IIS can be a hurdle, but with a proper understanding of its roots and the right tools at your disposal, it’s a manageable one. Always remember that your application’s needs are unique; hence, always test thoroughly after making any changes to configurations or infrastructure.

I have a very simple API created using ASP.NET Core 2.1. When a client page calls the API from localhost:8080, the API located at localhost:5000 returns HTTP:405.

Why? Note that the HTTP GET test method in AuthController.cs works just as expected. It is only the HTTP POST request returning HTTP:405.

Controllers\AuthController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using server.Models;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using System.Text;

namespace server.Controllers
{
    [Route("api/auth")]
    [ApiController]
    public class AuthController : ControllerBase
    {

        [HttpGet, Route("test")]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }

        [HttpPost, Route("login")]
        public IActionResult Login([FromBody]LoginModel user)
        {
            if (user == null)
            {
                return BadRequest("Invalid client request");
            }

            if (user.UserName == "johndoe" && user.Password == "def@123")
            {
                var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345"));
                var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);

                var tokeOptions = new JwtSecurityToken(
                    issuer: "http://localhost:5000",
                    audience: "http://localhost:5000",
                    claims: new List<Claim>(),
                    expires: DateTime.Now.AddMinutes(10),
                    signingCredentials: signinCredentials
                );

                var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
                return Ok(new { Token = tokenString });
            }
            else
            {
                return Unauthorized();
            }
        }
    }
}

Models\LoginModel.cs

namespace server.Models
{
    public class LoginModel
    {
        public string UserName { get; set;}
        public string Password { get; set; }
    } 
}

Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.AspNetCore.Cors.Infrastructure;

namespace server
{
    public class Startup
    {
        public IConfiguration Configuration { get; }
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,

                    ValidIssuer = "http://localhost:5000",
                    ValidAudience = "http://localhost:5000",
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345"))
                };
            });

            var corsBuilder = new CorsPolicyBuilder();
            corsBuilder.AllowAnyHeader();
            corsBuilder.AllowAnyMethod();
            corsBuilder.WithOrigins("http://localhost:8080");
            corsBuilder.AllowCredentials();

            services.AddCors(options =>
            {
                options.AddPolicy("SiteCorsPolicy", corsBuilder.Build());
            });

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

        // 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.UseHsts();
            }

            app.UseCors("SiteCorsPolicy");
            app.UseAuthentication();
            app.UseMvc();
        }
    }
}

index.html (localhost:8080)

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>JWT Auth</title>
    </head>
    <body>
        <p>Output:</p>
        <div id="output"></div>
        <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script>

            var item =  {
                UserName: "johndoe",
                Password: "def@123" 
            };

            $.ajax({
                type: "POST",
                accepts: "application/json",
                url: '/api/auth/Login',
                contentType: "application/json",
                data: JSON.stringify(item),
                error: function(jqXHR, textStatus, errorThrown) {
                alert("Something went wrong!");
                },
                success: function(result) {
                    console.log('Testing');
                }
            });

        </script>
    </body>
</html>

ASP.NET Core: Static Files cache control using HTTP Headers

A reader of my recent ASP.NET Core and Angular 2 book wrote me about a strange error occurred while publishing the OpenGameList Single-Page Application into production upon a Windows Server + IIS powered environment machine.

The published SPA seemed to be working OK at first, but when he logged in as Admin to update an item the command kept failing with the following message:

Error 405 — Methods not Allowed

I did my best to help him to troubleshoot the issue: after a few tests we found out that such error was coming out in response to any attempted PUT and DELETE request, while GET and POST methods were working fine.

Such weird discovery led me to dig through the web looking for a suitable explanation, until I eventually found the cause: it seems like the culprit is the WebDAVModule, which seems to set PUT and DELETE request methods disabled by default. In order to get them to work, we either need to change these defaults or disable it for the whole web application, which was what we did.

Here’s what we put in the web.config file to remove it for good:

<system.webServer>

  <modules runAllManagedModulesForAllRequests=«false»>

    <remove name=«WebDAVModule» />

  </modules>

</system.webServer>

Despite the rather easy workaround, such an issue is definitely a though one, as it will easily affect most ASP.NET Core Web API and Web Applications when they get deployed on a live environment: that’s because the WebDAV module, although not supported by IIS Express, happens to be enabled in most production servers. I guess that a lot of users will stumble upon it sooner or later… I definitely hope that this post will help some of them to overcome the hassle.

Error 405 : ASP.NET Core Web API PUT and DELETE Methods not allowed

Recently, while working with .Net core API I came across the issue of “Error 405 — Methods not Allowed”

After some research, I found out that both GET and POST requests working fine but neither PUT nor DELETE requests working.

Another thing is that the PUT and DELETE request was also working fine on my local machine but failed when we host on our Azure server.

When I explored the issue on the web it led me to the conclusion that WebDAVModule seems to set PUT and DELETE request methods disabled by default and due to that PUT and DELETE throw 405 errors.

To make the PUT and DELETE requests work, we need to override the WebDAVModule setting in web.config file by adding the below settings under “system.webServer”.

<system.webServer>

  <modules runAllManagedModulesForAllRequests=«false«>

    <remove name=«WebDAVModule« />

  </modules>

</system.webServer>

There may be 2 web.config files in your project, if that is the case then update the one that is inside the wwwroot folder.

Also with the latest version of .Net CORE (2.0 and above), there might be a case of no web.config file available at all, if that is your case then add a web.config file on your own.

Note: If you are facing the same issue with multiple APIs hosted on the same server, then either you can add the above entries under web.config file of all the affected API’s or you can remove the below the entry of WebDAVModule from ApplicationHost.config file under module section:

<add name=«WebDAVModule« />

ApplicationHost.config can be found at “C:\Windows\System32\inetsrv\config”

Popular posts from this blog

I created an Asp.Net Core 2.x Web API and configured Swagger on it, below is the code added in Configure method under Startup.cs file, for full swagger configuration, check here //Add swagger configuration app.UseSwagger(); app.UseSwaggerUI(c => {     c.SwaggerEndpoint( «../swagger/v1/swagger.json» , «Test API V1» ); }); On my local machine when I run the API it is automatically redirected to the Swagger page. However, when I hosted this API as an Azure web app it is not redirecting directly to the Swagger and to access the swagger, I had to append /swagger in the URL, for example, https://testapi.azurewebsites.net/swagger/ Solution: Set RoutePrefix to string.Empty under app.UseSwaggerUI like below: app.UseSwaggerUI(c => {     c.SwaggerEndpoint( «../swagger/v1/swagger.json» , «Test API V1» );      c.RoutePrefix = string .Empty; // Set Swagger UI at apps root }); And that’s it, now when you brows

The singleton pattern is one of the best-known patterns in software engineering. In a singleton pattern, we ensure that the class has only one instance and we provide a simple and global point of access to this object. This is useful when we require exactly one object of a class to perform our operations. Singleton classes don’t allow any parameters to be specified when creating the instance because a second request for an instance but with a different parameter could be problematic. In this article, I’ll provide you with a real-time example, a Comparison of Singleton with Static class, a UML class diagram of Singleton, and then the implementation of Singleton in various ways. Real-time example: The practical implementation of the Singleton design pattern can be seen in various applications used by us. Take the example of Microsoft word, there is only one instance of the word application active at a time even though the user opened multiple documents at a time. And all the req

Skip to content


New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement. We’ll occasionally send you account related emails.

Already on GitHub?
Sign in
to your account

Assignees

@ryanbrandenburg

Labels

area-mvc

Includes: MVC, Actions and Controllers, Localization, CORS, most templates

investigate

Needs: Author Feedback

The author of this issue needs to respond in order for us to continue investigating this issue.

Понравилась статья? Поделить с друзьями:

Интересное по теме:

  • 404 ошибка сервера причины
  • 404 ошибка сервера или клиента
  • 404 ошибка сайт не найден
  • 404 ошибка при заходе на сайт
  • 404 ошибка при post запросе

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии