【问题标题】:Wait for an Async method to finish from a separate method等待 Async 方法从单独的方法完成
【发布时间】:2014-01-30 20:47:11
【问题描述】:

使用PostSharp 使用OnEntryOnExit 方法为OnMethodBoundaryAspect 包装带有AOP 日志记录的WCF 服务调用。

进程:
OnEntry() 被调用,DateTime 表示调用开始的信号存储在属性中,并且异步任务在方法结束之前启动,同时该任务继续开。

此任务格式化有关服务调用的一些信息以进行记录,并且可能需要一些时间。这些值作为属性存储在此类中以进行日志记录。

OnExit() 被调用,另一个DateTime 表示呼叫结束的信号被存储。此时我需要确保以OnEntry() 方法启动的任务已完成,并且所有属性都已准备好记录到数据库中。

问题是如何确保在OnEntry() 开始的任务已完成以在OnExit() 中使用?我考虑过设置一个布尔值,while(false) {Thread.Sleep(100);},然后在为真时结束,但由于某种原因感觉不对。

下面是我目前为此设置的代码。

class LogMethodCallAttribute : OnMethodBoundaryAspect
{
    Int32 userId;
    String methodCall;
    String ip;
    DateTime entryTime;
    DateTime exitTime;

    /// Performs tasks on a Method before its execution.
    public override void OnEntry(MethodExecutionArgs args)
    {
        // Set OnEntry Time
        entryTime = DateTime.Now;
        
        if (ConfigurationManager.AppSettings["AOPLoggingEnabled"] == "1")
        {
            MessageProperties prop = OperationContext.Current.IncomingMessageProperties;
            // Queue the logging to run on the ThreadPool so the service can finish the request.
            Task.Factory.StartNew(() => SetUpLog(args, prop));            
        }
    }
    
    public override void OnExit(MethodExecutionArgs args)
    {
        // Set OnExit Time
        exitTime = DateTime.Now;
        
        // Need to make sure the Task running SetUpLog is complete and all props set.

        // Log the details of this method call.
        Logs.LogWebServiceCall(userId, methodName, ip, entryTime, exitTime);
    }
    
    // Format details for logging.
    private void SetUpLog(MethodExecutionArgs args, MessageProperties prop)
    {
        // Retrieve all the required data and do any formatting.
        userId = ...;
        methodCall = ...;
        ip = ...;
    }
}

【问题讨论】:

  • 将从Task.Factory.StartNew返回的任务存储在一个vriable中,并将Wait存储在OnExit中。

标签: c# wcf asynchronous postsharp


【解决方案1】:

编辑:好的,我想我误解了你。

基本上,你需要记住你已经开始的Task,然后你就可以打电话给Wait()等待它完成:

class LogMethodCallAttribute : OnMethodBoundaryAspect
{
    Task task;
    ... as before ...

    public override void OnEntry(MethodExecutionArgs args)
    {
        ...
        task = Task.Factory.StartNew(...);
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        exitTime = DateTime.Now;
        // Wait for the task to have completed...
        task.Wait();
        // Now you can use the fields
    }
}

我个人实际上 不会 只是在任务中设置字段 - 我会将任务设置为 Task<T> 用于某些包含日志记录参数的 T。然后,您可以将属性中的 only 字段设置为任务,并具有:

var loggingParameters = task.Result;
... use the logging parameters

【讨论】:

  • 服务调用本身可能需要一些时间。最初我们并不关心开始/结束时间,只是异步触发了日志记录并忘记了它。有了这个新要求,99.99% 的服务调用将花费更长的时间,并且所有数据都应该在准备就绪的字段中等待。如果我理解正确,你是说它应该是创建任务的方法在任务本身之前完成,这与我试图做的相反?
  • @WebDevNewbie:我怀疑我误解了您的要求。将编辑我的帖子。
  • 非常感谢,关于使用 Task 的额外建议也确实有帮助:)
猜你喜欢
  • 2021-06-27
  • 1970-01-01
  • 2022-11-19
  • 2022-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多