Monday, August 22, 2005
It seems there is a code camp every other week now! I just got back from the Portal "Mini" Code Camp in Charlotte this weekend, and now I see that there are two more coming in the Southeast!
Jacksonville Code Camp on August 27th
and
Charleston Code Camp on September 17th
Both are looking pretty good.
This post is about a week late, as we kicked off the first month of the Sharepoint 1, 2, 3! training series last monday night. Feedback has been overwhelmingly positive. With hardly any promotion (we were too busy working on the material), we still managed to draw about 65 for the seminar and 35 for the Hands-On Lab on tuesday. Early indications are that we will have far more than that at our level 200 and 300 sessions. I think we are already "sold out" on some of the future sessions.
There is LOTS of buzz circulating, which is a great feeling since the four of us (Matt, Brendon, Dan, and myself) have put a tremendous amount of work into it. The Hands-On Lab "experiment" went over especially well... it's not every day that you get to attend free training and take home a DVD with a running Virtual PC of the lab materials!
Intellinet has been an extremely supportive sponsor, and we are already working hard on making the next two months' sessions even better! There are some truly awesome ideas floating around right now centered on the work we are doing with the 1, 2, 3! Training series... so keep your eyes and ears open.
Wednesday, August 10, 2005
I blogged about this new local organization a few weeks ago, and tonight was the first meeting.
I thought this was a really good meeting. It was well-managed, very professional, and lots of great content in a format that is pretty new for me. I thought the "panel" discussion was really neat, not something I have seen attempted in a user group before.
It was quite interesting to view things from a more business-oriented perspective as opposed to just worrying about the nuts and bolts of building systems. I think this is a fundamental growth step for senior developers, there is only so far into "technology expert" that a person can go before running out of room to grow... and moving vertically to systems, integration, and finally enterprise architect is just a natural extension of that growth. And the career backgrounds of the panelists strengthened this view - they all came from a strong developer background.
I see that there is much I can learn from this group. I will definately be going to these meetings in the future.
Wednesday, August 03, 2005
In my previous post, I talked about how to properly design a service. However, I did not give any real examples of it. All talk and no code. In this post, I hope to show how to actually do it.
Example: Hello, World!
Because you can never wear out an old example, and everyone already knows the Software Requirements Specification (SRS) for "Hello, World!".
Contract-First Design
Starting out, we need to first define the contract of the service that will be known as HelloWorldService. While I could demonstrate the purist's SOA approach by starting out with actual XSD schema, I will instead show what 9 out of 10 developers will be more comfortable with - a .NET interface contract.
HelloWorldService is a simple service, it's functionality is comprised of only one operation, "HelloWorld". HelloWorld accepts a single string input: "PersonName". It also returns a single string value: "GreetingText". With these requirements in mind, I will lay out the following interfaces and supporting class types:
namespace HelloWorld.Interface { public class HelloWorldRequest { public string PersonName; } public class HelloWorldResponse { public string GreetingText; } public interface IDocHelloWorldService { // This is the document-centric design method HelloWorldResponse HelloWorld(HelloWorldRequest Request); } public interface IRpcHelloWorldService { // This is the Rpc-centric design method string HelloWorld(string PersonName); } }
All of these definitions are placed in a single assembly, HelloWorld.Interface.dll. This part is important if you decide to provide a Remoting option, as this will function as the shared assembly (the equivalent to COM's type library and WebServices' WSDL).
Define Seperate Endpoints and Implementations
Here is where the rubber hits the road. The guts of the service will live in the Implementation assembly. Actual endpoints will live in their own assemblies, or web projects. I will start out by building the Implementation assembly, named HelloWorld.Implementation.dll, which contains the following code:
namespace HelloWorld.Implementation { using HelloWorld.Interface; public class DocHelloWorld: MarshalByRefObject, IDocHelloWorldService { public HelloWorldResponse HelloWorld(HelloWorldRequest Request) { HelloWorldResponse Response = new HelloWorldResponse(); Response.GreetingText = "Hello, " + Request.PersonName + "!"; return Response; } } public class RpcHelloWorld: MarshalByRefObject, IRpcHelloWorldService { public string HelloWorld(string PersonName) { return "Hello, " + PersonName + "!"; } } }
Notice the difference in the amount of code needed to support each design method. Document-centric can require more code, but the trade-off is for increased control and flexibility.
Now, we can define endpoints.
The simplest "endpoint" is to merely add a direct reference to HelloWorld.Implementation.dll, and use the service classes directly. This will result in an in-process working instance, just like any other .NET object.
The next simplest endpoint is to configure the service as a Remotable object. You might have noticed that I chose to derive my implementation classes from MarshalByRefObject. This decision allows the Remoting system to expose my implementation classes as Remoting objects - objects that run in one process/machine, but are used in another process/machine transparently [almost] to the calling code.
I will not go into details of how to set up Remoting, Ingo Rammer does a MUCH better job than I could ever hope to in his book "Advanced .NET Remoting". In essence, you will need a remoting host (an IIS web application is the easiest), and you will need to add the web.config entries to expose IDocHelloWorld and IRpcHelloWorld as "well-known services". Note that you are exposing the interfaces here, and NOT the implementation objects... an important distinction. Then you simply dump the Interface and Implementation assemblies into the web's bin folder.
On the Remoting client side, you create a similar entry in the application's config file (alternatively, you can make calls in code to Remoting.Configuration to achieve the same effect). The client-side configuration causes .NET to channel requests for the service interface to be forwarded across the network to the target server. In your client application code, you simply use Activator.GetObject(typeof(IDocHelloWorld), "remoting url....") to request the remote instance. The framework takes care of the rest.
Finally, we can define a traditional Web Service endpoint. Since asmx is the simplest way to do this, we will use that technology in this example, although you could alternatively use WSE's non-asmx transport ability. We just create a plain-vanilla Web Service asmx in a web project (named DocHelloWorldWebService), and add a reference to HelloWorld.Interface.dll and HelloWorld.Implementation.dll. We modify the web service code like so:
public class DocHelloWorldWebService : System.Web.Services.WebService, IDocHelloWorld { using HelloWorld.Interface; using HelloWorld.Implementation; /* .... IDE generated stuff .... */ [WebMethod] public HelloWorldResponse HelloWorld(HelloWorldRequest request) { DocHelloWorld = new DocHelloWorld(); return DocHelloWorld(request); } }
We can also provide an RPC-centric version by adding a RpcHelloWorldWebService like this:
public class RpcHelloWorldWebService : System.Web.Services.WebService, IRpcHelloWorld { using HelloWorld.Interface; using HelloWorld.Implementation; /* .... IDE generated stuff .... */ [WebMethod] public string HelloWorld(string personName) { RpcHelloWorld = new RpcHelloWorld(); return RpcHelloWorld(personName); } }
Obviously, you would need to also do a few other things to complete the web service, such as giving a non-default namespace, etc.
Wrap-up
So, there you have it. An example of how to properly design a service in .NET. While not terribly difficult, it certainly is a totally new way of thinking about system design for many people. Hopefully this is of some benefit to you, who knows it might save you from a costly code refactoring when you suddenly have to support a new transport or service endpoint type.
In conclusion, I would also like to point out a few excellent resource books that are relevant to the subject:
"Advanced .NET Remoting", Ingo Rammer "Expert Service-Oriented Architecture in C#", Jeffrey Hasan
Last week I hooked up with a few other smart guys after the Atlanta .NET User Group meeting. We were at the regular post-nerd-meeting hangout - Buffalo Wild Wings on Mansell Road.
We talked about a number of interesting topics, including AJAX/Atlas, Vista, and Indigo. At one point, someone questioned the validity of Remoting in light of WebServices, and wondered why anyone was using it now that is is supposedly on the way out. And my perspective was "why choose at all?". It is perfectly feasible and dare I say it "good practice" to design your system to support both. In fact, if you do things right, you will even be prepared for a smoother migration to Indigo or WSE.
So what is the secret trick to designing a service like this? Simple: it's called "contract-first design". Back in the days of COM, you might have known it as "interface-first".
Contract-First Service Design
The concept is surprisingly simple. A "service", whether it be a Web Service, system Service, or logical in-process service, can be defined as a unit of system functionality that operates independently of other units, and provides a well-known and concise interface. What this means is that no matter how complex a peice of functionality may be, it can be described in terms of some abstract interface. In Service nomenclature, this interface is called the "contract". The "contract" states the individual methods (operations) that a given service implements.
When we talk about Web Services, the "contract" is expressed as a WSDL document. When we talk about Remoting, this contract is expressed as compiled IL in a shared assembly. In COM, the contract was expressed in the Type Library. Indigo's name for this idea is by far the most explicit and clear, the "ServiceContract".
When you define a contract, you are declaring the exact functionality that a service MUST provide, and which a client MAY consume. The Service is not allowed (theoretically) to provide funtionality that exceeds or falls short of that contract, and the Client is not able to request any functionality that falls outside the scope of the contract. Furthermore, the contract also defines the specifics of HOW the functionality is to be addressed... for example, an operation requires a specific set of inputs, and will not respond (or should not) to inputs which are invalid or incomplete.
Therefore, a Service Contract ensures a consistent and predictable interaction between client and service.
So HOW do we go about designing a .NET solution in such a manner?
Plan ahead.
It is far easier to produce an adaptable architecture if you plan ahead for the adaptability. This means thinking about your interface before you think about the implementation.
At a minimum, start with defining your interface(s). You will need to define a seperate interface for each logical service. If you are a SOA purist, then this is where you bust out with the XSD editor and define your messages, operations, and portTypes. If you are not an SOA purist, then this is where you start laying out .NET interface definitions (yes, the language constructs that are defined with the "interface" keyword). Even if you are going the pure-SOA route, you will want to run the xsd.exe compiler against your schema to create some .NET stubs.... then change those from "class" to "interface" definitions. Either way, on the .NET side you want a set of interface definitions for the services, and class definitions for the complex structures.
And here you must make a choice. Do you want to (A) design a completely document-centric service, or (B) an rpc-centric service? If you want document-centric services, then you will want to create explicit types for every operation/method, one for the input and one for the output... even if the content is not complex. If you want RPC-centric services, then you can save a small amount of effort by only defining explicit types for cases where you wish to return or accept complex structures. Design Method A OperationAResponse = {complex type or simple type...} OperationARequest = {complex type or simple type...} OperationA = function(OperationARequest), returns OperationAResponse Design Method B OperationB = function(complex or simple type(s)), returns simple type or void
One word of warning: stay away from "ref" or "out" parameters if you choose to follow Design Method A.
One thing you might notice about Design Method A is that all operations will have a similar pattern, regardless of inputs and outputs. This is not coincidental. The Request and Response structures are what we call "documents" in a document-centric SOA (also called "message-centric"). There is great flexibility and power in a message-centric design.
Define Seperate Endpoints and Implementations
This is what fouls up most attempts at designing a good service. Having the contract pre-defined is not enough - you must also differentiate the service from the consumer. In the real world, your service will almost always be centralized, but the consumer(s) will be dispersed. This means that one (1) service may have multiple (N) endpoints. An endpoint is merely an identifiable address where the implemented service functionality can be found.
The problem is that most people do not distinguish between the endpoint and the implementation. They simple fire up a new asmx file and start dumping code into it. This is a BAD PRACTICE. The asmx is simply and endpoint, and should not be doing any work except passing the calls over to a real implementation. In other words, the asmx should be nothing more than a Facade.
A better approach is to implement the service itself in an external class... better yet, in an external assembly. This implementation class should implement the defined interface, just as you would implement any other .NET interface in a class. Then, you also implement that very same .NET interface in your asmx, however in the asmx you simply forward the calls to an instance of the external implementation class. Your Web Service methods become extremely simple shells that are marked up with the [WebMethod()] attribute and delegate the work to the external class. Very clean and tidy.
Once you have implemented your service like this, many more options become available. You get the flexibility to create new endpoints, possibly with differing authorization abilities (external facing ones might enforce WSE security, while internal ones might not). You also get the ability to very easily expose the service via other transports... such as Remoting. Either create a new endpoint object that derives from MarshalByRefObject, or make the service implementation itself derive from MBRO. Then you can add a entry to an application config file, and your service is now exposed via Remoting, with an identical interface to the web service! And finally, you enable the consumer of your service to simply reference it directly as an assembly, if that is desired for performance or security.
Wrap-up
That wraps it up for this (somewhat basic) discussion of how to design good services. My next post will follow up with a concrete example of this process.
In conclusion, I would also like to point out a few excellent resource books that are relevant to the subject:
"Advanced .NET Remoting", Ingo Rammer "Expert Service-Oriented Architecture in C#", Jeffrey Hasan
Tuesday, August 02, 2005
If you missed this month's c# user group meeting, you definately missed out on some good information.
Chris Wallace started out by showing us the slick new profiling capabilities in VSTS 2005 for a few minutes. This will certainly be a handy set of tools available in VSTS.
Then Eric Marvets gave the main presentation on .NET Encryption. He did not show us a single line of code (there are plenty of examples on the web), but instead he felt it was more important to teach people how and [more importantly] when to apply or not apply particular cryptographic solutions. We all learned how Electronic Code Book ciphers and Chained Block ciphers work, their attack vectors, and in what situations they work best. We learned why when using CBC, you MUST ALWAYS generate a new Initialization Vector whenever the encrypted data is modified, and just exactly how that IV is used to make certain cryptographic solutions more secure. As a final tidbit of wisdom, we learned how DPAPI, while certainly an improvement over clear-text storage, is fundamentally no more secure than a good DACL.
8 out of 10 doctor's agree - The Atlanta C# Users Group lowers cholesterol while reducing hair loss and brightening your smile!*
* These statements have not been evaluated or approved by the FDA.
|
On this page....
Archives
| April, 2009 (1) |
| June, 2008 (3) |
| May, 2008 (1) |
| April, 2008 (1) |
| March, 2008 (2) |
| February, 2008 (3) |
| January, 2008 (6) |
| December, 2007 (2) |
| November, 2007 (2) |
| October, 2007 (5) |
| September, 2007 (1) |
| August, 2007 (4) |
| July, 2007 (3) |
| June, 2007 (1) |
| May, 2007 (3) |
| April, 2007 (3) |
| March, 2007 (3) |
| February, 2007 (3) |
| January, 2007 (6) |
| November, 2006 (3) |
| September, 2006 (1) |
| August, 2006 (2) |
| May, 2006 (2) |
| April, 2006 (2) |
| March, 2006 (2) |
| February, 2006 (4) |
| January, 2006 (4) |
| December, 2005 (3) |
| November, 2005 (4) |
| October, 2005 (5) |
| September, 2005 (8) |
| August, 2005 (6) |
| July, 2005 (10) |
| June, 2005 (2) |
| May, 2005 (6) |
| April, 2005 (12) |
| March, 2005 (8) |
| February, 2005 (12) |
| January, 2005 (19) |
| December, 2004 (17) |
| November, 2004 (9) |
| October, 2004 (8) |
| September, 2004 (9) |
| |
Navigation
Categories
About
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent
my employer's view in any way.
Sign In
|