我有一个基于MVC的网站,该网站的页面应提供OData格式的结果,同时还要记录发送的字节数,这些字节代表结果中的每条记录。
我使用以下代码从数据库中获取结果:

[EnableQuery]
public IHttpActionResult GetRecords(ODataQueryOptions<Record> queryOptions)
{
 DataProvider<Record> provider = GetRecordProvider();
 ...
 return OK<IQueryable<Record>>(provider.Queryable);
}

我试图通过连接到OData格式化程序
 config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create(new CustomODataSerializerProvider(), new DefaultODataDeserializerProvider()));

在哪里
public class CustomODataSerializerProvider : DefaultODataSerializerProvider
{
    public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
    {
        if (edmType.Definition.TypeKind == EdmTypeKind.Entity)
            return new CustomODataEntityTypeSerializer(this);
        else
            return base.GetEdmTypeSerializer(edmType);
    }
}

public class CustomODataEntityTypeSerializer : ODataEntityTypeSerializer
{
    public CustomODataEntityTypeSerializer(ODataSerializerProvider provider)
        : base(provider)
    {
    }

    public override ODataProperty CreateStructuralProperty(IEdmStructuralProperty structuralProperty, EntityInstanceContext entityInstanceContext)
    {
        var property = base.CreateStructuralProperty(structuralProperty, entityInstanceContext);
        if(property.Value == null) return null;
        else return property;
    }

    public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
    {
        base.WriteObject(graph, type, messageWriter, writeContext);
    }

    public override void WriteDeltaObjectInline(object graph, IEdmTypeReference expectedType, ODataDeltaWriter writer, ODataSerializerContext writeContext)
    {
        base.WriteDeltaObjectInline(graph, expectedType, writer, writeContext);
    }

    public override void WriteObjectInline(object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext)
    {
        int outputSize = 0;
        base.WriteObjectInline(graph, expectedType, writer, writeContext);
        writer.Flush();
        Log(outputSize);
        }
    }

我以为我可以找出WriteObjectInline调用生成的输出的长度,但无法弄清楚该怎么做。

我还尝试了另一种解决方案,使用
public class MeasuringJsonFormatter : ODataMediaTypeFormatter
{
    public MeasuringJsonFormatter(IEnumerable<Microsoft.Data.OData.ODataPayloadKind> payloadKinds)
        : base(payloadKinds)
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
    }
    public override bool CanReadType(Type type)
    {
        return false;
    }

    private bool IsSupportedType(Type type)
    {
        return type==typeof(Record);
    }
    private bool IsSupportedCollection(Type type)
    {
        return
                type.IsGenericType &&
                IsSupportedType(type.GetGenericArguments()[0]) &&
                typeof(IEnumerable<>).MakeGenericType(type.GetGenericArguments()[0]).IsAssignableFrom(type)
                ;

    }
    public override bool CanWriteType(Type type)
    {
        return IsSupportedType(type) || IsSupportedCollection(type);
    }
    public override System.Threading.Tasks.Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
    {
        return base.WriteToStreamAsync(typeof(string), Format(type, value, content), writeStream, content, transportContext);
    }
    public override System.Threading.Tasks.Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext, System.Threading.CancellationToken cancellationToken)
    {
        return base.WriteToStreamAsync(typeof(string), Format(type, value, content), writeStream, content, transportContext, cancellationToken);
    }
    private string Format(Type type, object value, System.Net.Http.HttpContent content)
    {
        if (IsSupportedType(type))
        {
            string result =JsonConvert.SerializeObject(value, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
            Log(result.Length);
            return result;
        }
        else if (IsSupportedCollection(type))
        {
            StringBuilder sb = new StringBuilder();
            foreach (object item in (value as IEnumerable)) sb.Append(Format(type.GetGenericArguments()[0], item, content));
            return sb.ToString();
        }
        else return "Unable to process type " + type.ToString();
    }

}

迷上了
config.Formatters.Insert(0, new MeasuringJsonFormatter(new ODataPayloadKind[] { ODataPayloadKind.Entry, ODataPayloadKind.Feed}));

但是这里的钩子(Hook)似乎不起作用:我为MeasuringJsonFormatter中定义的所有方法设置了断点,但没有命中。

谁能给我个指导的方向?

我正在将C#与Visual Studio 2010,MS ASP.NET MVC 5.2.3,用于OData v4的MS ASP.NET Web API 2.2一起使用

最佳答案

我不确定,但是如果您实现自己的ODataWriter版本,则可以检查条目的长度。看下面的示例:定制ODataWriter的https://blogs.msdn.microsoft.com/odatateam/2015/01/05/tutorial-sample-odatalib-custom-payload-format/。在CsvOutputContext中,您得到了

public void Flush()
{
    this.stream.Flush();
}
我认为您可以尝试在this.stream.Length之前检查Flush,但是我没有对其进行测试。
编辑
如果要添加数据或更改序列化程序保存数据的方式,则需要在自定义ODataWriter中覆盖WriteStart,如下所示:
public override void WriteStart(ODataFeed feed)
{
}

private void WriteEntry(ODataEntry entry)
{
    foreach (var header in this.headers)
    {
        var property = entry.Properties.SingleOrDefault(p => p.Name == header);
        if (property != null)
        {
            this.context.Writer.Write(property.Value);
        }
        this.context.Writer.Write(",");
    }
    this.context.Writer.WriteLine();
}
this.context.Writer.Write可让您添加所需的任何数据。只需查看我提供的示例链接即可。
编辑2
为了保存jpg文件之类的二进制数据,您需要对其进行序列化。看这个:
private void WriteEntry(ODataEntry entry)
{
    string file = @"C:\test.jpg";
    byte[] data = File.ReadAllBytes(file);
    using (MemoryStream fileStream = new MemoryStream(data))
    using (Image i = Image.FromStream(originalms))
    {
       i.Save(this.context.Writer, System.Drawing.Imaging.ImageFormat.Jpeg);
    }
}

10-05 20:48
查看更多