从 HttpResponseMessage 获取对象并使用 MethodInfo.Invoke()

时间:2021-01-15 19:23:39

标签: c# json http

我需要在记录 API 响应时过滤掉敏感数据。

我认为这应该在 LogRequestAndResponseHandler 类中完成。

这是我的代码:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // This call is required to ensure that the logging is done against the current website credentials.
        ContextService.SetContextUserCredentials(Global.GlobalData.userCred);

        // let other handlers process the request
        var result = await base.SendAsync(request, cancellationToken);

        StreamContent contentStream = result.Content as StreamContent;

        
        // First branch for non-stream content
        if (result.Content != null && (contentStream == null))
        {
        
            // All models will inherit this interface
            var method = typeof(IGDPRSafeCloneable).GetMethod("SafeCloneForLogging");

            var responseBody = method.Invoke(result.Content.GetType(), null); // res == 20

            
            responseBody = JsonConvert.DeserializeObject(responseBody.ToString());

            Logger.DisplayDebug(LoggingLevel.Info, "INFO", "RESPONSE BODY: " + responseBody);
        }

这显然不起作用,但我需要更改 var responseBody = method.Invoke(result.Content.GetType(), null);

但我不知道该怎么做。

以下是 SafeCloneForLogging 方法在我的模型类中的作用:

[DataContract]
public class SalesPerson : IGDPRSafeCloneable
{
    [DataMember(Name = "SalesmanId")]
    public int SalesmanId { get; set; }
    [DataMember(Name = "CarId")]
    public int CarId{ get; set; }
    [DataMember(Name = "SalesmanCode")]
    public string SalesmanCode { get; set; }
    [DataMember(Name = "Name")]
    public string Name { get; set; }

    public IGDPRSafeCloneable SafeCloneForLogging()
    {
        return new SalesPerson()
        {
            SalesmanId = SalesmanId,
            CarId= CarId,
            SalesmanCode = string.Empty,
            Name = string.Empty,
        };
    }
}

1 个答案:

答案 0 :(得分:1)

您问题的根本症结在于您试图在没有类型的情况下执行基于类型的操作。处理此问题的最简单方法是将类型传递给您的 SendAsync 方法,您可以将其反序列化并转换为 IGDPRSafeCloneable。如果可转换,则调用 SafeCloneForLogging 方法,如果不为 null 则记录。

public async Task<HttpResponseMessage> SendAsync<T>(HttpRequestMessage request, CancellationToken cancellationToken)
{
    // This call is required to ensure that the logging is done against the current website credentials.
    ContextService.SetContextUserCredentials(Global.GlobalData.userCred);

    // let other handlers process the request
    var result = await client.SendAsync(request, cancellationToken);

    StreamContent contentStream = result.Content as StreamContent;

    // First branch for non-stream content
    if (result.Content != null && (contentStream == null))
    {
        var responseBody = (
            (JsonConvert.DeserializeObject<T>(
                await result.Content.ReadAsStringAsync()
            ) as IGDPRSafeCloneable)?.SafeCloneForLogging());
        
        if (responseBody != null)
        {
            Logger.DisplayDebug(LoggingLevel.Info, "INFO", "RESPONSE BODY: " + responseBody);   
        }
    }
    
    return result;
}

但是,请注意这里有一些明显的缺点。您必须对内容进行两次处理……一次记录它,然后再次在 SendAsync 的调用程序中。

根据您的记录器,最好在日志站点添加清理,特别是如果您的记录器可以处理对象并且您在记录期间序列化对象。

相关问题