首页 > 解决方案 > POST 模型绑定不适用于带有 .net core c# 的命名空间路由约定

问题描述

我一直在尝试使用命名空间路由来动态构建一些 API,而无需担心对路由进行硬编码。但是,我确实从MSDN中找到了一个使用命名空间和文件夹结构作为 API 结构的示例。这是我必须使用命名空间路由的示例:

public class NamespaceRoutingConvention : Attribute, IControllerModelConvention
{
    private readonly string _baseNamespace;

    public NamespaceRoutingConvention(string baseNamespace)
    {
        _baseNamespace = baseNamespace;
    }

    public void Apply(ControllerModel controller)
    {
        var hasRouteAttributes = controller.Selectors.Any(selector => selector.AttributeRouteModel != null);
        if (hasRouteAttributes)
        {
            return;
        }

        var namespc = controller.ControllerType.Namespace;
        if (namespc == null) return;
        
        var templateParts = new StringBuilder();
        templateParts.Append(namespc, _baseNamespace.Length + 1, namespc.Length - _baseNamespace.Length - 1);
        templateParts.Replace('.', '/');
        templateParts.Append("/[controller]/[action]/{environment}/{version}");
        var template = templateParts.ToString();

        foreach (var selector in controller.Selectors)
        {
            selector.AttributeRouteModel = new AttributeRouteModel()
            {
                Template = template
            };
        }
    }
}

这是控制器:

namespace Backend.Controllers.Api.Project.Core
{
    public class UserController : ApiBaseController
    {
        public UserController()
        {
        }

        [HttpPost]
        public IActionResult Login(LoginInput loginInput) // <-- loginInput properties return null
        {
            if (!ModelState.IsValid) return BadRequest();
            
            return Ok(user);
        }
    }
}

Startup.cs

namespace Backend
{
    public class Startup
    {
       public void ConfigureServices(IServiceCollection services)
       {
          // Let's use namespaces as the routing default way for our APIs
          services.AddControllers(options =>
          {
            options.Conventions.Add(new NamespaceRoutingConvention(typeof(Startup).Namespace + ".Controllers"));
          });
       }
    }
}

一切正常,除了当我触发POSTapi 调用Login操作时,LoginInput不会填充我通过Postmanie发送的值{"username": "value", "password": "sample"},它总是返回null值。我不确定我做错了什么NamespaceRoutingConvention。请记住,如果我将其删除并在控制器中对路由进行硬编码,例如:

[ApiController]
[Route("api/project/core/[controller]/[action]/proda/v1")] 

它按预期工作。有任何想法吗?

标签: c#asp.net-core

解决方案


尝试改用这个:

[HttpPost]
public IActionResult Login([FromBody]LoginInput loginInput)
{
    if (!ModelState.IsValid) return BadRequest();
    
    return Ok(user);
}

我认为通过设置AttributeRouteModel,您可以防止通过ApiControllerAttribute在 Controller 中执行其工作来调用中间件,因此不应用将对象参数视为主体的默认设置。
虽然这是一个猜测,我一直无法在源代码中找到相应的代码。


推荐阅读