Monthly Archives: August 2011

Exchange Web Services (2007) – Part Two

This is the second part of a two part series describing how to connect to an Exchange Server, monitor for new mail, and locally download attachments.  The previous post described how to connect to the server and create a subscription detailing what notifications you wanted to receive from the server.  This post will continue on with actually requesting those notifications.

So every poll tick, we want to get any new notifications.  The GetSubscriptionItems() function gets any new event notifications, loops through them and retrieves the actual mail message, then if it has attachments, retrieves the attachments.

protected void GetSubscriptionItems()
{
BaseNotificationEventType[] events = GetEvents(SubscriptionInfo);

// Go through the event list that was returned. The server always returns at least one Status event
// which let's the caller know that the subscription is still alive (in push subscriptions scenarios,
// the Status even is sent periodically as a heart beat signal).
// In this example, we are only interested in ObjectChanged events, so we'll ignore any other event type.
foreach (BaseNotificationEventType evt in events)
{
BaseObjectChangedEventType objectChangedEvent = evt as BaseObjectChangedEventType;
if (objectChangedEvent != null)
{
ItemType item = GetItem(((ItemIdType)objectChangedEvent.Item).Id);
Logger.WriteLog("Received new message: " + item.Subject);
AttachmentType[] attachments = item.Attachments;
if (attachments != null && attachments.Length > 0)
GetAttachments((MessageType)item, attachments);
}
}
}

The GetEvents() function of course is the initial request to the Exchange service to get any new updates. In it you first create a GetEventsType object, similarly to all the other requests. Then you assign it the most recent watermark and the subscriptionId – the watermark updates with every request. Then after checking for errors, you use the GetEventsResponseType property Notifications.Items array as the return value with any actual notifications.

///<summary> /// Gets the latest events for a specific subscription.
/// </summary>
/// Subscription for whic to get the latest events.
/// Array of notification events.
public BaseNotificationEventType[] GetEvents(SubscriptionInformation subscriptionInfo)
{
// Create a GetEvents request
GetEventsType request = new GetEventsType();

// Setup the request
request.SubscriptionId = subscriptionInfo.Id;
request.Watermark = subscriptionInfo.Watermark;

// Call the GetEvents EWS method
GetEventsResponseType response = ServiceBinding.GetEvents(request);

// Extract the first response message that contains the information we need.
GetEventsResponseMessageType responseMessage = response.ResponseMessages.Items[0] as GetEventsResponseMessageType;

this.ThrowOnError("GetEvents", responseMessage);

// Update the watermark of the subscription info.
// GetEvents returns an updated watermark with every event. The latest watermark has to be passed back the next
// time GetEvents is called.
subscriptionInfo.Watermark = responseMessage.Notification.Items[responseMessage.Notification.Items.Length - 1].Watermark;

// Retrun the array of events.
return responseMessage.Notification.Items;
}

Back in GetSubscriptionItems, each notification is checked to ensure it is the correct type and the corresponding actual email is retrieved from the server, via the GetItem function. An ItemType actual encompasses emails, calendar items, tasks, and contacts. In this case we’re only interested in MessageType objects, so the results of this get cast later.

You’ll also notice that I’m adding an AdditionalProperty to the BaseShape. By adding the itemMimeContent to the BaseShape, the retrieved item will be able to be serialized to an .eml file and saved locally as a backup. .msg files cannot be saved. The rest of the code follows the fairly standard Exchange service procedure – make a GetX object, set the properties, get a GetXReponse from the function call on the ServiceBinding, check for errors, then return the result.

///<summary>
/// Retrieves the details of an item on the server.
/// </summary>
///Id of the item to retrieve the details of.
/// ItemType object containing the details of the item.
public ItemType GetItem(string id)
{
// Create a GetItem request object
GetItemType request = new GetItemType();

// Setup the request object:
// Set the response shape so it includes all of the item's properties.
// Two other base shapes are provided: IdOnly and Default
request.ItemShape = new ItemResponseShapeType();
request.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;
request.ItemShape.AdditionalProperties = new BasePathToElementType[1];
PathToUnindexedFieldType prop = new PathToUnindexedFieldType();
prop.FieldURI = UnindexedFieldURIType.itemMimeContent;
request.ItemShape.AdditionalProperties[0] = prop;

// Setup the array of item ids that we want to retrieve (only one item in this
// example)
ItemIdType itemId = new ItemIdType();
itemId.Id = id;

request.ItemIds = new BaseItemIdType[1];
request.ItemIds[0] = itemId;

// Call the GetItem EWS method, passing it the request that we just set up.
GetItemResponseType response = ServiceBinding.GetItem(request);

// Extract the first response message that contains the information we need.
ItemInfoResponseMessageType responseMessage = response.ResponseMessages.Items[0] as ItemInfoResponseMessageType;

// Fail if that response message indicates an error.
this.ThrowOnError("GetItem", responseMessage);

// Finally, return the item detail.
return responseMessage.Items.Items[0];
}

After getting the actual email message, then any attachments to that email are retrieved. This is done by creating a GetAttachmentType object and setting IncludeMimeContent to true on the AttachmentResponseShapeType. Then you set the array of RequestAttachentIdType to the AttachmentIds property of the GetAttachmentType object, and make the actual request to the ServiceBinding object.

Cycle through the results and verify that each does indeed have a file attachment and that it is the desired type (pdf in my case), then save each pdf to disk.

protected void GetAttachments(MessageType item, AttachmentType[] attachments)
{
GetAttachmentType getAttachment = new GetAttachmentType();

AttachmentResponseShapeType shape = new AttachmentResponseShapeType();
shape.IncludeMimeContent = true;
shape.IncludeMimeContentSpecified = true;
getAttachment.AttachmentShape = shape;

Listids = new List();

foreach (AttachmentType attachment in attachments)
{
if (attachment.ContentType == "application/pdf")
{
FileAttachmentType pdf = (FileAttachmentType)attachment;
Logger.WriteLog("PDF found: " + pdf.Name);
AttachmentIdType id = new AttachmentIdType();
id.Id = pdf.AttachmentId.Id;
ids.Add(id);
}
}

getAttachment.AttachmentIds = ids.ToArray();
Logger.WriteLog("Requesting PDFs (" + ids.Count + ")");
GetAttachmentResponseType response = ServiceBinding.GetAttachment(getAttachment);

foreach (AttachmentInfoResponseMessageType attachmentInfo in response.ResponseMessages.Items)
{
// Ensure attachment is File
if (attachmentInfo.Attachments[0].GetType().Name == "FileAttachmentType")
{
FileAttachmentType file = (FileAttachmentType)attachmentInfo.Attachments[0];
if (file.ContentType == "application/pdf")
{
string attachmentName = attachmentInfo.Attachments[0].Name.Substring(0, attachmentInfo.Attachments[0].Name.LastIndexOf('.'));
SaveFile(file.Content, attachmentName);
}
}
}
}

Voila! You’ve successfully retrieved and downloaded pdf attachments from all incoming email that you’ve subscribed to. Hopefully these two posts have been useful to you if you’re trying to set up a connection to and Exchange server and still back on 2007. I did skim over a few area – GetFolderByPath comes to mind – and I plan on addressing that in a later post.

Exchange Web Services (2007) – Part One

I was recently asked to create a windows service to interface with the client’s Exchange Server 2007. As I had never done that, I did some research and came across the Exchange Web Services. Basically, Exchange servers 2007 and later expose several web services to enable 3rd party tie-ins to the data. In my case, the client wanted all pdf’s in a certain folder to be downloaded along with the original email as they arrived.

It broke down into the following steps:

  • Reference the Web Service
  • Connect to the Exchange server
  • Start a subscription to the exchange service
  • Polling the exchange server
    • On poll, if the exchange servers reports new events, get items
    • Get attachments for items
    • Save attachments to a local folder

Referencing the Web Service

In order to use the Exchange Web Services, you must create a Web Reference that points to your Exchange Server. Right click on your project and select Add Service Reference from the context menu. Now, since I’m working with 2007, I have to do a few extra steps to make it work correctly – just adding a regular service reference does not work.

Click the Advanced button on the bottom left of the popup, then click the Add Web Reference button on the bottom left of that popup. Now you can actually enter the address of the Exchange Service:

https://my.exchange.server/EWS/services.wsdl

Connecting to the Exchange Server

To connect to the Exchange Service, you create an instance of the ExchangeServiceBinding class, providing it with the URL and login credentials for the Exchange Server.

ServiceBinding = new ExchangeServiceBinding();
ServiceBinding.Url = Url; // https://my.exchange.server/EWS/Exchange.asmx
ServiceBinding.Credentials = new NetworkCredential(Username, Password, Domain);

Starting a Subscription

After setting up the ServiceBinding object, in this case I wanted to create a subscription so that I could get updates as messages came in to the Exchange server. There are two types of subscriptions – push and pull. A push subscription requires an additional service to be running that the Exchange server can call as subscribed events occur. As my application did not require live updates, I went with a pull subscription.

Using a pull subscription, you periodically request any new subscribed to events that have occurred on the server. The events are specified when setting up the subscription. The folders you are paying attention to are also specified during this time.

SubscribeType request = new SubscribeType();

// Setup the request:
// Create a PullSubscription object
PullSubscriptionRequestType subscription = new PullSubscriptionRequestType();

// Indicate to what events to subscribe
subscription.EventTypes = new NotificationEventTypeType[1];
subscription.EventTypes[0] = NotificationEventTypeType.NewMailEvent;

BaseFolderType folder = GetFolderByPath(ServiceBinding, folderPath);

// And on which folder to subscribe for these events.
subscription.FolderIds = new BaseFolderIdType[1];
subscription.FolderIds[0] = folder.FolderId;
subscription.Timeout = 5;

request.Item = subscription;

Next, we will actually make the Subscribe request on the ServiceBinding object created previously, then check to make sure it succeeded.

// Call the Subscribe EWS method
SubscribeResponseType response = ServiceBinding.Subscribe(request);

// Extract the first response message that contains the information we need. This
SubscribeResponseMessageType responseMessage = response.ResponseMessages.Items[0] as SubscribeResponseMessageType;

this.ThrowOnError("CreatePullSubscription", responseMessage);

As this post is already getting a bit long, I’m going to break it up over a few posts. Hopefully this contained some information that helped you understand how to connection to an Exchange Web Server. The next post will cover getting notifications from the ServiceBinding.

Getting the Current Directory

Sometimes you need to know what directory an application is actually running in – to load a config file for example. The code below finds the current directory of the application, sets it as the current directory, then loads a config file relative to that.

String path = Assembly.GetExecutingAssembly().Location;
path = Path.GetDirectoryName(path);
Directory.SetCurrentDirectory(path);

XmlDocument doc = new XmlDocument();
doc.Load(@"config.xml");

Branding in SharePoint 2010

On Thursday afternoon I was asked to help a colleague out with an all day SharePoint 2010 training on Friday.  As I’m new to SharePoint I was uncertain how I could be of help, but was somewhat relieved when I was asked to do a segment on branding.  The audience was a group of 5 developers who (as I found out) had no SharePoint experience and were just sponges soaking up whatever bits of wisdom we gave them.  The short presentation I gave is below.

Getting Certified: The First Steps

mcts_thumb

This series will track some of the issues and questions I run into as I learn and attempt to become a SharePoint Developer.  My new job knows I am not a SharePoint developer and want to help me grow into one – I’ve now been developing and working with SharePoint 2010 for a month.  One of the steps involved in this process is taking SharePoint 2010 Application Developer exam and getting certified (list of certifications).

The first one I’ll be going after is TS: Microsoft SharePoint 2010, Application Development.  A direct overview from the exam description:

A Microsoft Certified Technology Specialist (MCTS) in Microsoft SharePoint 2010, Application Development should be able to perform the following tasks:
  • Write code that extends SharePoint 2010 (ok …)
  • Add and support code to an existing project (sure!)
  • Write code for and test custom features in a SharePoint solution such as a Visual Web Part or Event Receiver (no problem!)
  • Implement a solution designed by lead SharePoint Developer (easy!)
The candidate should also have the following experience:
  • 12 months with ASP.NET 3.5 with Visual Studio 2008 (or later) (nope …)
  •  6 months develop with SharePoint 2007 or later (nope again …)
  •  3 months with SP 2010 and VS2010 (includes beta releases) (nope a third time…)

The tasks sound easy enough considering they are amazingly generic.  Given that I have nothing resembling that amount of experience however, I’m hoping to make it up through sheer hard work, my blazing intellect, and an organized approach!  I’m definitely going to make use of the practice exam on MeasureUp.com, with the overall goal of taking the certification exam in about a month’s time from now.