【问题标题】:Unable to hit API endpoints with GET无法使用 GET 访问 API 端点
【发布时间】:2018-07-12 09:22:41
【问题描述】:

我正在构建一个用于在 .NET Core 中处理身份信息的 API,但每次我尝试拨打电话时都会收到 404。

当我环顾四周寻找答案时,似乎没有什么清楚的,因为发布的代码似乎很少。以下是我认为相关的所有内容。

控制器:

using Common.Extensions;
using Identity.Database.Contexts.Models;
using Identity.WebApi.Models;
using Identity.WebApi.Models.Tokens;
using Identity.WebApi.Services.Access;
using Identity.WebApi.Services.Accounts;
using Identity.WebApi.Services.Tokens;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

using Controller = Microsoft.AspNetCore.Mvc.Controller;
using Get = Microsoft.AspNetCore.Mvc.HttpGetAttribute;
using Post = Microsoft.AspNetCore.Mvc.HttpPostAttribute;
using Route = Microsoft.AspNetCore.Mvc.RouteAttribute;

namespace Identity.WebApi.Controllers
{
    [Route("api/[controller]")]
    public class IdentityController : Controller
    {
        private readonly IApplicationUserService _userService;
        private readonly IAccessService _accessService;
        private readonly ITokenService _tokenService;
        private readonly SignInManager<ApplicationUser> _signInManager;

        public IdentityController(IApplicationUserService userService, IAccessService accessService, ITokenService tokenService, SignInManager<ApplicationUser> signInManager)
        {
            _userService = userService;
            _accessService = accessService;
            _tokenService = tokenService;
            _signInManager = signInManager;
        }

        [Get]
        [AllowAnonymous]
        public string Index()
        {
            return new Dictionary<string,string>
            {
                { "status", "live" }
            }.Serialize();
        }

        [Post]
        [Route("create")]
        [AllowAnonymous]
        public Task<ISet<IdentityResult>> Create(string user)
        {
            var decodedUser = DecodeUser(user);

            var applicationUser = new ApplicationUser(new User
            {
                Id = Guid.NewGuid(),
                Name = decodedUser.Username,
                LastActive = DateTime.UtcNow
            });

            return _userService.Add(applicationUser, decodedUser.Password);
        }       

        private (string Username, string Password) DecodeUser(string encodedUser)
        {
            var decodedUser = encodedUser.DecodeFrom64().Split(':');
            return (Username: decodedUser[0], Password: decodedUser[1]);
        }

        private async Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
            => await _signInManager.UserManager.CheckPasswordAsync(user, password);
    }
}

初创公司:

using Identity.Database.Contexts;
using Identity.Database.Contexts.Access;
using Identity.Database.Contexts.Extensions;
using Identity.Database.Contexts.Models;
using Identity.WebApi.Models;
using Identity.WebApi.Services.Access;
using Identity.WebApi.Services.Accounts;
using Identity.WebApi.Services.Certs;
using Identity.WebApi.Services.Tokens;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Runtime.CompilerServices;

namespace Identity.WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(new CertService(Configuration) as ICertService)
                .AddTransient<IApplicationUserService, ApplicationUserService>()
                .AddTransient<IApplicationRoleService, ApplicationRoleService>()
                .AddTransient<IAccessService, AccessService>()
                .AddTransient<ICertService, CertService>()
                .AddTransient<ITokenService, TokenService>()
                .AddTransient<ICrudDao<AppDbContext, Role>, RoleDao>()
                .AddIdentities<ApplicationUser, ApplicationRole>()
                .AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>()
                .AddScoped<SignInManager<ApplicationUser>, SignInManager<ApplicationUser>>()
                .AddScoped<RoleManager<ApplicationRole>, RoleManager<ApplicationRole>>()
            .AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.Use(async (c, n) =>
            {
                await n();

                if (c.Response.StatusCode == 404)
                {
                    c.Request.Path = "/identity";
                    await n();
                }
            });

            app.UseStaticFiles();
            app.UseAuthentication();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc(r => { r.MapRoute(name: "default", template: "{controller=identity}/{action=Index}"); });
        }
    }
}

启动设置:

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:55048/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "api/identity/index",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApplication1": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "api/identity/index",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:55048/"
    }
  }
}

【问题讨论】:

  • 您能否包括您尝试到达的返回 404 的路线?

标签: c# .net-core asp.net-core-mvc asp.net-core-webapi


【解决方案1】:

在您的控制器顶部有:

[Route("api/[controller]")]
public class IdentityController : Controller

这意味着如果您的路由仅以api/ 开头,那么它将与控制器匹配。此外,您的 Index 操作上没有任何额外的路由属性,因此它只查找api/identity。但是,您的启动设置与该部分不匹配,并且由于您没有任何其他匹配它的路由,因此您会得到 404。

app.UseMvc 中的默认路由因此不起作用。

简单修复:在启动设置中将 launchUrl 更改为 api/identity...然后按照 @Nkosi 的 answer

【讨论】:

  • 哦...谢谢@Nkosi,我错过了。我认为您是对的 - 只需将启动设置更新为 api/identity
  • 是的,这个让我陷入困境。我现在正在访问控制器并看到我预期的依赖注入错误(第一次在 .NET Core 中这样做)。谢谢!
【解决方案2】:

如果使用属性路由,则在您的示例中没有 api/identity/index[HttpGet]Get 带有路由前缀,与

[Get] //<-- Matches GET api/identity
[AllowAnonymous]
public IActionResult Index() {
    var result = new Dictionary<string,string>
        {
            { "status", "live" }
        }.Serialize();
    return Ok(result);
}

由于这似乎是一个不希望返回视图的 Web API,因此带有路由模板的 Http{Verb} 属性将是用于路由的选项

在构建 REST API 时,您很少会想要在操作方法上使用 [Route(...)]。最好使用更具体的 Http*Verb*Attributes 来准确了解您的 API 支持什么。 REST API 的客户端应该知道哪些路径和 HTTP 动词映射到特定的逻辑操作。

[Post("create")]  //<-- Matches POST api/identity/create
[AllowAnonymous]
public async Task<IActionResult> Create(string user) {
    var decodedUser = DecodeUser(user);

    var applicationUser = new ApplicationUser(new User
    {
        Id = Guid.NewGuid(),
        Name = decodedUser.Username,
        LastActive = DateTime.UtcNow
    });

    ISet<IdentityResult> result = await _userService.Add(applicationUser, decodedUser.Password);
    return Ok(result);
}

参考Routing to Controller Actions

【讨论】:

    猜你喜欢
    • 2021-05-26
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多