Jan 13 2022 11:27 PM
As mentioned in the title, when I send a shared calendar invitation using the Exchange Managed API, I get the error "Value cannot be null. Parameter name: frontEndLocator".
Below is the full source code I used.
private static void EwsCalendarApi2()
{
string senderUserId = "Email address removed";
string senderUserPassword = "sharingUserPassword";
string sharedToUser = "Email address removed";
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Url = new Uri("https://mail.domain.com/EWS/Exchange.asmx");
service.UseDefaultCredentials = false;
var cred = new System.Net.NetworkCredential(senderUserId, senderUserPassword);
service.Credentials = cred;
Guid binSharingProviderGuid = new Guid("{AEF00600-0000-0000-C000-000000000046}");
byte[] byteSharingProviderGuid = binSharingProviderGuid.ToByteArray();
string sharedUserDn = GetMailboxDN(senderUserId, cred);
byte[] binInitiatorEntryId = HexStringToByteArray(GetIntiatorEntryID(sharedUserDn));
EmailMessage invitationRequest = new EmailMessage(service);
invitationRequest.Subject = "I'd like to share my calendar with you";
invitationRequest.Body = "Sent by Exchange Administrator on behalf of user";
invitationRequest.Sensitivity = Sensitivity.Normal;
invitationRequest.ItemClass = "IPM.Sharing"; /* Constant Required Value [MS-ProtocolSpec] */
invitationRequest.SetExtendedProperty(PidTagMessageClass, "IPM.Sharing");
invitationRequest.SetExtendedProperty(PidNameContentClass, "Sharing");
//PidTagNormalizedSubject
//PidTagSubjectPrefix
invitationRequest.SetExtendedProperty(PidLidSharingProviderGuid, byteSharingProviderGuid);//binary
invitationRequest.SetExtendedProperty(PidNameXSharingProviderGuid, "AEF0060000000000C000000000000046");
invitationRequest.SetExtendedProperty(PidLidSharingProviderName, "Microsoft Exchange");
invitationRequest.SetExtendedProperty(PidNameXSharingProviderName, "Microsoft Exchange");
invitationRequest.SetExtendedProperty(PidLidSharingProviderUrl, "http://www.microsoft.com/exchange");
invitationRequest.SetExtendedProperty(PidNameXSharingProviderUrl, "http://www.microsoft.com/exchange");
//invitationRequest.SetExtendedProperty(PidLidSharingConfigurationUrl, "");
//invitationRequest.SetExtendedProperty(PidNameXSharingConfigUrl, "");
invitationRequest.SetExtendedProperty(PidLidSharingFlavor, 0x00020500);
invitationRequest.SetExtendedProperty(PidNameXSharingFlavor, "20500");
invitationRequest.SetExtendedProperty(PidLidSharingCapabilities, 0x00040290);
invitationRequest.SetExtendedProperty(PidNameXSharingCapabilities, "40290");
invitationRequest.SetExtendedProperty(PiLidSharingLocalType, "IPF.Appointment");
invitationRequest.SetExtendedProperty(PidNameXSharingLocalType, "IPF.Appointment");
invitationRequest.SetExtendedProperty(PidLidSharingInitiatorEntryId, binInitiatorEntryId);//binary
invitationRequest.SetExtendedProperty(PidLidSharingInitiatorName, senderUserId.Split('@')[0]);//username
invitationRequest.SetExtendedProperty(PidLidSharingInitiatorSmtp, senderUserId);//user emailaddress
string invitationMailboxID = GetInvitationMailboxId(service, "exch01", sharedUserDn);
CalendarFolder folder = Microsoft.Exchange.WebServices.Data.CalendarFolder.Bind(service, WellKnownFolderName.Calendar);
string idForPowerShell = GetConvertedEWSIDinHex(service, folder.Id.UniqueId, senderUserId);
CreateSharingMessageAttachment(idForPowerShell, senderUserId, GetIntiatorEntryID(sharedUserDn), invitationMailboxID, sharedToUser, "calendar");
// Add a file attachment by using a stream
// We need to do the following in order to prevent 3 extra bytes from being prepended to the attachment
string tmpPath = Application.StartupPath + "\\temp\\";
if (!Directory.Exists(tmpPath)) Directory.CreateDirectory(tmpPath);
string sharMetadata = File.ReadAllText(tmpPath + "sharing_metadata.xml", Encoding.ASCII);
byte[] fileContents;
UTF8Encoding encoding = new System.Text.UTF8Encoding();
fileContents = encoding.GetBytes(sharMetadata);
// fileContents is a Stream object that represents the content of the file to attach.
invitationRequest.Attachments.AddFileAttachment("sharing_metadata.xml", fileContents);
// This is where we set those "special" headers and other pertinent
// information I noted in Part 1 of this series...
Attachment thisAttachment = invitationRequest.Attachments[0];
thisAttachment.ContentType = "application/x-sharing-metadata-xml";
thisAttachment.Name = "sharing_metadata.xml";
thisAttachment.IsInline = false;
// Add recipient info and send message
invitationRequest.ToRecipients.Add(sharedToUser);
invitationRequest.SendAndSaveCopy();
}
static String GetConvertedEWSIDinHex(ExchangeService esb, String sID, String strSMTPAdd)
{
// Create a request to convert identifiers.
AlternateId objAltID = new AlternateId();
objAltID.Format = IdFormat.EwsId;
objAltID.Mailbox = strSMTPAdd;
objAltID.UniqueId = sID;
//Convert PR_ENTRYID identifier format to an EWS identifier.
AlternateIdBase objAltIDBase = esb.ConvertId(objAltID, IdFormat.HexEntryId);
AlternateId objAltIDResp = (AlternateId)objAltIDBase;
return objAltIDResp.UniqueId.ToString();
}
public static String GetInvitationMailboxId(ExchangeService service, string mailBoxServer, string sharedUserLegacyDn)
{
//ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
//service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "Email address removed");
// Generate The Store Entry Id for the impersonated user
StringBuilder MailboxIDPointer = new StringBuilder();
string fqdn = mailBoxServer;
string legacyDN = sharedUserLegacyDn;
MailboxIDPointer.Append("00000000"); /* Flags */
MailboxIDPointer.Append("38A1BB1005E5101AA1BB08002B2A56C2"); /* ProviderUID */
MailboxIDPointer.Append("00"); /* Version */
MailboxIDPointer.Append("00"); /* Flag */
MailboxIDPointer.Append("454D534D44422E444C4C00000000"); /* DLLFileName */
MailboxIDPointer.Append("00000000"); /* Wrapped Flags */
MailboxIDPointer.Append("1B55FA20AA6611CD9BC800AA002FC45A"); /* WrappedProvider UID (Mailbox Store Object) */
MailboxIDPointer.Append("0C000000"); /* Wrapped Type (Mailbox Store) */
MailboxIDPointer.Append(ConvertStringToHex(fqdn)); /* ServerShortname (FQDN) */
MailboxIDPointer.Append("00"); /* termination bit */
MailboxIDPointer.Append(ConvertStringToHex(legacyDN)); /* Returns the userDN of the impersonated user */
MailboxIDPointer.Append("00"); /* terminator bit */
//service.ImpersonatedUserId = null;
return MailboxIDPointer.ToString();
}
public static void CreateSharingMessageAttachment(string folderid, string userSharing, string userSharingEntryID, string invitationMailboxID, string userSharedTo, string dataType)
{
XmlDocument sharedMetadataXML = new XmlDocument();
try
{
// just logging stuff as well during my debugging
using (StreamWriter w = new StreamWriter("SharingMessageMetaData.txt", false, Encoding.ASCII))
{
// Create a String that contains our new sharing_metadata.xml file
StringBuilder metadataString = new StringBuilder("<?xml version=\"1.0\"?>");
metadataString.Append("<SharingMessage xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
metadataString.Append("xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ");
metadataString.Append("xmlns=\"http://schemas.microsoft.com/sharing/2008\">");
metadataString.Append("<DataType>" + dataType + "</DataType>");
metadataString.Append("<Initiator>");
metadataString.Append("<Name>" + userSharing.Split('@')[0] + "</Name>");
metadataString.Append("<SmtpAddress>" + userSharing + "</SmtpAddress><EntryId>" + userSharingEntryID.Trim());
metadataString.Append("</EntryId>");
metadataString.Append("</Initiator>");
metadataString.Append("<Invitation>");
metadataString.Append("<Providers>");
metadataString.Append("<Provider Type=\"ms-exchange-internal\" TargetRecipients=\"" + userSharedTo + "\">");
metadataString.Append("<FolderId xmlns=\"http://schemas.microsoft.com/exchange/sharing/2008\">");
metadataString.Append(folderid);
metadataString.Append("</FolderId>");
metadataString.Append("<MailboxId xmlns=\"http://schemas.microsoft.com/exchange/sharing/2008\">");
metadataString.Append(invitationMailboxID);
metadataString.Append("</MailboxId>");
metadataString.Append("</Provider>");
metadataString.Append("</Providers>");
metadataString.Append("</Invitation>");
metadataString.Append("</SharingMessage>");
// MessageBox.Show(metadataString.ToString(), "metadataString before loading into soapEnvelope");
sharedMetadataXML.LoadXml(metadataString.ToString());
Console.WriteLine($"{0}, {1}, {2}", metadataString.ToString(), w, "Generate XML");
// MessageBox.Show("returning SOAP envelope now");
w.Close();
}
string tmpPath = Application.StartupPath + "\\temp\\";
if (!Directory.Exists(tmpPath)) Directory.CreateDirectory(tmpPath);
sharedMetadataXML.Save(tmpPath + "sharing_metadata.xml");
}
catch (Exception eg)
{
MessageBox.Show("Exception:" + eg.Message.ToString(), "Error Try CreateSharedMessageInvitation()");
}
}
static bool RedirectionUrlValidationCallback(String redirectionUrl)
{
bool redirectionValidated = false;
if (redirectionUrl.Equals("https://mail.domain.com/autodiscover/autodiscover.xml"))
{
redirectionValidated = true;
}
return redirectionValidated;
}
public static String GetMailboxDN(string senderUserId, System.Net.NetworkCredential cred)
{
string result = "error";
AutodiscoverService autodiscoverService = new AutodiscoverService();
// The following RedirectionUrlValidationCallback required for httpsredirection.
autodiscoverService.RedirectionUrlValidationCallback = RedirectionUrlValidationCallback;
autodiscoverService.Credentials = cred;
// Get the user settings.
// Submit a request and get the settings. The response contains only the
// settings that are requested, if they exist.
GetUserSettingsResponse userresponse = autodiscoverService.GetUserSettings(
senderUserId.ToString(),
UserSettingName.UserDisplayName,
UserSettingName.UserDN
);
foreach (var usersetting in userresponse.Settings)
{
if (usersetting.Key.ToString() == "UserDN")
{
result = usersetting.Value.ToString();
}
}
return result;
}
static string GetIntiatorEntryID(string legacyDN)
{
String result = String.Empty;
//// Bind to EWS
//ExchangeService service = ExchangeConnection.ExchangeService();
//service.ImpersonatedUserId =
//new ImpersonatedUserId(ConnectingIdType.SmtpAddress, senderUserId);
//// Get LegacyDN Using the function above this one
//string legacyDNinHex = ConvertStringToHex(sharedByLegacyDN);
string legacyDNinHex = ConvertStringToHex(legacyDN);
StringBuilder addBookEntryId = new StringBuilder();
addBookEntryId.Append("00000000"); /* Flags */
addBookEntryId.Append("DCA740C8C042101AB4B908002B2FE182"); /* ProviderUID */
addBookEntryId.Append("01000000"); /* Version */
addBookEntryId.Append("00000000"); /* Type - 00 00 00 00 = Local Mail User */
addBookEntryId.Append(legacyDNinHex); /* Returns the userDN of the impersonated user */
addBookEntryId.Append("00"); /* terminator bit */
result = addBookEntryId.ToString();
//service.ImpersonatedUserId = null;
return result;
}
static string ConvertStringToHex(string input)
{
// Take our input and break it into an array
char[] arrInput = input.ToCharArray();
String result = String.Empty;
// For each set of characters
foreach (char element in arrInput)
{
if (String.IsNullOrEmpty(result))
{
result = String.Format("{0:X2}", Convert.ToUInt16(element)).ToString();
}
else
{
result += String.Format("{0:X2}", Convert.ToUInt16(element)).ToString();
}
}
return result.ToString();
}
static byte[] HexStringToByteArray(string input)
{
byte[] Bytes;
int ByteLength;
string HexValue = "\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9|||||||\xA\xB\xC\xD\xE\xF";
ByteLength = input.Length / 2;
Bytes = new byte[ByteLength];
for (int x = 0, i = 0; i < input.Length; i += 2, x += 1)
{
Bytes[x] = (byte)(HexValue[Char.ToUpper(input[i + 0]) - '0'] << 4);
Bytes[x] |= (byte)(HexValue[Char.ToUpper(input[i + 1]) - '0']);
}
return Bytes;
}
static ExtendedPropertyDefinition PidTagMessageClass = new ExtendedPropertyDefinition(0x001A, MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameContentClass = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-c000-000000000046}"), "Content-Class", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingProviderGuid = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A01", MapiPropertyType.Binary);
static ExtendedPropertyDefinition PidNameXSharingProviderGuid = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Provider-Guid", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingProviderName = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A02", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingProviderName = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Provider-Name", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingProviderUrl = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A03", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingProviderUrl = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Provider-Url", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingConfigurationUrl = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A24", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingConfigUrl = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Config-Url", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingFlavor = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A18", MapiPropertyType.Integer);
static ExtendedPropertyDefinition PidNameXSharingFlavor = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Flavor", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingCapabilities = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A17", MapiPropertyType.Integer);
static ExtendedPropertyDefinition PidNameXSharingCapabilities = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Capabilities", MapiPropertyType.String);
static ExtendedPropertyDefinition PiLidSharingLocalType = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A14", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingLocalType = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Local-Type", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingInitiatorEntryId = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A09", MapiPropertyType.Binary);
static ExtendedPropertyDefinition PidLidSharingInitiatorName = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A07", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingInitiatorSmtp = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A08", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingRemoteName = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A05", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingRemoteName = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Remote-Name", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingRemoteType = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A1D", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingRemoteType = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Remote-Type", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingRemoteUid = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A06", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingRemoteUid = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Remote-Uid", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingRemoteStoreUid = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A48", MapiPropertyType.String);
static ExtendedPropertyDefinition PidNameXSharingRemoteStoreUid = new ExtendedPropertyDefinition(new Guid("{00020386-0000-0000-C000-000000000046}"), "X-Sharing-Remote-Store-Uid", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingResponseType = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A27", MapiPropertyType.String);
static ExtendedPropertyDefinition PidLidSharingResponseTime = new ExtendedPropertyDefinition(new Guid("{00062040-0000-0000-C000-000000000046}"), "0x00008A28", MapiPropertyType.String);
And errors.
ServiceDiagnostics_SendWatsonReportOnUnhandledException=System.ArgumentNullException: Value cannot be null. Parameter name: frontEndLocator
|
How can I fix this error?