我有一个基于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);
}
}