Welcome to MSDN Blogs Sign in | Join | Help

Welcome to The Metaverse

Navigating the service-oriented, identity aware metaverse

News

  • Disclaimer:
    The content of this blog are my own personal opinions and do not necessarily represent Microsoft's position, commitments or strategy. In addition, my thoughts and opinions often change, and as a weblog is intended to provide a semi-permanent point in time snapshot you should not consider out of date posts to reflect my current thoughts and opinions.




    Add to Technorati Favorites
Building Services Today

One of the readers of this blog asked if I have any guidance on how to design ASMX Services. I have had this question a lot recently, so I thought I'd better post some information:

We're currently working on an app that will demonstrate how to build SO systems using only today's technologies. We hope to publish this app in the next few months. I will blog about this as we get our plans in order. In the meantime, I hope the information below gives you a good starting point to jump off:

When designing Web Services, it's important to abide by the same rules you'd apply for designing any network addressable service or distributed app.

Key amongst these guidelines is “avoid the network wherever possible“. Otherwise stated - only traverse the network if you must and only pass across the network what you have to. I have stated this several times before in my Enterprise Services whitepaper and elsewhere in this blog. It is important when designing distributed systems to not fall into the trap of designing for architectural purity when building a service exposed to the network. One should generally take a very pragmatic approach and design methods that get the most done with the fewest network traversals. I urge you to concentrate on designing services that expose “chunky” methods that perform as much work as possible whilst passing only the information necessary to perform that task across the wire.

Here's an example of a “good“ service method:

[Serializable]
class Customer
{
    string name;
    int age;
    DateTime dob;

}

[WebService]
class CustomerServices
{
    ...
    [WebMethod]
    void AddCustomer(Customer cust);
   
...
}

The following is an example of a “bad“ design since every time you need to add a customer you have to make several calls across the network to the service:
class CustomerServices
{
    ...
    int CreateCustomer();
    void SetCustomerName(int id, string name);
    void SetCustomerAge(int id, int age);
    void SetCustomerGlass(int id, string custClass);
    ...
}

The second main point I would like to suggest is to design your services to map to your business rather than mapping to the way your IT systems work internally.

When it comes to implementing your services internally, I suggest a design thought process such as:

  1. I implement my business functionality in one or more .NET internal implementation classes. These classes may or may not call other utility classes which talk to databases, queues, existing components, other systems, etc. These classes should make no assumptions (yet) about transactions, security etc. (since we've not yet decided how to host them)
  2. I then design an ASMX façade class that exposes the service to the outside world. This class should be made most applicable to callers of my service offering nice chunky “most bang for the buck“ operations.
  3. Now I consider my transactional needs.
    1. If I do not need distributed transactions, I implement my Web Service's methods by calling to my internal implementation class. For example, a given operation may simply connect to the database and call a stored procedure, passing in the supplied data. In this case, a transaction spanning several components is unnecessary, but if a simple transaction is required, ASMX Services can be marked as supporting transactions should you need to.
    2. If I need my business functionality to support distributed transactions spanning several components, I opt to write an EnterpriseServices façade class (attributed appropriately) which calls my internal implementation class. My Web Service façade class should call this ES façade class rather than directly calling my internal implementation.
  4. I also consider my queueing needs - if I need to pass messages via queues, I consider whether I can use Queued Components or whether formatting messages and sending them manually via MSMQ is the best approach.
  5. I also consider my Remoting needs. Am I talking x-AppDomain in the same process? Do I need to send this message in some strange format to a listener elsewhere? If so, then I need to design my remoting classes, but otherwise, I opt for EnterpriseServices wherever possbile.

Of course, this design process is not exhaustive, but it should indicate the kind of thinking one could take when designing Services.

Hope it helps.

 

Posted: Wednesday, June 23, 2004 6:16 PM by RichTurner666

Comments

Matt Hamilton said:

What would you think of this (slightly different) implementation, Rich?

class CustomerServices
{
...
int CreateCustomer(string name, int age, DateTime dob);
}

?

I'm curious as to whether you think that the calling program should 'know' about the customer class - ie build one and pass it to CreateCustomer rather than simply creating a customer from its individual properties.

Cheers!
# June 24, 2004 1:05 AM

Clemens Vasters said:

+1, Rich

no, +2, actually

;-)
# June 24, 2004 5:32 AM

Alex Odintsov said:

We are using the same model as Matt described.
Our services methods take parameters as it would be a constructor for your class Customer.

Can you tell me (and Matt ;)) why sending a class is better then this approach?
# June 24, 2004 7:00 AM

Mike said:

Cool post, Rich. Do you have thoughts on whether it should be;

AddCustomer(Customer cust)

or

AddCustomers(Customers custs)

or

AddEntities(Entities ents)

where I guess I'm thinking that Entities is a superset of Customers in terms of schema.

I guess I'm keen to get your thoughts on the granularity here.
# June 24, 2004 8:53 AM

Christian Mogensen said:

Matt+Alex: the reason for not using a long list of params is that the Struct is more flexible in the long run. If you change the paramlist more things are likely to break than if you extend the struct.

Of course, you shouldn't change either one (published interfaces should be frozen), but life is often more complex than computers would like. :-)

Another advantage to using the struct approach is that the service client can call a service, get a struct back, twiddle it, and pass the struct back to another service. This is much easier on the client.

The long list of parameters requires that the client handles packing/unpacking the struct rather than making the service do it.

Of course, I could be completely and utterly wrong here, but this is my intuition as to why.
# June 24, 2004 9:03 AM

Rich Turner said:

LOL! How did I know that this one was going to come up?

Should I pass values or structs?

This is an endless discussion which, to be honest, essentially comes down to personal taste. From a perf perspective, either are fine since both models still perform minimal network traversals.

I personally prefer to create a struct on the caller and pass it to the method. This way if (during development) I need to change the shape of the struct I do it in one place - all the method declarations that accept or return this struct don't need to be touched. Also, If I declare a WebService and the "data classes" that support it, then any caller who references this service will be able to synthesize a local proxy class that simulates these data classes. Less work for the developer overall.

Note, however, that in .NET EnterpriseServices, if I pass just simple types, the ES infrastructure can shortcut some of the COM stack and you may see a perf improvement. How big an improvement is vairable however, and since I don't tend to find the cost of a method call to be particularly painful my ES apps, I tend to opt for coding simplicity instead.

Rich.
# June 24, 2004 11:11 AM

Phil said:

I tend to agree with Rich that structs have definite advantages over passing a list of params to a web method. I have another question about exposing internal domain model objects via a web service interface

http://staticground.blogspot.com/2004/06/web-services-exposing-internal-object.html

I think that it is probably a good idea to model the message structures that are exchanged between client and web service independently from the objects defined in the web service domain model. Assembler classes defined in the service stub layer can translate between web service objects and the underlying domain model objects. This provides a loosely-coupled object graph, where the web service objects and the domain model objects can mature independently. Another benefit, which ties into Rich's point about only passing required data across the wire, is that your domain model objects might contain data public fields that the web service does not care about, but other objects within the domain might utilize these public fields. In this case, an assembler object could create a new object that the web service can use, and the assembler can include only the pieces of data from the domain that the web service cares about.
# June 24, 2004 12:20 PM

Rich Turner said:

Phil's got it :) Quite agree with your approach. The contract with which you expose your service to the outside world should be very explicit terse, concrete and immutable wherever possible. By marshalling between your internal object representation and your external data representation, you're nicely insulating each side from one another.

This is especially important if your internal data structures contain information (such as internal ID's) that is not relavent to the outside world and is used entirely for internal processes - one wouldn't want such information leaking outside of your services.
# June 24, 2004 4:25 PM

Chris said:

We are building webservices to support our internal winform apps. Please comment on the following:

1. The proposed solution is not to have very few WebMethods. As in the primary being

string DoWork(string Request, string Data)

2. Typed datasets being the primary transport across the wire.


Please help, I may be quoting you in meetings!
# June 25, 2004 1:24 PM

Chris said:

Sorry correction:

1. The proposed solution is to have very few WebMethods. As in the primary being

string DoWork(string Request, string Data)
# June 25, 2004 1:28 PM

Serge said:

Rich's approach is the excellent example of having properly modeled classes and webmethods, also having in mind security and granularity of the class ,and variables declared inside the class rather then using structure type. Everything has been thought with clever mind, even memory allocation (as I have mentioned Class versus Structure).
Great code- right style!
thnx,
S
# June 25, 2004 1:57 PM

Tiago Pascoal's WebLog said:

# July 5, 2004 3:58 PM

Girish Bharadwaj said:

# July 19, 2004 10:12 PM

Willy-Peter Schaub said:

# January 21, 2005 3:13 AM
Anonymous comments are disabled
Page view tracker