This project is read-only.
v1.3

Installation

The installation is fairly simple. Just run the exe. This will create a service on your local computer and all the appropriate files in the correct folders.

You will not be able to start the service before you have configured it!

Configuration

You will need to configure the application to work with your team server. This has a number of steps:
  • Change the account that the service runns under

To allow the service to run correctly it must have permission to perform certain operation on your Team Foundation Server. To this end you need to set the account that the service runs under to TFSService or TFSSetup. I have used TFSSetup for all my tests.
You can do this by locating the service in the Service Manager and right clicking on it, selecting "properties" nad viewing the "Log On" tab. You should then set the account to an existing account with the desiered permissions for TFS.
  • Edit the application.config file to suit your needs

There are a number of config options for the TFS Event Handler Prototype. I will describe all of them in depth here. The first step is to set the WCF service options, which really only requires you to change one value.
<system.serviceModel>
        <services>
            <service name="RDdotNet.TeamFoundation.NotificationService">
                <endpoint address="http://[LocalMacheneName]:8677" binding="basicHttpBinding"
                    bindingConfiguration="" contract="RDdotNet.TeamFoundation.INotificationService" />
            </service>
        </services>
    </system.serviceModel> 

The important one is the LocalMacheneName variable, which should be set to the local machine name, or the domain name that points to your computer if you have a crazy proxy.

The next step is to set the real options for this software. This starts with the <RDdotNet.TeamFoundation> options and requires you to set a number of things.
<BaseAddress url="http://[LocalMacheneName]:3624/" />

Again you need to set the machine name, but make sure that the port is different.
<TeamServers>
            <TeamServer name="[TFS Server Name]"
                        url="http://[TFS Server Name]:8080/"
                        subscriber="[Subscriber AD Account]"
                        mailAddressFrom="[From Email Address]"
                        mailFromName="[Form name]"
                        mailServer="[email relay server]"
                        logEvents="True"
                        testMode="True"
                        testEmail="[email to send testes to]"
                        eventLogPath="C:\temp\TFSEventHandler\">
            </TeamServer>
        </TeamServers>

In the Team Servers section you need to list all of the team servers that you are going to be handling events for. The system will automatically add the event subscriptions for all team servers added here, but I have only tested with two and I now always run the service on the TFS server.

TeamServer Options

Name Type Description
name System.String This should be a friendly name for the team foundation server
url System.Uri The URI for the TFS server you wish to connect to including protocol and port.
mailFromAddress System.String The address from which you want all emails sent by the system to say that they are sent.
mailFromName System.String The display name of the from email address
mailServer System.String The mail server that you have permission for to send emails
logEvents System.Boolean A true or false value that enables logging of all events within that system. Excellent for debugging...
testMode System.Boolean When in test mode all emails sent by the system will only be sent to email address defined by testEmail. Set to false for production.
testEmail System.String The email address that, when testMode is enabled will receive all emails sent from the system.
eventLogPath System.String the location that the event logs will be written to. All events received get assigned a System.Guid and all logs pertaining to that event get saved in the corresponding folder.
subscriber System.String The AD account name of the account that is writing the events. Set to the name of your TFSSetup or TFSService accounts.




Now you are ready to set the event handlers. These are defined within the "Events" section:
<Events>
            <!-- 
                        Use one of the following events:
                                        AclChangedEven
                                        Branchmovedevent
                                        BuildCompletionEvent
                                        BuildStatusChangeEvent
                                        CommonStructureChangedEvent
                                        DataChangedEvent
                                        IdentityChangedEvent
                                        IdentityCreatedEvent
                                        IdentityDeletedEvent
                                        MembershipChangedEvent
                                        WorkItemChangedEvent)
                        Then you need to add handlers for the events.
                                          
                   Example:
                           <Event eventType="WorkItemChangedEvent">
                                <Handlers>
                                    <Handler type="RDdotNet.TeamFoundation.WorkItemTracking.AssignedToHandler"
                                             assemblyFileName="RDdotNet.TeamFoundation.WorkItemTracking.AssignedTo.dll"
                                             assemblyFileLocation="~\EventHandlers\WorkItemTracking\">
                                    </Handler>
                                </Handlers>
                            </Event>
                    -->
            <Event eventType="WorkItemChangedEvent">
                <Handlers>
                    <Handler type="RDdotNet.TeamFoundation.WorkItemTracking.AssignedToHandler"
                             assemblyFileName="RDdotNet.TeamFoundation.WorkItemTracking.AssignedTo.dll"
                             assemblyFileLocation="~\EventHandlers\WorkItemTracking\">
                    </Handler>
                </Handlers>
            </Event>
        </Events>

As you can see you are theoretically allows to us any events. Please keep in mind that only the WorkItemChangedEvent and the CheckInEvent have been tested. When you add the "Event" tag with the corresponding eventType (which is an enumerator) this tells the system which specific events to subscribe to.

You can then add handlers to an event. These handlers are fired whenever these events are received.

Name Type Description
eventType RDdotNet.TeamFoundation.EventTypes Enumerator that defines the list of possible events.
type System.Type This must be a valid type in the assembly listed in assemblyFileName
assemblyFileName System.String This must be a valid assembly found in the assemblyFileLocation
assemblyFileLocation System.String A location within the servers file system that holds this assembly. ~ denotes the applications root.



If you are using friendly server names or TeamPlain the you can change the TFS server links to be TeamPlain ones using the UrlReplacements config element:

<UrlReplacements>
            <!-- The Url Replaces change the url listed in the event to valid public items
            Examples:
                This item changes the TFS url to a TeamPlain v1 url
                <Replace eventType="WorkItemChangedEvent" 
                                         old=":8080/WorkItemTracking/WorkItem.aspx?artifactMoniker=" 
                                        new="/workitem.aspx?id=" />
                            
                These items change the server location to a public host header:
                <Replace eventType="WorkItemChangedEvent" 
                                         old="[ServerProductionEnviromentName]" 
                                         new="[PublicProductionEnviromentUri]" />
                <Replace eventType="WorkItemChangedEvent" 
                                         old="[ServerDevelopmentEnviromentName]" 
                                         new="[PublicDevelopmentEnviromentUri]" />
            -->
</UrlReplacements>


This works by replacing values within the URL in the events. You specify the event type, what to look for and what to replace it by. This allows grater control and the integration of TeamPlain into your world. If a task is assigned to someone outside of your departmental sphere who you have given permission to TFS but who know nothing about it, they will still get an email that will link them through to TeamPlain.

And that is you all set. if you have installed the service and set the account that is used to run the service you should get no errors when starting. No guarantees though :)
  • Test the service

comming soon
  • Turn off Debug Mode

When you have completed testing and are sure that it workd, all you have to do is change the testMode property to False and restart the service.

<TeamServers>
            <TeamServer name="[TFS Server Name]"
                        ...
                        testMode="True"
                        ...
            </TeamServer>
        </TeamServers>

Extensibility

Creating an event handler with the Team Foundation Server Event Handlers is very easy. You will need to inherit from the AEventHandler class which is part of RDdotNet.TeamFoundation.dll located in the install directory (I will make an SDK later).
Imports Microsoft.TeamFoundation.Client

Public MustInherit Class AEventHandler(Of TEvent)

    Public MustOverride Sub Run(ByVal EventHandlerItem As EventHandlerItem(Of TEvent), _
                                               ByVal ServiceHost As ServiceHostItem, _
                                               ByVal TeamServer As TeamServerItem, _
                                               ByVal e As NotifyEventArgs(Of TEvent))

    Public MustOverride Function IsValid(ByVal EventHandlerItem As EventHandlerItem(Of TEvent), _
                                               ByVal ServiceHost As ServiceHostItem, _
                                               ByVal TeamServer As TeamServerItem, _
                                               ByVal e As NotifyEventArgs(Of TEvent)) As Boolean

End Class

Both of the methods that the AEventHandler exposes have the same signature. Hear is what it all means...

Name Type Description
EventHandlerItem EventHandlerItem(Of TEvent) The event handler item contains information about the handler. This includes an instance of the config data, the handler its self and a status property. The TEvent generic makes sure that everything is strongly types for the event that you are dealing with.
ServiceHost ServiceHostItem Base Address of the service, Event Type, Host Config data and a link to the service host object.
TeamServer TeamServerItem Config data for the team server as well as an instance of the Microsoft.TeamFoundation.TeamFoundationServer object

e NotifyEventArgs(Of TEvent) This object allows access to all of the event specific data including the event object, the event type, the TFS Identity object and the TFS Subscription object. |

Lets look at the implementation that comes with the TFS Event Handler, the "AssignedToHandler". The IsValid method denotes wither the handler will acrualy run at all:
    Public Overrides Function IsValid(ByVal EventHandlerItem As EventHandlerItem(Of WorkItemChangedEvent), _
                                                    ByVal ServiceHost As ServiceHostItem, _
                                                    ByVal TeamServer As TeamServerItem, _
                                                    ByVal e As NotifyEventArgs(Of WorkItemChangedEvent)) As Boolean
        If e.Event Is Nothing Then
            Return False
        End If
        Dim assignedName As String = WorkItemEventQuerys.GetAssignedToName(e.Event)
        If String.IsNullOrEmpty(assignedName) Then
            Return False
        Else
            Return Not assignedName = WorkItemEventQuerys.GetChangedByName(e.Event)
        End If
    End Function

This method initially checks to see if the event exists and then queries the assigned name from the event using a work item event query which consists of:
Return eventData.CoreFields.StringFields.Find(New Predicate(Of StringField)(AddressOf FindAssignedTo)).NewValue

All this does is search the String fields associated with the core work item bits to find the "System.AssignedTo" value. You could so this manually, but I have a number of queries there and you can add any number you wish.

The logic: If Event exists and assigned name is not empty then check that the assigned name is not the changed name.

So in English with all of the crap split out: Did the user assign the work item to himself? If not then send them an email!

The rest, as they say, is just logic. The "Run" method calls the "IsValid" and then sends an email if it is in fact valid, hardly rocket science.

Last edited Jun 19, 2007 at 9:15 AM by hinshelmw, version 14

Comments

No comments yet.