I'm using EWS in my winforms application to create a new appointment in my Outlook (+ to get items from my Outlook Calendar).
The issue i'm having is the following:
Everything works perfect but currently it takes 20-25 seconds to retrieve my appointments (= calendar items in Outlook) and 13-20 seconds to create an appointment
The code that does this comes straight from 'Google':
private void btn_Test_Click(object sender, EventArgs e)
{
DateTime d1 = DateTime.Now;
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
try
{
service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new WebCredentials("mail", "pass");
/*service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;*/
service.AutodiscoverUrl("mail", RedirectionUrlValidationCallback);
service.Url = new Uri("https://mail.domain.com/EWS/Exchange.asmx");
}
catch (Exception ml2)
{
MessageBox.Show(ml2.ToString());
}
// We get 10 items in the calendar for the next week
DateTime startDate = DateTime.Now;
DateTime endDate = startDate.AddDays(7);
const int NUM_APPTS = 10;
// Initialize the calendar folder object with only the folder ID.
CalendarFolder calendar = CalendarFolder.Bind(service, WellKnownFolderName.Calendar, new PropertySet());
// Set the start and end time and number of appointments to retrieve.
CalendarView cView = new CalendarView(startDate, endDate, NUM_APPTS);
// Limit the properties returned to the appointment's subject, start time, and end time.
cView.PropertySet = new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End);
// Retrieve a collection of appointments by using the calendar view.
FindItemsResults<Appointment> appointments = calendar.FindAppointments(cView);
Console.WriteLine("\nThe first " + NUM_APPTS + " appointments on your calendar from " + startDate.Date.ToShortDateString() +
" to " + endDate.Date.ToShortDateString() + " are: \n");
foreach (Appointment a in appointments)
{
Console.Write("Subject: " + a.Subject.ToString() + " ");
Console.Write("Start: " + a.Start.ToString() + " ");
Console.Write("End: " + a.End.ToString());
Console.WriteLine();
}
DateTime d2 = DateTime.Now;
MessageBox.Show( "Seconds: " + (d2 - d1).TotalSeconds.ToString());
}
Since I have absolutely 0 experience with EWS (or developing while using API's) I was wondering if there was room for performance or I wanted to know if this is just normal? I haven't found anything EWS = SLOW related so I was worrying a bit.
Could it be that my code is wrong or that i need to configure one thing or another server sided to improve results?
Thanks
The most likely thing to slow down you code is
service.AutodiscoverUrl("mail", RedirectionUrlValidationCallback);
service.Url = new Uri("https://mail.domain.com/EWS/Exchange.asmx");
You do an AutoDiscover and then set the link manually which is make the first AutoDiscover Call redundant. Auto-discover will do multiple searches of Local AD domain, DNS records to try and discover the correct URL to use so I would suggest if you are going to hardcode the URL you remark out the first line.
Also your testing logic only looks at the total time to execute you function which isn't going to be helpfully you should look at the time to complete each operation eg
FindItemsResults<Appointment> appointments = calendar.FindAppointments(cView);
or
CalendarFolder calendar = CalendarFolder.Bind(service, WellKnownFolderName.Calendar, new PropertySet());
or any Save, Send type method call when the actually call to the server is made if you time this that will give you a true indication of the speed of each call.
Related
I would like to change the "next_billing_date" on subscription when the customer restart the subscription from suspended state.
The situation is (example):
Customer has monthly subscription, she pay every 2nd of the month and we deliver the product.
Customer Suspend the subscription....
When the customer resume the subscription she can set up a new delivery date. So we would like to change the "next_billing_date" in the agreement details to the (delivery date) - 1 day.
What I tried:
Agreement agreement = Agreement.Get(apiContext, formulate.SubscriptionId);
agreement.agreement_details.next_billing_date = string.Format("{0}Z", formulate.NextDeliveryDate.Value.AddHours(-16).ToString("s"));
PatchRequest pr = new PatchRequest()
{
new Patch()
{
op = "replace",
path = "/",
value = new Plan() { description = "Restarting subscription (" + formulate.SubscriptionId.ToString() + ") - " + DateTime.Now.ToString() }
}
};
agreement.Update(apiContext, pr);
agreement.ReActivate(apiContext, asd);
The PatchRequest is just dummy, because need a PatchRequest for the agreement.Update method.
I thought I can update the agreement this way, but unfortunately the "Next Payment Date" didn't change on the subscription. Everything else is fine.
Is anybody can help me what I should do?
Many thanks
Zoltan
I followed this guide to retrieve Meetings in Exchange made via Outlook; https://msdn.microsoft.com/en-us/library/office/dn495614(v=exchg.150).aspx
Everything runs fine, no exceptions but it doesn't return any results. I then tried FindItems instead of FindAppointments and this does return my results. Why does FindAppointments not return the meetings?
I'm creating test appointments in Outlook online. By clicking Menu > Calendar > New, I complete the details of the event and then add attendees before saving. These are returned by FindItems() but there doesn't seem to be a property to retrieve Location and Attendee list? Where FindAppointments would give me the properties I need if the data was returned. I have had Outlook installed on a computer previously where creating a meeting specifically mentions the word 'Meeting' where this appears to be calendar items. I'm not sure what the difference is?
My end goal is when users schedule meetings via Outlook and I'll have an application that retrieves details of those meetings inc. an attendee list and location.
Many thanks for any pointers!
We need to add list of required items to property set, in the given example the property set is restricted.
In property code
// Limit the properties returned to the appointment's subject, start time, and end time.
cView.PropertySet = new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End);
instead of above use below property set,
cView.PropertySet = new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End, AppointmentSchema.Location, AppointmentSchema.RequiredAttendees);
or the best for initial learning is
// Limit the properties returned to the appointment's subject, start time, and end time.
cView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
Manged to find a solution taken from this thread
The code could do with a tidy up but it correctly pulls down the appointments and allows me to get the data that I need.
FindItemsResults<Item> result = service.FindItems(WellKnownFolderName.Calendar, new CalendarView(DateTime.Now, DateTime.Now.AddDays(7)));
foreach(Item item in result.Items)
{
ServiceResponseCollection<GetItemResponse> itemResponseCollection = service.BindToItems(new[] { new ItemId(item.Id.UniqueId) }, new PropertySet(BasePropertySet.FirstClassProperties));
foreach(GetItemResponse itemResponse in itemResponseCollection)
{
Appointment appointment = (Appointment)itemResponse.Item;
Console.WriteLine("Subject: " + appointment.Subject);
Console.WriteLine("Location: " + appointment.Location);
Console.WriteLine("AppointmentType: " + appointment.AppointmentType.ToString());
Console.WriteLine("Body: " + appointment.Body);
Console.WriteLine("End: " + appointment.End.ToString());
Console.WriteLine("UniqueId: " + appointment.Id.UniqueId);
Console.WriteLine("Start: " + appointment.Start.ToString());
Console.WriteLine("When: " + appointment.When);
Console.WriteLine("Required Attendees: ");
foreach (var attendee in appointment.RequiredAttendees)
{
Console.WriteLine(attendee.Name);
}
}
We have an Exchange Server 2010 SP2 running here on premise.
I'm using the EWS Managed API (I've tried both API/DLL version 1.2 and 2.1) to connect to it. I'm able to retrieve calendar, EWS Service name and version info, but on line "var appointments = calendar.FindAppointments(calenderView);" I get a 501 - Not Implement exception (see image).
I've searched the net but can't find any info on this error, nor do I find info on MSDN.
Below is the code I use:
Main Method:
private void Main_Load(object sender, EventArgs e)
{
ConnectWithExchange();
GetCalendarItems();
}
Instantation
/// <summary>
/// http://msdn.microsoft.com/en-us/library/office/ff597939(v=exchg.80).aspx
/// </summary>
private void ConnectWithExchange()
{
// 01. Instantiate ExchangeService
_exchange = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
// 02. Connect with credentials
_exchange.UseDefaultCredentials = true;
// or pass through credentials of a service user:
// _exchange.Credentials = new WebCredentials("user#name", "password", "domain");
// 03. Set correct endpoint
// http://msdn.microsoft.com/en-us/library/office/gg274410(v=exchg.80).aspx
// _exchange.Url = new Uri("https://outlook.kdg.be/EWS/Exchange.asmx");
// or use autodiscover
_exchange.AutodiscoverUrl("name#domain.com"); // works ok
// 04. Display version and info
UxExchangeVersion.Text = _exchange.Url.ToString(); // works ok
}
Retrieving Calendar Items
/// <summary>
/// http://msdn.microsoft.com/en-us/library/office/dn439786(v=exchg.80).aspx
/// </summary>
private void GetCalendarItems()
{
// 01. Init calendar folder object with the folder ID
CalendarFolder calendar = CalendarFolder.Bind(_exchange, WellKnownFolderName.Calendar, new PropertySet(FolderSchema.DisplayName));
// 02. Set start and end time and number of appointments to retrieve
CalendarView calenderView = new CalendarView(DateTime.Now, DateTime.Now.AddDays(7), 150);
// 03. Limit the properties returned
calenderView.PropertySet = new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End);
// 04. Fetch the appointments
var appointments = calendar.FindAppointments(calenderView);
// var appointments = _exchange.FindAppointments(calendar.Id, new CalendarView(DateTime.Now, DateTime.Now.AddDays(7))); // **failure point**
// 05. Display appiontments in list
// 05A. Fetch calender name
uxCalenderName.Text = calendar.DisplayName + " (" + calendar.Id.Mailbox + ")";
// 05B. Fill list
uxAppointments.Items.Clear();
foreach (var appointment in appointments)
{
var appointmentString = new StringBuilder();
appointmentString.Append("Subject: " + appointment.Subject.ToString() + " ");
appointmentString.Append("Start: " + appointment.Start.ToString() + " ");
appointmentString.Append("End: " + appointment.End.ToString());
uxAppointments.Items.Add(appointmentString.ToString());
}
}
I ran GetCalendarItems() and it works fine for me. I noticed that you don't have the URL redirection callback in _exchange.AutodiscoverUrl. I'm surprised that you can get the URL without a redirection.
internal static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
Can you tell me about your target server? What version of Exchange are you targeting?
I want to manage the booking policy of a room, maximum duration of a meeting for example. Do someone has idea how do you do that via Managed API?
The managed API cannot police max duration but what you need todo is validate the entry before you submit a reservation...
public override bool IsNoOverTimeLimit(Reservation reservation)
{
return reservation.End.Subtract(reservation.Start).TotalMinutes <= 120;
}
if(!IsNoOverTimeLimit)
{
var errorMsg = new Label();
var fontSize = FontUnit.Point(10);
errorMsg.Font.Size = fontSize;
errorMsg.Text = "Reservation time is limited to " + ((float)30 / 60).ToString(CultureInfo.InvariantCulture) + " hours at a time.<br /> ";
placeHolder.Controls.Add(errorMsg);
}
My version is way more complicated than this but you get the point. Just simply check the reservation before you submit and if over time limit, return to page with some pretty warning..
I would like to add a recurring event with C#. I found on the Web that the following should work. When I run the method to insert the entry, It fails on the
EventEntry insertedEntry = service.Insert(calendarUri, entry); statement !
I get this error :
"Execution of request failed:
https://www.google.com/calendar/feeds/user#gmail.com/private/full?gsessionid=6eGsOTuhQ-YUVWp2BV_25g"
When I remove the recurrence code, everything works fine ! I noticed that this piece of code is pretty old ! How can I simply add a recurring event on Google Calendar with the .NET library ?
EventEntry entry = new EventEntry();
entry.Title.Text = "Hello World !";
// Recurring event:
String recurData =
"RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20131010;BYDAY=SU\r\n";
Recurrence recurrence = new Recurrence();
recurrence.Value = recurData;
entry.Recurrence = recurrence;
string htmlDescription = "Woww, really ?";
if (htmlDescription != null && htmlDescription.Length > 0)
{
entry.Content.Type = "html";
entry.Content.Content = htmlDescription;
}
Where eventLocation = new Where();
eventLocation.ValueString = "Somewhere";
entry.Locations.Add(eventLocation);
DateTime start = DateTime.Now;
When eventTime = new When();
eventTime.StartTime = start;
DateTime endTime = DateTime.Now.AddHours(2);
eventTime.EndTime = endTime;
entry.Times.Add(eventTime);
eventTime.AllDay = true;
EventEntry insertedEntry = service.Insert(calendarUri, entry);
Straight from Google (click the .NET example if it doens't come up as a default):Create Recurring Events
Hopefully this will give you some ideas if not out-right answer your question.
Cheers.
Your recurrence string telling it when to end requires a full time entry. You simply said UNTIL=20131010. The question is 20131010 where? We can assume you want midnight, but then... midnight where?
String recurData =
"RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20131010T000000-05:00;BYDAY=SU\r\n";
The above change should make your event recur until Midnight US Eastern time on 2013-10-10.