如何在Web API中上传“text / plain”字符串

时间:2013-06-15 23:23:56

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

我正在拼命尝试在Web API中上传普通(text / plain)字符串,而我的Controller只是拒绝正确地进行路由。所有我得到的是一个404(未找到)HTTP错误(我很高兴所有“获取”方法开箱即用:-()

以下是我的路线:

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”控制器的最后一条路线。我正在移植一个遵循该路由模式的自定义写入HTTP服务器(“id / action”)。它适用于所有“获取”方法。我可以通过使用:http://localhost:49410/10/users来获取ID为“10”的设备的“用户”列表...但是当我尝试上传“字符串数据”时它无效。这是我控制器上的相关方法:

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)Not Found。”

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

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

2 个答案:

答案 0 :(得分: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;
    }
}

答案 1 :(得分:1)

达雷尔米勒提供了一个非常好的解决方案,这不是真正的答案,但我想最终会有更多的支持,而不是我自己对自己问题的回答。我不知道我们可以通过使用HttpRequestMessage类型的参数来“避免Action Selection的痛苦”!这非常好,我可以看到很多场景,它真的非常有用。

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

这是路线:

    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]字符串数据,因为它需要表单数据。最终的解决方案是使用一个好的,旧的StreamReader来读取请求中的正文。我将在今天晚些时候使用完整代码更新解决方案。