C# 在Dynamics CRM插件中:如何强制代码不等待异步响应
这是我的设想。我必须通过Dynamics CRM插件代码(C#)异步调用Azure函数,这很好。但是我不希望代码等待Azure函数的响应。我只想完成代码执行并退出 Azure功能将在必要时处理CRM中的更新 我不想等待的原因是在CRM Online中完成插件执行有2分钟的时间限制。但是,Azure功能可能需要几分钟才能完成此过程 下面是我的插件类代码,它正在同步调用Azure函数。(我可以在下面的文档中将调用转换为异步,但按照这种方法,我的代码仍将等待响应)C# 在Dynamics CRM插件中:如何强制代码不等待异步响应,c#,asynchronous,async-await,dynamics-crm,azure-functions,C#,Asynchronous,Async Await,Dynamics Crm,Azure Functions,这是我的设想。我必须通过Dynamics CRM插件代码(C#)异步调用Azure函数,这很好。但是我不希望代码等待Azure函数的响应。我只想完成代码执行并退出 Azure功能将在必要时处理CRM中的更新 我不想等待的原因是在CRM Online中完成插件执行有2分钟的时间限制。但是,Azure功能可能需要几分钟才能完成此过程 下面是我的插件类代码,它正在同步调用Azure函数。(我可以在下面的文档中将调用转换为异步,但按照这种方法,我的代码仍将等待响应) 您需要两个函数 函数#1将由您的插件
您需要两个函数 函数#1将由您的插件调用(基本上就是您现在所做的)。它将验证输入。如果输入成功,它将把一条消息(可能包括来自调用者的相关数据)放在一个列表中。在服务总线队列上放置消息后,它将终止并向调用者返回一条成功消息(即插件代码) 函数#2将由Azure服务总线队列消息触发。此函数将根据消息内容(来自函数#1)处理长时间运行的代码 : 此模式通常使用,因为它提供事务执行安全性。如果您只有一个函数,如上所述,并且函数失败,那么调用将丢失,因为没有要完成的侦听器
使用两个函数,我们就有了安全性。如果函数#1失败(验证或在队列中放置消息),调用者将失败,您的插件代码可以根据需要进行处理。如果函数#2失败,它将返回服务总线并排队等待重试(默认情况下,它最多重试5次,然后写入毒药队列。)您需要两个函数 函数#1将由您的插件调用(基本上就是您现在所做的)。它将验证输入。如果输入成功,它将把一条消息(可能包括来自调用者的相关数据)放在一个列表中。在服务总线队列上放置消息后,它将终止并向调用者返回一条成功消息(即插件代码) 函数#2将由Azure服务总线队列消息触发。此函数将根据消息内容(来自函数#1)处理长时间运行的代码 : 此模式通常使用,因为它提供事务执行安全性。如果您只有一个函数,如上所述,并且函数失败,那么调用将丢失,因为没有要完成的侦听器
使用两个函数,我们就有了安全性。如果函数#1失败(验证或在队列中放置消息),调用者将失败,您的插件代码可以根据需要进行处理。如果函数#2失败,它将返回服务总线并排队等待重试(默认情况下,它最多重试5次,然后写入有毒队列。)我对这个问题感到困惑。你说你知道如何使它异步,你的问题是“我如何使它异步?”你已经知道了。让它异步!如果您的问题是“我使其异步,但我不想同步等待结果,如何?”则删除同步等待。如果您的问题是“我使其异步,但我不想异步等待结果,如何?”则删除异步等待。在异步代码中,如果不进行等待,就不会发生等待。这就是“异步”的意思。但也就是说,删除异步等待是极其危险的。如果异步操作抛出?如果没有任何东西可以异步等待,那么就没有什么东西可以捕获异常!我说“我必须通过Dynamics CRM插件代码(C#)异步调用Azure函数,这很好。但我不想让代码等待Azure函数的响应。我只想完成代码执行并退出”。也就是说,如果我根据提供的文档转换代码,代码执行仍然挂起并等待web API的响应(本例中为Azure函数)。我只是不想让代码等待这个响应。我想强制代码立即退出。我觉得你在问一个关于你没有发布的代码的问题。很难对我们看不到的代码提出建议。我被这个问题弄糊涂了。你说你知道如何使它异步,你的问题是“我如何使它异步?”你已经知道了。让它异步!如果您的问题是“我使其异步,但我不想同步等待结果,如何?”则删除同步等待。如果您的问题是“我使其异步,但我不想异步等待结果,如何?”则删除异步等待。在异步代码中,如果不进行等待,就不会发生等待。这就是“异步”的意思。但也就是说,删除异步等待是极其危险的。如果异步操作抛出?如果没有任何东西可以异步等待,那么就没有什么东西可以捕获异常!我说“我必须通过Dynamics CRM插件代码(C#)异步调用Azure函数,这很好。但我不想让代码等待Azure函数的响应。我只想完成代码执行并退出”。也就是说,如果我根据提供的文档转换代码,代码执行仍然挂起并等待web API的响应(本例中为Azure函数)。我只是不想让代码等待这个响应。我想强制代码立即退出。我觉得你在问一个关于你没有发布的代码的问题。很难对我们可以使用的代码提出建议
public class CallAzureFunc : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an entity type you are expecting.
if (entity.LogicalName != "account")
return;
// Obtain the organization service reference which you will need web service calls.
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
try
{
// Plug-in business logic goes here.
Data data = new Data
{
name = entity.Attributes["name"].ToString()
};
string result = CallFunction(tracer, data);
tracer.Trace($@"result: {result}");
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in MyPlug-in.", ex);
}
catch (Exception ex)
{
tracer.Trace("MyPlugin: {0}", ex.ToString());
throw;
}
}
}
private string CallFunction(ITracingService tracer, Data data)
{
string json = JsonConvert.SerializeObject(data);
string apiUrl = "https://<AzureFunctionName>.azurewebsites.net/api/";
string token = "<token>";
string content = null;
string apiMethod = "CreateContactFromLead";
string inputJson = json;
string result = ApiHelper.ExecuteApiRequest(apiUrl, token, content, apiMethod, inputJson, tracer);
return result;
}
}
internal static string ExecuteApiRequest(string apiUrl, string token, string content, string apiMethod, string inputJson, ITracingService tracer)
{
try
{
var data = Encoding.ASCII.GetBytes(inputJson);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Format(apiUrl + apiMethod));
request.Method = "POST";
request.ContentLength = inputJson.Length;
request.ContentType = "application/json";
request.ContentLength = data.Length;
request.Headers.Add("x-functions-key", token);
request.Accept = "application/json";
// Send the data
Stream newStream = request.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
// Get the resposne
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response != null)
{
tracer.Trace("ApiHelper > ExecuteApiRequest > response.StatusCode: " + response.StatusCode);
tracer.Trace("ApiHelper > ExecuteApiRequest > response.StatusDescription: " + response.StatusDescription);
}
if (response.StatusCode == HttpStatusCode.OK || response.StatusDescription == "OK" || response.StatusDescription == "200")
{
content = ReadStream(response, tracer);
}
else if (response.StatusCode == HttpStatusCode.NoContent || response.StatusDescription == "No Content" || response.StatusDescription == "204")
{
content = null;
}
else
{
if (response != null)
{
throw new Exception(String.Format("Status Code: {0}, Status Description: {1}",
response.StatusCode,
response.StatusDescription));
}
}
return content;
}
catch (Exception ex)
{
tracer.Trace("ApiHelper > ExecuteApiRequest > error: " + ex.Message);
throw;
}
}
private static string ReadStream(HttpWebResponse response, ITracingService tracer)
{
try
{
var responseJson = string.Empty;
if (response != null)
{
Stream dataStream = response.GetResponseStream();
if (dataStream != null)
{
using (StreamReader reader = new StreamReader(dataStream))
{
while (!reader.EndOfStream)
{
responseJson = reader.ReadToEnd();
}
}
}
}
return responseJson;
}
catch (Exception ex)
{
tracer.Trace("ApiHelper > ReadStream > error: " + ex.Message);
throw ex;
}
}
[FunctionName("ServiceBusQueueTriggerCSharp")]
public static void Run(
[ServiceBusTrigger("myqueue", AccessRights.Manage, Connection = "ServiceBusConnection")]
string myQueueItem,
Int32 deliveryCount,
DateTime enqueuedTimeUtc,
string messageId,
TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
log.Info($"EnqueuedTimeUtc={enqueuedTimeUtc}");
log.Info($"DeliveryCount={deliveryCount}");
log.Info($"MessageId={messageId}");
}