
The developer community, including those vested deeply in the Microsoft .NET platform, has expressed particular interest in using Force.com Web Services to expose data and business logic from the Force.com platform to custom, external applications.
This article will show you how to create custom Force.com logic that you can call from within a Force.com application or from within a custom ASP.NET application hosted outside Salesforce.com. You will learn how to do the following:
When finished with the article, you will understand how to do the following:
This article provides a basic, high-level demonstration of Visualforce. For a more comprehensive introduction to Visualforce, I suggest that you read Jon Mountjoy’s Force.com Tutorial: An Introduction to Visualforce.
Before we move forward, let’s define exactly what “calling custom Force.com logic from Visualforce pages and ASP.NET Web forms” actually looks like. Figure 1 illustrates how Force.com Apex code, exposed as a Web Service to an ASP.NET Web form, pulls data out of Salesforce.com and displays it to a user viewing an ASP.NET Web page.
In order to make this process happen, several systems must connect:
For this walk-through, you will need Visual Studio 2005 (using Microsoft Visual Basic) and Visualforce. If you don’t already have Visual Studio, you can [ http://msdn2.microsoft.com/en-us/express/aa975050.aspx download] a free copy of Microsoft Visual Web Developer 2005 Express Edition. You can use Visualforce to create unique user experiences and data interactions for use within your Force.com applications. Unlike Visual Studio, Force.com applications are available on-demand, through your Web browser. There is no software to install. Of course, you will need a Salesforce.com Developer Edition account with Visualforce enabled.
You don’t need to use live company data and risk making a mess of things: Force.com Developer Edition accounts are free and easy to create. By joining the developer.force.com (DFC), you get a Developer Edition account as well as access to developer forums and other member benefits. Signup for your free Force.com Developer Edition account.
Code that is written in a Microsoft .NET language (such as Visual Basic.NET or C#) is compiled into a Microsoft .NET assembly (a file with an.exe or .dll extension). Microsoft .NET assemblies are hosted by the Microsoft .NET Runtime, which must be installed on your computer (or Web server, if your application is an ASP.NET Web application). This Microsoft .NET runtime provides services to your application, manages memory and security to the user’s computer, and so forth.
Similarly, Force.com pages are hosted by the Force.com platform, which provides services such as security and memory management to your application. The primary difference between these two approaches is that you don’t need to set up any servers or configure any software to begin coding with Force.com. Salesforce.com does all the setup and configuration for you. Furthermore, Salesforce.com handles future upgrades so that you don’t have to worry about software updates, patches, or service packs.
Apex code, the procedural language that is a part of the Force.com platform, is very rigorous. You host your code in the Force.com platform, which in turn is hosted by Salesforce.com, so the code is checked for consistency and syntax when it is compiled for you. The code runs on Salesforce.com servers and therefore is multi-tenant and automatically upgradeable. Your custom methods and objects get all the scalability of the Force.com platform. Your Apex code won’t break when Salesforce.com introduces a new release of Force.com.
You don’t need to know how Force.com works internally to be productive and build applications quickly … but a little knowledge won’t hurt. For more information about the Force.com platform, visit the Platform page and read the Force.com whitepaper
To expose business logic from Force.com to your application, you have two choices:
You will use the Apex Class Editor in either option, but a Force.com Web Service provides the additional benefit of letting external applications access your Force.com business logic and data.
Fortunately, you can take advantage of both options simply by adding the global keyword in front of the class name, as Figure 2 shows. In this article, I will show you how to use the global keyword with your class so that your service can be available to your Visualforce application as well as to the ASP.NET Web page that we’ll create by using Visual Studio .NET.
To create a Force.com Web Service, you must first create an Apex class. To create an Apex class, log into your Developer Edition account, click Setup / App Setup / Build / Code, then click New. Next, add the following code into the body of the Apex Class Editor:
global class getLeadInfo {
}
Click Save.
You put your Force.com business logic into a custom Apex method. To create your method, you’ll use Apex code, which runs within the Force.com platform and is available within other Force.com classes. As Figure 3 shows, this code contains a method called getLeadAddressByEmail, which uses Salesforce Object Query Language (SOQL) to look up a Lead record based on an email address. The query returns a lead object with only the Street, City, State, and PostalCode attributes.
To expose the methods in your Apex class as a Force.com Web Service, all you need to do is use the webService annotation within a global class. Also be sure to use the static keyword, which is required for all Force.com Web Services. And of course, you’ll need to write the Web Service code. The following code is the same as in the previous sample. Global and static have been highlighted for emphasis.
global class getLeadInfo {
WebService static Lead getLeadAddressByEmail(string LeadEmail) {
Lead c = [SELECT Street, City, State, PostalCode from Lead WHERE Email = :LeadEmail];
Lead l = new Lead(Street = c.Street, City = c.City, State = c.State, PostalCode = c.PostalCode);
return l;
}
}
Once you have created your Force.com Web Service, you can generate the Web Service Definition Language (WSDL) document that describes the Web Service. This document will come in handy later in the process, when you use the Visual Studio Web Reference wizard to access the Force.com Web Service. (This step is described in “Creating a Web Reference”.)
During Dreamforce 2007, Salesforce.com announced Visualforce: a new tool to create custom user interfaces and data interactions for the Force.com platform. Visualforce is a feature that developers can use to create a customized application user interface. You can use Visualforce to shape the presentation of your Force.com applications by combining data from multiple Force.com objects. You can also use Visualforce to blend data from Web Services into your applications so that you can create special-purpose mash-up applications.
Let’s create a Visualforce page that enables you to use an email address to look up a lead in Salesforce.com and return the lead’s mailing address. We will use the Force.com Apex Class (“getLeadInfo”) that we created in the previous section. Figure 4 illustrates how a Force.com Web Service, exposed to a Visualforce page, pulls data out of Salesforce.com and displays it to the user.
To get started, create a Web page. As I mentioned earlier, creating a Force.com page within Visualforce is easy. Just type in the URL of the page you want to create, for example, https://na2.salesforce.com/apex/leadLookup1 (again, replace na2 with the subdomain that you see when you are logged into salesforce.com). You should see a page similar to the one that Figure 5 shows.
Click Create page leadLookup1 to create your page. You will see a page similar to the one in Figure 6. Drag the top of the lower frame a few inches higher to see the Visualforce Page Editor.
In the lower frame, the Visualforce Page Editor shows you the code that makes up your page; in the upper frame, you’ll see a preview of the page. As you can see from the Visualforce Page Editor, a page is a combination of standard HTML elements and Apex tags. Visualforce also supports JavaScript, style sheets, Cascading Style Sheets (CSS), and most other capabilities with which Web developers are familiar, such as those available in Adobe Flash and Microsoft Silverlight.
To understand Visualforce, it is helpful to understand the Model-View-Controller (MVC) design pattern. MVC is a common way of architecting applications and is used in a variety of application development frameworks. Many developers will find this pattern familiar.
At the heart of MVC is the idea of separating the user experience into three component roles:
For those of you familiar with ASP.NET, the role of Model is often played by a DataSet or DataTable. A typed ASP.NET DataSet, for example, can play the Model role by representing the data in your database. The View and Controller roles, however, can be translated only loosely into ASP.NET. The View role, for example, is usually handled by the .aspx file, and the role of Controller is partially handled by the code-behind page (e.g., .aspx.vb).
In Visualforce, the MVC roles are clearer. Standard and custom Salesforce objects play the Model role is. The Visualforce page handles the View role. And the Visualforce Controller handles the Controller role.
Note that in an October 2007 blog post, Scott Guthrie discussed the announcement that Microsoft is in the process of creating an ASP.NET MVC framework for developers to use within Visual Studio. While this framework won’t be on demand like Visualforce, it may make it easier for developers to switch back and forth between the two environments.
To access your Apex class (which has been exposed as a Web Service) from within Visualforce, you first need to create an entry page. Let’s use the leadLookup1 page that you created in the previous section. Next, add the following code to your Page Editor:
<apex:page controller="leadLookupController">
<apex:form>
<apex:pageBlock title="Lead Search">
<apex:outputLabel value="Email" />:
<apex:inputText value="{!searchString}" />
<apex:facet name="footer">
<apex:outputPanel>
<apex:commandButton action="{!step2}" value="Search" />
</apex:outputPanel>
</apex:facet>
</apex:pageBlock>
</apex:form>
</apex:page>
Each Apex tag represents a Visualforce Component. For example, an outputLabel is an HTML control used to display a label for another component, such as the inputText. An inputText is an HTML control that acts as an input box for submitting information, such as the searchString variable. A commandButton is a control similar to an HTML button and can be set to submit, reset, or image. For a list of all Visualforce Components, click Component Reference ( in the same Web page section as Save).
This code sample also includes a reference to the page controller. To create a controller, add the controller attribute to the Apex page tag, as follows:
<apex:page controller="leadLookupController">
As soon as you click Save, you will receive an error message stating “Error: Apex class 'leadLookupController' does not exist”. This is expected behavior. Click Create Apex class 'leadLookupController'. You will get another error message stating “Error: Unknown property 'leadLookupController1.searchString'”. Again, this is expected behavior. Click Create Apex method 'leadLookupController1.getSearchString'. You will get a third error message stating “Error: Unknown method 'leadLookupController1.step2()'”. Once again, this is expected behavior. Click Create Apex method 'leadLookupController1.step2'. Your controller, searchString property, and step2 method all will be created.
Click the new Controller button (next to Page Editor) to see the code within the leadLookupController class. Next, add the code for the Controller:
'''public class''' leadLookupController {
private String emailString;
'''public''' void setSearchString(String val) {
emailString = val;
}
'''public''' String getSearchString() {
return emailString ;
}
'''public''' Lead getLead() {
Lead lead = getLeadInfo.getLeadAddressByEmail(emailString);
'''return''' lead;
}
'''public''' PageReference step2() {
'''return''' Page.leadLookup2;
}
}
The getLead method calls the getLeadAddressByEmail method that you created earlier as a part of the getLeadInfo class, then returns an object of type Lead.
The PageReference step2 method redirects the application to leadLookup2 to display the search results. However, leadLookup2 doesn’t exist yet; you’ll need to add it. Follow the same steps you used to create leadLookup1. Paste the following code into your Visualforce Page Editor:
<apex:page controller="leadLookupController">
<apex:form>
<apex:outputLabel value="Email" />:
<apex:outputLabel value="{!SearchString}" /><br/>
<apex:outputLabel value="Street" />:
<apex:outputLabel value="{!Lead.street}" /><br/>
<apex:outputLabel value="City" />:
<apex:outputLabel value="{!Lead.city}" /><br/>
<apex:outputLabel value="State" />:
<apex:outputLabel value="{!Lead.state}" /><br/>
<apex:outputLabel value="Zip" />:
<apex:outputLabel value="{!Lead.postalcode}" /><br/>
</apex:form>
</apex:page>
The code uses the outputLabel values to output the results from the email search by displaying the results from the getLeadAddressByEmail method of the getLeadInfo class.
Bold text=ASP.NET Web Form= Now you understand how to call your custom Force.com logic from within Visualforce. But as mentioned earlier, you may not be able to move your existing application and logic to Force.com overnight. In this next section, we will show you how to call your Force.com code from an external ASP.NET Web application. Create an ASP.NET Web Form
For the purposes of this article, we’re going to keep the Web form simple: a standard ASP.NET Web form in an ASP.NET Web site. Later, you can convert this Web form to an AJAX widget or business object. To create your Web form, first create a new ASP.NET Web site called SFLeadLookup.
Verify that the Default.aspx Web form has been generated. If you add a new Web form, make sure that the Place code in separate file check box is selected.
Next, add a text box, named txtEmail, and its associated label to your form. This field will be used to look up the lead according to email address. Then, add text boxes named txtAddress, txtCity, txtState, and txtZip, along with the associated labels, to your form. These fields will be prefilled when the provided email address is found.
Add a button to the form. Name the button cmdSubmit.
You are now ready to add the functionality to use a lead’s email to look up the lead’s address. This process requires the custom business logic that you created earlier. To access this custom business logic from ASP.NET, you must make sure that the class object is a global class and that the service is identified as static, as Figure 3 shows.
You can confirm and update as necessary by using Setup / App Setup / Build / Code and clicking Edit for the getLeadInfo class. Your business functionality is now ready to be accessed by your ASP.NET application or by any external application that has the appropriate credentials.
To access your Force.com Web Service, your application must provide the user ID and password from a valid Salesforce.com account that has API access enabled. For this example, you’ll use your existing Developer Edition account because the API Enabled option is already selected. For production, you should create a custom profile to use only for accessing the API; this profile should have the API Only User property selected.
Your application must also pass a session ID string with each Web Service call. A session ID is a temporary ID provided by Salesforce. By default, session ID is valid for 2 hours. With Administration privileges, you can change the session expiration timeout through the Setup / Administration Setup / Security Controls / Session Settings interface.
Obtaining a session ID can be a challenge. Your ASP.NET Web form can request a session ID by making a Web Service call from Salesforce, using the user ID and password from your API-enabled account. This session ID can be stored locally in a database, text file, or application-level variable. It can be re-used by your application until the session expires, at which time your API-enabled user ID and password account may generate another session ID.
To obtain a session ID, your application must query the login method of the Salesforce.com API. The login method will return a session ID, which your application will use to access your custom Force.com Web Service. To access the Salesforce.com API by using ASP.NET, you need to create a Web Reference.
To create a Web Reference from your ASP.NET application to the Salesforce.com API, you first must export the application’s WSDL document. To do this, visit Setup / App Setup / Integrate / API and click Download Enterprise WSDL. You will see the XML that describes this Web Service API. You can use the Enterprise WSDL document to access data directly from Salesforce.com, but for now, you will use this service to create a session ID.
Next, create a Web Reference within your Visual Studio project. Right-click the project name (e.g., SFLeadLookup) and select Add Web Reference. In the Add Web Reference dialog box, there is a text box labeled URL. Type (or paste) the enterprise.wsdl file path into the URL text box, then click Go. You should see the SForceService description displayed in the Add Web Reference window, along with many methods. Change the Web Reference name to sforce and click Add Reference. You will see the sforce proxy library created within your project’s Web References folder.
Next, you must add code to your Web form to access the SForceService login method and retrieve the session ID. The following code uses the sforce proxy object that you created to obtain a session ID.
Imports sforce
Partial Class _Default
Inherits System.Web.UI.Page
Private _userId As String = "dave@server.com"
Private _password As String = "mypassword"
Private _sessionId As String
Private _serverUrl As String
Private _nextLoginTime As DateTime
Protected Sub cmdSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdSubmit.Click
' See if Session ID exists
_sessionId = IIf(Application("_sessionId") Is Nothing, Application("_sessionId"), "")
_serverUrl = IIf(Application("_serverUrl") Is Nothing, Application("_serverUrl"), "")
_nextLoginTime = IIf(Application("_nextLoginTime") Is Nothing, Application("_nextLoginTime"), #1/1/2000#)
If (Not isConnected()) Then
getSessionInfo()
End If
End Sub
Public Function isConnected() As Boolean
If _sessionId <> "" And _sessionId <> Nothing Then
If Now() > _nextLoginTime Then
isConnected = False
Else
isConnected = True
End If
Else
isConnected = False
End If
End Function
Sub getSessionInfo()
Dim lr As sforce.LoginResult
Dim ss As sforce.SforceService = New sforce.SforceService
lr = ss.login(_userId, _password)
_sessionId = lr.sessionId
Application("_sessionId") = lr.sessionId
_serverUrl = lr.serverUrl
Application("_serverUrl") = lr.serverUrl
Application("_nextLoginTime") = Now()
End Sub
End Class
The process of creating a Web Reference from your ASP.NET application to your Force.com Web Service is similar to creating a Web reference to the Salesforce.com API. First, you must export the WSDL document for the getLeadInfo class. Visit Setup / App Setup / Build and click WSDL (next to getLeadInfo). You will see the XML that describes the Web Service. Save the document to a location on your computer’s hard drive (e.g., c:\getLeadInfo.wsdl).
Next, create a Web Reference within your Visual Studio project. Right-click your project name and select Add Web Reference. In the Add Web Reference dialog box, type (or paste) the getLeadInfo.wsdl file path into the URL text box, then click Go. You should see your getLeadInfoService displayed in the Add Web Reference window, along with the getLeadAddressByEmail method. To make the Web Reference name more descriptive, change it to getLeadInfo and click Add Reference. You will see the getLeadInfo proxy library created within the project’s Web References folder.
The connection from your Web form to your custom Force.com Web Service is almost complete. The red code in the following code sample uses the getLeadInfo proxy object that you created to query your custom Force.com Web Service with the lead’s email address (e.g., jrogers@btca.com). If the lead is found, the code displays the address (street, city, state, and zip code) for the lead. To keep things simple, no error trapping has been provided.
Add the following lines of red code to your Default.aspx code-behind page.
Imports sforce
Imports getLeadInfo
Partial Class _Default
Inherits System.Web.UI.Page
Private _userId As String = "dave@server.com"
Private _password As String = "mypassword"
Private _sessionId As String
Private _serverUrl As String
Private _nextLoginTime As DateTime
Private _leadEmail As String
Protected Sub cmdSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdSubmit.Click
' Confirm Lead Email Exists
_leadEmail = Me.txtEmail.Text
' See if Session ID exists
_sessionId = IIf(Application("_sessionId") Is Nothing, Application("_sessionId"), "")
_serverUrl = IIf(Application("_serverUrl") Is Nothing, Application("_serverUrl"), "")
_nextLoginTime = IIf(Application("_nextLoginTime") Is Nothing, Application("_nextLoginTime"), #1/1/2000#)
If (Not isConnected()) Then
getSessionInfo()
End If
' Call getLeadInfo Web Service
Dim getLeadInfo As getLeadInfoService = New getLeadInfoService
getLeadInfo.SessionHeaderValue = New getLeadInfo.SessionHeader
getLeadInfo.SessionHeaderValue.sessionId = Me._sessionId
Dim getLeadInfoResponse As getLeadInfo.Lead
getLeadInfoResponse = getLeadInfo.getLeadAddressByEmail(_leadEmail)
Me.txtAddress.Text = getLeadInfoResponse.Street.ToString
Me.txtCity.Text = getLeadInfoResponse.City.ToString
Me.txtState.Text = getLeadInfoResponse.State.ToString
Me.txtZip.Text = getLeadInfoResponse.PostalCode.ToString
End Sub
Public Function isConnected() As Boolean
If _sessionId <> "" And _sessionId <> Nothing Then
If Now() > _nextLoginTime Then
isConnected = False
Else
isConnected = True
End If
Else
isConnected = False
End If
End Function
Sub getSessionInfo()
Dim lr As sforce.LoginResult
Dim ss As sforce.SforceService = New sforce.SforceService
lr = ss.login(_userId, _password)
_sessionId = lr.sessionId
Application("_sessionId") = lr.sessionId
_serverUrl = lr.serverUrl
Application("_serverUrl") = lr.serverUrl
Application("_nextLoginTime") = Now()
End Sub
End Class
Now that you have completed the coding, the only thing left to do is to build and run your project. The URL to your project will look something like the following:
http://localhost:3187/SFLeadLookup/default.aspx
The input and output will look like the Web form that Figure 7 shows.
With the release of the Force.com platform, Salesforce is demonstrating its commitment and ability to provide a complete development environment for building and delivering applications on the Force.com PaaS. You can take full advantage of the platform and build complete applications upon it or, as demonstrated in this article, you can extend the power of the Force.com platform to your ASP.NET Web applications.
Author -Dave Nielsen
Download the complete code samples for this article.
Tour de Force Francisco will be a content-rich day, with unique opportunities to learn new skills, get expert guidance, and hear inside information on the latest Force.com development technologies. And every attendee will leave with a hard copy of the new Force.com Cookbook.