Wpf Desktop Api 调用持续时间比实际 api 响应时间长约 8-10 秒
Wpf Desktop Api call duration more longer than actual api response time about 8-10 seconds
案例如下:
我在大约 80 个客户端上安装了 wpf 应用程序,它们使用单个 .net 框架 api 进行数据处理。我在 Wpf 和 api 应用程序的某些地方有秒表跟踪器来跟踪持续时间。代码示例:
我的 api 属性:
public class DurationControlLoggerAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var controller = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var action = actionContext.ActionDescriptor.ActionName;
actionContext.ActionArguments.Add("_stopwatch_", Stopwatch.StartNew());
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (ConfigurationManager.AppSettings["ApiLogger"].ToLower().Trim() != "true")
return;
var controller = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var action = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
var stopWatch = (Stopwatch)actionExecutedContext.ActionContext.ActionArguments["_stopwatch_"];
stopWatch.Stop();
var scope = actionExecutedContext.ActionContext.Request.GetDependencyScope();
var commonService = (ICommonService)scope.GetService(typeof(ICommonService));
commonService.InsertLog(new Model.Common.LogModel
{
InsertDate = DateTime.Now.ToString(),
LogLevel = "API",
MachineName = "API",
Message = $"Controller : {controller} - Action : {action} - TotalSeconds : {stopWatch.Elapsed.TotalSeconds}",
StackTrace = string.Empty
});
}
}
动作示例:
[HttpPost]
[DurationControlLogger]
public bool InsertProduct(ProductModel model)
{
return _mainService.TracingService.InsertProduct(model);
}
这个动作过程持续时间约为0.03秒。另一方面,wpf api 调用持续时间约为 10 秒。 Wpf 代码块在下面:
var Stopwatch = Stopwatch.StartNew();
var isSuccess = DataHelper.InsertProduct(Product);
Stopwatch.Stop();
if (Stopwatch.Elapsed.TotalSeconds > 2)
DataHelper.InsertTraceLog($"ProducrtBusiness - InsertProduct TotalSecond : {Stopwatch.Elapsed.TotalSeconds}");
DataHelper.InsertProduct 方法执行基本的 http post 请求。代码在这里:
public static class HttpClientHelper
{
public static T Post<T>(object model, string url)
{
var resultStatus = false;
T resultData = default(T);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(url, content).Result;
if (response.IsSuccessStatusCode)
{
string data = response.Content.ReadAsStringAsync().Result;
var result = JsonConvert.DeserializeObject<T>(data);
resultStatus = response.StatusCode == System.Net.HttpStatusCode.OK;
resultData = result;
}
}
return resultStatus ? resultData : default(T);
}
.....
有人知道那种情况吗?
编辑
我添加最后一个日志代码。这是代码:
`
var 秒表 = Stopwatch.StartNew();
HttpResponseMessage response = client.PostAsync(url, content).Result;
stopwatch.Stop();
if (stopwatch.Elapsed.TotalSeconds > 2)
{
AppendToFile($"{DateTime.Now.ToString()} - {model.ToString()} - {stopwatch.Elapsed.TotalSeconds} - Content: {jsonData}");
}
`
此日志持续时间有时仍为 8-10 秒。
好吧,很可能(据我所见)您正在 运行在主消息泵(UI 线程)上使用此代码。在此方法调用期间,您正在执行异步调用 (PostAsync) 并调用 'Result' - 使其同步 运行。但是,当您的 UI 线程正在等待时,一些其他消息(UI 更新?)在消息泵上排队,并在您调用结束秒表之前得到处理(更高的 DispatcherPriority?) - 延迟定时器结束。
这纯粹是推测,但我建议您在异步代码中使用一些 async/await,并尝试在单独的线程上执行这些数据访问任务
我将我的 HttpClientHelper class post 方法更改为:
public static async Task<T> PostAsync<T>(object model, string url)
{
var resultStatus = false;
T resultData = default(T);
using (var client = new HttpClient(
new HttpClientHandler()
{
UseProxy = false
}
))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var jsonData = JsonConvert.SerializeObject(model);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var stopwatch = Stopwatch.StartNew();
HttpResponseMessage response = await client.PostAsync(url, content);
stopwatch.Stop();
if (stopwatch.Elapsed.TotalSeconds > 2)
{
AppendToFile($"{DateTime.Now.ToString()} - {model.ToString()} - {stopwatch.Elapsed.TotalSeconds} - Content: {jsonData}");
}
if (response.IsSuccessStatusCode)
{
string data = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<T>(data);
resultStatus = response.StatusCode == System.Net.HttpStatusCode.OK;
resultData = result;
}
}
return resultStatus ? resultData : default(T);
}
对于我的问题,client.PostAsync() 方法必须 运行 async。我认为这与一些线程管理问题有关。但是这段代码现在对我有用。
案例如下: 我在大约 80 个客户端上安装了 wpf 应用程序,它们使用单个 .net 框架 api 进行数据处理。我在 Wpf 和 api 应用程序的某些地方有秒表跟踪器来跟踪持续时间。代码示例:
我的 api 属性:
public class DurationControlLoggerAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var controller = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var action = actionContext.ActionDescriptor.ActionName;
actionContext.ActionArguments.Add("_stopwatch_", Stopwatch.StartNew());
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (ConfigurationManager.AppSettings["ApiLogger"].ToLower().Trim() != "true")
return;
var controller = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var action = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
var stopWatch = (Stopwatch)actionExecutedContext.ActionContext.ActionArguments["_stopwatch_"];
stopWatch.Stop();
var scope = actionExecutedContext.ActionContext.Request.GetDependencyScope();
var commonService = (ICommonService)scope.GetService(typeof(ICommonService));
commonService.InsertLog(new Model.Common.LogModel
{
InsertDate = DateTime.Now.ToString(),
LogLevel = "API",
MachineName = "API",
Message = $"Controller : {controller} - Action : {action} - TotalSeconds : {stopWatch.Elapsed.TotalSeconds}",
StackTrace = string.Empty
});
}
}
动作示例:
[HttpPost]
[DurationControlLogger]
public bool InsertProduct(ProductModel model)
{
return _mainService.TracingService.InsertProduct(model);
}
这个动作过程持续时间约为0.03秒。另一方面,wpf api 调用持续时间约为 10 秒。 Wpf 代码块在下面:
var Stopwatch = Stopwatch.StartNew();
var isSuccess = DataHelper.InsertProduct(Product);
Stopwatch.Stop();
if (Stopwatch.Elapsed.TotalSeconds > 2)
DataHelper.InsertTraceLog($"ProducrtBusiness - InsertProduct TotalSecond : {Stopwatch.Elapsed.TotalSeconds}");
DataHelper.InsertProduct 方法执行基本的 http post 请求。代码在这里:
public static class HttpClientHelper
{
public static T Post<T>(object model, string url)
{
var resultStatus = false;
T resultData = default(T);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(url, content).Result;
if (response.IsSuccessStatusCode)
{
string data = response.Content.ReadAsStringAsync().Result;
var result = JsonConvert.DeserializeObject<T>(data);
resultStatus = response.StatusCode == System.Net.HttpStatusCode.OK;
resultData = result;
}
}
return resultStatus ? resultData : default(T);
}
.....
有人知道那种情况吗?
编辑
我添加最后一个日志代码。这是代码: ` var 秒表 = Stopwatch.StartNew();
HttpResponseMessage response = client.PostAsync(url, content).Result;
stopwatch.Stop();
if (stopwatch.Elapsed.TotalSeconds > 2)
{
AppendToFile($"{DateTime.Now.ToString()} - {model.ToString()} - {stopwatch.Elapsed.TotalSeconds} - Content: {jsonData}");
}
`
此日志持续时间有时仍为 8-10 秒。
好吧,很可能(据我所见)您正在 运行在主消息泵(UI 线程)上使用此代码。在此方法调用期间,您正在执行异步调用 (PostAsync) 并调用 'Result' - 使其同步 运行。但是,当您的 UI 线程正在等待时,一些其他消息(UI 更新?)在消息泵上排队,并在您调用结束秒表之前得到处理(更高的 DispatcherPriority?) - 延迟定时器结束。 这纯粹是推测,但我建议您在异步代码中使用一些 async/await,并尝试在单独的线程上执行这些数据访问任务
我将我的 HttpClientHelper class post 方法更改为:
public static async Task<T> PostAsync<T>(object model, string url)
{
var resultStatus = false;
T resultData = default(T);
using (var client = new HttpClient(
new HttpClientHandler()
{
UseProxy = false
}
))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var jsonData = JsonConvert.SerializeObject(model);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var stopwatch = Stopwatch.StartNew();
HttpResponseMessage response = await client.PostAsync(url, content);
stopwatch.Stop();
if (stopwatch.Elapsed.TotalSeconds > 2)
{
AppendToFile($"{DateTime.Now.ToString()} - {model.ToString()} - {stopwatch.Elapsed.TotalSeconds} - Content: {jsonData}");
}
if (response.IsSuccessStatusCode)
{
string data = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<T>(data);
resultStatus = response.StatusCode == System.Net.HttpStatusCode.OK;
resultData = result;
}
}
return resultStatus ? resultData : default(T);
}
对于我的问题,client.PostAsync() 方法必须 运行 async。我认为这与一些线程管理问题有关。但是这段代码现在对我有用。