Search This Blog

Monday, September 27, 2010

Sample code (C#) to send mail using Exchange Web Services (EWS) Managed API hosted on a Microsoft Online Services / Exchange Online platform.

After going through lots of searches for sending out a simple mail hosted on Microsoft Online Services / Exchange Online / BPOS (Business Productivity Online Standard Suite), I came up with an answer.

We will also be able to write code to use the classic SMTP method and call the smtp server (smtp.mail.microsoftonline.com) and use the port 587 as described in their team blog (http://blogs.technet.com/b/msonline/archive/2009/09/02/using-smtp-relay-with-exchange-online.aspx).

But what-if, if we have a requirement to send out outlook meeting requests / responses OR Appointment OR Task OR any other Outlook item. Then the answer is to use EWS.

But EWS also had some confusions added to it like in many of the sites, there were suggestions to use the ExchangeServiceBinding class which is generated after adding the Web / Service reference. But when I added the web / service reference then the ExchangeServiceBinding call has been deprecated / missing.

Then finally, I found a solution to use the Exchange Web Services (EWS) Managed API which can be downloaded here (http://www.microsoft.com/downloads/en/details.aspx?FamilyID=c3342fb3-fbcc-4127-becf-872c746840e1).

There are lots of descriptions and how to’s for using the EWS API as well as EWS. But my approach would provide a solution to combine EWS API to access Exchange Online hosted using Microsoft Online Services / BPOS.

Below are the steps and sample code to use the EWS API. Once you download and install the API, create any C# project (Preferably using .Net Framework 3.5 and above) and copy the 2 files available at “Program Files\Microsoft\Exchange\Web Services\1.0\” Microsoft.Exchange.WebServices.dll and Microsoft.Exchange.WebServices.xml to your local folder.

And then add a reference to the above said dll to your project and add a using clause to the Microsoft.Exchange.WebServices.Data namespace.

using Microsoft.Exchange.WebServices.Data;



To access EWS by using the EWS Managed API, all you need is an instance of the ExchangeService class, as shown in the following example.



ExchangeService service = new ExchangeService();



There are only 2 options available now for the ExchangeVersion Enum. In my case it was as above OR alternatively it can be as Exchange2010.



We can set the URL of the service in one of two ways:



1. Manually, if we know the URL of Exchange Web Services or if we have previously determined it via the Autodiscover service.



2. By using the Autodiscover service.



To set the URL manually, use the following:



service.Url = new Uri("https://red001.mail.microsoftonline.com/ews/Exchange.asmx");



To set the URL by using Autodiscover, use the following:



service.AutodiscoverUrl(“Someone@example.com”);



Please change your Url according to your location.



Asia Pacific (APAC)

https://red003.mail.apac.microsoftonline.com



Europe, the Middle East, and Africa (EMEA)

https://red002.mail.emea.microsoftonline.com



North America

https://red001.mail.microsoftonline.com



Generally people recommend to use the Auto Discover service as there would be more frequent changes to the server configuration. But for a trial and error method I had used the manual Url method.



Now we come to the tricky part of the story (at-least in my case).



We will change the settings of Use Default Credentials to false.



service.UseDefaultCredentials = false;



And we will have the credentials assigned to the service through WebCredentials class. Alternatively NetworkCredentials also can be used for non web-based applications.



service.Credentials = new WebCredentials("<<user@example.com>>", "<<password>>");



This class will have an additional overloaded constructor with the domain as an optional parameter. We will leave that overloaded constructor and use the above mentioned constructor alone.



Then, we will have the message object instantiated through EmailMessage class with the overloaded constructor having service object created above as parameter.



EmailMessage message = new EmailMessage(service);





And we will add the Subject, Body & ToRecipents as mentioned below.



message.Subject = "Hello world!";
message.Body = "Sent using the EWS Managed API.";
message.ToRecipients.Add("<<someone@example.com>>");



Finally, we will send the message using the Send method.



message.Send();



If we need to send as well as save the message in the Sent Items folder then we cal use the



message.SendAndSaveCopy();



the final snippet would look something like below;




ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Url = new Uri("https://red001.mail.microsoftonline.com/ews/Exchange.asmx");
service.UseDefaultCredentials = false;
service.Credentials = new WebCredentials(“<<user@example.com>>”, “passw0rd”);

EmailMessage message = new EmailMessage(service);
message.Subject = "Hello world!";
message.Body = "Sent using the EWS Managed API.";
message.ToRecipients.Add("someone@example.com");
message.Send();




Tuesday, September 14, 2010

How to add a Custom Field to an existing Work Item Type in TFS 2010 Process Template (MSF for Agile 5.0)

If there is a requirement to add a custom field to the TFS 2010 process template / to customize a Work Item Type in TFS 2010 by adding a custom field to it, then this post might be of use to you.

In my case, there was a specific requirement to add a custom field by name “Branch” to the Work Item “Bug” in order to track the bugs specific for each branch. We had a limited set of branches (MOSS 2007, SP 2010) so that we can track the same.

For this we need to have the TFS 2010 Power Tools installed which is available for download @ http://visualstudiogallery.msdn.microsoft.com/en-us/3e8c9b68-6e39-4577-b9b7-78489b5cb1da.

Once Power Tools is installed, we can customize the work item type by traversing thro the Tools menu of Visual Studio IDE.

Tools -> Process Editor -> Work Item Types -> Open WIT from Server.

1_open_wit 

In here, chose the required team project collection and expand the work item type (in our case Bug) from the specific team project.

2_wit

Click on New as shown below.

 3_new_wit

A new window for Field Definition opens up and key in the values as shown below.

4_field_defn 

Name: You can give in any name depending on your project requirements. In my case it is Branch.
Type: Chose from a list of available values (String, Integer, Double, Datetime etc). In this case I chose to have it as String.
Reference Name: This is the tricky part of it. Now we are going to define a custom type which is the Reference Name. There are some default types such as System.Id, System.AreaId, Microsoft.VSTS.Common.* etc which would not suit our needs for adding a custom field. Hence, we will have Reference Name as a custom defined type MyProject.Branch (thanks to Johnny Brown - my colleague for helping me to find this out).
Help Text: Help Text
Reportable: Chose from available values such as None, Dimension, Detail & Measure. For a more detailed explanation of what these values mean is explained @ http://msdn.microsoft.com/en-us/library/ms194942.aspx. Here I opted for Dimension.
Formula: This is enabled only when we chose Measure as Reportable.

And then let us move on to Rules tab.

5_rules

Click on New as shown below.

 6_rules_new

There are various Rule Types already defined like below.

 7_allowed_values

We need to choose the appropriate rule type based on our project needs. Here, I chose ALLOWEDVALUES, DEFAULT and REQUIRED.

ALLOWEDVALUES:

8_allowed_values

Click on New as shown below.

 9_allowed_values_new

which will take us to the List Item Edit window. From here we can add the values we had identified for the custom field. Here I added 3 values 2007, 2010 & Both.

10_list_item_edit

DEFAULT:

Next, we will add another rule DEFAULT.

11_default

We will select From: as value and Value: as any 1 of the values from we created during ALLOWEDVALUES.

12_default_value 

REQUIRED:

And then we will add the REQUIRED rule for which is fairly straight forward.

Finally, we will get a screen like the one shown below.

13_field_definition_ok

By clicking on OK here our new Custom Field is added to the Work Item Type -> Bug in our case. And the same should reflect as shown in the image below.

14_field_done 

Now as we have completed the creation of Custom Field, we need to move onto placing the newly created field in the layout of the Work Item. So let’s move onto Layouts tab as shown below.

15_layout 

We need to choose a location to place our newly created Custom Field. I preferred to have it along with Area & Iteration as these fields are most commonly used as filters in Reporting.

For this we need to Right Click on Column above a level to that of Area and chose New Control.

16_new_control

This will take us to the screen as shown below:

17_new_control

Onto the right, we need to modify the values of 2 fields (Label & Field Name). We will have the Label as Branch: and we can choose the Field Name from the list of available values. Here, we will have the newly created Custom Field during our previous step as one of the option.

18_field_name 

After giving the values Field Name and Label, let us have a feel of our new layout by clicking on the Preview Form as shown below.

19_preview_form

The layout should look something like below with the newly created Custom Field Branch having its values from the ALLOWEDVALUES rule we created earlier above.

20_preview_layout 

And as of now, we are not dealing with modifying the workflow. Hence I leave it here and click on Save. The Save should happen without any errors / exceptions. If it happens, we are successful in creating a Custom Field to an existing Work Item Type (wit).

To double check that we are successful in creating the Custom Field, try creating a new work item (bug) and which should land in a similar screen as shown below with the new Custom Field and its Values appearing as mentioned earlier.

21_bug_done 

The story doesn’t end here as we need to bring this newly created Custom Field into the Reports section which is much more twisting and I will explain the same in my next post here shortly.