使用OAuth创建具有关联性的流式订阅时,EWS托管api收到500个内部服务器错误

使用OAuth创建具有关联性的流式订阅时,EWS托管api收到500个内部服务器错误,oauth,streaming,exchangewebservices,subscription,affinity,Oauth,Streaming,Exchangewebservices,Subscription,Affinity,我有一个应用程序,它通过托管API使用EWS流式订阅(由于NuGet版本已过时,因此从GitHub上的最新源代码构建),并一直在对其进行增强,以使用相同的GroupingInformation和ExternalNewsUrl用户设置对邮箱进行分组订阅,以减少连接数,如中所述 我还介绍了Exchange Online的现代身份验证: 我只在一个相对较小的Azure租户上测试了这些更改。当我尝试在组上创建后续订阅时,它与基本身份验证完美配合,但与OAuth身份验证一起,它总是失败,出现HTTP错误5

我有一个应用程序,它通过托管API使用EWS流式订阅(由于NuGet版本已过时,因此从GitHub上的最新源代码构建),并一直在对其进行增强,以使用相同的GroupingInformation和ExternalNewsUrl用户设置对邮箱进行分组订阅,以减少连接数,如中所述

我还介绍了Exchange Online的现代身份验证:

我只在一个相对较小的Azure租户上测试了这些更改。当我尝试在组上创建后续订阅时,它与基本身份验证完美配合,但与OAuth身份验证一起,它总是失败,出现HTTP错误500。EWS错误消息为“请求失败,因为EWS无法为此请求联系相应的CAS服务器”

当使用OAuth时,我为锚邮箱上的第一个订阅的请求和响应,然后为第二个订阅的请求和失败响应,包括XML跟踪的一个摘录。发出这些请求时,两个邮箱的GroupingInformation值为“VE1PR03”

OAuth的使用对请求路由的影响并不明显

POST/EWS/Exchange.asmx HTTP/1.1
内容类型:text/xml;字符集=utf-8
接受:text/xml
用户代理:MyApp/2.2.0.20149(ExchangeServicesClient/2.2.1.0)
接受编码:gzip,deflate
X-AnchorMailbox:user1@xyz.onmicrosoft.com
X-PreferServerAffinity:true
授权:持证人ey。。
user1@xyz.onmicrosoft.com
user1@xyz.onmicrosoft.com
NewMailEvent
HTTP/1.1200ok
传输编码:分块
内容编码:gzip
改变:接受编码
X-CalculatedFETarget:VI1P194CU002.internal.outlook.com
X-BackEndHttpStatus:200200
缓存控制:专用
内容类型:text/xml;字符集=utf-8
设置Cookie:exchangecookie=5bf5f04d41dd4205b2fd96f211c5b2b4;expires=周四,2021年6月17日14:06:18格林威治标准时间;路径=/;保护HttpOnly
设置Cookie:X-BackEndOverrideCookie=VE1PR03MB5854.eurprd03.prod.outlook.com~1943309328;路径=/;保护HttpOnly
服务器:Microsoft IIS/10.0
X-FEProxyInfo:VI1P194CA0032.EURP194.PROD.OUTLOOK.COM
X计算的目标:VE1PR03MB5854.eurprd03.prod.outlook.com
X-RUM-Validated:1
x-ms-appId:f456225c-aef6-41fc-bbd5-8a5c9c9287d6
X-FromBackend-ServerAffinity:True
x-EWSHADLER:订阅
X-AspNet-Version:4.0.30319
X-BeSku:WCS5
X-DiagInfo:VE1PR03MB5854
X-BEServer:VE1PR03MB5854
X-代理路由正确性:1
X-Proxy-BackendServerStatus:200
X-FEServer:VI1P194CA0032,LO2P265CA0158
X-Powered-By:ASP.NET
日期:2020年6月17日星期三14:06:18 GMT
无误
JWB2ZTFWCJAZBWI1DU0LMV1CNBYZDAZLNBYB2QUB3V0BG9VAY5JB20QAAADJEVXSPM2ESK94+CICSMEP28L5VHETGIEAAAONZLUKW2B5kMN/hjFV/so0=
POST/EWS/Exchange.asmx HTTP/1.1
内容类型:text/xml;字符集=utf-8
接受:text/xml
用户代理:MyApp/2.2.0.20149(ExchangeServicesClient/2.2.1.0)
接受编码:gzip,deflate
X-AnchorMailbox:user1@xyz.onmicrosoft.com
X-PreferServerAffinity:true
Cookie:X-BackEndOverrideCookie=VE1PR03MB5854.eurprd03.prod.outlook.com~1943309328
授权:持证人ey。。
user2@xyz.onmicrosoft.com
user2@xyz.onmicrosoft.com
NewMailEvent
HTTP/1.1500内部服务器错误
X-CalculatedFETarget:VI1P194CU002.internal.outlook.com
X-BackEndHttpStatus:500500
X-FEProxyInfo:VI1P194CA0034.EURP194.PROD.OUTLOOK.COM
X计算的目标:VE1PR03MB5854.eurprd03.prod.outlook.com
X-RUM-Validated:1
x-ms-appId:f456225c-aef6-41fc-bbd5-8a5c9c9287d6
X-BeSku:WCS5
X-DiagInfo:VE1PR03MB5854
X-BEServer:VE1PR03MB5854
X-代理路由正确性:1
X-Proxy-BackendServerStatus:500
X-FEServer:VI1P194CA0034,LO2P265CA0158
内容长度:839
缓存控制:专用
内容类型:text/xml;字符集=utf-8
日期:2020年6月17日星期三14:06:18 GMT
设置Cookie:exchangecookie=39b2d19d8e9740128573cb1af6358c33;expires=周四,2021年6月17日14:06:18格林威治标准时间;路径=/;保护HttpOnly
服务器:Microsoft IIS/10.0
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
*
a:ErrorInvalidRequest
请求失败,因为EWS无法为此请求联系相应的CAS服务器。
错误无效请求
请求失败,因为EWS无法为此请求联系相应的CAS服务器。

经过进一步调查,我解决了这个问题,只需为组中的每个订阅使用相同的
ExchangeService
对象(我已经为每个订阅创建了一个新的
ExchangeService
)。该分组现在可用于OAuth和基本身份验证。关于维护亲和性的文章确实说了“在剩下的过程中创建并使用一个ExchangeService对象”,我应该更确切地理解这一点

在创建每个订阅(包括第一个订阅)之前,当然需要将
ExchangeService.ImpersonatedUserId
设置为相关邮箱用户的SMTP地址,在创建第一个订阅之后,将第一个订阅响应中的
X-BackendOverrideCookie
cookie值分配添加到
HttpHeaders


我希望这对处理流媒体订阅的其他人有用。

要将
X-BackEndOverrideCookie
传递给后续请求,请执行以下操作之一:

  • 对同一分组中的每个订阅使用相同的
    ExchangeService
    。这将自动处理
    X-BackEndOverrideCookie
  • 使用新的
    ExchangeService
    ,但手动复制
    X-BackEndOve
    
    string backEndOverrideCookie =
        service1.CookieContainer.GetCookies(service1.Url)["X-BackEndOverrideCookie"]?.Value;
    ...
    if (!string.IsNullOrWhiteSpace(backEndOverrideCookie))
        service2.CookieContainer.SetCookies(service2.Url, "X-BackEndOverrideCookie=" + backEndOverrideCookie);
    
    var cookieContainer = service.CookieContainer;
    service.Credentials = new OAuthCredentials(authenticationResult.AccessToken);
    service.CookieContainer = cookieContainer;