in

Foo Theory

Partners in Community - serving up some ice cold Kool-Aid!
Welcome to footheory.com.  The bloggers and contributing members on this site are consultants, project/program managers and software architects working across the US.  Our community will focus on Microsoft technologies, .NET architecture, software patterns & practices and just plain stream of consciousness.

Bennie's Weblog

  • Software as a Service - A high level overview

    Table of Contents

    Software as a service is a term is frequently making headlines in a number of trade journals. In all articles on the subject, Software as a Service is mentioned as the "next big thing", which is going to revolutionize the software industry as we know it.

    This article will provide a high-level overview of the subject. The article structured as follows:

    1. In the first section we introduce Software as a Service (know by its acronym Saas), provide a definition and discuss some fundamental topics that form the basis for the technology. Also, since the concept of a "tenant" and "multi-tenancy" is closely associated with Saas, we will include a definition for these terms in the same section.
    2. The next section will address how Saas can mitigate the software acquisition risks for an organization.
    3. Often, a (false) rumor has been spread throughout the industry, that SaaS eliminates the need for an client organization's IT staff. In our next section, we clarify this misconception, and show how SaaS can empower an IT organization to focus on new initiatives that contribute measurable, immediate value to the client's organization.
    4. Next, we discuss the three core attributes that are essential for an effective single instance, multi-tenant application architecture.
    5. Four different maturity models have been defined for a multi-tenant SaaS application, our next section discusses these different maturity levels and their specifics.
    6. In the last section of this article, I provide the reader with some guidance of how the select the appropriate maturity level for their organization's  Saas application(s).

    This article is mostly non-technical is nature. However, I am planning to follow-up this article with a number of technical articles, where we dive into some of the more challenging areas that make it possible to create a highly scalable, configurable and multi-tenant-efficient SaaS solution.

    Introduction

    When you ask a number of software professionals for a definition of the term "Software as a Service", you will get many different, and sometimes conflicting answers. Slowly tough, more and more experts are starting to agree on the fundamental principles that define Software as a Service, and the concepts that differentiate the technology from traditional, on-premise packaged software solutions.

    The current, widely-accepted definition for Software as a Service can best be phrased as follows:

    Saas is software deployed as a multi-tenant hosted service and accessed over the Internet.

    Saas should not be confused with the services provided by traditional Application Service Providers (ASPs). An ASP typically provides a "shrink-wrapped" application to business users over  the Internet, and therefore can be better compared with a traditional on-premise IT application which has been deployed and hosted by a third-party. These applications were architected as a single-tenant application, and were not designed to share data and business process logic with other applications. Since we used the term tenant here I feel like another definition is in order:

    A tenant is a client organization, which is using an application that has been deployed as a SaaS Application.

    Multitenancy refers to the architectural principle, in which a single instance of the software runs on as Software as a Service (SaaS) vendor's servers, servicing multiple client organizations (tenants). Multitenancy can be contrasted with a multi-instance architecture, where separate software instances (or hardware systems) are set up for different client organizations. With a multitenant architecture, a software application is designed to virtually partition its data and configuration so that each client organization works with a different virtual application instance.

    A typical SaaS application is offered either directly by the vendor or by an intermediary party called an aggregator, which bundles SaaS offerings from different vendors and offers them as part of a unified application platform.

    I strongly believe that Saas is going to have a major impact on the software industry, because software as a service will change the way people build, sell, buy and use software. For this to happen though, software vendors need resources and information about developing Saas applications effectively.

    When you take a look at our definition for Saas, it should become immediately clear that it does not prescribe any specific application architecture; it does not say anything about

    Saas and Software Acquisition Risk Mitigation

    Another area in which Saas applications tend to be different as compared to on-premise software is in their licensing model. On-Premise software applications typically have a high cost of entry, either because the application has to be developed from scratch by the internal or external IT staff, or in the case of a purchased application, because of the high up-front licensing fees. In contrast, SaaS application access is typically sold based upon a subscription model. The different subscription models offered by SaaS vendors are:

    • A flat time-based fee (monthly, yearly etc.). This time-based fee will typically be much lower than the large up-front licensing fees for purchased on-premise applications.
    • Usage based upon the metered activity by the customer, where 'usage activity' can be measured in a variety of ways, including number of business transactions, number of orders processed etc.

    Some vendors will use a combination of both models, charging a flat time based fee in addition to some usage-based premium. In addition, most Saas vendors offer a "try before you buy" option, where a potential tenant has the opportunity to try out the application for a period of time before needing to make a commitment towards becoming a full-fledged customer.

    In the traditional model, deploying large scale business-critical software systems (SAP anyone ? ;-) has been a major undertaking. As we mentioned earlier, deploying these systems across a large enterprise can cost hundred of thousands of dollars in up-front licensing cost, and usually requires a small (or sometimes large  ;-) army of IT personnel and consultants to customize and integrate it with with the organization's other systems and data. The time, staff and budget requirements of a deployment of this magnitude represents a significant risk for an organization of any size, and often puts such software out of reach of smaller organizations that would otherwise be able to derive great benefits  from the applications.

    The subscription-based delivery model of SaaS applications changes this whole mindset. SaaS applications don't require the deployment of a large infrastructure at the customer's location, which eliminates or drastically reduces the upfront commitment of resources. With no significant initial investment to amortize, an enterprise that deploys a Saas application that turns out to produce disappointing results can walk away and pursue a different direction, without having to abandon an expensive on-premise infrastructure.

    Does Saas eliminate the need for an IT organization?

    One (wrong) conclusion that some people draw from the deployment of SaaS-based application is that it eliminates, or drastically reduces the need for an internal IT staff of an tenant's organization. Indeed with SaaS, the job of deploying  an application and keeping it running from day to day - testing and installing patches, managing upgrades, monitoring performance, ensuring high availability, and so forth - is handled by the provider.

    But, rather than eliminating the need for an internal IT staff, by transferring the responsibility for the above-mentioned "overhead" activities to a third-party, the IT department can focus more on high-value activities that align with and support the business goals of the enterprise. Instead of being primarily reactive and operations-focused, the chief information offices (CIO) and IT staff can more efficiently function as technology strategists to the rest of the company, working with the business units to understand their business needs and advise them on how to best use technology to accomplish their objectives.

    So, instead of being made obsolete by SaaS, the IT department has an opportunity to contribute to the success of the enterprise more directly than ever before. For example, based upon business requirements, the IT staff could create "composite applications" and "executive dashboards", which act as integrators and collectors of the valuable data contained in the different Saas applications. A successful service-centric IT organization can directly produce more value for the business by providing services that draw from both internal and external sources and align closely with the overall business goals of the organization.

    The Three Attributes of a Single Instance Multi-Tenant Architecture

    From an application's architect point of view, there are three key differentiators that separate a well-design SaaS application from a poorly designed one. A well-designed SaaS application is:

    1. Scaleable
    2. Multi-Tenant-efficient
    3. Configurable

    A graphical representation of these three important differentiators is shown below:

    SaasDifferentiators

    Scaling the application means achieving maximum  concurrently and using application resources more efficiently - for example, optimizing locking duration, statelessness, efficiently leveraging sharing pooled resources  such as thread and network connections, caching frequently used reference data, and partitioning large databases. Note that I am not stating here that a standard single-tenant application should NOT be designed  in a scaleable manner, but because of the resource-intensive nature of a multi-tenant application, these requirements are more amplified, and achieving maximum scalability is therefore even more important.

    Multi-tenancy may be the most significant paradigm shift that an architect accustomed to designing isolated, single-tenant applications has to make. For example, when a user at one company accesses customer information by using a CRM application (e.g. SalesForce.com), service, the application instance that the user connects to may be accommodating users from dozens, or even hundreds, of other companies - all completely unbeknownst to any of the users. This requires an architecture that maximizes the sharing of resources across tenants, but in such a manner that the application is still able to differentiate data belonging to different customers. For example, in a multi-tenant environment, it might be prohibitive to allocate an expensive resource, such as a WIN32 process to a single tenant (we will have more to say about this topic in the next section). Also, the architect needs to ensure 100% data privacy for each tenant while maintaining an acceptable performance for each tenant.

    Of course, if a single application instance on a single server has to accommodate users from several different companies at once, you can't simply write custom code to customize the end-user experience; anything you do to customize the application for one customer will change the application for other customers as well. Instead of customizing the application in the traditional sense, each customer uses metadata to configure the way the application appears and behaves for its users. The challenge for the SaaS Architect is to ensure that the task of configuring applications is simple and easy for the customers, without incurring extra development or operation costs for each configuration. Note that configuration is this context can apply to a number of different areas:

    1. Allowing tenants to add custom fields or tables to the database.
    2. Providing a mechanism by which a tenant can customize the user interface and the look and feel of the application (for example, in the case of a web application, the user should be able to upload custom a style sheet for the application).
    3. Allowing tenants to customize the business process workflows, by including some type of process editor in the tenant's administrator user interface.

    Saas as a Service-Oriented Architecture Maturity Model

    In the above sections, we have discussed the business and technical benefits of Saas. The biggest impact of SaaS tough might be the fact that SaaS finally provides an organization with the right incentives for moving IT towards  a services-centric model or in other words: a "real", applied SOA strategy with concrete,  tangible benefits.

    Broadly speaking, SaaS service maturity can be expressed using a model with four distinct levels. Each level is distinguished from the previous one by the addition of one of the three attributes listed above. A graphical level with the different maturity levels is shown below:

    Saas Overview

    Maturity Level I : Ad Hoc / Custom

    The first level of maturity is similar to the traditional application service provider (ASP) model of software delivery, dating back to the 1990s. At this level, each customer (or tenant) has its own customized version of the hosted application, and runs its own instance of the application on the hosts's servers. Architecturally, software at this maturity level is very similar to traditionally-sold LOB (Line-of-Business) software, in that different clients within the organization connect to a single instance running on behalf of its other customers. Note that at this maturity level, application maintenance tends to be complication and time consuming. If a common bug is found, the fix has to be integrated into the code base for each different instance, and each instance has to be individually tested, validated and re-deployed.

    Typically, traditional client-server applications can be moved to a SaaS model at the first level of maturity, with relatively little development effort, and without re-architecting the entire system from the ground up. Although this level offers few of the benefits of a fully mature Saas solution, it does allow vendors to reduce cost by consolidating server hardware and administration.

    Maturity Level II: Configurable

    At the second level of maturity, the vendor hosts a separate instance of the application for each customer (of tenant). Whereas in the first level each instance is individually customized for the tenant, at this level all instances use the same code implementation, and the vendor meets customer's needs by providing detailed configuration options that allow the customer to change how the application looks and behaves to its users. Despite being identical to one another at the code level, each instance remains wholly isolated from all others.

    Moving to a single code base for all of a vendor's customers greatly reduces a Saas application's service requirements, because any changes made to the code base can be easily provided to  all of the vendor's customers at once, thereby eliminating the need to upgrade or slipstream individual customized instances. However, repositioning a traditional application as SaaS at the second maturity level can require significant more re-architecting than at the first level, if the application has been designed for individual customization rather than configuration metadata. Therefore, it is important to note that if an enterprise architect is architecting a new application, which might be initially be deployed as a single-tenant application, but has the potential to be migrated to a multi-tenant solution, it is recommended that you take a close look at the architecture of your application, and build in some of the core "enabling" building blocks that would enable you to move to a multi-tenant solution without re-architecting the entire application.

    Similarly to the first maturity level, the second level requires that the vendor provide sufficient hardware and storage to support a potentially large number of application instances running concurrently.

    Maturity Level III: Configurable, Multi-Tenant-Efficient

    At the third level of maturity, the vendor runs a single instance that serves every customer, with configurable metadata providing a unique user's experience and feature set for each one. Authorization and security policies ensure that each customer's data is kept separate from that of other customers; and, from the end user's perspective, there is no indication that the application instance is being shared among multiple tenants.

    This approach eliminates the need to provide server space for as many instances as the vendor has customers, allowing for more more efficient use of computing resources that the second level, which translates directly into lower costs. A significant disadvantage of this approach is that the scalability of the application is limited. Unless partitioning is used to manage database performance, the application can be scaled only by moving it to a more powerful server (scaling up), until diminishing returns make it impossible to add more power cost-effectively.

    Maturity Level IV: Scalable, Configurable, Multi-Tenant-Efficient

    At the fourth and final level of maturity, the vendor hosts multiple customers on a load-balanced farm of identical instances, with each customer's kept separate, and with configurable metadata providing a unique user experience and feature set for each customer. A SaaS system is scalable to an arbitrarily large number of customers, because the number of servers and instances of the back end can be increased or decreased as necessarily to match demand, without requiring additional re-architecting of the application, and changes or fixes can be rolled out to thousands of tenants as easily as a single tenant.

    Selecting the Appropriate Maturity Level for your Application

    Given all of the above information, you might wonder what maturity level you should target for your SaaS application? Intuitively, one might expect the fourth level to be the ultimate goal for any SaaS application, but this is definitely not always the case. Indeed, it might be more helpful to think of SaaS maturity as a continuum between isolated data and code on one end, as shared data and code on the other, as is shown on the figure below:

    SelectingAMaturityModel

    Where your application should fall in this continuum depends on your business area, architectural experience and operational needs, and on customer considerations. As you'll be able to see event from this simple explanation, all of these considerations are interrelated to some degree.

    1. Business Model. Does an isolated approach make financial sense? Forsaking the economic and management benefits of a shared approach means offering your application to the consumer at a higher cost; however; under some circumstances, it may be worth it to meet other needs. In addition, customers might have strong legal (e.g HIPPAA for the health care industry) or cultural resistance to an architectural model in which multiple tenants share access to an application, even if you can demonstrated that it does not place confidential data at risk. Ultimately, of course, you'll need a business model that shows how your  application can make money at whichever maturity level you've targeted.
    2. Architectural Model. Can your application be made  to run in a single local instance, without a complete architectural overhaul? if you seeking to move a desktop-based or traditional client-server or distributed application to an Internet-based delivery system, then its architecture might be fundamentally incompatible with a single-instance, metadata-centric approach, and you may determine that it will never make financial sense to invest the development effort necessary to transform it into a fully mature SaaS application. If you are designing and building a net-native application from the ground up, you will probably have a lot more freedom to take a single-instance approach.
    3. Operational Model. Can you guarantee your service level agreements (SLAs) without isolation? You (and your legal department ;-) should carefully example the obligations imposed by any existing SLAs that you have with your existing customers, with regard to considerations such as downtime, support operations, and disaster recovery, and determine whether these obligations can be met under an application architecture in which multiple unrelated customers share access to a single application instance.

    Conclusion

    This concludes our high-level overview of SaaS. Obviously this is a very rich topic, but I hope that in the course of reading this article, you got a good basic understanding of what SaaS is, what its benefits are to an organization, the different maturity levels, and how to select a maturity level that is appropriate for your organization.

    During the course of the coming week, I will be following up on this article with a more technical paper, which will describe some of the architectural challenges associated with building a single-instance, multi-tenant efficient and scalable application, so stay tuned!

  • Team Foundation Server Extensibility - Navigating the Object Model

    Introduction

    In my previous post I introduced Team Foundation Server's customization and extensibility features. I mentioned how the TFS core functionality is exposed by means of the Team Foundation Core Services (TFCS), which are essentially a set of five different Web Services. The functionality of these web services is encapsulated by the Team Foundation Server Object Model (TFSOM), which is what Microsoft recommends you use to implement a Team Foundation extension.

    The Team Foundation Object Model is implemented in a series of assemblies, some of which we will take a detailed look at in this post. We will explore some of the core objects in this object model, and we will build a small wrapper class library, called FooTheory.TFS.TFSConnectivity. We will use this class library as our foundation to create the following custom extensibility clients:

    1. A PowerShell PSDrive provider called FooTheory.TFS.TFSProvider. This provider will allows us to treat the TFS repository as a logical drive, so we will be able to use our favorite commands such as  dir, cd, copy, new (or their "offical"cmdlet names: Get-ChildItems, Set-Location, Copy-Item, New-Item)  to manipulate TFS artifacts such as Work Items, Stored Queries, Team Projects, Reports etc.
    2. An event listener called FooTheory.TFS.EventListener. This is a WCF-based service, which can subscribe to TFS events, and receive these events through HTTP. The other clients, such as the PSDrive provider and the WPF client will be able to host this service, enabling them to be informed of any changes to their TFS artifacts of interest.
    3. A rich WPF-based client called FooTheory.TFS.TFSExplorer. This client will take full advantage of the graphical expressiveness of Windows Presentation foundation to allow the user to navigate the complete TFS object model, including Work Items, Reports, Source Code trees etc.

    An overview of the assemblies is shown in the figure below:

    MainLayers

    To start out, we will take a look at the TFSOM client assemblies which need to reference in our class library in order to implement our functionality.

    TFSOM Client Assemblies

    To leverage the functionality of the TFSOM, we need references to the following assemblies:

    DllOverview

     

    If you have Team Explorer installed on your client, these assemblies should be located in the C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies location, together with all of the TFSOM assemblies. (If you have Orcas installed, you need to substitute "Visual Studio 9" for "Visual Studio 8" in the above path). Also, if you have Team Foundation Server 2008 installed, these assemblies will be the client assemblies for the Team TFS 2008, but these assemblies are 100% backwards compatible with TFS 2005 object model, so you can use the same assemblies to access both TFS versions.

    In the next section we will take a look at the high-level design of our FooTheory.TFs.TFSConnnectivity custom class library.

    The FooTheory.TFS.TFSConnectivity assembly

    The main goal behind creating this assembly is to provide a simple API that provides access to some of the core functionality that we need to implement, for example:

    • Connecting and authenticating to a Team Foundation Server Instance.
    • Retrieving a list of all Team Projects .
    • Retrieve the Process Template of a given Team Project instance.
    • Retrieving the Microsoft Project mapping properties for a Team Project instance.
    • Subscribing and unsubscribing to a TFS Event Type.
    • Retrieving all stored Work Item Queries for a given project.
    • Executing a stored query, retrieving the resulting Work Items in the process.

    The main class in our assembly is the FooTheory.TFS.TFSConnectivity.TFSServer class. An overview class diagram of this class and its main relationships is shown in the figure below:

    Overview

    Note: The FooTheory.TFS.TFSConnectivity.dll assembly uses the Patterns & Practices Enterprise Library 3.1. Specifically, it leverages the Logging and Exception Handling blocks to enhance the robustness of the assembly. We'll have a few words to say about our usage of the Enterprise library at the end of this post.

    Next, we will take a more detailed look at the class that is at the center of the Team Foundation Server Object Model, the Microsoft.TeamFoundation.Client.TeamFoundationServer class.

    After we have a better understanding of this class, we will use our understanding of the TeamFoundationServer class to design and implement our TFSConnectivity assembly.

    The TeamFoundationServer Object

    The TeamFoundationServer object is the core object of the TFSOM. It contains the basic attributes of the Team Foundation Server that it is connected to. In addition, It provides access to the Team Foundation Core Services, as well as any other services that have been registered with Team Foundation Server, such as:

    • Version Control
    • Work Item Tracking
    • Project Templates
    • Event subscriptions

    The TeamFoundationServer object is defined in the Microsoft.TeamFoundation.Client namespace, so you will need to have a reference to the Microsoft.TeamFoundation.Client.dll if your want to use it in your code.

    You can get a reference to a TeamFoundationServer instance in one of two ways:

    • You can use the TeamFoundationFactory.GetServer() method. This is the most commonly used strategy to create a TeamFoundationServer instance. The GetServer() method of the TeamFoundationServerFactory class supports the following overloads:
      • You can only pass in the name of the server:
    public static TeamFoundationServer GetServer(string name);
    You can pass in the name of the TFS server and an object that implements the ICredentialsProvider  interface:
    public static TeamFoundationServer GetServer(
                string name, ICredentialsProvider fallbackCredentialsProvider)
    • You can also choose to call the TeamFoundationServer constructor directly. The different overloads are shown below:
    public TeamFoundationServer(String name);
    public TeamFoundationServer(
        string name,
        ICredentials credentials);
    public TeamFoundationServer(
        string name,
        ICredentialsProvider credentialsProvider);
    public TeamFoundationServer(
        string name,
        ICredentials credentials,
        ICredentialsProvider credentialsProvider);
    
    The main difference between these two approaches is the fact that the Factory method caches the instance by the Uri of the server. The first time you call GetServer() with a specific server Uri, the factory will create a new TeamFoundationServer instance, add  it to cache (indexed by the server Uri) and return it to the caller. The next time you call GetServer() with the same server Uri (regardless of the ICredentialsProvider that is passed in), you will get exactly the same Uri instance. 

    The TeamFoundationServerFactory class was initially created to support the behavior of Team Explorer. In Team Explorer, you will notice that you will get the authentication dialog the first time your bring up the Explorer, but afterwards you are no longer prompted although behind the scenes, the team explorer code might have to call the Factory's GetServer() method multiple times. But, since the code is calling the GetServer() method with the same server Uri each time, you will NOT be prompted again.

    When you call the TeamFoundationServer constructor directly, you are obviously creating a new instance each time.

    As far as passing in credentials, you have basically two choices:

    • You can pass in a reference to an object that implements the ICredentialsProvider interface. While you can pass in any instance that implements this interface, in a UI-based scenario you probably would want to use Microsoft.TeamFoundation.Client.UICredentialsProvider class. When you create a new instance of this class, it will automatically pop up the authentication dialog. So the following code:
                    // Create an instance of the UICredentialsProvider.
                    // Note that creating this instance will automatically
                    // popup the TFS authentication dialog
                    ICredentialsProvider provider = new UICredentialsProvider();

    Will popup the following dialog:

    TFSLogindialog

    • You can pass in any NetworkCredential instance, for example:
                    // Create our Network Credentials
                    NetworkCredential credentials = new NetworkCredential(TFSUserName, TFSPassword);
    

    Implementation in the FooTheory.TFS.TFSConnectivity Library

    Connecting to Team Foundation Server

    The FooTheory.TFS.TFSConnectivity.TFSServer class contains an embedded instance of a TeamFoundationServer instance in the m_tfsServer field, and exposed through the TeamFoundationServer property:

            // This is our Team Foundation Server instance
            private TeamFoundationServer m_tfsServer;
    
            /// <summary>
            /// This read-only property returns our current
            /// TeamFoundationServer instance
            /// </summary>
            public TeamFoundationServer TeamFoundatonServer
            {
                get { return m_tfsServer; }
            }
    

    The TFSServer class offers three overloads for the Connect() method, as shown below:

            public bool Connect(string serverName)
    
            public bool Connect(string serverName, NetworkCredential credentials)
    
            public bool Connect(string serverName, ICredentialsProvider credentialsProvider)
    

    The first overload does not take any type of credentials, and will use the UICredentialsProvider to pop up the connect dialog shown in the previous section. The other overloads either take a NetworkCredential or an object that implements ICredentialsProvider. After successfully connecting and authenticating, a reference to the TeamFoundationServer object instance is stored in the m_tfsServer field.

    The full implementations of the different Connect methods is shown below:

       1: /// <summary>
       2: /// This overload of the Connect Method will prompt
       3: /// the users for a set of credentials, by means of the
       4: /// UICredentialsProvider. It then calls our "generic"
       5: /// connect method, which takes an ICredentialsProvider
       6: /// as its second argument
       7: /// </summary>
       8: /// <param name="serverName"></param>
       9: /// <returns></returns>
      10: public bool Connect(string serverName)
      11: {
      12:     using (new Tracer(LoggingCategoryConstant.TFS_CONNECTIVITY_CONNECT))
      13:     {
      14:         //  Create an instance of our Creditials by means of the
      15:         //  UICredentialsProvider. Since we are using the 
      16:         //  UICredentialsProvider here, this  method will popup 
      17:         //  an authentication dialog for us and create a set 
      18:         //  of Credentials for us, which are passed to our other 
      19:         //  Connect overload that takes a generic 
      20:         //  ICredentialsProvider argument
      21:         // Create an instance of the UICredentialsProvider.
      22:         // Note that creating this instance will automatically
      23:         // popup the TFS authentication dialog
      24:         ICredentialsProvider provider = new UICredentialsProvider();
      25:         return Connect(serverName, new UICredentialsProvider());
      26:     }
      27: } // method Connect
      28:  
      29: /// <summary>
      30: /// This overload of the Connect Method takes a NetworkCredential.
      31: /// This method is typically used from a server client, which does
      32: /// not have the possibility to prompt the client for a username/password
      33: /// </summary>
      34: /// <param name="serverName"></param>
      35: /// <param name="credentials"></param>
      36: /// <returns></returns>
      37: public bool Connect(string serverName, NetworkCredential credentials)
      38: {
      39:     using (new Tracer(LoggingCategoryConstant.TFS_CONNECTIVITY_CONNECT))
      40:     {
      41:         //  Log our parameters
      42:         addLogEntry(
      43:             LoggingCategoryConstant.TFS_CONNECTIVITY_TRACE,
      44:             "Connect method with ServerName and Credentials Called",
      45:             EventIdentifier.ConnectToTfs,
      46:             EventPriority.StandardPriority,
      47:             TraceEventType.Verbose,
      48:             createCredentialsContextInfo(serverName, credentials));
      49:  
      50:         // Create our Network Credentials
      51:         NetworkCredential credentials = new NetworkCredential(TFSUserName, TFSPassword);
      52:  
      53:         // Here, we can pass the network credentials directly to the
      54:         // TeamFoundationServer constructor, so we have no need to used
      55:         // the factory here. You cannot use the factory methods with any 
      56:         // object instance that implements ICreditials, but it is supported
      57:         // in the standard constructor, as we are using it here
      58:         try
      59:         {
      60:             m_tfsServer = new TeamFoundationServer(serverName, credentials);
      61:             m_tfsServer.Authenticate();
      62:  
      63:             //  If we succcessfully authenticated, we can go ahead an extract
      64:             //  some reference to some commonly used service interfaces
      65:             if (m_tfsServer.HasAuthenticated)
      66:             {
      67:                 extractServiceInterfaces();
      68:             }
      69:         }
      70:         catch (Exception ex)
      71:         {
      72:             bool rethrow = ExceptionPolicy.HandleException(ex, ExceptionPolicyName.EXTERNAL_LIBRARY_POLICY);
      73:             if (rethrow)
      74:             {
      75:                 throw;
      76:             }
      77:         }
      78:     }
      79:  
      80:     // Return the authentication status
      81:     return m_tfsServer.HasAuthenticated;
      82:  
      83: } // method Conection
      84:  
      85: /// <summary>
      86: /// This is our "generic" Connect method. This method takes any object 
      87: /// instance that implements ICredentialsProvider. It uses the 
      88: /// TeamFoundationServerFactory GetServer method to retrieve the 
      89: /// TeamFoundationServer implementation
      90: /// </summary>
      91: /// <param name="serverName"></param>
      92: /// <param name="credentialsProvider"></param>
      93: /// <returns></returns>
      94: public bool Connect(string serverName, ICredentialsProvider credentialsProvider)
      95: {
      96:     using (new Tracer(LoggingCategoryConstant.TFS_CONNECTIVITY_CONNECT))
      97:     {
      98:         //  Log our parameters
      99:         addLogEntry(
     100:             LoggingCategoryConstant.TFS_CONNECTIVITY_TRACE,
     101:             "Connect method with ServerName and Credentials Called",
     102:             EventIdentifier.ConnectToTfs,
     103:             EventPriority.StandardPriority,
     104:             TraceEventType.Verbose,
     105:             createCredentialsContextInfo(serverName, credentialsProvider));
     106:  
     107:         // Create a TeamFoundationServer instance through the factory,
     108:         // and authenticate
     109:         try
     110:         {
     111:             m_tfsServer =
     112:                 TeamFoundationServerFactory.GetServer(serverName, credentialsProvider);
     113:             m_tfsServer.Authenticate();
     114:  
     115:             //  If we succcessfully authenticated, we can go ahead an extract
     116:             //  some reference to some commonly used service interfaces
     117:             if (m_tfsServer.HasAuthenticated)
     118:             {
     119:                 extractServiceInterfaces();
     120:             }
     121:         }
     122:         catch (Exception ex)
     123:         {
     124:             bool rethrow = ExceptionPolicy.HandleException(ex, ExceptionPolicyName.EXTERNAL_LIBRARY_POLICY);
     125:             if (rethrow)
     126:             {
     127:                 throw;
     128:             }
     129:         }
     130:  
     131:     }
     132:     // Return the authentication status
     133:     return m_tfsServer.HasAuthenticated;
     134:  
     135: } // method Connect

    The first connect method uses the UICredentialsProvider class to retrieve the credentials from the user, and then calls the third overload of the Connect() method, which uses the TeamFoundationFactory.GetServer() method to connect to the Server, and the TeamFoundationServer's Authenticate() method to authenticate with the server.

    The second Connect() overload accepts a NetworkCredential. Since the factory does not have an overload that takes an object that implement ICredentials, this method directly calls the TeamFoundationServer constructor, which does have an overload that accepts an ICredentials object instance.

    Also, note that after successfully connecting and authenticating to the TFS server, all overloads call the extractServiceInterfaces() private method. This method extracts all relevant service interfaces from the TeamFoundationServer instance, and cache them as fields of the class, as is shown below:

            /// <summary>
            /// This method extract our most commonly used service interface
            /// from the TFS Server instance, and caches them in our private
            /// fields
            /// </summary>
            private void extractServiceInterfaces()
            {
                if (m_tfsServer != null)
                {
                    m_commonStructureSvc = (ICommonStructureService)m_tfsServer.GetService(typeof(ICommonStructureService));
                    m_workItemStore = (WorkItemStore)m_tfsServer.GetService(typeof(WorkItemStore));
                    m_processTemplateSvc = (IProcessTemplates)m_tfsServer.GetService(typeof(IProcessTemplates));
                    m_eventService = (IEventService)m_tfsServer.GetService(typeof(IEventService));
                }
            } // method extractServiceInterfaces

    Note how we use the GetService(typeof(xxx)) pattern to retrieve each interface and/or object references (only the WorkItemStore is a object reference, all the others are interface references).

    Retrieving Project Information

    ... coming soon ...

  • An Introduction to Team Foundation Server Extensibility

    Introduction

    A large number of developers are using Team Foundation Server for a variety of tasks such as Source Control, Bug Tracking, Requirements gathering, running nightly builds and managing the overall life cycle of a software development project.

    Visual Studio Team System provides rich integration with Team Foundation Server through Team Explorer, which provides the basic connectivity to TFS. Users can use Source Control Management to manage their source code, manage Work Items, create Build types, run Unit Tests and Load Tests, run one of many SQL Server 2005 Reporting Services-based Team Reports etc.

    In addition to Visual Studio, Office 2003 and Office 2007 also offer direct or indirect connectivity to Team Foundation Server. You can have Work Items show up as Tasks in Outlook 2007, you can export a Microsoft Project 2003 schedule to TFS, creating Work Items in the process, or you can export and import your Work Items to and from Excel 2007.

    Even if you are working outside of the realm of the  .NET and the Microsoft development platform, you can use the TeamPrise plug-in for Eclipse to provide connectivity from your favorite Java development environment to Team Foundation Server.

    What a lot of people don't realize is that Team Foundation Server also offers a powerful development object model, empowering the developer to create custom development tools, specialized clients, custom WebParts for a Team Project SharePoint portal and so on. Team Foundation Server was developed from the ground up with extensibility in mind. Indeed, TFS itself is build upon the Team Foundation Core Services, which are a set of Web Services used by Team Foundation Server itself to implement the different functional areas for Team Foundation Server.

    As a developer, you will seldom have a reason to directly use the Team Foundation Core services. Indeed, Microsoft created the Team Foundation Server Object Model to increase the productivity of the TFS developer. The classes in this object model interact with the Web Services of the Team Foundation Server Co