Monday, June 21, 2004

Last week I had the privilege to speak at a series of Microsoft Architect Councils alongside Roger Sessions and Jack Greenfield. The cities where we spoke were Birmingham, Tampa, Orlando and Fort Lauderdale.

 

Roger Sessions is quite well-known as an expert in architecture. His latest book discusses architecture using a ‘software fortress’ metaphor, where applications are a Fortress, accepting input through a Guard and using Envoys to communicate with other applications. I found the metaphor to be very interesting and accurate in many ways. It dovetails very nicely with my viewpoint on most things, including application design, service design and the role of SOA, web services and remoting.

 

In particular, I think it fits nicely with my view on distributed object-oriented application design. CSLA .NET enables the creation of the code that goes inside one of Roger’s Fortress constructs – be that an application or a service. While XML messages pass back and forth between fortresses, inside the fortress we need some way to actually create functionality and implement business features. This is where object-oriented programming comes into play.

 

And Roger’s model allows for the use of distributed technologies inside a fortress as well. So where appropriate, it is perfectly realistic to employ distributed object-oriented concepts in such an environment.

 

 

Jack Greenfield is a very well-known personality in the patterns space and in the software modeling space. He currently works for Microsoft as an Architect for Enterprise Frameworks and Tools (the Visual Studio Team System product), focusing specifically on modeling tools, including the SOA designer, class designer, etc. Jack comes from Rational and really provides some excellent insight into how both that world and the Microsoft world work. His current focus is on ‘industrializing’ the software industry – moving us to a place where we create software factories rather than creating software directly. Very interesting stuff!

 

I had a great time discussing various topics with Jack, including whether industrialization of software is actually a good thing. After all, the industrial revolution was not particularly good for the people working in factories. In the long run, it enabled our society to move beyond an industrial economy and then things got better for everyone, but during the industrial period life pretty much sucked for all but an elite few. I think it would be a shame if the industrial metaphor for software included those details…

 

Jack doesn’t think this will occur, and I hope he’s right. I’m not entirely convinced, but I guess we’ll see.

 

The whole things smells a lot like CASE to me, and that ultimately didn’t work out. It cost corporations a lot of money, and made a lot of money for some vendors and consultants, but ultimately didn’t work. I asked Jack why he thought the current crop of tools would work where CASE failed. His answer is that we’ve matured as an industry. Specifically our ability to describe complex systems through metadata has matured, as has our ability to generate code based on that metadata. I guess we’ll find out one way or the other over the next 5-10 years. If he’s right, then the stuff he’s working on will have a far greater impact on software development than web services, SOAP or SOA could ever dream of.

 

In any case, I do think that the creation of more powerful modeling tools that are more closely linked to our code and actual deployment environment are very compelling. Certainly the designers coming in Team System are version 1.0 products, and will only go so far, but there’s no doubt in my mind that this type of close-to-the-code designer has a strong future.

 

Of course Jack had to fend off critical questions about why the Class Designer (and the others) deviate from UML. I thought he had very good answers for each question, and I personally agree with the direction Microsoft is going. But then again, I am coming from a VB background – very pragmatic and focused on getting actual work done.

 

Pure UML may be able to accurately describe .NET code through various arcane notations, but the reality as that most developers will never understand anything that must be described as “arcane”… The more obvious and comprehensible a notation, the better it will serve those of us trying to just build decent software. The whole idea behind academic research is to come up with concepts that can be adapted to the real world and made practical and useful. I think UML fits the academic definition nicely, and the Class Designer is a good shot at adapting it to something that’s tangibly useful for the majority of .NET developers.

 

Monday, June 21, 2004 11:11:44 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, June 11, 2004

I recently had a reader of my business objects book ask about combining CSLA .NET and SOA concepts into a single application.

 

Certainly there are very valid ways of implementing services and client applications using CSLA such that the result fits nicely into the SOA world. For instance, in Chapter 10 I specifically demonstrate how to create services based on CSLA-style business objects, and in some of my VS Live presentations I discuss how consumption of SOA-style services fits directly into the CSLA architecture within the DataPortal_xyz methods (instead of using ADO.NET).

 

But the reader put forth the following, which I wanted to discuss in more detail. The text in italics is the reader’s view of Microsoft’s “standard” SOA architecture. My response follows in normal text:

 

1. Here is the simplified MS’s “standard” layering,

 

(a) UI Components

(b) UI Process Components [UI never talk to BSI/BC directly, must via UIP]

 

(c) Service Interfaces

(d) Business Components [UIP never talk to D directly, must via BC]

(e) Business Entities

 

(f) Data Access Logic Components

 

I’m aware of its “transaction script” and “anemic domain model” tendency, but it is perhaps easier for integration and using tools.

 

To be clear, I think this portrayal of ‘SOA’ is misleading and dangerous. SOA describes the interactions between separate applications, while this would lead one into thinking that SOA is used inside an application between tiers. I believe that is entirely wrong – and if you pay attention to what noted experts like Pat Helland are saying, you’ll see that this approach is invalid.

 

SOA describes a loosely-coupled, message-based set of interactions between applications or services. But in this context, the word ‘service’ is synonymous with ‘application’, since services must stand alone and be entirely self-sufficient.

 

Under no circumstance can you view a ‘tier’ as a ‘service’ in the context of SOA. A tier is part of an application, and implements part of the application’s overall functionality. Tiers are not designed to stand alone or be used by arbitrary clients – they are designed for use by the rest of their application. I discussed this earlier in my post on trust boundaries, and how services inherently create new trust boundaries by their very nature.

 

So in my view you are describing at least two separate applications. You have an application with a GUI or web UI (a and b or ab), and an application with an XML interface (c, d, e and f or cdef).

 

To fit into the SOA model, each of these applications (ab and cdef) is separate and must stand alone. They are not tiers in a single application, but rather are two separate applications that interact. The XML interface from cdef must be designed to service not only the ab application, but any other applications that need its functionality. That’s the whole point of an SOA-based model – to make this type of functionality broadly available and reusable.

 

Likewise, application ab should be viewed as a full-blown application. The design of ab shouldn’t necessarily eschew business logic – especially validation, but likely also including some calculations or other data manipulation. After all, it is the job of the designer of ab to provide the user with a satisfactory experience based on their requirements – which is similar, but not the same, as the set of requirements for cdef.

 

Yes, this does mean that you’ll have duplicate logic in ab and cdef. That’s one of the side-effects of SOA. If you don’t like it, don’t use SOA.

 

But there’s nothing to stop you from using CSLA .NET as a model to create either ab or cdef or both.

 

To create ab with CSLA .NET, you’d design a set of business objects (with as little or much logic as you felt was required). Since ab doesn’t have a data store of its own, but rather uses cdef as a data store, the DataPortal_xyz methods in the business objects would call the services exposed by cdef to retrieve and update data as needed.

 

To create cdef with CSLA .NET, you’d follow the basic concepts I discuss in Chapter 10 in my VB.NET and C# Business Objects books. The basic concept is that you create a set of XML web services as an interface that provides the outside world with data and/or functionality. The functionality and data is provided from a set of CSLA .NET objects, which are used by the web services themselves.

 

Note that the CSLA-style business objects are not directly exposed to the outside world – there is a formal interface definition for the web services which is separate from the CSLA-style business objects themselves. This provides separation of interface (the web services) from implementation (the CSLA-style business objects).

 

Friday, June 11, 2004 6:25:44 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  | 
 Tuesday, June 08, 2004

My recent .NET Rocks! interview was fun and covered a lot of ground. One technology that we discussed was the Whitehorse designers - the SOA designer and Class Designer - that are slated for Visual Studio 2005. In fact, Brian Randell and I co-authored an article on these designers that will come out in the July issue of MSDN Magazine.

Since the Class Designer is an extension of the UML static class diagram concept, the conversation looped briefly through a discussion of the value and history of UML. At least one blog discussion was spurred by this brief interlude.

I use UML on a regular basis, primarily in Visio. I use it as a design tool and for documentation. I don't use it for code-generation at all, because I have yet to find a UML tool that generates code I consider to be acceptable. I think UML is a decent high level modeling tool for software, and I strongly recommend that anyone doing object-oriented design or programming use UML to design and document their system. Having a decent OO diagram is totally comparable to having an ER diagram for your database. You shouldn't be caught without either one!

At the same time, I think UML has become rather dated. There are concepts in both Java and .NET that just can't be expressed in UML diagrams in a reasonable manner. For instance, component-level scoping (Friend in VB, internal in C#) just isn't there. Nor is the concept of a property as opposed to a field. Nor can you really express events or delegates.

If you are going to even try to do code-gen from a diagram, the diagram must include all the concepts of your platform/language. Otherwise you'll never be able to generate the kind of code that a programmer would actually write. In other words, you can use UML to provide abstract concept diagrams for .NET programs, but you can't use UML to express the details because UML simply doesn't have what it takes.

Recognizing this, Microsoft has created this new Class Designer tool for Visual Studio 2005. It is very comparable to a static class diagram. It uses the same symbology and notation as UML. However, it extends UML to include the concepts of field vs property, events, component-level scoping and more. In short, the Class Diagram tool allows us to create UML static class diagrams that can express all the details of a VB or C# program in .NET.

If you are familiar with UML static class diagrams and with .NET, learning the Class Designer notation will take you all of 10 seconds or less. Seriously - it is just UML with a handful of concepts we've all been wishing for over the past several years.

But the real benefit is the real-time code synchronization. The Class Designer is in your project and is directly generated from your code. It is not generated from meta-data, but instead is generated from your VB or C# (or J#) code directly. This means that changes to the diagram are changes to your code. Changes to your code are changes to the diagram. The two are totally linked, because the source for the diagram is the code.

This is not reverse-engineering like we have today with Visio or other tools, this is directly using the VB/C# code as the 'meta-data' for the diagram.

(To be fair, there is an XML file for the diagram as well. This file contains layout information about how you've positioned the graphical elements of the diagram, but it doesn't include anything about your types, methods, properties, fields, etc. - that all comes from the code.)

My only reservation about the Class Designer is that I've mostly moved beyond doing such simple code-gen. Since coming out with my CSLA .NET">VB.NET and C# Business Objects books, I've really started to appreciate the power of code generators that generate complete business classes, including basic validation logic, data access logic and more. Readers of my books have created CodeSmith templates for my CSLA .NET framework, Kathleen Dollard wrote an XSL-based generator in her code-gen book and Magenic has a really powerful one we use when building software for our clients.

While the Class Designer is nice for simple situations, for enterprise development the reality is that you'll want to code-gen a lot more than the basic class skeleton...

Tuesday, June 08, 2004 9:16:04 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  | 
 Sunday, June 06, 2004

I am very happy to report that I'll be giving a full-day workshop on distributed object-oriented application design in .NET this fall at VS Live Orlando. If you are interested in this topic in general, or CSLA .NET specifically, then here's an opportunity to get a full day brain-dump as part of a great overall conference!

Over the past year I've given some 2 hour sessions on this topic as part of the main VS Live conference, and I've had several people come up after the session asking why it isn't a full-day workshop. After all, it is a very big topic to cover in just a couple hours!

Fawcette agrees, and so has decided to do a pre-con for the Orlando conference in September on the topic.

While I'll certainly cover some basic concepts and ideas around distributed object-oriented systems, the fact is that I'll be focusing mostly on how these concepts shaped CSLA .NET and how CSLA .NET addresses many of the issues we face when designing and building such systems. I'll discuss serialization, remoting, n-level undo, why reflection is sometimes very useful, abstraction of business logic and encapsulation of business data and more. I'll also discuss the creation of Windows, Web and Web services interfaces to the business objects.

I'll also dive into some of the more advanced issues that have come up on the CSLA .NET email forum - including items such as concurrency, near real-time notification of simultaneous edits, centralization of business logic (the RuleManager functionality), object-relational mapping issues (including dealing with inheritance) and some thoughts on batch processing and reporting.

Finally, I also plan to spend a bit of time discussing what .NET 2.0 means to object-oriented programming. I'll discuss the (very cool) new data binding enhancements in Windows Forms, and the (not quite as cool) enhancements in Web Forms. I'll also talk about what Indigo is likely to mean for distributed object-oriented systems - including a discussion about why using remoting today is not at all a bad thing!

 

Sunday, June 06, 2004 8:08:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, June 02, 2004

Most people (including me) don’t regularly Dispose() their Command objects when doing data access with ADO.NET. The Connection and DataReader objects have Close() methods, and people are very much in the habit (or should be) of ensuring that either Close() or Dispose() or both are called on Connection and DataReader objects.

 

But Command objects do have a Dispose() method even though they don’t have a Close() method. Should they be disposed?

 

I posed this question to some of the guys on the ADO.NET team at Microsoft. After a few emails bounced around I got an answer: “Sometimes it is important”

 

It turns out that the reason Command objects have a Dispose method is because they inherit from Component, which implements IDisposable. The reason Command objects inherit from Component is so that they can be easily used in the IDE on designer surfaces.

 

However, it also turns out that some Command objects really do have non-managed resources that need to be disposed. Some don’t. How do you know which do and which don’t? You need to ask the dev that wrote the code.

 

It turns out that SqlCommand has no un-managed resources, which is why most of us have gotten away with this so far. However, OleDbCommand and OdbcCommand do have un-managed resources and must be disposed to be safe. I don’t know about OracleCommand – as that didn’t come up in the email discussions.

 

Of course that’s not a practical answer, so the short answer to this whole thing is that you should always Dispose() your Command objects just to be safe.

 

So, follow this basic pattern in VB.NET 2002/2003 (pseudo-code):

 

Dim cn As New Connection("…")

cn.Open()

Try

  Dim cm As Command = cn.CreateCommand()

  Try

    Dim dr As DataReader = cm.ExecuteReader()

    Try

      ' do data reading here

 

    Finally

      dr.Close() ' and/or Dispose() – though Close() and Dispose() both work

    End Try

 

  Finally

    cm.Dispose()

  End Try

 

Finally

  cn.Close() ' and/or Dispose() – though Close() and Dispose() both work

End Try

 


And in C# 1.0 and 2.0 (pseudo-code):

 

using(Connection cn = new Connection("…"))

{

  cn.Open()

  using(Command cm = cn.CreateCommand())

  {

    using(DataReader dr = cm.ExecuteReader())

    {

      // do data reading here

    }

  }

}

 

And in VB 8 (VB.NET 2005) (pseudo-code):

 

Using cn As New Connection("…")

  cn.Open()

  Using cm As Command = cn.CreateCommand()

    Using dr As DataReader = cm.ExecuteReader()

      ' do data reading here

    End Using

  End Using

End Using

 

 

Wednesday, June 02, 2004 10:33:20 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  | 
 Monday, May 31, 2004

A few weeks ago I posted an entry about a solution to today's problem with serializing objects that declare events. It was pointed out that there's a better way to handle the list of delegates, and so here's a better version of the code.

  _
  Private mNonSerializable As EventHandler
  Private mSerializable As EventHandler

  Public Custom Event NameChanged As System.ComponentModel.EventHandler
    AddHandler(ByVal value As System.ComponentModel.EventHandler)
      If value.Target.GetType.IsSerializable Then
        mSerializable = CType([Delegate].Combine(mSerializable, value), EventHandler)

      Else
        mNonSerializable = CType([Delegate].Combine(mNonSerializable, value), EventHandler)
      End If
    End AddHandler

    RemoveHandler(ByVal value As System.ComponentModel.EventHandler)
      If value.Target.GetType.IsSerializable Then
        mSerializable = CType([Delegate].Remove(mSerializable, value), EventHandler)

      Else
        mNonSerializable = CType([Delegate].Remove(mNonSerializable, value), EventHandler)
      End If
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As System.ComponentModel.EventArgs)
      If mNonSerializable IsNot Nothing Then mNonSerializable(sender, e)
      If mSerializable IsNot Nothing Then mSerializable(sender, e)
    End RaiseEvent
  End Event

Monday, May 31, 2004 9:37:08 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  | 
 Saturday, May 29, 2004

This week at Tech Ed in San Diego I got an opportunity to talk to David Chappell and trade some thoughts about SOA, Biztalk and Web services. I always enjoy getting an opportunity to talk to David, as he is an incredibly intelligent and thoughtful person. Better still, he always brings a fresh perspective to topics that I appreciate greatly.

 

In this case we got to talking about his Biztalk presentation, which he delivered at Tech Ed. Unfortunately I missed the talk due to other commitments, but I did get some of the salient bits from our conversation.

 

David put forth that the SOA world is divided into three things: services, objects and data. Services interact with each other following SOA principles of loose coupling and message-based communication. Services are typically composed of objects. Objects interact with data – typically stored in databases.

 

All of this makes sense to me, and meshes well with my view of how services fit into the world at large. Unfortunately we had to cut the conversation short, as I had a Cabana session to deliver with Ted Neward, Chris Kinsman and Keith Pleas. Interestingly enough, Ted and I got into some great discussions with the attendees of the session about SOA, the role of objects and where (or if) object-relational mapping has any value.

 

But back to my SOA conversation with David. David’s terminology scheme is nice, because it avoids the use of the word ‘application’. Trying to apply this word to an SOA world is problematic because it becomes rapidly overloaded. Let’s explore that a bit based on my observations regarding the use of the word ‘application’.

 

Applications expose services, thus implying that applications are “service hosts”, or that services are a type of interface to an application. This makes sense to most people.

 

However, we are now talking about creating SOA applications. These are applications that exist only because they call services and aggregate data and functionality from those services. Such applications may or may not host services in and of themselves.

 

If that wasn’t enough, there’s the idea being that tiers within an application should expose services for use by other tiers in the application. It is often postulated that these tier-level services should be public for use by other applications as well as the ‘hosting’ application.

 

So now things are very complex. An application is a service. An application hosts services. An application is composed of services. An application can contain services that may be exposed to other parts of itself and to others. Oy!

 

Thus, the idea of avoiding the word ‘application’ strikes me as being a Good Thing™.

The use of the trademark symbol for this phrase flows, as far as I know, from J. Michael Straczynski (jms). It may be a bit of Babylon 5 insider trivia, but every time I use the phrase, the ™ goes through my head...

Later in the conference, David and I met up again and talked further. In the meantime I’d been thinking that something was missing from David’s model. Specifically, it is the people. Not only users, but other people that might interact with the overall SOA system at large. David put forth that there’s a couple other things in the mix – specifically user interfaces and workflow processes, and that this is where the people fit in.

 

However, I think there’s a bit more to it than this. I think that for an SOA model to be complete, the people need to truly fit into the model itself. In other words, they must become active participants in the model in the same way that services, objects and data are active participants. Rather than saying that a user interface is another element of the model, I propose that the human become another element of the model.

 

As an aside, I realize that there’s something a bit odd or even scary about treating human beings as just another part of a system model, but I think there’s some value in this exercise. This is no different than what business process analysts do when they are looking at manufacturing processes. Humans are put at the same level as machines that are part of the process and are assigned run rates, costs, overhead and so forth. From that perspective, applying this same view to software seems quite valid to me.

 

So, the question then becomes whether a human is a new entity in the model, or is a sub-type of service, object or data. The way to solve this is to see if a human can fit the role of one of the three pre-existing model concepts.

 

My first instinct was to view a human as a service. After all, services interact with other services, and the human interacts with our system and visa versa. However, services interact using loose coupled, message-based communication. Typically our systems interact with users through a Windows or Web interface. This is not message-based, but rather is really quite tightly coupled. We give the user specific, discrete bits of data and we get back specific, discrete bits of data.

 

Certainly there are examples of message-based interaction with humans. For instance, some systems send humans an email or a fax, and the human later responds in some fashion. Even in this case, however, the human’s response is typically tightly coupled rather than message-based.

 

Ultimately, then, I don’t think we can view a human as a type of service due to the violation of SOA communication requirements.

 

How about having a human be an object? Other than the obvious puns about objectification of humans (women, men or otherwise), this falls apart pretty quickly. Objects live inside of services and interact with other objects within that service. While it is certainly true that objects use tightly coupled communication, and so do humans, I think it is hard to argue that a human is contained within a given service.

 

Only one left. Are humans data? Data is used by objects within a service. More generally, data is an external resource that our system uses by calling a service, which uses its objects to interact with this external resource. Typically this is done by calling stored procedures, where we send the resource a set of discrete data or parameters, and the resource returns a set of discrete data.

 

This sounds terribly similar to how our system interacts with humans. If we turn the idea of a user interface on its head, we could view our system as the actor, and the human as a resource. In such a case, when we display data on a screen, we are basically providing discrete data parameters to a resource (the human) in much the same way we provide parameters to a database via a stored procedure call. The human then responds to our system by providing a set of results in the form of discrete data. This could easily be viewed as equivalent to the results of a stored procedure call.

 

Following this train of thought, a human really can be viewed as a resource very much like a data source. Any user interfaces we implement are really nothing more than a fancy data access layer within a service. A bit more complex than ADO.NET perhaps, but still the same basic concept. Our system needs to retrieve or alter data and we’re calling out to an external resource to get it.

 

I put this idea forward to David, who thought it sounded interesting, but didn’t see where it helped anything. I can’t say that I’m convinced that it helps anything either, but intuitively I think there’s value here.

 

I think the value may lie in how we describe our overall system. And this is important, because SOA is all about the overall systems in our organizations.

 

Nothing makes this more evident than Biztalk 2004 and its orchestration engine. This tool is really all about orchestrating services together into some meaningful process to get work done. However, people are part of almost any real business process, which implies that somewhere in most Biztalk diagrams there should be people. But there aren’t. Maybe that’s because people aren’t services, so Biztalk can’t interact with them directly. Instead, Biztalk needs to interact with services that in turn interact with the people as a resource – asking for them to provide data, or to perform some external action and report the result (which is again, just data).

 

Then again, maybe my thought processes are just totally randomized after being on the road for four weeks straight and this last week being Tech Ed, which is just a wee bit busy (day and night)… I guess only time will tell. When we start seeing humans show up in our system diagrams we’ll get a better idea how and where we, as a species, fit into this new SOA world order.

Saturday, May 29, 2004 8:53:54 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  | 
 Saturday, May 15, 2004

In .NET 1.x there's a problem serializing objects that raise events when those events are handled by a non-serializable object (like a Windows Form). In .NET 2.0 there's at least one workaround in the form of Event Accessors.

The issue in question is as follows.

I have a serializable object, say Customer. It raises an event, say NameChanged. A Windows Form handles that event, which means that behind the scenes there's a delegate reference from the Customer object to the Form. This delegate that is behind the event is called a backing field. It is the field that backs up the event and actually makes it work.

When you try to serialize the Customer object using the BinaryFormatter or SoapFormatter, the serialization automatically attempts to serialize any objects referenced by Customer - including the Windows Form. Of course Windows Form objects are not serializable, so serialization fails and throws a runtime exception.

Normal variables can be marked with the NonSerialized attribute to tell the serializer to ignore that variable during serialization. Unfortunately, an event is not a normal variable. We don't actually want to prevent the event from being serialized, we want to prevent the target of the event delegate (the Windows Form in this example) from being serialized. The NonSerialized attribute can't be applied to targets of delegates, and so we have a problem.

In C# it is possible to use the field: target on an attribute to tell the compiler to apply the attribute to the backing field rather than the actual variable. This means we can use [field: NonSerialized()] to declare an event, which will cause the backing delegate field to be marked with the NonSerialized attribute. This is a bit of a hack, but does provide a solution to the problem. Unfortunately VB.NET doesn't support the field: target for attributes, so VB.NET doesn't have a solution to the problem in .NET 1.x.

Though there is a solution in C#, the solution is not an elegant solution, so in both VB.NET and C# we really need a better answer. I have spent a lot of time talking with the folks in charge of the VB compiler, and hope they come up with an elegant solution for VB 2005. In the meantime, here’s an answer that will work in either language in .NET 2.0.

In VB 2005 we’ll have the ability to declare an event using a “long form” using a concept called an Event Accessor. Rather than declaring an event using one of the normal options like:

Public Event NameChanged()

or

Public Event NameChanged As EventHandler

where the backing field is managed automatically, you’ll be able to declare an event in a way that you manage the backing field:

  Public Custom Event NameChanged As EventHandler

    AddHandler(ByVal value As EventHandler)

    End AddHandler

    RemoveHandler(ByVal value As EventHandler)

    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)

    End RaiseEvent

  End Event

In this model we have direct control over management of each event target. When some code wants to handle our event, the AddHandler block is invoked. When they detach from our event the RemoveHandler block is invoked. When we raise the event (using the normal RaiseEvent keyword), the RaiseEvent block is invoked.

This means we can declare our backing field to be NonSerialized if we so desire. Better yet, we can have two backing fields – one for targets that can be serialized, and another for targets that can’t be serialized:

  _

  Private mNonSerializableHandlers As New Generic.List(Of EventHandler)

  Private mSerializableHandlers As New Generic.List(Of EventHandler)

Then we can look at the type of the target (the object handling our event) and see if it is serializable or not, and put it in the appropriate list:

  Public Custom Event NameChanged As EventHandler

    AddHandler(ByVal value As EventHandler)

      If value.Target.GetType.IsSerializable Then

        mSerializableHandlers.Add(value)

      Else

        If mNonSerializableHandlers Is Nothing Then

          mNonSerializableHandlers = _

            New Generic.List(Of EventHandler)()

        End If

        mNonSerializableHandlers.Add(value)

      End If

    End AddHandler

    RemoveHandler(ByVal value As EventHandler)

      If value.Target.GetType.IsSerializable Then

        mSerializableHandlers.Remove(value)

      Else

        mNonSerializableHandlers.Remove(value)

      End If

    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)

      For Each item As EventHandler In mNonSerializableHandlers

        item.Invoke(sender, e)

      Next

      For Each item As EventHandler In mSerializableHandlers

        item.Invoke(sender, e)

      Next

    End RaiseEvent

  End Event

The end result is that we have declared an event that doesn’t cause problems with serialization, even if the target of the event isn’t serializable.

This is better than today’s C# solution with the field: target on the attribute, because we maintain events for serializable target objects, and only block serialization of target objects that can’t be serialized.

Saturday, May 15, 2004 10:52:16 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [8]  |