Blackbaud.AppFx.WebAPI.dll

Note: For examples that use Blackbaud.AppFx.WebAPI.dll, see AppFxWebService.asmx API.

Note: Blackbaud.AppFx.WebAPI.dll is a wrapper API for AppFxWebService targeted to .NET developers.

When you write a custom .NET client application, you can add a web reference to the AppFxWebService that uses WCF or add a classic SoapClient web reference. Alternatively, you can reference the Blackbaud.AppFx.WebAPI.dll assembly that we describe in this article within your client project, which is just a standalone assembly with only the generated SOAP client classes for the AppFxWebService. If you installed the Infinity SDK, you may find the Blackbaud.AppFx.WebAPI.dll within SDK\DLLReferences folder. In this scenario, we have access to all the platform features through the AppFxWebService. However, this service is late bound, loosely typed, and not the easiest to use.

So the AppFxWebService.asmx is a single SOAP endpoint that allows you to invoke the various features that are defined. This endpoint routes invocations to all business operations of the same category through a common web method that is parameterized by the ID or Name of the operation that is invoked. For example, the following code (from the Blackbaud CRM SDK WebAPIDemo sample) shows how to call the "Constituent Search" record search operation. You can see from the code that one parameter to the web method is the ID of that specific operation (yellow highlight) and that the filter (green highlight) and output are defined in a loosely typed fashion. This is required because the SearchListLoad method (orange highlight) is used for all searches, and a different search such as the "Event Search" will have a different set of parameters and filters

Private Sub btn_Search_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Search.Click 

        Try 
            InitAppFxService() 

            'create a request to invoke the Constituent Search from the Blackbaud.AppFx.Constituent.Catalog 
            Dim req As New ServiceProxy.SearchListLoadRequest 
            req.ClientAppInfo = GetRequestHeader() 
            req.SearchListID = New Guid("23C5C603-D7D8-4106-AECC-65392B563887") 

            'create a field value set to hold any filters we want to pass in 
            Dim fvSet As New DataFormFieldValueSet 

            'add a field value for each filter parameter.  In this case, we're using the quickfind feature and passing in the FULLNAME.  Note that 
            'we also have to include to search only primary addresses, to avoid getting multiple rows in the output if the record has multiple 
            'addresses. 
           fvSet.Add(New DataFormFieldValue("FULLNAME", txt_ConstituentSearch.Text)) 
            fvSet.Add(New DataFormFieldValue("ONLYPRIMARYADDRESS", True)) 

            'create a dataform item to contain the filter field value set 
            Dim dfi As New DataFormItem 
            dfi.Values = fvSet 

            'pass the filter dataform item to the request 
            req.Filter = dfi 

            'invoke the search 
            Dim reply As ServiceProxy.SearchListLoadReply = _service.SearchListLoad(req) 

            Dim selectedRow As ServiceProxy.ListOutputRow = Nothing 
            If reply.Output.RowCount = 0 Then 
                MsgBox("No records were found.", MsgBoxStyle.Information) 
            ElseIf reply.Output.RowCount > 1 Then 
                Using f As New SelectSearchResultsForm(_service, GetRequestHeader(), req.SearchListID, reply) 
                    If f.ShowDialog = Windows.Forms.DialogResult.OK Then 
                        selectedRow = f.SelectedRow 
                    End If 
                End Using 
            Else 
                selectedRow = reply.Output.Rows(0) 
            End If 

            If selectedRow IsNot Nothing Then 
                Dim recordID As Guid = New Guid(selectedRow.Values(0)) 
                Dim name As String = selectedRow.Values(1) 
                txt_ConstituentSearch.Text = name 
                LoadRecord(recordID) 
            End If 

        Catch exSoap As System.Web.Services.Protocols.SoapException 
            'If an error occurs we attach a SOAP fault error header. 
            'You can check the proxy.ResponseErrorHeaderValue to get rich 
            'error information including a nicer message compared to the raw exception message. 
            Dim wsMsg As String 
            If _service.ResponseErrorHeaderValue IsNot Nothing Then 
                wsMsg = _service.ResponseErrorHeaderValue.ErrorText 
            Else 
                wsMsg = exSoap.Message 
            End If 
            MouseWaitStop() 
            MsgBox(wsMsg) 

        Catch ex As Exception 
            MouseWaitStop() 
            MsgBox(ex.Message) 

        End Try 

    End Sub

The above sample shows that it is relatively easy to invoke any search operation that is available in the application as long as you know the ID, the filter parameter names, and the offsets of the output fields. The other categories of operations such as "Create Record" or "Delete Record" follow a similar pattern with a distinct web method for each kind of operation that is parameterized by the ID of the operation to be invoked.

There’s a Visual Studio Template for That…

One of the cool things about the Infinity SDK is all of the Visual Studio templates to create projects and Infinity features/specs. One such template is the "Web API Client Template."

This template helps you to jump start a project by automatically creating a reference to Blackbaud.AppFx.WebApi, Blackbaud.AppFx.XMLTypes, Blackbaud.AppFx.dll, among others. Here is a newly created project based on this and its assembly references.

The template stubs out some code within Module1.vb to initialize the appfxwebserviceprovider class, display a data form outside of the Infinity shell ShowDataFormExample(), display a search list outside of the shell ShowSearchExample(), and, within the WebApiExample(), add an individual through the Blackbaud.AppFx.Constituent.Catalog.WebApiClient.AddForms.Constituent.IndividualSpouseBusinessAddForm namespace within the within the Blackbaud.AppFx.Constituent.Catalog.WebApiClient.dll.

Note: To use the WebApiExample(), you need to add a reference to the Blackbaud.AppFx.Constituent.Catalog.WebApiClient.dll assembly and comment out the appropriate code within the sub.

As a quick example, I modified Module1.vb in the following ways:

  1. Placed a call to the ShowSearchExample() sub within Main(). ShowSearchExample utilizes the DataFormWebHostDialog component to display the search list feature.

  2. Uncommented the following line of code within ShowSearchExample(). This provides the appropriate security credentials to the Infinity application that verifies the current domain user to see if the user has permissions to use the search list. For information about how to secure Infinity features, see Add Features to Infinity System Role.

    form.Credentials = System.Net.CredentialCache.DefaultCredentials

To start the project, I press F5 and the search list appears outside the Infinity shell. How cool is that? I can look for a constituent and when I click the Select button, a message box shows me the name of the selected constituent.

Pros of the Blackbaud.AppFx.WebAPI.dll

  • Lightweight

  • Lower level

  • General purpose/access any Infinity feature from a .NET app

  • The Blackbaud.AppFx.WebAPI.dll eases some of the burden of talking to the AppFxWebService when authoring a custom .NET application.

Cons of the Blackbaud.AppFx.WebAPI.dll

  • Still cumbersome to use since it's basically a wrapper around the AppFxWebService.asmx

  • Still not focused on individual, specific features

  • Not meant for non-.NET client applications such as PHP, Java, etc.

For more background information about Infinity Web APIs, see:

Introduction to the Infinity Web Service APIs

Or a for a more in depth discussion, see:

API Overview