解决 C#包装程序Async方法未执行AX 2012方法,但同步正常

已加入
2020年12月19日
留言内容
12
编程经验
3-5
我正在尝试使用C#包装器异步调用AX 2012方法,但是AX 2012方法未执行。相同的数据已通过同步调用正确处理,并且正在正确执行。以下是C#中Controller的代码。为什么不执行异步方法?

我试图不加等待地称呼它。我尝试调试,但是由于线程不同,它可能无法工作。

同步部分工作正常,但是由于Flow的限制,调用此API的MS Flow超时。

您能告诉我如何使异步工作吗?


C#:
//It dynamically sets the AIF Url and calls the method to consume AIF services
using SXA_FlowIntegrationWebAPI.Helpers;
using SXA_FlowIntegrationWebAPI.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace SXA_FlowIntegrationWebAPI.Controllers
{
public class MainController : ApiController
{
    [ActionName("Method")]
    [HttpPost]
    [Authorize]
    public IHttpActionResult CallMethod(ClassMethodCallRequest request)
    {
        dynamic retValue;
        using (var client = new AX2012.SXAFlowIntegrationServiceClient())
        {
            try
            {
                var callContext = new AX2012.CallContext();
                callContext.Company = request.companyId;
                callContext.LogonAsUser = User.Identity.Name;

                client.InnerChannel.OperationTimeout = new TimeSpan(0, 10, 00);
                client.Endpoint.Address = new System.ServiceModel.EndpointAddress(request.aifURL);
                if (request.methodName == "async")
                {
                    retValue = "";
                    //client.callMethodAsync(callContext, request.className, request.methodName, request.dataJsonStr);
                    CallMethodAsyncCustom(client, callContext, request);
                }
                else
                {
                    retValue = client.callMethod(callContext, request.className, request.methodName, request.dataJsonStr);
                }
            }
            catch(Exception e)
            {
                return Json(new ClassMethodCallResponse
                {
                    status = "Error",
                    userName = User.Identity.Name,
                    className = request.className,
                    methodName = request.methodName,
                    aifURL = request.aifURL,
                    error = e
                });
            }
        }
        return Json(new ClassMethodCallResponse
        {
            status = "Success",
            userName = User.Identity.Name,
            className = request.className,
            methodName = request.methodName,
            aifURL = request.aifURL,
            data = retValue,
        });
    }

    public static async System.Threading.Tasks.Task<string> CallMethodAsyncCustom(AX2012.SXAFlowIntegrationServiceClient client, AX2012.CallContext callContext, ClassMethodCallRequest request)
    {
         await  System.Threading.Tasks.Task.Run(() => client.callMethodAsync(callContext, request.className, request.methodName, request.dataJsonStr));
         return "Completed";
    }
}
 
Solution
我通过使用client.Open()和client.close()解决了该错误,而不是在using关键字内部创建了client。我猜在异步调用返回之后,它试图访问已被处置的对象。

但是我的主要问题仍然没有解决。 JSON不会立即返回到Power Automate。它就像同步一样工作。然后我使用了一个task.run(()=>client.callAsync(....)),它也等待并且没有立即得到响应。但是,即使我的流量超时了。它执行了我所需的任务。但是这里的问题是它做了两次。

我的任务是在表格中插入行。它创建了两次标题。并在第一个标头中插入行,直到超时。然后再次插入创建第二个标题的行。在这一切中...

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,423
位置
弗吉尼亚州切萨皮克
编程经验
10+
交叉发布在StackOverflow中:

在CRM Dynamics站点中(顺便说一句,此问题是适当的位置,因为这似乎是一个需要有关CRM Dynamics API的特定知识的问题):
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,423
位置
弗吉尼亚州切萨皮克
编程经验
10+
并且您会告诉其他论坛,当一个解决方案出现时,已经找到了解决方案,这样其他人就可以避免浪费时间了吗?

Anyway, where is the documentation for AX2012.SXAFlowIntegrationServiceClient.callMethodAsync()? Does it truly call thing asynchronously as the name implies? My Google searches for it has only turned up your questions, but no documentation for it.

Anyway, if AX2012.SXAFlowIntegrationServiceClient.callMethodAsync() were truly following the modern naming convention where *Async() implies that it returns a Task, then the issue looks to be in these lines of code:
C#:
public static async System.Threading.Tasks.Task<string> CallMethodAsyncCustom(AX2012.SXAFlowIntegrationServiceClient client, AX2012.CallContext callContext, ClassMethodCallRequest request)
{
     await  System.Threading.Tasks.Task.Run(() => client.callMethodAsync(callContext, request.className, request.methodName, request.dataJsonStr));
     return "Completed";
}

This is because the await there is awaiting the lambda, but the lambda just goes and calls another asynchronous method without awaiting. You should just have written that method as:
C#:
public static async System.Threading.Tasks.Task<string> CallMethodAsyncCustom(AX2012.SXAFlowIntegrationServiceClient client, AX2012.CallContext callContext, ClassMethodCallRequest request)
{
     await  client.callMethodAsync(callContext, request.className, request.methodName, request.dataJsonStr);
     return "Completed";
}
 
已加入
2020年12月19日
留言内容
12
编程经验
3-5
你好
很抱歉在多个论坛中发帖。我向您保证,一旦获得解决方案,我将全部对其进行更新。

至于callMethodAsync文档,这是代码,
C#:
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
        SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodResponse SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationService.callMethod(SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest request) {
            return base.Channel.callMethod(request);
        }
        
        public string callMethod(SXA_FlowIntegrationWebAPI.AX2012.CallContext CallContext, string _className, string _methodName, string _data) {
            SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest inValue = new SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest();
            inValue.CallContext = CallContext;
            inValue._className = _className;
            inValue._methodName = _methodName;
            inValue._data = _data;
            SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodResponse retVal = ((SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationService)(this)).callMethod(inValue);
            return retVal.response;
        }
        
        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
        System.Threading.Tasks.Task<SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodResponse> SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationService.callMethodAsync(SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest request) {
            return base.Channel.callMethodAsync(request);
        }
        
        public System.Threading.Tasks.Task<SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodResponse> callMethodAsync(SXA_FlowIntegrationWebAPI.AX2012.CallContext CallContext, string _className, string _methodName, string _data) {
            SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest inValue = new SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest();
            inValue.CallContext = CallContext;
            inValue._className = _className;
            inValue._methodName = _methodName;
            inValue._data = _data;
            return ((SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationService)(this)).callMethodAsync(inValue);
        }


我尝试使用您建议的代码,但仍然无法正常工作。
 
已加入
2020年12月19日
留言内容
12
编程经验
3-5
我实际上不需要异步方法的回复。我已经解决了AX 2012方面的任何错误。但是主要问题是没有调用AX 2012方法。

另外,我想问一下,异步是在C#端执行的吗?还是我必须手动在AX 2012中编写异步代码?

这是接口代码:
C#:
public interface SXAFlowIntegrationService {
       
        // CODEGEN: Generating message contract since the wrapper name (SXAFlowIntegrationServiceCallMethodRequest) of message SXAFlowIntegrationServiceCallMethodRequest does not match the default value (callMethod)
        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/SXAFlowIntegrationService/callMethod",  回复 Action="http://tempuri.org/SXAFlowIntegrationService/callMethodResponse")]
        [System.ServiceModel.FaultContractAttribute(typeof(SXA_FlowIntegrationWebAPI.AX2012.AifFault), Action="http://tempuri.org/SXAFlowIntegrationService/callMethodAifFaultFault", Name="AifFault", Namespace="http://schemas.microsoft.com/dynamics/2008/01/documents/Fault")]
        SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodResponse callMethod(SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest request);
       
        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/SXAFlowIntegrationService/callMethod",  回复 Action="http://tempuri.org/SXAFlowIntegrationService/callMethodResponse")]
        System.Threading.Tasks.Task<SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodResponse> callMethodAsync(SXA_FlowIntegrationWebAPI.AX2012.SXAFlowIntegrationServiceCallMethodRequest request);
    }

我只有方法"callMethod"在Ax 2012中。是否可能正在搜索"callMethodAsync" in Ax 2012 ?

我假设它应该调用我的方法"callMethod"以异步方式而不是"callMethodAsync".

编辑:另外,上面的接口代码是自动生成的。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,423
位置
弗吉尼亚州切萨皮克
编程经验
10+
Even if you don't need the reply, you still need to await it. async/await does not magically create a thread to run code. Code needs to run on some thread, so by using await you are essentially yielding control of the current thread over to the code that is encapsulated by the Task.
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,423
位置
弗吉尼亚州切萨皮克
编程经验
10+
另外,我想问一下,异步是在C#端执行的吗?还是我必须手动在AX 2012中编写异步代码?
我不知道,也不在乎。最终由Microsoft收购的Great Plains使其成为CRM Dynamics间接地是第一次离开Microsoft的原因。说我怀恨在心是一种轻描淡写。

文档说什么?
 
Last edited:
已加入
2020年12月19日
留言内容
12
编程经验
3-5
我尝试调试它并从发出异步调用时得到了这些异常"CallMethodAsyncCustom"方法。我已经使该方法也返回类型void而不是字符串,因此我可以在没有任何警告的情况下从原始方法调用。

C#:
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in System.ServiceModel.Internals.dll
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in System.ServiceModel.Internals.dll
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in System.ServiceModel.Internals.dll
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in System.ServiceModel.Internals.dll
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in System.ServiceModel.Internals.dll
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in mscorlib.dll
A first chance exception of type 'System.ServiceModel.CommunicationObjectAbortedException' occurred in mscorlib.dll

您知道为什么会产生这些异常吗?
 
已加入
2020年12月19日
留言内容
12
编程经验
3-5
我通过使用client.Open()和client.close()解决了该错误,而不是在using关键字内部创建了client。我猜在异步调用返回之后,它试图访问已被处置的对象。

但是我的主要问题仍然没有解决。 JSON不会立即返回到Power Automate。它就像同步一样工作。然后我使用了一个task.run(()=>client.callAsync(....)),它也等待并且没有立即得到响应。但是,即使我的流量超时了。它执行了我所需的任务。但是这里的问题是它做了两次。

我的任务是在表格中插入行。它创建了两次标题。并在第一个标头中插入行,直到超时。然后再次插入创建第二个标题的行。在此,根据需要插入了所有行。

如何首先返回我的响应,然后开始执行此方法?为什么任务会运行两次,直到我的流程超时,然后再次正确创建所有行?
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,423
位置
弗吉尼亚州切萨皮克
编程经验
10+
但是我的主要问题仍然没有解决。

我不敢苟同。从帖子1:
我正在尝试使用C#包装器异步调用AX 2012方法,但是AX 2012方法未执行。

从帖子#13听起来您已经解决了问题,并且该方法正在执行。

如果您认为异步方法未异步执行,请打开一个新线程。
 
最佳 底部