来自 Exchange Web 服务的响应是无效的 XML

问题描述 投票:0回答:1

我使用下面的代码对 Exchange-365 服务器进行身份验证并发送电子邮件,但我得到的结果是“从服务收到的响应不包含有效的 XML”。

代码是根据此处的代码示例获取的:https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application -通过使用-oauth

这里:https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-send-email-messages-by-using-ews-in-exchange #使用-ews-托管-api发送新电子邮件消息

我的 Entra 应用程序设置正确。

using System.Diagnostics;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Identity.Client;
using Task = System.Threading.Tasks.Task;

namespace My.Sandbox.CoreConsoleApp;

internal class Program
{
    // ReSharper disable once IdentifierTypo
    private const string MyEntraAppClientId = "client-id";

    // ReSharper disable once IdentifierTypo
    private const string MyEntraAppTenantId = "tenant-id";
    private const string MyClientSecretValue = "client-secret-value";

    // ReSharper disable once IdentifierTypo
    private const string MyEntraAppRedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient";
    private const string Outlook365EndpointUrl = "https://outlook.office365.com/EWS/Exchange.asmx";

    /// <summary>
    ///     Specifies the primary mailbox against which operations should be performed. Useful in scenarios involving
    ///     multiple mailboxes or delegate access. Ensures accurate handling of tasks by directing requests
    ///     to the intended mailbox, facilitating secure and contextually relevant operations within Exchange environments.
    /// </summary>
    // ReSharper disable once InconsistentNaming
    // ReSharper disable once IdentifierTypo
    private const string Headers_XAnchormailbox = "X-AnchorMailbox";

    private static void Main(string[] args)
    {
        Task.Run(() => ConnectUsingAppOnlyAuthentication("[email protected]")).Wait();
    }

    private static async Task ConnectUsingAppOnlyAuthentication(string accountAddress)
    {
        try
        {
            var authResult = GetToken();

            // Configure the ExchangeService with the access token
            var ewsClient = new ExchangeService
            {
                Url = new Uri(MyEntraAppRedirectUri),
                Credentials = new OAuthCredentials(authResult.AccessToken),
                ImpersonatedUserId =
                    new ImpersonatedUserId(ConnectingIdType.SmtpAddress, accountAddress)
            };

            // ReSharper disable once CommentTypo
            //Include x-anchormailbox header
            ewsClient.HttpHeaders.Add(Headers_XAnchormailbox, accountAddress);

            var email = new EmailMessage(ewsClient);
            email.ToRecipients.Add("[email protected]");
            email.Subject = "HelloWorld";
            email.Body = new MessageBody("This is the first email I've sent by using the EWS Managed API.");
            await email.SendAndSaveCopy();
        }
        catch (MsalException ex)
        {
            Console.WriteLine($@"Error acquiring access token: {ex}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($@"Error: {ex}");
        }

        if (Debugger.IsAttached)
        {
            Console.WriteLine(@"Hit any key to exit...");
            Console.ReadKey();
        }
    }

    private static AuthenticationResult GetToken()
    {
        // Using Microsoft.Identity.Client 4.22.0
        var applicationBuilder = ConfidentialClientApplicationBuilder
            .Create(MyEntraAppClientId)
            .WithClientSecret(MyClientSecretValue)
            .WithTenantId(MyEntraAppTenantId)
            .Build();

        // The permission scope required for EWS access
        var ewsScopes = new string[] { Scope.Outlook365_Default.Value };

        // Make the token request
        return applicationBuilder.AcquireTokenForClient(ewsScopes).ExecuteAsync().Result;
    }

    /// <summary>
    ///     Represents an OAuth scope, which determines the resources and application can access
    ///     and the actions it can perform.
    /// </summary>
    [DebuggerDisplay("{Value}")]
    internal class Scope
    {
        #region constructors

        private Scope(string value)
        {
            Value = value;
        }

        #endregion

        #region properties

        public string Value { get; }

        #endregion

        #region static members

        // ReSharper disable once InconsistentNaming
        public static readonly Scope Outlook365_Ews_AccessAsUser_All =
            new("https://outlook.office365.com/EWS.AccessAsUser.All");

        /// <summary>
        ///     The default scope for Exchange Online ("https://outlook.office365.com/.default")
        /// </summary>
        public static readonly Scope Outlook365_Default =
            new("https://outlook.office365.com/.default");

        #endregion
    }
}

我遇到的例外是:

Microsoft.Exchange.WebServices.Data.ServiceRequestException: The response received from the service didn't contain valid XML. ---> System.Xml.XmlException: Root element is missing.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlAsyncCheckReader.Read()
   at System.Xml.XmlCharCheckingReader.Read()
   at Microsoft.Exchange.WebServices.Data.EwsXmlReader.Read()
   at Microsoft.Exchange.WebServices.Data.EwsXmlReader.Read(XmlNodeType nodeType)
   at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadXmlDeclaration(EwsServiceXmlReader reader)
   --- End of inner exception stack trace ---
   at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadXmlDeclaration(EwsServiceXmlReader reader)
   at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadPreamble(EwsServiceXmlReader ewsXmlReader)
   at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadResponse(EwsServiceXmlReader ewsXmlReader, WebHeaderCollection responseHeaders)
   at Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.ReadResponseXml(Stream responseStream, WebHeaderCollection responseHeaders)
   at Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.ReadResponse(IEwsHttpWebResponse response)
   at Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.<InternalExecuteAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.<ExecuteAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.Exchange.WebServices.Data.Item.<InternalCreate>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.Exchange.WebServices.Data.EmailMessage.<InternalSend>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
c# web-services exchangewebservices microsoft365
1个回答
0
投票
            var ewsClient = new ExchangeService
        {
            Url = new Uri(MyEntraAppRedirectUri),
            Credentials = new OAuthCredentials(authResult.AccessToken),
            ImpersonatedUserId =
                new ImpersonatedUserId(ConnectingIdType.SmtpAddress, accountAddress)
        };

不正确,您在 ExchangeService 构造函数中使用了不正确的 URL,我认为您打算使用

URL = new Uri(Outlook365EndpointUrl),

因为您使用了 MyEntraAppRedirectUri,所以您对该端点的任何 SOAP 请求返回的响应都将是 HTML 错误。

© www.soinside.com 2019 - 2024. All rights reserved.