通过IHttpHandler序列化ProtoBuf会产生无效结果

时间:2019-02-07 00:26:01

标签: c# protobuf-net gtfs

我正在使用ASP.NET WebForms,这意味着我将通过ASPX或ASHX页面发送Protobuf数据。

我正在尝试构建一个GTFSRT文件,为此它有一个名为GTFSRealTimeBindings的Nuget包。它使用Protobuf和Protobuf-net压缩并发送数据。

我遇到的问题是,在发送数据时,某些东西变得混乱,因此无法在接收端读取它,而且我不确定如何纠正它。我认为它在编码中,但是我没有设置它,所以我不确定如何更改它。

我最终要做的是编写一个http处理程序(ashx页面),该处理程序将从另一个源下载GTFS文件,然后简单地尝试转发它。我知道可以从其他来源读取和解码GTFS文件。但是,每次我尝试从ashx页面中处理文件时,都无法解码protbuf对象。

这是一个非常基本的代码集:

public class Vehicles : IHttpHandler
{

  public void ProcessRequest(HttpContext context)
  {

      WebRequest req = HttpWebRequest.Create("https://cdn.mbta.com/realtime/VehiclePositions.pb");
      FeedMessage feed = Serializer.Deserialize<FeedMessage>(req.GetResponse().GetResponseStream());

      Serializer.Serialize(context.Response.OutputStream, feed);
  }
}

在此代码段中,您将注意到我正在从cdn.mbta.com下载Protobuf文件,然后只是尝试获取我得到的结果并将其传递回去。

当我尝试将其读入示例应用程序时:

WebRequest req = HttpWebRequest.Create("http://localhost:54988/Secure/Admin/Reports/GtfsRt/Vehicles.ashx");
FeedMessage feed = Serializer.Deserialize<FeedMessage>(req.GetResponse().GetResponseStream());

我收到的消息是: '无效的电线类型;这通常意味着您已覆盖文件而没有截断或设置长度;参见http://stackoverflow.com/q/2152978/23354'

如果在点击该页面时运行Fiddler,我注意到从cdn.mbta.com获得的响应与该页面给出的响应是不同的(当然要减去标题)。

例如,fiddler中mbta.com的前两行显示:

2.0] y1601“ T

但是我回复的前两行是: 2.0瓦 y1601“ N

关于导致此问题的原因以及如何纠正的任何想法? 我尝试使用

设置编码
content.Response.ContentEncoding=Encoding.Utf8

我和我经历了所有其他编码,以尝试正确设置它。

======更新====== 为了回答Marc的问题,我采用了响应有效负载的Base64字符串,并且一旦我继续转发,来自第一个源的响应就与该响应不匹配。

来自mbta.com的响应(限于前几个字符): Cg0KAzIuMBAAGI / e8eIFEl0KBXkwNzIzIlQKHAoIMzkyNTAwNjcqAjg4MAAaCDIwMTkwMjA3IABCDg

我的服务回复(限制为前几个字符): CgsKAzIuMBiP3vHiBRJXCgV5MDcyMyJOChgKCDM5MjUwMDY3GggyMDE5MDIwNyoCODgSFA3skilCFQ

如您所见,它们是不同的。我将研究一个可以上传以演示该问题的解决方案。再次谢谢你!

2 个答案:

答案 0 :(得分:1)

我认为我已经能够提出解决方案。

我的Web代码变成了以下内容:

    public void ProcessRequest(HttpContext context)
    {
        context.Response.Clear();
        context.Response.Buffer = true;
        context.Response.AddHeader("content-disposition", "attachment;filename=VehiclePositions.pb");
        context.Response.ContentType = "application/x-protobuf";
        WebRequest req = HttpWebRequest.Create("https://cdn.mbta.com/realtime/VehiclePositions.pb");
        FeedMessage feed = Serializer.Deserialize<FeedMessage>(req.GetResponse().GetResponseStream());
        using (MemoryStream ms = new MemoryStream())
        {
            Serializer.Serialize(ms, feed);
            context.Response.BinaryWrite(ms.ToArray());
            context.Response.End();
        }
    }

不知道它是否相关,但是在调试时,我注意到有时请求不会到达Web服务。删除了身份验证,它现在可以解码消息。我相信这是可行的,就像我逐步浏览Web代码一样,但这是需要注意的事情。 再次谢谢你马克!

答案 1 :(得分:0)

如果您不看二进制文件,在提琴手中的响应看起来会很棘手。最好的选择是在HexView选项卡上查看;绿色的一切都是标题。黑色的一切都是有效载荷。

使用原始的https://cdn.mbta.com/realtime/VehiclePositions.pb网址,我注意到这大约是26k,但是有效载荷字节为66591,内部使用gzip;因此,您需要确保先接受Fiddler的报价才能对其进行解码-然后我在Fiddler中进行了“ base-64复制”(仅在HexView标签中包含有效负载,而不是标头)并通过{ {3}}(使用base-64选项),并解析到最后。

所以:我的建议是:

  • 对您的处理者进行类似的请求
  • 检查长度-是66k吗?还是26k?或者是其他东西?如果是26k,是否标记为gzip编码?
  • 当您为每个副本复制有效负载base-64时(如果需要,请进行gzip解码):base-64相同吗?
  • https://protogen.marcgravell.com/decode对您的处理程序说的base-64有什么看法?它接受它并解析到最后吗?

这应该有助于您发现问题;或帮助我识别您的身份。