2016-07-20 1 views
8

У меня есть веб-сайт, основанный на MVC со страницей, которая должна отображать результаты в формате OData, а также регистрировать, сколько байтов было отправлено, представляя каждую запись в результате. получить результаты из БД, используя этот код:Измерение вывода из ответа 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})); 

но здесь крюк, кажется, не работает: я установить точки останова для всех методов, определенных в MeasuringJsonFormatter и никого не было.

Может ли кто-нибудь дать мне направление, где искать?

Я использую C# с Visual Studio 2010, MS ASP.NET MVC 5.2.3, MS ASP.NET Web API 2.2 для OData v4

+0

Вы нашли решение этого? –

+0

Вы пробовали эту идею http://weblogs.asp.net/fredriknormen/log-message-request-and-response-in-asp-net-webapi? – DmitryBLR

ответ

4

Я не уверен, но если вы реализуете свою собственную версию ODataWriter, то вы можете проверить длину записи. Посмотрите на этот пример: https://blogs.msdn.microsoft.com/odatateam/2015/01/05/tutorial-sample-odatalib-custom-payload-format/ пользовательского ODataWriter. В CsvOutputContext вы получили

public void Flush() 
{ 
    this.stream.Flush(); 
} 

Я думаю, вы можете попробовать проверить this.stream.Length до того Flush, но я не проверял.

EDIT

Если вы хотите добавить данные или изменить способ сериализатору сохраняет ваши данные, необходимые для переопределения WriteStart внутри пользовательского ODataWriter, как это:

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 позволяет добавлять whatver данные, которые вы хотели , Просто посмотрите пример ссылки, которую я предоставил.

EDIT2

Для того, чтобы сохранить двоичные данные, такие как 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); 
    } 
}