测量OData响应的输出

Lib*_*orV 8 c# asp.net asp.net-mvc odata

我有一个基于MVC的网站,其中一个页面应该提供OData格式化的结果,同时还记录发送了表示结果中每条记录的字节数.我使用以下代码从DB获取结果:

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

我试图通过它挂钩到OData格式化程序

 config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create(new CustomODataSerializerProvider(), new DefaultODataDeserializerProvider()));
Run Code Online (Sandbox Code Playgroud)

哪里

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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我以为我能够找出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();
    }

}
Run Code Online (Sandbox Code Playgroud)

迷上了

config.Formatters.Insert(0, new MeasuringJsonFormatter(new ODataPayloadKind[] { ODataPayloadKind.Entry, ODataPayloadKind.Feed}));
Run Code Online (Sandbox Code Playgroud)

但这里的钩子似乎不起作用:我将断点设置为在其中定义的所有方法MeasuringJsonFormatter,并且没有被击中.

任何人都可以给我一个指导方向吗?

我正在使用C#与Visual Studio 2010,MS ASP.NET MVC 5.2.3,MS ASP.NET Web API 2.2 for OData v4

小智 4

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

public void Flush()
{
    this.stream.Flush();
}
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)