2

我拼命尝试在 Web API 中上传纯(文本/纯)字符串,而我的控制器只是拒绝正确地进行路由。我得到的只是一个 404(未找到)HTTP 错误(我很高兴所有“Get”方法都可以开箱即用:-()

这是我的路线:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "IntegraApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        config.Routes.MapHttpRoute(
            name: "ServComAdminApi",
            routeTemplate: "admin/{action}",
            defaults: new { controller = "admin", action = RouteParameter.Optional }
        );
        config.Routes.MapHttpRoute(
            name: "ServComApi",
            routeTemplate: "{id}/{action}",
            constraints: new { id = @"\d+" },
            defaults: new { controller = "servcom", action = "info" }
        );

        // Get rid of XML responses
        var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
        config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
    }
}

相关路由是映射到“servcom”控制器的最后一个路由。我正在移植一个遵循该路由模式(“id/action”)的自定义编写的 HTTP 服务器。它适用于所有“获取”方法。我只需使用以下命令就可以获得ID为“10”的设备的“用户”列表:http://localhost:49410/10/users...但是当我尝试上传“字符串数据”时它不起作用。这是我的控制器上的相关方法:

public class ServcomController : ApiController
{
    [HttpPut, HttpPost]
    public string Vis(long idTerm)
    {
        return "PUT/POST Vis for: " + idTerm;
    }
}

它被精简到最低限度。我什至没有阅读实际的字符串数据。因为我不会发送表单编码数据,只是一个纯字符串(这个 API 目前在 3G 下使用,所以任何字节节省都很好,因为我们需要尽量减少数据计划的使用),我没有使用 [FromBody] 属性作为它根本行不通。

这是用于测试它的客户端代码:

using System;
using System.Net;

namespace TestPutPostString
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Sending 'HELLO WORLD!'");
            var wc = new WebClient();
            var res = wc.UploadString("http://localhost:49410/101/vis", "PUT", "HELLO WORLD!");
            Console.WriteLine("Response: " + res);
            Console.ReadKey(true);
        }
    }
}

它失败并显示:“远程服务器返回错误:(404)未找到。”

上面的代码与我的手写 HTTP 服务器完美配合,该服务器使用 TcpServer 并且是针对该 API 的特定需求从头开始编写的(我在使用 2 年后将其迁移到 Web.API,因为它更容易托管以这种方式在 Azure 上)。使用带有手写 HTTP 堆栈的相同示例程序,消息的正文在到达服务器时确实具有“HELLO WORLD!”。为什么不将其路由到 ServComController.Vis() 方法?

我发错了吗?WebClient.UploadString() 是否以其他不可预测的方式工作?还是我的控制器方法签名错误?路线错了吗?我错过了什么!?!?:-)

4

2 回答 2

2

如果您想避免操作选择的痛苦,您可以将您的签名更改为,

public class ServcomController : ApiController
{
    [HttpPut, HttpPost]
    public HttpResponseMessage Vis(HttpRequestMessage request)
    {
        var idTerm = request.GetRouteData().Values["idTerm"];
        var body = request.Content.ReadAsStringAsync().Result;
        return "PUT/POST Vis for: " + idTerm;
    }
}
于 2013-06-16T01:04:27.633 回答
1

Darrel Miller 提供了一个很好的解决方案,这不是实际的答案,但我想最终会得到比我自己对我自己的问题的回答更多的支持。我不知道我们可以通过使用 type 的参数来“避免操作选择的痛苦” HttpRequestMessage!这非常好,我可以看到很多场景,它会非常非常有用。

但这并不是他的回答会得到更多支持的唯一原因:这是因为我的问题很愚蠢!我犯了一个非常愚蠢的错误。

这是路线:

    config.Routes.MapHttpRoute(
        name: "ServComApi",
        routeTemplate: "{id}/{action}",
        constraints: new { id = @"\d+" },
        defaults: new { controller = "servcom", action = "info" }
    );

这是我试图将路线映射到的方法:

public class ServcomController : ApiController
{
    [HttpPut, HttpPost]
    public string Vis(long idTerm)
    {
        return "PUT/POST Vis for: " + idTerm;
    }
}

当然不会匹配!在路由中我使用了“id”作为参数,而在这个方法中我使用了“idTerm”作为参数,所以在匹配路由的 ServComController 上真的没有任何动作!

解决方案只是将其更改为:

public class ServcomController : ApiController
{
    [HttpPut, HttpPost]
    public string Vis(long id) // << "idTerm" to "id"
    {
        return "PUT/POST Vis for: " + idTerm;
    }
}

而且由于正文不是形式编码的,我将无法使用 [FromBody]string 数据,因为它需要表单数据。最终的解决方案是使用一个好的、旧StreamReader的方法从请求中读取正文。今天晚些时候,我将使用完整代码更新解决方案。

于 2013-06-16T16:26:41.897 回答