In lokalen Exchange-Umgebungen muss Ihr Add-In die folgenden Schritte ausführen, um Anlagen direkt aus Exchange abzurufen.
Rufen Sie das Rückruftoken vom Exchange-Server ab.
Senden Sie Rückruftoken und Anlageninformationen an den Remotedienst.
Rufen Sie die Anlagen mithilfe der ExchangeService.GetAttachments
-Methode oder des GetAttachment
-Vorgangs vom Exchange-Server ab.
Jeder Schritt wird in den folgenden Abschnitten mithilfe von Code aus dem Beispiel Outlook-Add-in-JavaScript-GetAttachments ausführlich behandelt.
Hinweis
Der Code in diesen Beispielen wurde gekürzt, um die Anlageninformationen hervorzuheben. Das Beispiel enthält zusätzlichen Code zum Authentifizieren des Outlook-Add-Ins beim Remoteserver sowie zum Verwalten des Anforderungszustands.
Abrufen eines Rückruftokens
Das Office.context.mailbox-Objekt stellt die getCallbackTokenAsync
-Methode zum Abrufen eines Tokens bereit, das der Remoteserver für die Authentifizierung beim Exchange-Server verwenden kann. Der folgende Code zeigt eine Funktion in einem Add-In, das die asynchrone Anforderung zum Abrufen des Rückruftokens startet, sowie die Rückruffunktion, die die Antwort abruft. Das Rückruftoken wird im Dienstanforderungsobjekt gespeichert, das im nächsten Abschnitt definiert wird.
function getAttachmentToken() {
if (serviceRequest.attachmentToken == "") {
Office.context.mailbox.getCallbackTokenAsync(attachmentTokenCallback);
}
}
function attachmentTokenCallback(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
// Cache the result from the server.
serviceRequest.attachmentToken = asyncResult.value;
serviceRequest.state = 3;
testAttachments();
} else {
showToast("Error", "Couldn't get callback token: " + asyncResult.error.message);
}
}
Die genaue Vorgehensweise zum Senden von Informationen an den Remotedienst ist abhängig davon, welcher Dienst von Ihrem Outlook-Add-In aufgerufen wird. In diesem Beispiel ist der Remotedienst eine Web-API-Anwendung, die mit Visual Studio erstellt wurde. Die Anlageninformationen werden vom Remotedienst in einem JSON-Objekt erwartet.
Die Office.context.mailbox.ewsUrl-Eigenschaft wird verwendet, um die URL der Exchange-Webdienste (EWS) auf dem Exchange-Server bereitzustellen, auf dem das Postfach gehostet wird. Diese URL wird dann vom Remotedienst verwendet, um in einem späteren Schritt die ExchangeService.GetAttachments-Methode oder den EWS-Vorgang GetAttachment aufzurufen.
Der folgende Code dient zum Initialisieren eines Objekts mit den Anlageninformationen:
// Initialize a context object for the add-in.
// Set the fields that are used on the request
// object to default values.
const serviceRequest = {
attachmentToken: '',
ewsUrl: Office.context.mailbox.ewsUrl,
attachments: []
};
Die Office.context.mailbox.item.attachments
-Eigenschaft enthält eine Sammlung von AttachmentDetails
-Objekten, und zwar eines für jede Anlage für das Element. In den meisten Fällen kann das Add-In die Anlagen-ID-Eigenschaft eines AttachmentDetails
-Objekts an den Remotedienst übergeben. Wenn der Remotedienst weitere Details zu der Anlage benötigt, können Sie das gesamte AttachmentDetails
-Objekt oder einen Teil davon übergeben. Der folgende Code definiert eine Methode, die das gesamte AttachmentDetails
-Array im serviceRequest
-Objekt platziert und eine Anforderung an den Remotedienst sendet.
function makeServiceRequest() {
// Format the attachment details for sending.
for (let i = 0; i < mailbox.item.attachments.length; i++) {
serviceRequest.attachments[i] = JSON.parse(JSON.stringify(mailbox.item.attachments[i]));
}
$.ajax({
url: '../../api/Default',
type: 'POST',
data: JSON.stringify(serviceRequest),
contentType: 'application/json;charset=utf-8'
}).done(function (response) {
if (!response.isError) {
const names = "<h2>Attachments processed using " +
serviceRequest.service +
": " +
response.attachmentsProcessed +
"</h2>";
for (let i = 0; i < response.attachmentNames.length; i++) {
names += response.attachmentNames[i] + "<br />";
}
document.getElementById("names").innerHTML = names;
} else {
app.showNotification("Runtime error", response.message);
}
}).fail(function (status) {
}).always(function () {
$('.disable-while-sending').prop('disabled', false);
})
}
Abrufen der Anlagen vom Exchange-Server
Ihr Remotedienst kann entweder die verwaltete EWS API-Methode GetAttachments oder den EWS-Vorgang GetAttachment verwenden, um Anlagen vom Server abzurufen. Die Dienstanwendung benötigt zwei Objekte um die JSON-Zeichenfolge in .NET Framework-Objekte zu deserialisieren, die auf dem Server verwendet werden können. Der folgende Code zeigt die Definitionen der Deserialisierungsobjekte:
namespace AttachmentsSample
{
public class AttachmentSampleServiceRequest
{
public string attachmentToken { get; set; }
public string ewsUrl { get; set; }
public string service { get; set; }
public AttachmentDetails [] attachments { get; set; }
}
public class AttachmentDetails
{
public string attachmentType { get; set; }
public string contentType { get; set; }
public string id { get; set; }
public bool isInline { get; set; }
public string name { get; set; }
public int size { get; set; }
}
}
Verwenden der verwalteten EWS-API zum Abrufen der Anlagen
Wenn Sie die verwaltete EWS-API im Remotedienst einsetzen, können Sie die GetAttachments-Methode verwenden, die eine EWS-SOAP-Anforderung erstellt, sendet und empfängt, um die Anlagen abzurufen. Microsoft empfiehlt die verwaltete EWS-API, da sie weniger Codezeilen erfordert und eine intuitivere Benutzeroberfläche für EWS-Anrufe bereitstellt. Der folgende Code sendet eine Anforderung, um alle Anlagen abzurufen, und gibt die Anzahl und die Namen der verarbeiteten Anlagen zurück.
private AttachmentSampleServiceResponse GetAtttachmentsFromExchangeServerUsingEWSManagedApi(AttachmentSampleServiceRequest request)
{
var attachmentsProcessedCount = 0;
var attachmentNames = new List<string>();
// Create an ExchangeService object, set the credentials and the EWS URL.
ExchangeService service = new ExchangeService();
service.Credentials = new OAuthCredentials(request.attachmentToken);
service.Url = new Uri(request.ewsUrl);
var attachmentIds = new List<string>();
foreach (AttachmentDetails attachment in request.attachments)
{
attachmentIds.Add(attachment.id);
}
// Call the GetAttachments method to retrieve the attachments on the message.
// This method results in a GetAttachments EWS SOAP request and response
// from the Exchange server.
var getAttachmentsResponse =
service.GetAttachments(attachmentIds.ToArray(),
null,
new PropertySet(BasePropertySet.FirstClassProperties,
ItemSchema.MimeContent));
if (getAttachmentsResponse.OverallResult == ServiceResult.Success)
{
foreach (var attachmentResponse in getAttachmentsResponse)
{
attachmentNames.Add(attachmentResponse.Attachment.Name);
// Write the content of each attachment to a stream.
if (attachmentResponse.Attachment is FileAttachment)
{
FileAttachment fileAttachment = attachmentResponse.Attachment as FileAttachment;
Stream s = new MemoryStream(fileAttachment.Content);
// Process the contents of the attachment here.
}
if (attachmentResponse.Attachment is ItemAttachment)
{
ItemAttachment itemAttachment = attachmentResponse.Attachment as ItemAttachment;
Stream s = new MemoryStream(itemAttachment.Item.MimeContent.Content);
// Process the contents of the attachment here.
}
attachmentsProcessedCount++;
}
}
// Return the names and number of attachments processed for display
// in the add-in UI.
var response = new AttachmentSampleServiceResponse();
response.attachmentNames = attachmentNames.ToArray();
response.attachmentsProcessed = attachmentsProcessedCount;
return response;
}
Verwenden von EWS zum Abrufen von Anlagen
Wenn Sie EWS in Ihrem Remotedienst verwenden, müssen Sie eine GetAttachment-SOAP-Anforderung erstellen, um Anlagen vom Exchange-Server abzurufen. Der folgende Code gibt eine Zeichenfolge zurück, die die SOAP-Anforderung enthält. Der Remotedienst verwendet die String.Format
-Methode, um die Anlage-ID für eine Anlage in die Zeichenfolge einzufügen.
private const string GetAttachmentSoapRequest =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""https://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""https://www.w3.org/2001/XMLSchema""
xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"">
<soap:Header>
<t:RequestServerVersion Version=""Exchange2016"" />
</soap:Header>
<soap:Body>
<GetAttachment xmlns=""http://schemas.microsoft.com/exchange/services/2006/messages""
xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"">
<AttachmentShape/>
<AttachmentIds>
<t:AttachmentId Id=""{0}""/>
</AttachmentIds>
</GetAttachment>
</soap:Body>
</soap:Envelope>";
Schließlich verwendet die folgende Methode eine EWS-GetAttachment
-Anforderung, um die Anlagen vom Exchange-Server abzurufen. Diese Implementierung führt eine separate Anforderung für jede Anlage aus und gibt die Anzahl verarbeiteter Anlagen zurück. Jede Antwort wird in einer separaten ProcessXmlResponse
-Methode verarbeitet, die als Nächstes definiert wird.
private AttachmentSampleServiceResponse GetAttachmentsFromExchangeServerUsingEWS(AttachmentSampleServiceRequest request)
{
var attachmentsProcessedCount = 0;
var attachmentNames = new List<string>();
foreach (var attachment in request.attachments)
{
// Prepare a web request object.
HttpWebRequest webRequest = WebRequest.CreateHttp(request.ewsUrl);
webRequest.Headers.Add("Authorization",
string.Format("Bearer {0}", request.attachmentToken));
webRequest.PreAuthenticate = true;
webRequest.AllowAutoRedirect = false;
webRequest.Method = "POST";
webRequest.ContentType = "text/xml; charset=utf-8";
// Construct the SOAP message for the GetAttachment operation.
byte[] bodyBytes = Encoding.UTF8.GetBytes(
string.Format(GetAttachmentSoapRequest, attachment.id));
webRequest.ContentLength = bodyBytes.Length;
Stream requestStream = webRequest.GetRequestStream();
requestStream.Write(bodyBytes, 0, bodyBytes.Length);
requestStream.Close();
// Make the request to the Exchange server and get the response.
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
// If the response is okay, create an XML document from the response
// and process the request.
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var responseStream = webResponse.GetResponseStream();
var responseEnvelope = XElement.Load(responseStream);
// After creating a memory stream containing the contents of the
// attachment, this method writes the XML document to the trace output.
// Your service would perform it's processing here.
if (responseEnvelope != null)
{
var processResult = ProcessXmlResponse(responseEnvelope);
attachmentNames.Add(string.Format("{0} {1}", attachment.name, processResult));
}
// Close the response stream.
responseStream.Close();
webResponse.Close();
}
// If the response is not OK, return an error message for the
// attachment.
else
{
var errorString = string.Format("Attachment \"{0}\" could not be processed. " +
"Error message: {1}.", attachment.name, webResponse.StatusDescription);
attachmentNames.Add(errorString);
}
attachmentsProcessedCount++;
}
// Return the names and number of attachments processed for display
// in the add-in UI.
var response = new AttachmentSampleServiceResponse();
response.attachmentNames = attachmentNames.ToArray();
response.attachmentsProcessed = attachmentsProcessedCount;
return response;
}
Jede Antwort vom GetAttachment
-Vorgang wird an die ProcessXmlResponse
-Methode gesendet. Diese Methode überprüft die Antwort auf Fehler. Wenn keine Fehler gefunden werden, werden die Dateianlagen und Elementanhänge verarbeitet. Die ProcessXmlResponse
-Methode führt den größten Teil der Arbeit zum Verarbeiten der Anlage aus.
// This method processes the response from the Exchange server.
// In your application the bulk of the processing occurs here.
private string ProcessXmlResponse(XElement responseEnvelope)
{
// First, check the response for web service errors.
var errorCodes = from errorCode in responseEnvelope.Descendants
("{http://schemas.microsoft.com/exchange/services/2006/messages}ResponseCode")
select errorCode;
// Return the first error code found.
foreach (var errorCode in errorCodes)
{
if (errorCode.Value != "NoError")
{
return string.Format("Could not process result. Error: {0}", errorCode.Value);
}
}
// No errors found, proceed with processing the content.
// First, get and process file attachments.
var fileAttachments = from fileAttachment in responseEnvelope.Descendants
("{http://schemas.microsoft.com/exchange/services/2006/types}FileAttachment")
select fileAttachment;
foreach(var fileAttachment in fileAttachments)
{
var fileContent = fileAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Content");
var fileData = System.Convert.FromBase64String(fileContent.Value);
var s = new MemoryStream(fileData);
// Process the file attachment here.
}
// Second, get and process item attachments.
var itemAttachments = from itemAttachment in responseEnvelope.Descendants
("{http://schemas.microsoft.com/exchange/services/2006/types}ItemAttachment")
select itemAttachment;
foreach(var itemAttachment in itemAttachments)
{
var message = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Message");
if (message != null)
{
// Process a message here.
break;
}
var calendarItem = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}CalendarItem");
if (calendarItem != null)
{
// Process calendar item here.
break;
}
var contact = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Contact");
if (contact != null)
{
// Process contact here.
break;
}
var task = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Tontact");
if (task != null)
{
// Process task here.
break;
}
var meetingMessage = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingMessage");
if (meetingMessage != null)
{
// Process meeting message here.
break;
}
var meetingRequest = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingRequest");
if (meetingRequest != null)
{
// Process meeting request here.
break;
}
var meetingResponse = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingResponse");
if (meetingResponse != null)
{
// Process meeting response here.
break;
}
var meetingCancellation = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingCancellation");
if (meetingCancellation != null)
{
// Process meeting cancellation here.
break;
}
}
return string.Empty;
}