我在运行连接到CRM的WCF服务时遇到问题:它经常产生CommunicationObjectAbortedExceptions,这让我想知道我是否做错了什么。许多人开始使用它们之后开始发生这些行为,在测试系统上它没有问题。
但是,让我们从头开始:我编写了两个WCF服务,使用我自己的库连接到Microsoft CRM2013组织服务,以在CRM上执行查询。这些服务定期从CRM中调用,每天大约有100-200人使用。
这个工作基本上没问题,但我经常得到一些例外情况,如下所示(请参阅完整堆栈跟踪的帖子底部):
System.ServiceModel.CommunicationObjectAbortedException:中止对'
http://crm/MyOrganization/XRMServices/2011/Organization.svc
'的HTTP请求。这可能是由于当请求仍在进行时本地通道被关闭。如果不需要此行为,则更新代码,以便在请求操作仍在进行时不会关闭通道。
通常我的意思是每天大约100次,大多数情况下,每隔5-30分钟会抛出几个异常,分批的3-6个例外。我不知道为什么会这样。我在两个服务中使用我的库中的以下类初始化与CRM组织服务的连接:
public class CrmManager : IDisposable
{
private static CrmConnection s_connection;
public static CrmConnection Connection
{
get
{
if (s_connection == null)
{
s_connection = new CrmConnection("CrmTvTest");
}
return s_connection;
}
}
public static IOrganizationService ServiceProxy
{
get { return s_serviceProxy ?? (s_serviceProxy = new CachedOrganizationService(Connection)); }
}
可以看出,我每个WCF服务连接一次组织服务,使用CrmConnection
来处理连接细节,这些细节存储在静态变量中(作为单例,因为建立连接是昂贵的,不应该这样做经常对我的理解)。然后传递给CachedOrganizationService
,由于同样的原因,它是静态的。 WCF服务使用默认实例管理(PerSession
AFAIK),这意味着每个用户可能有1个连接和组织服务。
我的连接字符串看起来像这样(当然删除了任何合理的数据):
<connectionStrings>
<add name="CrmTvTest" connectionString="Url=http://crm/MyOrganization; Username=user; Password=pw;"/>
然后,我使用与CrmServiceContext
对象的连接,从我的CrmManager类使用此方法执行查询。当然,这总是在using语句中调用:
using (CrmServiceContext context = new CrmServiceContext(CrmManager.ServiceProxy))
{
// do some stuff...
}
如何防止这些异常不断发生?我觉得这与CRM连接使用的安全令牌有关,但是当我使用CrmConnection
类时,这应该不是问题。它应该自动刷新它们。
任何建议都会非常受欢迎,因为我现在正在思考这个问题。
更新1
我转而使用Developer Extensions并使用CrmConnector类,但没有用(我更新了上面的代码)。我也尝试将CrmConnection
类直接传递给CrmServiceContext:
using (CrmServiceContext context = new CrmServiceContext(CrmManager.Connection))
这导致了与in this Stackoverflow Question相同的问题,没有使用负载均衡器(我们最初做过,但禁用负载平衡以消除它导致问题的可能性。
完整Stacktrace:
---> System.Net.WebException:请求已中止:请求已取消。 System.Service.Net.HttpWebRequest.GetResponse()at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)---内部异常堆栈跟踪结束---
服务器堆栈跟踪:位于System.ServiceModel.Channels的System.ServiceModel.Channels.HttpChannelFactory
1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) at System.ServiceModel.Channels.SecurityChannelFactory
1.SecurityRequestChannel.Request(消息消息,TimeSpan超时)的System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException,HttpWebRequest请求,HttpAbortReason abortReason)。 System.ServiceModel.Channels上的System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall,ProxyOperationRuntime操作)中的ServiceChannel.Call(String action,Boolean oneway,ProxyOperationRuntime operation,Object [] ins,Object [] outs,TimeSpan timeout)。 ServiceChannelProxy.Invoke(IMessage消息)在[0]处重新抛出异常:位于Microsoft.Xrm的System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&msgData,Int32类型)的System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)。位于Microsoft.Xrm.Sdk.Linq的Microsoft.Xrm.Sdk.Client.OrganizationServiceContext.Execute(OrganizationRequest请求)的Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.ExecuteCore(OrganizationRequest请求)中的Sdk.IOrganizationService.Execute(OrganizationRequest请求)。 Microsoft.Xrm.Sdk.Linq上的Microsoft.Xrm.Sdk.Linq.QueryProvider.Execute(QueryExpression qe,Boolean throwIfSequenceIsEmpty,Boolean throwIfSequenceNotSingle,Projection projection,NavigationSource source,List
1 linkLookups, String& pagingCookie, Boolean& moreRecords) at Microsoft.Xrm.Sdk.Linq.QueryProvider.Execute[TElement](QueryExpression qe, Boolean throwIfSequenceIsEmpty, Boolean throwIfSequenceNotSingle, Projection projection, NavigationSource source, List
1 linkLookups)中的QueryProvider.RetrieveEntityCollection(OrganizationRequest请求,NavigationSource源)。 Microsoft.Xrm.Sdk.Linq.QueryProvider.System.Linq.IQueryProvider.Execute [TResult](表达式表达式)中的QueryProvider.Execute [TElement](表达式表达式) at System.Linq.Queryable.SingleOrDefault [TSource](IQueryable`1 source)at crmConnector.Entities.Contact.Get(Guid p_id,Boolean p_includeRelatedEntities)in j:\ IntDev \ Libraries \ CrmConnector \ Entities \ Contact.cs:line 63 at CrmExtensionService.CrmExtension.GetPersonalizedEmailSignature(String p_contactId,String p_systemUserId)in j:\ IntDev \ Services \ CrmExtensionService \ CrmExtension.svc.cs:line 460
我们有同样的问题,负载均衡器是罪魁祸首。现在我们通过在负载均衡器中进行少量配置来激活负载均衡器来解决此错误。我们在负载均衡器上启用了具有最少连接算法的粘性会话。因此,如果在负载平衡时未启用此功能,则来自一个服务器的请求的经过身份验证的连接将被路由到不同的服务器,即使相同的会话也会失败。一旦启用粘性会话(会话持久性为客户端IP)请求转到同一服务器(在这种情况下返回连接而不是新连接)它运行良好。
因此,在摆弄了大约两个月后,我们发现了问题:CRM FrontEnd的负载平衡是罪魁祸首。我认为这也被禁用,禁用了我们的CRM服务的负载平衡,但事实并非如此。我们的CRM服务定期与服务器1的组织服务建立连接,然后在操作中间切换到服务器2并发生这些异常。
我们仍然试图弄清楚如何在激活负载平衡的情况下使其工作,但暂时我们将其禁用以防止这些错误弹出。
StackOverflow上有一个类似的例子:Sporadic exceptions calling a web service that is load balanced。我们目前正在使用webHttpBinding并且很快就尝试切换到basicHttpBinding但是没有让它工作(但正如我所说,这只是一个快速的尝试)。