Building awesome Mac clients for web services built with Visual Studio and C#

By: Pawel Glowacki

Abstract: This article demonstrates a simple ASP.NET 4.0 C# web service and a Mac OS X client application for it built with Delphi XE2 and FireMonkey

Introduction

If your customers are asking you about a “Mac” version of your existing Windows application, you may want to look at the new Embarcadero FireMonkey application development platform. FireMonkey makes it very easy to create great looking, native, compiled applications for Mac as well as for Windows. FireMonkey is a great way for building clients application with advanced GUI features like programmable effects and animations to your existing web services implemented with Microsoft Visual Studio 2010.

This article demonstrates a simple ASP.NET 4.0 C# web service and a Mac OS X client application for it built with Delphi XE2 and FireMonkey.

    Architecture

In this constantly changing world of new platforms and development environments it makes a lot of sense to reuse existing code and services and just add to them new client application types running on new platforms.

Currently we are observing on the market that more and more customers are using Mac computers and mobile devices.

Many developers focusing so far primarily on Windows development are looking into ways for creating applications for Mac OS.

“SOA” and “Service Oriented Architecture” is main stream and there are chances that you already have your application logic and data access functionality encapsulated in service applications.

In this article we are going to build a simple 3D client application for a C# web service that can be compiled from the same source code as a Windows or a Mac OS executable.

Let’s have a look at simple architecture consisting of:

  • Service application: Visual Studio 2010 Visual C# ASP.NET web service
  • Client application: FireMonkey 3D Delphi XE2 application running on Windows and Mac

Both service and client applications are intentionally very simple to make it easy for developers trying to follow up the steps described here.

There are different types of services that can be built on the .NET platform. The most popular ones are ASP.NET web services, but you can also build WCF services.

In this article we are going to focus on ASP.NET web services.

    C# Visual Studio 2010 “Hello World” ASP.NET Web Service

I’m using a clean Windows 7 Enterprise N SP1 installation running in a VMWare Fusion 3 virtual machine running on Mac OS X 10.6.

First make sure that you have Visual Studio 2010 installed. I’m using “Profeessional” edition.

Inside Visual Studio 2010 select “File”, “Project” and “New”.

Inside the “New Project” dialog open “Visual C#” project templates and select “ASP.NET Empty Web Application”.

Enter the name of the project and path. In my case the new project name is “HelloWorldAspNetWebService1” and path is “C:\Demos”.

Hide image
Click to see full-sized image

I always like to do “Save All” right after creating the new project from the wizard.

expand view>>

The second step is to add a “Web Service” to our empty ASP.NET web application project.

From the “Project” menu click on “Add New Item”.

Inside the “Add New Item” dialog select “Web Service” and click on “Add”.

Hide image
Click to see full-sized image

Optionally we could rename the default “WebService1” file name to something else, but for demo purposes let’s keep it simple and stick with the default name.

expand view>>

The wizard added a new “WebService1.asmx” and “WebService1.asmx.cs” files to the project.

The contents of the “WebService1.asmx” is very straightforward.

<%@ WebService Language="C#" CodeBehind="WebService1.asmx.cs" Class="HelloWorldAspNetWebService1.WebService1" %>

The actual web service C# code can be found in “WebService1.asmx.cs”.

Some lines from the actual source code have been stripped out for readability.

namespace HelloWorldAspNetWebService1
{
    [WebService(Namespace = "http://cooldemos.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class WebService1 : System.Web.Services.WebService
    {
        [WebMethod]
        public string HelloWorld()
        {
            return "Hello World from a C# ASP.NET web service!";
        }
    }
}

In order to expose a method of a class as a web service in the world of ASP.NET and C# you need to use special custom attributes. Every method that needs to be exposed as a web service needs to be marked with a special “[WebMethod]” custrom attribute. It is also a good practice to mark the class definition that contains web methods with the “[WebService]” custom attribute.

One of the first things in implementing ASP.NET web services is to change the default namespace “tempuri.org” to something unique. I have modified “tempuri” to “cooldemos”, but this could be anything.

The second change was to modify the string returned from the “HelloWorld” web method to “Hello World from a C# ASP.NET web service!”.

The “HelloWorld” is a C# method that takes no arguments and returns a string value.

If you click on the green arrow button inside the Visual Studio IDE, you should see the default web page of our newly created web service.

Hide image
WebService1_testpage_in_ie

On this web page there is a link to the WSDL document that describes the service in a standard way, so it is possible to invoke this web service from clients built in other programming languages. For example C++ or Delphi.

Hide image
Click to see full-sized image

Now we need to make this web service accessible from a remote machine, so client applications running on different computers could invoke this service.

expand view>>

In the above link you can see that the localhost is listening on a non-standard HTTP port, this is because our web service web app is hosted in test web server integrated with Visual Studio and the HTTP port used is random.

We need to make sure that our web service is using the default HTTP port 80, so the port number does not have to be specified in the URL.

Our ASP.NET web service needs to be deployed to the IIS instance and accessible from a remote Mac machine. We need to create a new web application in IIS manager console.

Start “Internet Information Services (IIS) Manager”. Right click on the “Default Web Site” node and select “Add Application” from the context menu.

Hide image
NewWebAppInIIS

You can now enter the name of the web application as it is going to be visible to client applications. I have entered “AspNetHelloWorld” as the name of the web application, but this could be anything.

If you now start Internet Explorer, you should be able to invoke the test page of our web service using a more friendly URL, like http://localhost/AspNetHelloWorld/WebService1.asmx.

Our test web service has been created. Now it is time to build a Mac client for it.

Before doing so, let’s verify that the Windows machine that we deployed our test service is accessible from a Mac computer where we are going to deploy the client.

Open a web browser on the Mac computer and enter the above URL to the address bar, but you need to replace “localhost” with the IP address or DNS name of the Windows machine.

Hide image
Click to see full-sized image

It looks like I’m able to connect from Safari web browser on my Mac to the C# web service test page!

expand view>>

    Delphi XE2 FireMonkey Client Application for Mac

Embarcadero RAD Studio XE2 is a Windows program, so you need Windows to install RAD Studio. RAD Studio XE2 is the IDE and can be used to write C++ and Delphi native applications for Windows 32-bit, Windows 64-bit and Mac OS 10.x. The RAD Studio XE2 release is by many programmers considered the most important version of Delphi and C++Builder since version 1, because of the new application development platform called FireMonkey. With FireMonkey you can create great looking, visually stunning, compiled applications for multiple operating systems, that take full advantage of contemporary hardware, especially the GPU or the Graphical Processing Unit. What’s really unique about FireMonkey that it is using advanced graphical technologies that are typically used by 3D game developers for rendering general-purpose business applications.

Delphi XE2 and C++Builder XE2 contains “WSDL Importer” wizard functionality, that makes it easy to generate client-side proxies in Delphi or C++ language to interoperate with any services that exposes WSDL information.

Start RAD Studio XE2.

From the main menu select “File” and then “New” and “Other…” to display the “New Items” dialog.

Inside the “New Items” dialog go to “Delphi Projects” and click on the “FireMonkey 3D Application” icon to create a new FireMonkey application.

Hide image
Click to see full-sized image

Select “File” and “Save All”. Browse to a directory of your choice and save all the files.

expand view>>

In my case I have decided to create a new “C:\Demos\HelloWorldClient” folder and saved there the main form unit as “FormHelloWorldClientUnit” and the whole project as “FireMonkeyHelloWorld3DClient”.

I have also changed the “Name” property of the main form in the Object Inspector to “FormHelloWorldClient” and “Caption” property to “FireMonkey 3D Delphi XE2 Client for ASP.NET "Hello World" C# Web Service”.

We have now an empty Delphi XE2 FireMonkey 3D application. You can optionally click on the “Run” button to see the empty application running with a blank form.

In order to keep this demo simple our user interface is going to be minimal, however I’m going to you some effects and animations to make it a little bit more interesting.

The idea is that we are going to have form with a button and a memo. When you click on the button the client application will connect over the network with the ASP.NET web service, invoke the “HelloWorld” and display the string value returned from the service.

One little nice thing in FireMonkey architecture is that you can mix 3D and 2D components on the same form. I would like to use a button and a memo components in the 3D form.

The first component to be added to my 3D form is going to be “TLayer3D” component that can be used as a surface for traditional 2D, or in FireMonkey parlance “HD”, components.

One of the fastest way of working with RAD Studio IDE is by using “IDE Insight”.

You just press “Ctrl” and “.” keys on the keyboard at the same time to display the “IDE Insight” dialog. Start typing “TLayer3D” and select it in the dialog to add it to form.

Hide image
IDE_Insight_TL

At this stage you should see the empty 2D layer in 3D space.

Later on we are going to add some animations to our form, so the position and orientation of this layer are going to be animated in 3D space.

Let’s first make this 3D layer to occupy the whole view of the 3D form. In this way we will make an impression of a traditional 2D form.

Hide image
Click to see full-sized image

Change “Projection” property of the “Layer3D1” component from “pjCamera” to “pjScreen”.

expand view>>

Next change the “Align” property from “alNone” to “alClient”.

Now our form looks very much like a traditional 2D form.

Add “TButton” and “TMemo” components to the layer 3D component. When the control is added to Layer3D component it is initially placed in the left top corner of the form, so we need to move it more to the centre and resize accordingly.

I have also increased the size of the font for both button and a memo to “24” and “18” respectively.

Now change the “Text” property of the button to “Call C# “Hello World” web service”.

To make the user interface a little bit more fancy let’s to the button control a glow effect. In FireMonkey there are many effect components that can be just dropped on other components to modify how the parent component looks.

Make sure that the “Button1” component is selected in the form designer and add to it “TGlowEffect” component. On the left top window of the IDE there is “Structure” view where you can check which components own which other components. You can always drag and drop components directly in the “Structure” view to change the ownership.

Now we have a fancy yellow glow effect around the button. It is a cool thing that the effect is just a normal component with properties that can be manipulated through Object Inspector at design time.

Hide image
Click to see full-sized image

The next step is to use the “WSDL Importer” wizard to generate a proxy unit for communicating with a remote ASP.NET C# web service.

expand view>>

Click again on “File”, “New” and “Other…” to display the “New Items” dialog and in “Delphi Projects” category select “WebServices” and click on the “WSDL Importer” icon.

Hide image
WSDLImporterIcon

Click on OK to start the “WSDL Importer” wizard.

In the first dialog enter the URL to ASP.NET C# “Hello World” web service created earlier.

Depending on the actual physical address of the machine where the web wervice is running the first part of the URL with host name can be different, but the rest should be the same.

Hide image
WSDL_step1

On the second screen of the wizard leave the default option for the default SOAP version to be used.

Hide image
WSDLWizardScreen2

On the third page of the wizard leave all the default import options.

Hide image
WSDLWizardScreen3

Click on “Finish”.

The new file called “WebService1.pas” will be added to our FireMonkey project with automatically generated Delphi code for accessing the remote C# ASP.NET “Hello World” web service.

In order to call the remote web services we need to add this newly generated file to the “uses” clause of the main form of our application and add code to the button’s onclick event to call “HelloWorld” web method and display received result in the memo.

Make sure that the main form is opened in the code editor and select “Use Unit…” from the “File” menu and select “WebService1” unit to be added to the implementation uses clause of the main form.

In the generated code in “WebService1.pas” unit there is global function called “GetWebService1Soap” that returns the reference to interface that represents the functionality of the remote service implemented in Delphi code.

Our C# web service exposes only one method called “HelloWorld” that takes no parameters and returns a string value. In the generated code there is the definition of “WebService1Soap” interface with “HelloWorld” function that returns string value.

type
  WebService1Soap = interface(IInvokable)
    function HelloWorld: string; stdcall;
  end;

If we call “GetWebService1Soap” global function with no parameters, we are going to contact the server that was used during the WSDL import procedure, however we can provide a different IP address or DNS host name, so we do not have to use hardcoded values.

function GetWebService1Soap(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): WebService1Soap;

Switch to the form view and double-click on the “Button1” component to generate empty “OnClick” event handler where we need to add one line of Delphi code that calls the remote service and adds to “Memo1” component the string value returned from the remote “HelloWorld” C# method.

Inside the “OnClick” event handler of the button enter the following line of code:

uses WebService1;

procedure TFormHelloWorldClient.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(GetWebService1Soap.HelloWorld);
end;

“Save All” and run the project for example by clicking on the green triangle run button.

If you click the button a number of times you should see the following view:

Hide image
Click to see full-sized image

expand view>>

Excellent! Our Windows FireMonkey application can connect to a remote C# ASP.NET web service.

Now we need to compile it for Mac OS X!

In the Project Manager (typically located in the top right corner of the IDE) locate “Target Platforms” node. Right click on it a select “Add Platform…”.

Hide image
AddPlatformCtxMenu

In the dialog select “OS X” as the platform to be added.

Now you should see an additional “OS X” platform with Apple icon.

Embarcadero RAD Studio XE2 is still a Windows application, so you need Windows to work with RAD Studio XE2.

RAD Studio comes with multiple compilers, including Windows 32/64-bit compilers and native OS X compiler. Basically you just need to select active target platform and recompile your project and you can build applications that natively run on Windows and OS X. That’s truly unique capability. Being able to target Windows and OS X from the same Delphi or C++Builder code is something that no other IDE on the market can currently provide.

The resulting compiled executable can run with no dependencies on any recent, Intel-based version of Mac OS X, including Mac OS X 10.6 and later.

If you want to start the Mac executable directly from inside the IDE running on a logically separate you need to start “Platform Assistant” server on Mac that communicates with the RAD Studio XE2 IDE and make it possible to remotely deploy and debug applications.

Make sure that the “PAServer” is running on the Mac machine where you want to deploy your FireMonkey client to.

Hide image
Click to see full-sized image

By default the “PAServer” listens on port 64211. You also need to check the IP address that is assigned to your Mac computer where you want to deploy the client app to. You can verify the IP address through “Network” applet inside the Mac OS X “System Preferences” dialog.

expand view>>

Once you know the IP address of the Mac machine and you know that the PAServer is running there we need to verify that the RAD Studio IDE can communicate with it.

Right click on the “OS X” node in the “Target Platforms” in Project Manager and select “Assign Remote Profile…” option. In the “Select Remote Profile” dialog click on “Add” to define a new profile.

Hide image
Add_remote_profile

In the wizard just enter the name of the new profile.

Hide image
Create_a_remote_profile

In my case this is “Pawel Mac”, but that could be anything. You could also have more then one remote Mac machine profile to deploy your application to.

On the next screen you need to enter the actual IP address or hostname of the Mac machine and the port number which is by default 64211.

Hide image
Host_machine_info_screen

Enter your Mac password there as well and click on “Test Connection” to verify that you can connect to Mac.

Leave all the default options on the last screen of the wizard and click on “Finish”.

The new profile should be created for you.

Hide image
All_platforms_in_PM

Now when click on the “Run” green arrow the application should be compiled with the Mac compiler and deployed to the remote machine. In my case I’m running Windows in VMWare virtual machine on Mac, so the “remote” Mac is my main physical machine.

When you switch to Mac you should see our client running on Mac OS X!

Hide image
Click to see full-sized image

That’s something! There is no other technology on the market today that let you create native, compiled executable from the same source code for Windows and for Mac OS X!

expand view>>

At this stage we could finish the client application, but let’s add a two little things to make it nicer.

First we are going to add a call to “TOSVersion.ToString” method to display information about the current platform where our client application is actually running.

The second thing is to add a fancy animation that will rotate and move the “Layer3D1” component in the 3D space.

Modify the “OnClick” event by adding few lines of code.

procedure TFormHelloWorldClient.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(GetWebService1Soap.HelloWorld);
  Memo1.Lines.Add(TOSVersion.ToString);
  Layer3D1.AnimateFloat('RotationAngle.X', 360, 2, TAnimationType.atInOut, TInterpolationType.itBack);
  Layer3D1.AnimateFloat('Position.Z', 500, 1);
  Layer3D1.AnimateFloatDelay('Position.Z', 0, 1, 1);
end;

The call to “TOSVersion.ToString” method is quite straightforward. In FireMonkey from the same source code, you can compile to different operating system. Using methods of “TOSVersion” type you can programmatically inspect on which operating system we are running.

The last three lines of code are performing the animation of “RotationAngle.X” and “Position.Z” properties of the “Layer3D1” component. By combining multiple animations you can achieve very interesting visual effects!

Hide image
Click to see full-sized image

expand view>>

    Summary

That’s it. You can use Microsoft Visual Studio 2010 and Embarcadero RAD Studio XE2 side-by-side. You can leverage your exiting investment in your .NET code and implement non-Windows, native, compiled clients with FireMonkey technology that can communicate with your .NET services and run on modern Mac computers.

    References

Server Response from: ETNASC02