c# - 属性路由和查询字符串

标签 c# asp.net-web-api asp.net-web-api-routing

我是 web api 的新手,具有 WCF 背景,作为准备工作,我在深入学习之前观看了 Shawn Wildermuth 关于该主题的 Pluralsight 类(class)。他的类(class) Material 是围绕更传统的路由设计的。本类(class)深入探讨的主题之一是 HATEOAS,以及使用基本 API Controller 和模型工厂实现这一目标的难易程度。

我在实现属性路由时遇到的第一件事是需要 UrlHelper 将路由名称作为 Link() 方法的第一个参数,这是在 WebApiConfig 中配置的常规路由中继承的。 CS.

我通过使用 Name 属性装饰我的一个 Controller 路由属性来解决这个问题,看起来该 Controller 中的所有方法都可以访问 name 属性,无论我将它放在哪个方法上(参见下面的代码)。虽然我觉得这有点奇怪,但它确实有效。现在我已经实现了 HATEOAS,我注意到它生成的 URL 是查询字符串格式,而不是“url”格式(我知道这个词是错误的,但请耐心等待)。而不是 .../api/deliverables/1 我得到 .../api/deliverables?id=1。

这是“好的”,但不是所需的输出。虽然我仍然没有弄清楚如何调整 URL 返回值的格式,但我想我会针对我的 Controller 测试查询字符串,并发现在查询字符串格式中我的 Controller 不起作用但在“url "格式化它。

然后我花了一个小时试图找出原因。我尝试了不同的装饰(即 [FromUri],从我的阅读来看,它只对默认为消息正文的复杂对象是必需的)设置默认值、约束并使其成为可选的(即 {id?})。

下面是有问题的代码,包括 Controller 、基本 API Controller 和使 HATEOAS 实现成为可能的模型工厂。

我的 3 个问题是:

1) 如何让 Controller 接受查询字符串中的“id”和 url 格式(.../deliverables/1 和 .../deliverables?id=1。

2) 如何让 URL 助手的 Link 方法返回 url 格式的值(目前它作为查询字符串返回。

3) 在 WebAPI 2 中命名路由的正确方法。我在做什么(为单个方法分配一个名称,而其他方法似乎继承它只是闻起来有味道,我不得不相信这会崩溃,因为我实际上开始实现更多复杂的代码。Shawn 的实现在某些方面有缺陷吗?我喜欢不必为了测试/开发目的而硬编码 URL,但也许 UrlHelper 不是实现此目的的最佳方法。它似乎带来了很多可能不会的包袱有必要。

Controller :

[RoutePrefix("api/deliverables")]
public class DeliverablesController : BaseApiController
{
    private readonly IDeliverableService _deliverableService;
    private readonly IUnitOfWork _unitOfWork;

    public DeliverablesController(IDeliverableService deliverableService, IUnitOfWorkAsync unitOfWork)
    {
        _deliverableService = deliverableService;
        _unitOfWork = unitOfWork;
    }

    [Route("", Name = "Deliverables")]
    public IHttpActionResult Get()
    {
        return Ok(_deliverableService.Get().Select(TheModelFactory.Create));
    }

    [Route("{id}")]
    public IHttpActionResult Get(int id)
    {
        return Ok(TheModelFactory.Create(_deliverableService.Find(id)));
    }

    [Route("")]
    public IHttpActionResult Post([FromBody]DeliverableModel model)
    {
        try
        {
            var entity = TheModelFactory.Parse(model);

            if (entity == null)
            {
                return BadRequest("Could not parse Deliverable entry in body.");
            }

            _deliverableService.Insert(entity);
            _unitOfWork.SaveChanges();

            return Created(Request.RequestUri + "/" + entity.Id.ToString(CultureInfo.InvariantCulture),TheModelFactory.Create(entity));


        }
        catch (Exception exception)
        {
            return BadRequest(exception.Message);
        }
    }
}

基础 API Controller :

public abstract class BaseApiController : ApiController
{
    private ModelFactory _modelFactory;

    protected ModelFactory TheModelFactory
    {
        get
        {
            return _modelFactory ?? (_modelFactory = new ModelFactory(Request));
        }
    }
}

模型工厂:

public class ModelFactory
{
    private readonly UrlHelper _urlHelper;

    public ModelFactory(HttpRequestMessage request)
    {
        _urlHelper = new UrlHelper(request);
    }

    public DeliverableModel Create(Deliverable deliverable)
    {
        return new DeliverableModel
               {
                   Url = _urlHelper.Link("deliverables", new { id = deliverable.Id }),
                   Description = deliverable.Description,
                   Name = deliverable.Name,
                   Id = deliverable.Id
               };
    }

    public Deliverable Parse(DeliverableModel model)
    {
        try
        {
            if (string.IsNullOrEmpty(model.Name))
               return null;

            var entity = new Deliverable
                         {
                             Name = model.Name,
                             Description = !string.IsNullOrEmpty(model.Description)
                                 ? model.Description
                                 : string.Empty
                         };

            return entity;
        }
        catch (Exception)
        {
            return null;
        }
    }
}

需要澄清的是,非属性(传统)路由对于 URI 和查询字符串格式都没有问题:

config.Routes.MapHttpRoute(
            name: "deliverables",
            routeTemplate: "api/deliverables/{id}",
            defaults: new { controller = "deliverables", id = RouteParameter.Optional }
        );

最佳答案

在我看来,这是属性路由的问题之一。这就是为什么我在特殊情况下使用它。我对大多数路由使用路由表,然后在特殊情况下使用属性路由。

为了以您的方式解决这个问题,您是否考虑过 Get(id) 上的多个路由? (我实际上认为这行不通,但值得一试)。

关于c# - 属性路由和查询字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23069545/

相关文章:

c# - 使用 AppSettings.json 和 Startup.cs 将服务引用注入(inject) .NET

c# - 在 metroapp 中显示存储在存储文件中的图片

asp.net-mvc - Web API 和 AngularJS SPA 应用程序的身份验证

c# - POST HttpRequestMessage 为空

c# - 405 方法不允许 - ASP.NET Web API

c# - Controller Action 命名约定

c# - 使用 ASP NET MVC 4 和 webapi 的自定义 http 处理程序和路由处理程序

c# - BeginRouteForm 不适用于 API 路由?

c# - EF Core 数据库中已经有一个名为 'AspNetRoles' 的对象

c# - 动态添加填充有绑定(bind)文本框的网格行