24

Tenemos un calendario público para nuestra empresa configurado en una carpeta pública de Exchange 2007. Puedo recuperar mis citas del calendario personal para el día actual usando el siguiente código. He buscado en línea alta y baja y no puedo encontrar un ejemplo de alguien que recupera información del calendario de un calendario de carpeta pública.Extraer citas de calendario público de Exchange 2007 mediante la API de servicios web de Exchange

Parece que debería ser factible, pero no puedo por mi vida ponerlo en funcionamiento. ¿Cómo puedo modificar el código a continuación para acceder al calendario? No estoy interesado en crear citas a través de asp.net, solo recuperando una lista simple. Estoy abierto a cualquier otra sugerencia también. Gracias.

AÑADIDO BOUNTY
- No puedo ser la única persona que alguna vez tenía que hacer esto. Hagamos que este problema se resuelva para las generaciones futuras.

actualizado de nuevo debido a la ignorancia
- me olvidó mencionar que el proyecto que estoy trabajando es .NET 2.0 (muy importante ¿no le parece?).

* Añadido mi solución de código siguiente *
- He reemplazado mi ejemplo de código original con el código que terminó trabajando. Muchas gracias a Oleg por proporcionar el código para encontrar la carpeta pública, que fue la parte más difícil. He modificado el código usando el ejemplo de aquí http://msexchangeteam.com/archive/2009/04/21/451126.aspx para usar el método FindAppointments más simple.

Este sencillo ejemplo devuelve una cadena html con las citas, pero puede usarla como base para personalizar según sea necesario. Puedes ver nuestra ida y vuelta bajo su respuesta a continuación.

using System; 
using Microsoft.Exchange.WebServices.Data; 
using System.Net; 

namespace ExchangePublicFolders 
{ 
    public class Program 
    { 
     public static FolderId FindPublicFolder(ExchangeService myService, FolderId baseFolderId, 
     string folderName) 
     { 

     FolderView folderView = new FolderView(10, 0); 
     folderView.OffsetBasePoint = OffsetBasePoint.Beginning; 
     folderView.PropertySet = new PropertySet(FolderSchema.DisplayName, FolderSchema.Id); 

     FindFoldersResults folderResults; 
     do 
     { 
      folderResults = myService.FindFolders(baseFolderId, folderView); 

      foreach (Folder folder in folderResults) 
       if (String.Compare(folder.DisplayName, folderName, StringComparison.OrdinalIgnoreCase) == 0) 
        return folder.Id; 

      if (folderResults.NextPageOffset.HasValue) 
       folderView.Offset = folderResults.NextPageOffset.Value; 
     } 
     while (folderResults.MoreAvailable); 

     return null; 
    } 

    public static string MyTest() 
    { 
     ExchangeService myService = new ExchangeService(ExchangeVersion.Exchange2007_SP1); 

     myService.Credentials = new NetworkCredential("USERNAME", "PASSWORD", "DOMAIN"); 
     myService.Url = new Uri("https://MAILSERVER/ews/exchange.asmx"); 

     Folder myPublicFoldersRoot = Folder.Bind(myService, WellKnownFolderName.PublicFoldersRoot); 
     string myPublicFolderPath = @"PUBLIC_FOLDER_CALENDAR_NAME"; 
     string[] folderPath = myPublicFolderPath.Split('\\'); 
     FolderId fId = myPublicFoldersRoot.Id; 
     foreach (string subFolderName in folderPath) 
     { 
      fId = Program.FindPublicFolder(myService, fId, subFolderName); 
      if (fId == null) 
      { 
       return string.Format("ERROR: Can't find public folder {0}", myPublicFolderPath); 

      } 
     } 

     Folder folderFound = Folder.Bind(myService, fId); 
     if (String.Compare(folderFound.FolderClass, "IPF.Appointment", StringComparison.Ordinal) != 0) 
     { 
      return string.Format("ERROR: Public folder {0} is not a Calendar", myPublicFolderPath); 

     } 

     CalendarFolder AK_Calendar = CalendarFolder.Bind(myService, fId, BasePropertySet.FirstClassProperties); 

     FindItemsResults<Appointment> AK_appointments = AK_Calendar.FindAppointments(new CalendarView(DateTime.Now,DateTime.Now.AddDays(1))); 


     string rString = string.Empty; 


     foreach (Appointment AK_appoint in AK_appointments) 
     { 

      rString += string.Format("Subject: {0}<br />Date: {1}<br /><br />", AK_appoint.Subject, AK_appoint.Start);  
     } 

     return rString; 
    } 

    } 
} 
+0

¡Hola! El código 'FindItemsResults ' parece agradable. Me parece que olvidaste configurar 'PropertySet' para' CalendarView'. Es importante. Si solo usará las propiedades 'Subject' y' Start' de las citas de los resultados de búsqueda, debe establecer estas dos propiedades 'ItemSchema.Subject' y' AppointmentSchema.Start'. Si no lo hace, todas las 'PropertySet.FirstClassProperties' se enviarán desde el servidor de Exchange. Incluí en la carpeta vinculando este conjunto de propiedades solo para mostrar cuánto hay. Además, te recomiendo que continúes usando paginación. – Oleg

+0

Por cierto, el uso de 'ItemView' y' FindItemsResults ' se debe a que modifiqué otro ejemplo que enumeraba los correos electrónicos.En la carpeta Buzón, encontrará ** no solo correos electrónicos, sino también requisitos para cumplir con una cita. Entonces, para enumerar el buzón, mejor debería usar la clase base 'Item'. Parece que con la carpeta de calendario no tendrás el problema, pero piensa en este posible problema. ¡Mis mejores deseos y buena suerte! – Oleg

+0

@Oleg Voy a mantener la paginación. Quité el PropertySet porque quería jugar con todas las propiedades. Voy a volver a agregarlo una vez que decida exactamente qué propiedades quiero usar. Por el momento, me limitaré al calendario, pero si necesito acceder a un buzón de correo electrónico, usaré la vista de artículo. – NinjaBomb

Respuesta

15

Como se prometió aquí hay un ejemplo de código. Usé the Microsoft Exchange Web Services (EWS) Managed API 1.0 y le recomiendo que haga lo mismo. La mayoría de los comentarios que en el código

using System; 
using Microsoft.Exchange.WebServices.Data; 
using System.Net; 

namespace ExchangePublicFolders { 
    class Program { 
     static FolderId FindPublicFolder (ExchangeService myService, FolderId baseFolderId, 
      string folderName) { 

      // We will search using paging. We will use page size 10 
      FolderView folderView = new FolderView (10,0); 
      folderView.OffsetBasePoint = OffsetBasePoint.Beginning; 
      // we will need only DisplayName and Id of every folder 
      // se we'll reduce the property set to the properties 
      folderView.PropertySet = new PropertySet (FolderSchema.DisplayName, 
       FolderSchema.Id); 

      FindFoldersResults folderResults; 
      do { 
       folderResults = myService.FindFolders (baseFolderId, folderView); 

       foreach (Folder folder in folderResults) 
        if (String.Compare (folder.DisplayName, folderName, StringComparison.OrdinalIgnoreCase) == 0) 
         return folder.Id; 

       if (folderResults.NextPageOffset.HasValue) 
        // go to the next page 
        folderView.Offset = folderResults.NextPageOffset.Value; 
      } 
      while (folderResults.MoreAvailable); 

      return null; 
     } 

     static void MyTest() { 
      // IMPORTANT: ExchangeService is NOT thread safe, so one should create an instance of 
      // ExchangeService whenever one needs it. 
      ExchangeService myService = new ExchangeService (ExchangeVersion.Exchange2007_SP1); 

      myService.Credentials = new NetworkCredential ("[email protected]", "myPassword00"); 
      myService.Url = new Uri ("http://mailwebsvc-t.services.local/ews/exchange.asmx"); 
      // next line is very practical during development phase or for debugging 
      myService.TraceEnabled = true; 

      Folder myPublicFoldersRoot = Folder.Bind (myService, WellKnownFolderName.PublicFoldersRoot); 
      string myPublicFolderPath = @"OK soft GmbH (DE)\Gruppenpostfächer\_Template - Gruppenpostfach\_Template - Kalender"; 
      string[] folderPath = myPublicFolderPath.Split('\\'); 
      FolderId fId = myPublicFoldersRoot.Id; 
      foreach (string subFolderName in folderPath) { 
       fId = FindPublicFolder (myService, fId, subFolderName); 
       if (fId == null) { 
        Console.WriteLine ("ERROR: Can't find public folder {0}", myPublicFolderPath); 
        return; 
       } 
      } 

      // verify that we found 
      Folder folderFound = Folder.Bind (myService, fId); 
      if (String.Compare (folderFound.FolderClass, "IPF.Appointment", StringComparison.Ordinal) != 0) { 
       Console.WriteLine ("ERROR: Public folder {0} is not a Calendar", myPublicFolderPath); 
       return; 
      } 

      CalendarFolder myPublicFolder = CalendarFolder.Bind (myService, 
       //WellKnownFolderName.Calendar, 
       fId, 
       PropertySet.FirstClassProperties); 

      if (myPublicFolder.TotalCount == 0) { 
       Console.WriteLine ("Warning: Public folder {0} has no appointment. We try to create one.", myPublicFolderPath); 

       Appointment app = new Appointment (myService); 
       app.Subject = "Writing a code example"; 
       app.Start = new DateTime (2010, 9, 9); 
       app.End = new DateTime (2010, 9, 10); 
       app.RequiredAttendees.Add ("[email protected]"); 
       app.Culture = "de-DE"; 
       app.Save (myPublicFolder.Id, SendInvitationsMode.SendToNone); 
      } 

      // We will search using paging. We will use page size 10 
      ItemView viewCalendar = new ItemView (10); 
      // we can include all properties which we need in the view 
      // If we comment the next line then ALL properties will be 
      // read from the server. We can see there in the debug output 
      viewCalendar.PropertySet = new PropertySet (ItemSchema.Subject); 
      viewCalendar.Offset = 0; 
      viewCalendar.OffsetBasePoint = OffsetBasePoint.Beginning; 
      viewCalendar.OrderBy.Add (ContactSchema.DateTimeCreated, SortDirection.Descending); 

      FindItemsResults<Item> findResultsCalendar; 
      do { 
       findResultsCalendar = myPublicFolder.FindItems (viewCalendar); 

       foreach (Item item in findResultsCalendar) { 
        if (item is Appointment) { 
         Appointment appoint = item as Appointment; 
         Console.WriteLine ("Subject: \"{0}\"", appoint.Subject); 
        } 
       } 

       if (findResultsCalendar.NextPageOffset.HasValue) 
        // go to the next page 
        viewCalendar.Offset = findResultsCalendar.NextPageOffset.Value; 
      } 
      while (findResultsCalendar.MoreAvailable); 
     } 
     static void Main (string[] args) { 
      MyTest(); 
     } 
    } 
} 

Debe actualizar la cadena myPublicFolderPath al valor con su carpeta de calendario pública. Configuré myService.TraceEnabled = true que produce salida larga con información de depuración. Deberías de causar eliminar la línea para producción.

ACTUALIZADO: Algunos enlaces adicionales que puedes encontrar en Create new calendar system support in Exchange OWA. Si aún no ha visto los videos y desea usar los servicios web de Exchange, le recomendaría que los vea allí. Podría ahorrarle tiempo en el futuro.

+0

¡Gracias! Dejé fuera una información muy importante en mi pregunta. Mi proyecto está estancado en .NET 2.0. Lo siento por eso. Ya que es culpa mía y la solución que me han proporcionado es extremadamente completa y tomó algo de tiempo para armarla, les daré la recompensa. Como no puedo agregar el dll al proyecto sin actualizarlo, ¿qué harías? Lo primero que pienso es tener un sitio web totalmente separado que sirva a un servicio web para extraer los datos del calendario, pero eso suena a excesivo. ¿Qué piensas? – NinjaBomb

+0

@NinjaBomb: Si miras la salida de depuración que produce mi programa de prueba ('myService.TraceEnabled = true') puedes ver que EWS Managed API 1.0 envía las mismas solicitudes que puedes enviar por WebProxy. Por ejemplo, mira http://msdn.microsoft.com/en-us/library/aa493892(v=EXCHG.140).aspx. Puede causar que no use 'FolderQueryTraversalType.Deep' para carpetas públicas, pero puede modificar el código fácilmente para que haga lo mismo que' FindPublicFolder' de mi programa. – Oleg

+0

@NinjaBomb: en el modo de buscar en http://msdn.microsoft.com/en-us/library/bb402172(v=EXCHG.140).aspx y http://msdn.microsoft.com/en-us/ library/aa563918 (v = EXCHG.140) .aspx y así sucesivamente puede encontrar el ejemplo de código correspondiente en EWS como proxy (vea http://msdn.microsoft.com/en-us/library/exchangewebservices(v=EXCHG. 140) .aspx) e implemente su programa. Consulte también Operaciones de servicios web de Exchange (url: http://msdn.microsoft.com/en-us/library/bb409286(v=EXCHG.140).aspx) – Oleg

1
+0

Gracias por los enlaces. He visto la publicación de geekswithblogs.net sobre la búsqueda de carpetas públicas en cada búsqueda que he realizado. A menos que me lo haya perdido totalmente, no veo dónde saca citas del calendario de una carpeta pública. Verificará el método WebDAV, pero no encontré ningún ejemplo de que se use para los calendarios de Exchange 2007 o si funcionará. – NinjaBomb

+0

WebDAV están en desuso y no se incluyen en Exchange 2010. (vea http://msdn.microsoft.com/en-us/library/dd877032.aspx). Uno puede acceder a la carpeta pública de Exchange 2007 con los servicios web de Exchange. Si encuentro un poco de tiempo, publicaré un ejemplo más adelante. – Oleg

+0

Oleg ¡Publica una respuesta con un buen ejemplo de sacar citas de un calendario de carpeta pública que funciona de mi lado y obtienes la recompensa! Revisé todos los ejemplos que Microsoft proporcionó para los servicios web de Exchange, pero ninguno de ellos involucra carpetas públicas. Voy a probar lo que publicas tan pronto como pueda. – NinjaBomb

Cuestiones relacionadas