Accessing Salesforce SOAP API through a Proxy Server with a .NET Service Reference

soap If you need to access the Salesforce SOAP API through a proxy server using a .NET Service Reference, you may be confused about how to do this exactly. This would be needed if your .NET application needed to access Salesforce through a firewall. Unfortunately, there is precious little info out there on the Internet (especially when it comes to accessing Salesforce specifically) about how to do this precise thing, hence why I am writing this post.

When adding a web reference (which by the way is considered outdated) you would accomplish this by creating a new WebProxy object, setting the host and port for this object, along with any network credentials that might be needed and then assigning this object to the services Proxy class. This is considered such an outdated method by Microsoft, that MSDN has retired the content that references how to do it.

Microsoft prefers that you use a Service Reference when accessing web services, yet the code to do this is not so easily found. Turns out the solution is pretty simple. Service References allow you to do more advanced configuration through the more easily accessed web.config or app.config files.

BTW, If you want to learn more about the differences between service and web references, check out my DeveloperForce article on this very subject.

The simplest way to configure your application is to add something like the following to your web.config or app.config file:

<system.net>
<defaultProxy useDefaultCredentials=”true”>
<proxy usesystemdefault=”True” proxyaddress=”http:\\Proxy IP Address:Proxy Port”/>
</defaultProxy>
</system.net>

You just need to replace the Proxy IP Address and Proxy Port placeholders with whatever values apply.

Hope this helps someone avoid a lot of wasted time searching the Internet.

Force.com Canvas and .NET Considerations

Introduced in Winter 2013, Force.com Canvas offers a way to host non-native (aka, non-force.com) web applications within Salesforce. Using a signed request, applications developed with your language of choice (including .NET) can connect to Salesforce and access data without requiring the authenticated Salesforce user to also log in to your web application.

I really like this technology because it opens up lots of opportunities for developers and allows shops with little Force.com experience another option. However, that does not mean that using it is all sunshine and butterflies. For one, it is very new and so there is not a lot of documentation out there (especially about .NET). The official developers guide is focused more towards Java developers, yet there are some very specific considerations that need to be made when working in the .NET environment. I recently had the opportunity to convert a Java Canvas app to an MVC Canvas app and this article highlights some of the main considerations you need to make when working in that environment.

MVC Project must use No Authentication

If you are creating a new MVC app, you will need to click “Change Authentication” when creating the project and select “No Authentication” (see NewMVCprojectImage). This will mean that the authentication scaffolding that ASP.NET adds to the project will not be included. I was not able to make a canvas app work with this scaffolding included. Perhaps, it can be done, but the only way I could make it work was to create a new project without the authentication (which makes sense since the authentication is being handled by the signed request and Force.com Canvas).

Must set SSL Enabled Property to True

Regardless of whether an ASP.NET Web forms or MVC application is used, you will need to set the site binding as HTTPS by setting the SSL Enabled property to True. You will also need to ensure that the Managed Pipeline Mode is set as Integrated. These properties can be CanvasMVCPropertiesaccessed by right-clicking the project in Solution Explorer and looking at the properties in the Properties window(see image). Also, note here that the SSL URL is the one you will want to use as the Canvas App URL when setting up the Connected App in Salesforce.

May want to consider using the following GitHub project to do handle the Server-side Authentication

In my project, I created a couple of class files to handle the server side validation of the signed request token passed in from Salesforce. However, to make your life easier and speed your time to development, you may want to consider downloading and using the following GitHub code to do the verification part. I did not find this code until after I had written mine and I thought mine was more streamlined, so I opted to go with it instead. But, looking at Shawn Blanchard’s code could give you a HUGE head start. If you don’t like that example, then you can check out the code that Paul Short posted here. It shows how to do the verification part for both a web form app and an MVC app.

 

 

 

 

 

 

Nothing but .NET Series on DeveloperForce

microsoftnetYesterday marked the beginning of a new series of posts I am doing for the DeveloperForce Blog on .NET integration with Force.com. The first post, which you can find here goes over the differences between using a service reference versus a web reference when connecting to the Force.com SOAP API using .NET.

I actually discovered a surprise result when doing the research for this post, so if you work with.NET integration at all, I highly suggest you check it out.

Comparing the Force.com SOAP API to the New Salesforce Toolkit for .NET

Last week I sat in on a webinar titled, “Build Customer Centric Applications Using the Salesforce Toolkit for .NET“, presented Tools_ce2c5aby Wade Wegner and Richard Seroter. As a .NET developer, I was excited to see a new way of connecting Salesforce via .NET. But, I was REALLY excited when I heard that the new toolkit was open-source and provided native libraries that utilized the async and await model in .NET.

I instantly knew that this new method would provide a lightning fast, near real-time alternative for connecting to Salesforce. And, after a little effort putting together a benchmark application, I was able to prove it.

At first, I tried to create a web application using Visual Studio 2010 that would test both the Force.com SOAP API and the new Salesforce Toolkit for .NET. Unfortunately, since the new Salesforce toolkit depends on the Task object and the async and await keywords (which came about with .NET Framework 4.5), using Visual Studio 2010 was not an option.

So, I moved the code to a Visual Studio 2012 web application and added the new Salesforce Toolkit via NuGet Packet Manager (NOTE: that you will need to have NuGet client version 2.8.1 or above, so you may have to take an extra step of upgrading that as I did).

The test application was simple. For both tests, a connection to Salesforce was established and a new case was created. A StopWatch timer was used to measure the run time to the millisecond. The Results?

Well, you should not be surprised to learn that the async-based task using the new toolkit was so fast, it did not even register a single millisecond. That’s right, the time returned was 0.0.

Creating the case via the Force.com SOAP API took an average of 2.32 seconds. Now, you might think 2.32 seconds ain’t bad. But, that time will always vary and could be much longer depending on the process to perform, amount of data and connection speed. There is just no WAY a synchronous method will ever be able to compete with an asynchronous process in terms of processing speed. PERIOD!!!

Now, that also does not mean that the new toolkit does not have it’s issues to consider. Asynchronous processing by itself brings about all sorts of other considerations (such as more complexity), and the following lists some things to consider if you choose to move forward with using the new Salesforce Toolkit for .NET in your org:

  1. You will have to create a connected app in your Salesforce org and then reference the consumer secret and key it provides inside of your code. See this post by Richard Seroter for more on that.
  2. If you use the new toolkit with an ASP.NET page, you will need to do a few extra things, like add an Async=”true” attribute to your page tag and register the async task. Go here to find more information about how to use asynchronous methods in ASP.NET 4.5.
  3. You will have to create a class that defines the Salesforce object you are accessing. This is the most annoying part for me and something I would like to see addressed. With the Force.com SOAP API, you can reference these definitions through the Web Reference you create. You do not have to create them specifically. This means that the Salesforce Toolkit is loosely tied to your org and therefore does not respect any required fields when it comes to object creation. I actually experimented with using the Case reference from the SOAP API in my asynchronous call using the new toolkit, and got back an error when I tried to add a case with no ClosedDateSpecified. This error was not thrown back when I used my own custom class to define the minimal fields for a Case object.

As far as the code is concerned, the following is the code used to perform the test using the new Salesforce Toolkit for .NET:

public class Case
{
        public string Id { get; set; }
        public string Subject { get; set; }
        public string Description { get; set; }
        public string AccountId { get; set; }
        public string Priority { get; set; }
        public string Status { get; set; }
}

public partial class Test : System.Web.UI.Page
{
        public const String subject = "Test Case";
        public const String description = "testing";
        public const String accountId = "001d000001UsLAX";
        public const String priority = "Medium";
        public const String status = "New";
        public const String username = "your user name here";
        public const String password = "your password and security code here";
        public const String consumerKey = "your connected apps consumer key here";
        public const String consumerSecret = "your connected apps consumer secret here";

        protected void Page_Load(object sender, EventArgs e)
        {
            
        }
        protected void NewToolkit_Click(object sender, EventArgs e)
        {
            //Time how long it takes 
            Stopwatch sp = new Stopwatch();
            sp.Start();
            RegisterAsyncTask(new PageAsyncTask(TestToolkit));
            sp.Stop();
            TimeSpan ts = sp.Elapsed;
            //Display the Results of timer
            lblResults.Text = "Runtime: "
                + String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                    ts.Hours, ts.Minutes,
                    ts.Seconds, ts.Milliseconds / 10);
        }
        
        async Task TestToolkit()
        {
            
            //create a connection and get a token to create a new client
            var auth = new AuthenticationClient();
            await auth.UsernamePasswordAsync(consumerKey, consumerSecret, username, password);
            var instanceUrl = auth.InstanceUrl;
            var accessToken = auth.AccessToken;
            var apiVersion = auth.ApiVersion;
            var client = new ForceClient(instanceUrl, accessToken, apiVersion);

            Case sfCase = new Case()
            {
                Subject = subject,
                Description = description,
                AccountId = accountId,
                Priority = priority,
                Status = status
            };

            string Id = await client.CreateAsync("Case", sfCase);
            lblMessage.Text = "The following case was saved sucessfully: " + Id;

        }
}

Google Charts and ASP.NET

I recently had the opportunity to redesign a very small web application that was used to display residential housing statistics. The previous application was created over 10 years ago and as you can imagine, now leaves a lot to be desired. It was an ASP.NET application that used many post back operations to render charts using a very limited 3rd party charting tool. It performed slowly and lacked a lot of the key functionality the client wished for (namely the ability to display data for multiple subdivisions within the same chart).

My mission was to create a new ASP.NET solution that performed well on all devices (as this is critical for a web applications success), and was easy to use, yet delivered as much information as possible on a single page. After much consideration, I decided to use the Google Charting API to render the charts. Google Chart tools are simple, free and interactive.

I also utilized Bootstrap to create a modern and responsive design and JQuery to enable a fast and asynchronous user interface. Since this post is titled, “Google Charts and ASP.NET”, I will only focus on the code used to render the actual charts. The solution (as seen below) is what I ended up with.

MLSStats

As this is a technical blog, I will now share with you some of the code used to create this solution. The amount of HTML markup used in the ASP.NET page is actually quite small. The code that is used to render the Google Charts is created dynamically in server-side code and is written back to the web page inside of individual div blocks for each data metric.

To use the application, the user selects a subdivision using any one of the four criterias provided (Parish, Area, City, or Zip).  If the user selects a certain value (for example, “East Baton Rouge” as the Parish), then JQuery and an Ajax call is used to populate the subdivision select box with only the subdivisions for that parish. The user can add as many subdivisions as they want and once all the charts are rendered (which takes only a few seconds), they can flip between each data metric by selecting one of the tabs across the top.

When a user clicks the “Add a Subdivision” button, a server-side call is made to a method which collects all the search criteria and then passes this off to a function called renderChart in a class called Chart. The code (which is seen below) will call the renderChart once for each data metric displayed and will return a string that contains the JavaScript code needed to render that particular Google Chart.

var sc = new SearchCriteria();
sc.parish = ddlParish.Value.Trim() == "" ? null : ddlParish.Value;
sc.area = ddlArea.SelectedValue.Trim() == "" ? null : ddlArea.SelectedValue;
sc.city = ddlCity.SelectedValue.Trim() == "" ? null : ddlCity.SelectedValue;
sc.zip = ddlZip.SelectedValue.Trim() == "" ? null : ddlZip.SelectedValue;
sc.sub = Request.Form[ddlSubdivision.UniqueID];
sc.timeFrame = ddlTimeframe.Value;
if (this.optParish.Checked) sc.type = "parish";
if (this.optArea.Checked) sc.type = "area";
if (this.optCity.Checked) sc.type = "city";
if (this.optZip.Checked) sc.type = "zip";

var chart = new Chart();
ltAvgPriceSqFt.Text = chart.renderChart("AvgPriceSqFt", sc);
if (chart.blnDataFound)
{
     ltAvgSalesPrice.Text = chart.renderChart("AvgSalesPrice", sc);
     ltMedSalesPrice.Text = chart.renderChart("MedSalesPrice", sc);
     ltAvgSPLP.Text = chart.renderChart("AvgSPLP", sc);
     ltAvgSPOLP.Text = chart.renderChart("AvgSPOLP", sc);
     ltAvgDOM.Text = chart.renderChart("AvgDOM", sc);
     ltTotalListings.Text = chart.renderChart("TotalListings", sc);
}

Each time a subdivision is added to a chart, it is also added to a Subdivision List stored in the HTTP Cache. Since it is possible for the user to click Add Subdivision more than once, without changing what subdivision is selected, we want to prevent the same subdivision from being added to the cache multiple times. The following code is the first thing executed in the renderChart function:

List lst = new List();
Cache cache = HttpContext.Current.Cache;
if (cache["selectedSubs"] != null)
{
    lst = (List)cache["selectedSubs"];
    if (lst.Count > 0)
    {
        //Make sure the selected subdivision is not the same as one
        //of the ones already cached
        int idx = -1;
        idx = lst.FindIndex(x => x.SubdivisionName == sc.sub && x.Parish == sc.parish
                    && x.City == sc.city && x.Zip == sc.zip);
        if (idx > -1) lst.RemoveAt(idx);
        if (lst.Count > 0) blnMultipleSubs = true;
    } 
}

The next thing to do is to get the data used to render the charts. The renderChart function makes a call out to one of two other functions (either GetSqlDataForMultipleSubs or GetSqlDataForSingleSub) within the Chart class to do this. The code below, which returns a DataTable shows this:

if (blnMultipleSubs)
{
    dt = GetSqlDataForMultipleSubs(numberToReturn, sc, lst);
}
else
{
    dt = GetSqlDataForSingleSub(numberToReturn, sc);
}

The last thing to do is to loop through the data in the DataTable variable named dt and build a string that will be returned by the function. The code below will accomplish this:

if (dt.Rows.Count > 0)
{
    blnDataFound = true;
    str.Append(@"
    google.load(*visualization*, *1*, { packages: [*corechart*] });
    google.setOnLoadCallback(drawChart);
                                
    function drawChart() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Date');");

    if (blnMultipleSubs)
    {
        foreach (Subdivision sub in lst)
        {
            str.Append(" data.addColumn('number', '" + sub.SubdivisionName + "');");
        }
    }

    str.Append(" data.addColumn('number', '" + sc.sub + "');");
    str.Append(" data.addRows([ ");

    for (int i = 0; i <= dt.Rows.Count - 1; i++)
    {
        str.Append("['" + dt.Rows[i]["date"].ToString() + "', ");
        if (blnMultipleSubs)
        {
            foreach (Subdivision sub in lst)
            {
                str.Append(dt.Rows[i][sub.SubdivisionName].ToString() 
               == "" ? "null," : dt.Rows[i][sub.SubdivisionName].ToString() + ",");
            }
            str.Append(dt.Rows[i][sc.sub].ToString() == "" ? "null]" : dt.Rows[i][sc.sub].ToString() + "]");
        }
        else
        {
            str.Append(dt.Rows[i]["number"].ToString() + "]");
        }

        if (i + 1 < dt.Rows.Count)
        {
            str.Append(", ");
        }
        else
        {
            str.Append("]);");
        }
    }

    str.Append(@"
            var options = {width: 850, height: 400, 
           pointSize: 10, chartArea: {left: 80}, curveType: *function*, ");
                    
    if (numberToReturn == "AvgPriceSqFt")
    {
        str.Append(@"vAxis: { format: '$#,###' }, 
        title: *Average Price Per Square Foot for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgSalesPrice")
    {
        str.Append(@"vAxis: { format: '$#,###'}, 
        title: *Average Sales Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "MedSalesPrice")
    {
        str.Append(@"vAxis: { format: '$#,###' }, 
        title: *Median Sales Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgSPLP")
    {
        str.Append(@"vAxis: { format: '#%' }, 
        title: *Average Sales Price/Listing Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgSPOLP")
    {
        str.Append(@"vAxis: { format: '#%' }, 
        title: *Average Sales Price/Original Listing Price for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "AvgDOM")
    {
        str.Append(" title: *Average Days On Market for " + sc.timeFrame + "*}; ");
    }
    else if (numberToReturn == "TotalListings")
    {
        str.Append(" title: *Total Listings for " + sc.timeFrame + "*}; ");
    }

    str.Append(@" 
        var chart = new google.visualization.LineChart(
             document.getElementById('" + numberToReturn + @"'));");

    if (numberToReturn == "AvgPriceSqFt" || numberToReturn == "AvgSalesPrice"
        || numberToReturn == "MedSalesPrice")
    {
        str.Append(@"
            var formatter = new google.visualization.NumberFormat(
                {prefix: *$*, negativeColor: *red*, negativeParens: true});
            formatter.format(data, 1);");
    }

    str.Append(@" 
        chart.draw(data, options); }");

    str.Append(@" 
    

NOTE: Hover over dots in chart to see individual data points

"); return str.ToString().Replace('*', '"'); } else { blnDataFound = false; str.Append(@" hidestuff('startInfo');

ATTENTION:
No data was found for the " + sc.sub + " subdivision. Please select another subdivision or a different timeframe.

"); return str.ToString().Replace('*', '"'); }

The end result for a call to renderChart will be a string of JavaScript code that will be written back to the HTML page inside of one of the predefined Literal placeholders. For example, a call to renderChart in which there are no other subdivisions in the cache and the search criteria was Parish = “EBR”, Subdivision was “Broadmoor East” and time frame was “5 years”, would produce the following output for just one of the data metrics (in this case the AvgPriceSqFt):


google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(drawChart);


function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Date'); data.addColumn('number', 'BROADMOOR EAST'); data.addRows([ ['2009', 78.36], ['2010', 68.38], ['2011', 61.25], ['2012', 55.76], ['2013', 71.61]]);
var options = {width: 850, height: 400, pointSize: 10, chartArea: {left: 80}, curveType: "function", vAxis: { format: '$#,###' },
title: "Average Price Per Square Foot for 5 Years"};
var chart = new google.visualization.LineChart(document.getElementById('AvgPriceSqFt'));
var formatter = new google.visualization.NumberFormat(
{prefix: "$", negativeColor: "red", negativeParens: true});
formatter.format(data, 1);
chart.draw(data, options); }

I really enjoyed working with Google Charts and found it to be very lightweight and flexible. I did not find it necessary to use the Google .NET Wrapper to work with it and ASP.NET. In fact, I will do a separate post about this since it will take a while to go into why this is the case and this post is already too long.

Hope this helps someone. I will try to save all the code to files and post links to them in the post later.

Why a .NET Developer Loves Force.com

When I graduated from College 20 years ago, I had no idea how much would change in the world of Software Development. Back then, the college I attended taught students COBOL as the primary language (and yes, I realize that some people reading this will not even know what that is).

It is lucky for me that I love learning new things. My entire career has been one VERY long lesson – one that changes on an almost daily basis. Blink and you’ll miss the next great language, platform or tool.

While learning new things never bothered me, the other day a simple exercise demonstrated to me how much of a hit my productivity has taken as a result of all the constant big changes in the .NET world of development.

I have been focused on .NET development ever since it emerged and before that, I was a big Visual Basic developer. A little over two years ago, I was introduced to the world of Force.com. One of my clients was using Salesforce and they needed to make it work well with the .NET-based Portal platform they were using.

Despite some initial hesitations, I found myself liking the platform more and more. I loved how stable it was and how I did not have to waste days tracking down crazy server configuration issues (like I did so often when deploying .NET applications). So over the past two years, I have spent as much time as possible learning all about it. A few months ago, I earned the Developer certification and I am currently studying for the advanced certification.

I really came to appreciate the platform when the other day I decided to use it to build a prototype application for a new client. The client was unsure about whether to go further with a project to replace their membership management system. In less than two days (10 hours total), I was able to put together a bare-bones membership management system using a free developer edition.

gbrarams

The prototype application (which has been intentionally blurred to hide sensitive data) included tabs for Documents, Reports, Dashboards, Chatter and Ideas, right off the bat. No programming required. Not a single line of code had to be written. All I did was use the declarative features of the platform to build the app and then I used the Apex Data Loader to import a large group of production member data into the new system. This really helped the client to see the potential of the platform.

I could have never put together something like this on the .NET platform so quickly. The reality is that it would have taken weeks to have put together a .NET prototype with the same amount of functionality. Now, do not get me wrong. I Still love .NET and I am not trying to put it down in any way. But, I have to be honest when I acknowledge that being a .NET developer these days can be a tad bit overwhelming. It seems like just when you have some new tool or language figured out, it has become obsolete and no one is using it any more.

I doubt I will ever get to the point where I am focused solely on any one platform (Force.com or .NET). I think the trick to being valuable as a developer is to keep an open mind and have as vast a skill set as possible. There is never one tool for every job in this business.

I would love to hear what you think???