Chapter 2. Building Web Services with ASMX

In This Chapter

  • Getting acquainted with SOAP

  • Creating an ASMX service

  • Running an ASMX service

  • Building the SHARP code

In Chapter 1 I state that services provide access to functional code over the wire. Though it wasn't covered, it probably became obvious that one just can't call a method on a remote machine without some kind of wrapper. The black magic that makes .NET methods work in a client program don't work over the Internet.

There have been a bunch of remote procedure call (as it is called) protocols over the years. Some you might be familiar with include:

  • CORBA

  • DCOM

  • RCW

  • OpenBinder

  • LINX

  • DLPI

  • STREAMS

  • DDE

  • Even AJAX, in its own way.

The benefit to using services is that they are based on a:

  • standard

  • human readable

  • extendable

  • protocol

None of the other messaging protocols are all of those. They all have some small (or occasionally large) problem that prevents the benefits of remote procedure access to really shine. Web services provide what is actually needed. The second Web service protocol to provide these benefits in usable form is SOAP. (ReST is the first, but that is a story for a later chapter.)

Getting to Know SOAP

Simple Object Access Protocol or SOAP is an XML-based protocol for sending messages over the Internet, usually via HTTP. You can think of it as an envelope for remote procedure calls because that is exactly what it is.

The major benefit to SOAP, aside for its rather global acceptance and its longevity, is the rich experience that it provides the client. There are a lot of developer features in SOAP, like transactions and security, and they all work pretty well.

SOAP and standards

Standards are discussed in this book elsewhere, but it bears discussing here too. Here is how standards-based development works:

  1. Either because of industry need or a company idea, some organization develops a standard. This is usually a recognized organization like the World Wide Web Consortium (W3C) or a company, like Microsoft or IBM.

  2. The standard is distributed to the community for review.

  3. After community acceptance, the standard is certified, either by the originating organization or an organization like IEEE or ISO.

  4. Some company, when developing a product, realizes that it needs a feature that happens to be described by that standard.

  5. After reviewing the standard, the company decides to implement the standard.

Realistically, regardless of certification, only when a large number of companies implement a standard does it actually become a genuine standard. Many so-called "Web" browsers over the years supported "standard" protocols like VRML and such that never made it.

It's true, folks. The Internet superhighway is littered with the broken documents of dead standards.

The WS-* standards

The WS-* (usually pronounced WS-star, referring to the wildcard * character that references all standards that begin with WS) standards fit right in here. These are Web service standards that apply to protocols like SOAP. They are written by a standards organization, reviewed, certified, and have been used.

What is better is that the additional standards include a lot of really neat functionality that makes SOAP a very rich development experience. Usually, distributed communication standards leave transactions, security, and other such functionality up to the developer.

SOAP isn't like that. It is supposed to have all that stuff baked in.

The WS-* standards include all this useful functionality:

  • Web Services Transactions (WS-TX): Coordinates the outcome of broadly distributed communications.

  • Web Services Reliable Exchange (WS-RX): Provides a confirmation of communication for service calls.

  • Web Service Federation (WS-FED): Allows for a federation of trust between service providers.

  • Web Service Remote Portlets (WS-RP): A standard for Web parts using services (like you see in SharePoint).

  • Web Service Security (WS-SX): A supported trusted exchange.

  • Web Services Discovery (WS-DD): A way to find services in a large enterprise.

  • Building Information Exchange (oBIX): Allows buildings to talk to each other about their wiring. No, I'm not kidding!

  • OASIS ebXML: A business XML standard that is designed to provide a standardized data model for communications.

In general, these are fantastic additions. They define a set of functionality that all Web service development software providers — Microsoft, IBM, Sun, open source initiatives, whomever — can implement. If you need transactions, they are there. Security? Baked in.

The impact to you

The problem is that these standards were used differently by every company that implemented them.

No, I am not kidding. The problem with standards this detailed in scope is that in order to be useful they must either leave a lot to the imagination or define everything. OASIS erred on the side of being too loose, and the implementations are a mess.

If you are working inside the Microsoft stack — meaning, you are communicating with other .NET projects — you are golden. Within the Microsoft platform, everything is defined the same.

However, if you are communicating outside the .NET Framework — say with IBM or Sun — you should expect problems if you are using WS-* defined functionality.

The take-home is that SOAP includes a lot of standard functionality that isn't found anywhere else. Sure, some distributed message contracts have a lot of features found in SOAP, and SOAP might not be completely implemented the same everywhere, but there isn't anything else that even tries to provide this functionality in a standardized way.

From this perspective, SOAP is a fantastic platform. Need transactions, especially secure transactions? SOAP has them. Need large binary attachments? SOAP has that. Have BPEL requirements? There's a SOAP for that.

Big, fat, and slow

All this eating at the trough of standardized features has made SOAP, well, a little large-boned. Let me give you an example. The XML required just to set the context for transactions (the service equivalent of a cookie) is:

<wscoor:CoordinationContext
             xmlns:wsa="http://www.w3.org/2005/08/addressing"
             xmlns:wscoor="http://docs.oasis-open.org/
                               ws-tx/wscoor/2006/06"
             xmlns:myApp="http://www.example.com/myApp"
             S11:mustUnderstand="true">
             <wscoor:Identifier>
                  http://Fabrikam123.com/SS/1234
             </wscoor:Identifier>
             <wscoor:Expires>3000</wscoor:Expires>
             <wscoor:CoordinationType>
                http://docs.oasis-open.org/ws-tx/wsat/2006/06
             </wscoor:CoordinationType>
             <wscoor:RegistrationService>
                 <wsa:Address>
                  http://Business456.com/
                             mycoordinationservice/
    registration
                  </wsa:Address>
                  <wsa:ReferenceParameters>
                     <myApp:BetaMark> ... </myApp:BetaMark>
<myApp:EBDCode> ... </myApp:EBDCode>
            </wsa:ReferenceParameters>
        </wscoor:RegistrationService>
        <myApp:IsolationLevel>
              RepeatableRead
        </myApp:IsolationLevel>
    </wscoor:CoordinationContext>

In the Java world, 10MB SOAP messages are not uncommon — although that includes the payload — and that works out to what, 200,000 lines? In one HTTP call? That's probably a bit much.

SOAP dramatically increases your overhead in communication. If you don't need the security, federation, and transaction capabilities of SOAP, consider ReST — covered in Chapter 4. If you are communicating in a homogenous Microsoft environment, consider binary encoding.

On the other hand, if you are communicating in moderately heterogeneous environments and do in fact need an encrypted, federated transaction using a common enterprise data model, by all means look at SOAP.

Making an ASMX Service

You can write a SOAP service in ASMX or WCF.

ASMX doesn't stand for anything — it is ASPX with the P changed to an M, which means Service. (Try not to laugh.) It is the extension of an ASP.NET Web file that provides a service rather than a Web page.

The thing is, ASMX allows only for SOAP. WCF does other things. Here I cover ASMX; I leave ASMX here because WCF's additional functionality makes WCF a clear winner in this race. (For writing in WCF, check out Chapter 3.)

Nonetheless, if you are making a publically consumable service and need it to be straightforward and simple to deploy, then ASMX might be for you. Certainly, there is a lot of ASMX service code out there which you might have to maintain.

Let's just start by building one.

Creating a new service

ASMX Web services are ASP.NET projects. As such, they seem a lot like ASP. NET Web applications — because they are ASP.NET Web applications. You can actually put an ASMX file in a regular ASP.NET application, and a Web file in a Web service application like we do in the following step list. The template is just there to help you get started.

  1. Open Visual Studio and click on New Project.

    The New Project dialog box appears.

  2. In Installed Templates under the Visual C# node, select Web.

  3. In the box to the right, click ASP.NET Web Service Application.

  4. Change the Name to ANewService and the Solution to Book7Chapter2.

    An example is shown in Figure 2-1.

  5. Click OK.

This process generates a project that has all the right references for a Web service project in ASMX and gives you a sample file to start with.

Analyzing the file setup

Note that although a Service1.asmx file (and the usual code-behind file) is created, the markup file has only one line in it:

<%@ WebService Language="C#" CodeBehind="Service1.asmx.cs"
    Class="ANewService.Service1" %>

This is by design. Nothing goes in the markup file. All the magic is in the code-behind.

Make a new Web service.

Figure 2-1. Make a new Web service.

Breaking down the sample code

The Service1.asmx.cs file does all the work in our new service, starting with the code in the template. Let's run through that code a line at a time:

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.Services; 6
6
7 namespace ANewService
8 {
9     /// <summary>
10    /// Summary description for Service1
11    /// </summary>
12    [WebService(Namespace = "http://tempuri.org/")]
13    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
14    [System.ComponentModel.ToolboxItem(false)]
15    // To allow this Web Service to be called from script, using ASP.NET AJAX,
   uncomment the following line.
16   // [System.Web.Script.Services.ScriptService]
17   public class Service1 : System.Web.Services.WebService
18   {
19
20      [WebMethod]
21        public string HelloWorld()
22        {
23            return "Hello World";
24        }
25    }
26 }

There are eight things to point out:

  • Line 5 brings in the System.Web.Services namespace; it's essential to the rest of the template.

  • Line 12 sets the Namespace for the service. The namespace, just like the namespace of your .NET classes, can be anything you want. It doesn't refer to a real place on the Web.

  • Line 13 sets the Web Service Binding. WS-I is the Web Services Interoperability organization who (you guessed it) sets even more standards for Web services. Basic Profile 1.1 is more or less the industry standard. You can find out more at http://www.ws-i.org.

  • Line 14 declares if the item should be a Toolbox item in design time environments. This declares whether it should show up in design time Toolboxes.

  • Line 16 (when uncommented) activates runtime support for AJAX.

  • Line 17 is a normal, everyday class definition, but notice that it inherits System.Web.Service.WebService.

  • On Line 20, you can see the [WebMethod] attribute. This allows you to control what methods are available to the service from the class, and there are a few attributes for fine-grained control.

  • The code itself is fairly boring — the functional code is exactly the same as it would be in a normal class. All the things that make it a Web service are in the declaration.

Running the service

Press F5 and run the service. If all goes well, you should see something like Figure 2-2. This is the default visualization for a service — remember that you didn't make a user interface; IIS did this for you, to make it easier to test. External users can't see this.

Clicking the Service Description gives you the WDSL for the whole service. This is what a non-.NET application needs to build its proxy. Note that all it does is append a ?WSDL to the end of the URL.

Clicking the Hello World link gives you a test screen and implementation guidance for the method. You will have one of these links for every one of the methods in the class marked with WebMethod.

Running the default service.

Figure 2-2. Running the default service.

Building the code for SHARP

First you need to get set up. Here's what you need to do to start using the Web template:

  1. Add a new Web Service Application project to the solution by right-clicking the solution and selecting Add New Project. Name the project SharpAsmx.

  2. Note

    If you haven't already, add a data connection to the ConferenceDB. The database is downloadable from csharpfordummies.net.

  3. Right-click on the SharpAsmx project and add an Entity Data Model by selecting Add ...New Item and picking ADO.NET Entity Data Model from the list. (It's under Data.) I named it SHARP.edmx.

  4. When the Entity Data Model wizard appears, select Generate from Database and click Next.

  5. In Choose Your Data Connection, pick the ConferenceDb you added in Step 1. Keep the rest of the defaults.

  6. When it asks you to copy the file to your project, choose No.

    You don't need copies of the database floating around.

  7. In Choose Your Database Objects, pick all the tables except sysdiagrams, and change the Model Namespace to SharpModel.

    An example appears in Figure 2-3.

  8. Click Finish.

Adding the Sharp tables to the model.

Figure 2-3. Adding the Sharp tables to the model.

That's how you set up an ASMX Web service project. You have a data source, an entity model (you could use your organization's domain model, or hand-rolled procedures and ADO.NET, or whatever), and a starting point for the service.

Note

Next, you set up some services that make sense of your user interface. There are two schools of thought on this. First, you can roll up the entity model in the service signature itself. Second, you could write a separate business layer and just call the Business Layer (BL) methods with the services.

The deciding factor is reuse. If you will later need to roll exactly this logic into a standalone application (anything that won't use the services), then make a separate BL. For simplicity, we will do the former.

  1. Using the default template, delete the default HelloWorld methodand put in a method signature for a new conferencesAtLocation method. It will accept a conferenceId (maybe from Web site navigation) and return a list of conferences at that location.

    public List<Conference> conferencesAtLocation(int locationId)
    {
    
    }
  2. The first step is just to get the entities from the Entity Data Model. Addthe bold lines. They set up a context for the Entity Framework, thenget the list of conferences.

    public List<Conference> conferencesAtLocation(int locationId)
    {
        ConferenceDbEntities conferenceContext = new ConferenceDbEntities();
        ObjectSet<Conference> allConferences = conferenceContext.Conferences;
    }
  3. Next, write a Linq query to just get the conferences with the locatio-nId. This is in the bold lines below.

    public List<Conference> conferencesAtLocation(int locationId)
    {
        ConferenceDbEntities conferenceContext = new ConferenceDbEntities();
        ObjectSet<Conference> allConferences = conferenceContext.Conferences;
        var conferenceQuery = from c in allConferences
                              where c.LocationId == locationId
                              select c;
    }
  4. In order to use the results of the Linq query, you must use an iterator. You need to dispose of the context. Finally, you return the results. These steps are in the bold lines added below:

    public List<Conference> conferencesAtLocation(int locationId)
    {
        ConferenceDbEntities conferenceContext = new ConferenceDbEntities();
        ObjectSet<Conference> allConferences = conferenceContext.Conferences;
    var conferenceQuery = from c in allConferences
    where c.LocationId == locationId select c;List<Conference> locationConferences = conferenceQuery.ToList(); conferenceContext.Dispose();return locationConferences;
    }
  5. To make it a Web service, you need to add the WebMethod decorator on the method signature, and you are done.

    [WebMethod]
    public List<Conference> conferencesAtLocation(int locationId)
    {
      ConferenceDbEntities conferenceContext = new ConferenceDbEntities();
      ObjectSet<Conference> allConferences = conferenceContext.Conferences;
      var conferenceQuery = from c in allConferences
                 where c.LocationId == locationId
                 select c;
      List<Conference> locationConferences = conferenceQuery.ToList();
      conferenceContext.Dispose();
    
      return locationConferences;
    }
  6. Press F5 to run the test page, and click on the conferencesAtLocation method link. Enter 3 into the Test field, and the result should come back like Figure 2-4 if everything is good.

So what about all that other stuff that goes into SOAP? Security, transactions, and like that? It's all baked in, but it's well beyond the scope of this book.

For instance, check out the SoapHeader attribute. It allows you to specify even the most complex security attributes on your Web methods. There's more, too. Check out MSDN.

Deploying

Deploying an XML Web Service is just like deploying a Web application. They are effectively the same thing.

One benefit of ASMX over WCF is the simple configuration. In fact, if you check out the configuration file for the application you built here, you'll see that the only configuration information revolves around the Entity Model. Adding an ASMX service to a Web project is easy.

Note

Something important that you need to know: After you deploy, the sample test page doesn't run anymore. You'll still get the information service page, but if you try to run the test script, you'll get the message shown in Figure 2-5. This is just for security and can be overridden, though I don't advise overriding it in a production setting.

Results of our service.

Figure 2-4. Results of our service.

Can't run test scripts in production!

Figure 2-5. Can't run test scripts in production!

Consuming services in your applications

Consuming an ASMX service works just like consuming any other service, from any provider. To see what I mean, follow these steps.

  1. Create a new C# Console application in the project. I called mine ConsumeSharp.

  2. Right-click on the project and select Add Service Reference.

  3. Click the Discover button.

    Visual Studio finds all the services in your solution. In a real project, you probably would put a URL in the Address text box.

  4. Select the Registration.asmx service and set the Namespace to SharpReference.

    An example is shown in Figure 2-6.

  5. Click OK.

Visual Studio does a ton of work for you here. There is no magic — Visual Studio reads the WSDL of the service referenced and builds a proxy just as though it were a service written in C++ or Java.

Adding a service reference.

Figure 2-6. Adding a service reference.

As such, the objects returned to you will be more along the lines of a service than what you would expect in C#, especially as delivered by ASMX. The code in the console application to consume your now-proxied service looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            SharpReference.RegistrationSoapClient serviceReference = new
    SharpReference.RegistrationSoapClient();
            SharpReference.Conference[] conferences = serviceReference.
    conferencesAtLocation(3);
            Console.WriteLine("There will be {0} conferences at location number
    3.", conferences.Length)
            Console.ReadKey();
        }
    }
}

Notice that the conferencesAtLocation method now returns an array rather than a List<Conference>. The consuming language doesn't have to have generics, but it does have to have arrays (if it conforms to WS-I). That's the only assumption we can make. (See Figure 2-7.)

Right-click on the console application and press F5. The console application should start, and it should find the two rows in the array just as it would in the list.

Running the consumed service.

Figure 2-7. Running the consumed service.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.42.129