如果我有定期的方法通话,我需要启动'使用async / await,启动它的最佳方法是什么?在没有详细说明的情况下,我使用Hangfire来处理作业,并且由于某些情况我认为超出了问题的范围,因此Hangfire作业同步运行,但后来我想要以后启动异步并等待,以便实际的工作代码'可以根据需要/期望使用async / await。是否低于启用异步和等待的最佳方式?
public void SynchMethod()
{
var inputPackage = XElement.Parse( "NormallyPassedIn" );
var hangfireJob = CreateJob( inputPackage );
Task.Run( async () =>
{
// This Execute method implementation wants to use await on several
// helper methods it calls, so this is how I thought to allow for that
await hangfireJob.Execute( inputPackage );
} ).GetAwaiter().GetResult();
}
更新2:阻止尽可能高......
因此,尝试将Stephen的阻止建议尽可能高(基本上是在第一次/仅跨域调用),我尝试将代码更改为以下内容:
var appDomain = AppDomain.CreateDomain( info.ApplicationName, AppDomain.CurrentDomain.Evidence, info );
...
instance = appDomain.CreateInstanceAndUnwrap( jobInvokerType.Assembly.FullName, jobInvokerType.FullName ) as JobInvoker;
...
instance.Process( this, inputPackage.ToString() ).GetAwaiter().GetResult();
使用过程功能:
public async Task Process( IHangfireJobContext jobContext, string inputPackageXml )
{
...
var hangfireJob = CreateJob( assembly, jobTypeName );
await hangfireJob.Execute( inputPackage, jobContext );
}
请记住hangfireJob.Execute
是真实的'我希望能够使用async / await的方法。只要hangfireJob.Execute
使用await
,就会抛出以下异常:
类型 ' System.Threading.Tasks.Task`1 [[System.Threading.Tasks.VoidTaskResult, mscorlib,版本= 4.0.0.0,文化=中性, 公钥= b77a5c561934e089]]'在Assembly&#m; mscorlib中, Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089'是 没有标记为可序列化。
服务器堆栈跟踪:at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType 输入) System.Runtime.Serialization.FormatterServices.GetSerializableMembers(类型 type,StreamingContext context)at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(对象 obj,ISurrogateSelector surrogateSelector,StreamingContext context, SerObjectInfoInit serObjectInfoInit,IFormatterConverter转换器, ObjectWriter objectWriter,SerializationBinder binder)at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(对象 obj,ISurrogateSelector surrogateSelector,StreamingContext context, SerObjectInfoInit serObjectInfoInit,IFormatterConverter转换器, ObjectWriter objectWriter,SerializationBinder binder)at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(对象 graph,Header [] inHeaders,__BinaryWerer serWriter,Boolean fCheck)
在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(流 serializationStream,Object graph,Header [] headers,Boolean fCheck)
在 System.Runtime.Remoting.Channels.CrossAppDomainSerializer.SerializeMessageParts(ArrayList的 argsToSerialize)at System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage..ctor(IMethodReturnMessage 先生 System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage.SmuggleIfPossible(即时聊天 msg)at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoDispatch(字节[] reqStmBuff,SmuggledMethodCallMessage走私了Mcm, SmuggledMethodReturnMessage&安培;走私的人 System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatchCallback(对象[] 参数)在[0]处重新抛出异常:at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(即时聊天 reqMsg,IMessage retMsg)at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&安培; msgData,Int32类型)at BTR.Evolution.Hangfire.JobInvoker.Process(IHangfireJobContext jobContext,String inputPackageXml)at BTR.Evolution.Hangfire.JobInvoker.Invoke(XElement inputPackage, PerformContext performContext,IJobCancellationToken cancelToken) C:\ BTR \ Source \ Evolution \ BTR.Evolution.Hangfire \ JobInvoker.cs:第86行
所以我改回了:
public void Process( IHangfireJobContext jobContext, string inputPackageXml )
并将.GetAwaiter().GetResult()
移至hangfireJob.Execute()的末尾:
hangfireJob.Execute( inputPackage, jobContext ).GetAwaiter().GetResult();
然后一切正常。将斯蒂芬的答案标记为正确。不知道为什么我无法阻止第一个/唯一一个跨越域名的电话,但可能是预期的。
更新1:AppDomain创建/推理
所以我想我会根据下面的评论更新问题。我真正运行的工作流程如下,我遇到的主要问题是我正在创建一个AppDomain并跨域调用。
Hangfire启动我的工作(JobInvoker.Invoke
)以运行(您可以让您的工作成为同步或异步工作)。最初,我试图像public async Task Invoke( XElement inputPackage, PerformContext performContext, IJobCancellationToken cancellationToken )
一样异步运行。
JobInvoker.Invoke
通过var appDomain = AppDomain.CreateDomain( info.ApplicationName, AppDomain.CurrentDomain.Evidence, info );
JobInvoker.Invoke
通过instance = appDomain.CreateInstanceAndUnwrap( jobInvokerType.Assembly.FullName, jobInvokerType.FullName )
创建对象。
我尝试调用带有签名instance.Process
的{{1}}方法。
public async Task Process( IHangfireJobContext jobContext, string inputPackageXml )
通过反映使用上面instance.Process
的代码创建了一个对象。这个var hangfireJob = CreateJob()
对象的方法是签名中需要hangfireJob
。
async
通过instance.Process
调用hangfireJob。
await hangfireJob.Execute()
签名为hangfireJob.Execute
。
然后代码看起来好得多,因为我只需将public async Task Execute( XElement inputPackage, IHangfireJobContext jobContext )
放在我的所有方法上,然后随意使用async
。但是只要await
尝试使用hangfireJob.Execute
并且我收到以下异常(请记住这是在单独的AppDomain中运行,因此异常):
类型 ' System.Threading.Tasks.Task`1 [[System.Threading.Tasks.VoidTaskResult, mscorlib,版本= 4.0.0.0,文化=中性, 公钥= b77a5c561934e089]]'在Assembly&#m; mscorlib中, Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089'是 没有标记为可序列化。
这就是为什么我尝试引入'来自await
内的异步编码(实际上由我的原始instance.Process
表示),因为我的SynchMethod
方法确实需要hangfireJob.Execute
签名,所以我可以做一些async
来电。
鉴于此信息,可能所有评论都不再适用?如果您认为它们或者它是否像执行await
一样简单(并删除await hangfireJob.Execute( inputPackage ).GetAwaiter().GetResult()
包装器),请告诉我。
答案 0 :(得分:2)
在一般情况下,您应该强烈避免阻止异步代码。
此规则的一个例外是控制台应用上的Main
方法。
Win32服务的一个有趣的怪癖是它们在架构上与Console应用程序类似。具体来说,他们有一个“主”,在服务停止之前不应退出,并且他们没有提供SynchronizationContext
。因此,在您的服务实现中阻止是适当的。
但是,我建议您遵循与在控制台应用程序中阻止相同的最佳做法:仅在一个点上阻止,尽可能远离堆栈。
就具体情况而言,GetAwaiter().GetResult()
就足够了;没有Task.Run
。