Mrinal さんのプロフィールMrinalフォトブログリスト ツール ヘルプ

Mrinal

所在地
好きなもの/好きなこと
Live and let live , let the peace rule our lives .

Amen !!

Mrinal

Don't Walk as if you own the earth , but walk as if you don't care who owns it .
8月6日

SOA Vs EDA

Original Link -> http://blogs.msdn.com/mikegil/archive/2005/01/21/357953.aspx

by Mike Wolf .

 

A Comparison of Service Oriented Architecture (SOA) and Event Driven Architecture (EDA)

 

I was in a conversation with one of my clients the other day when he casually asked me, “So what are your thoughts on the question of SOA vs. EDA?”.  My blank, uncomprehending stare caused him to continue by explaining that representatives from a large “research and advise” firm that I shall not name had been talking to them about their enterprise architecture and seemed to think that they needed to strive for an EDA capable platform, not “just” SOA.  He referred me to a document that had been written by a couple of fine fellows from this firm, which I read and was the inspiration for this blog.

 

Asking which is better or even which is better under which circumstances, seems to me to be like asking which is better: a) Democracy or b) Capitalism?  Neither has anything to do with the other.  About the only similarities that I could argue that SOA has with EDA are that a) they are both badly named (although I will definitely agree the SOA is a much less informative name than EDA) and b) they are not architectures but rather design paradigms.  They are intended to address totally different parts of the problem space and both, either or neither can be used simultaneously in any given “System”.

 

I have said previously that the purpose of SOA is to enable the Manageability of System Complexity; as far as the definition of SOA I think the closest we can get is the generally accepted “Four Tenets of SOA” as proposed by Don Box:

 

  1. Boundaries are Explicit
  2. Services are Autonomous
  3. Services share Schema and Contract, not Class
  4. Compatibility is based upon Policy

 

You will notice that nothing what so ever in the above refers to RPC, calls out the cardinality of the Message passing nor defines any responsibility for determining message routing at either the client or the “service”.  It says nothing about either the holding of state nor the delivery of messages.  All that we are saying is that the boundaries between sub-parts of the system are clearly defined and loosely coupled, the definition is entirely in terms of the Message that is passed across the boundary.  There is no dependency between components other than compliance with the Message format and Contract that defines the exchange.  Any component (either in existence at the time of the creation of the system or subsequently built) that will supply and/or consume such messages in accordance with the explicit policy will be able to function in the system as a whole.  There is absolutely no requirement here for SOAP, XML, RPC or any “predefined” Message routing – these certainly MAY be defined by the Policies and enforced in the Contracts but they would represent one possible implementation of Service Orientation, not Service Orientation itself.

 

EDA is all about Message routing, part of the system that SOA says nothing what so ever about.  There are basically two methods of defining message routing; it can be predetermined – flow based – such as you might see in a traditional, client server type application, a “new age” BizTalk Orchestration or even a “prehistoric” Mainframe JCL job.  If it is not predetermined then it must be evaluated at runtime based on the content of the message or events that occur during the system operation, you might see this in an Email System, a Pub-Sub architecture or Windows itself.  The later is required in EDA.  You could think of Windows programming as the classic Event Driven Architecture – you have lots of subsystems all sitting around doing “nothing” waiting for messages to get dropped into their message loops after which the spring into action to do “something” and may then post messages to other message loops based on what was in the message they received.  It is of course quite possible (even perhaps quite normal) to see systems that are hybrids of these two.  So flows are predetermined because they can be, where as others are not.

 

If you have a system that respects the above tenets but uses only predefined message flows then you have SOA but do not have EDA.  If you have a system that does not respect the above tenets but “reacts” to messages that are sent in response to “events” and may be routed in different paths depending on their content, then you have EDA but not SOA.  If you have a system that reacts to events in order to send messages in non-predetermined paths in a manner that respects the above Tenets then you have SOA and EDA.  If non-of this applies then you have neither SOA nor EDA.  It really is that simple!

 

I once designed an Order Management System that would was both Event Driven and Service Oriented.  Basically a collection of “Services” sat on the perimeter of a communications hub.  As each Service acted on the Order (perhaps by pre-authorizing the billing, or by checking available Inventory), if it altered the state of the order in any way it would raise an event that would say so.  Any service could subscribe to this event and supply a filter which would be applied against all changed orders.  If an order had changed such that the given filter recognized it as “interesting” to that service, then the service would be notified, it may then act on the order itself and may or may not change the order, repeating the whole process.  Why design a system this way?  Well by respecting the rules of SOA we gain the manageability of what will fast become a very complex system.  Sub-parts can be added, removed, changed or moved quickly and easily.  By making the system Event Driven we completely decouple each “service” from each other – each acts upon the Order(s) when it determines that it needs to.  Thus when the business process changes there is no complex altering of Routing and trying to squeeze in new “services” or eliminate existing ones (perhaps under only certain circumstances).  The system is both Flexible and Manageable.

 

Is there a down side?  Well complying with SOA in this case makes certain efficiencies harder to incorporate.  Because each of the services had distinct and well respected boundaries, one service can not leverage the internal state or another in its decision making except by caching already known results.  Adding the caching provided the performance required, but definitely added to the development complexity (I have said before that SOA does not reduce complexity, it merely strives to make it manageable).  Making it Event Driven made it tremendously flexible, message routing was determined entirely at runtime and could be customized for each individual order.  The downside is that there is no easy way to predict any given message flow so it adds to the testing burden.

 

I really think that the confusion over what is and what is not Service Oriented stems from people’s preconceptions of what is meant by the extremely overloaded term “Service”.  I have said many times in the past that Service Oriented Architecture is an extremely poor name because it is really not at all descriptive of what it really is all about.  I can’t do anything about the flavor, if you don’t like it you won’t like it, but I hope this blog may have made the Alphabet Soup just a little less murky.

7月4日

Cryptography and .NET Framework - Part 2 (Secret key Encryption)

Original Link -> http://www.dotnetbips.com/0d7895a3-7b0b-465d-92f9-a0e2e26c494d.aspx?articleid=298

By Bipin Joshi .

 

Introduction :

 

In the Part 1 we learnt the basics of Cryptography and related .NET Framework classes. In this article we are going to see how to work with Secret Key Encryption using Triple-DES algorithm.

Triple-DES

The System.Security.Cryptography namespace contains a class called TripleDESCryptoServiceProvider that provides Triple-DES encryption to your data. DES stands for Data Encryption Standard and the word triple is used because it encrypts the original data thrice.

The secret key encryption needs two things to encrypt the data:

  • A secret key
  • An initialization vector

The encryption algorithms employ use a chaining technique to encrypt the data. In this technique the entire data to be encrypted is divided in smaller blocks. The previously encrypted block of data is used to encrypt the current one and the process repeats.

The Initialization Vector (IV) serves as a seed that is used to encrypt and decrypt the first block of bytes. This ensures that no two blocks of data produce the same block of encrypted text.

For using TripleDESCryptoServiceProvider the encryption key must be of 24 bytes and the initialization vector must be of 8 bytes.

Example of using TripleDESCryptoServiceProvider class

In this example we will first create a class called SecurityHelper that will help us encrypt and decrypt string data. Here is the code for the class:

Imports System.Security.Cryptography
Imports System.IO
Imports System.Text
Public Class SecurityHelper
    Public Key() As Byte
    Public IV() As Byte
    Public Function Encrypt(ByVal strData As String) As Byte()
        Dim data() As Byte = ASCIIEncoding.ASCII.GetBytes(strData)
        Dim tdes As TripleDESCryptoServiceProvider = 
	New TripleDESCryptoServiceProvider
	If Key Is Nothing Then
		tdes.GenerateKey()
		tdes.GenerateIV()
		Key = tdes.Key
		IV = tdes.IV
	Else
		tdes.Key = Key
		tdes.IV = IV
	End If
        Dim encryptor As ICryptoTransform = 
	tdes.CreateEncryptor()
        Dim ms As New MemoryStream
        Dim cs As CryptoStream = 
	New CryptoStream(ms, encryptor, CryptoStreamMode.Write)
        cs.Write(data, 0, data.Length)
        cs.FlushFinalBlock()
        ms.Position = 0
        Dim result(ms.Length - 1) As Byte
        ms.Read(result, 0, ms.Length)
        cs.Close()
        Return result
    End Function
    Public Function Decrypt(ByVal data() As Byte) As String
        Dim tdes As TripleDESCryptoServiceProvider = 
	New TripleDESCryptoServiceProvider
        tdes.Key = Key
        tdes.IV = IV
        Dim decryptor As ICryptoTransform = 
	tdes.CreateDecryptor()
        Dim ms As New MemoryStream
        Dim cs As CryptoStream = 
	New CryptoStream(ms, decryptor, CryptoStreamMode.Write)
        cs.Write(data, 0, data.Length)
        cs.FlushFinalBlock()
        ms.Position = 0
        Dim result(ms.Length - 1) As Byte
        ms.Read(result, 0, ms.Length)
        cs.Close()
        Return ASCIIEncoding.ASCII.GetString(result)
    End Function
End Class

Let's examine the code step by step:

  • We create a class called SecurityHelper with two functions Encrypt() and Decrypt(). The former accepts the string to be encrypted and returns encrypted form of the string as a byte array. The later accepts the encrypted data in the form of a byte array and returns decrypted data as a string.
  • The class has two public variables of byte array type. They are used to assign the secret key and initialization vector.
  • In the Encrypt() function we first convert the string to be encrypted into a byte array using GetBytes() method.
  • We then create an instance of TripleDESCryptoServiceProvider class
  • The key and initialization vector can be supplied externally by you or TripleDESCryptoServiceProvider class can generate one automatically for you. If user has not supplied key and IV we call GenerateKey() and GenerateIV() methods respectively. These methods create a random key and IV automatically for you. We assign the generated key and IV to public variables Key and IV.
  • Then we call CreateEncryptor() method of TripleDESCryptoServiceProvider class and collect its return value in a variable of type ICryptoTransform. The ICryptoTransform interface defines the basic operations of cryptographic transformations.
  • We then create a memory stream. The encrypted data will be put inside this stream.
  • We also create a CryptoStream and pass the memory stream and the encryptor created above.
  • Next, we write the data to be encrypted to the CryptoStream object. The CryptoStream object stores the encrypted version of the data in the supplied memory stream.
  • Finally, we read the memory stream for encrypted data. Put that data in an array of bytes and return it to the caller.

Decryption process is similar but follows reverse path. The only major difference between encryption and decryption code is that in case of decryption we call CreateDecryptor() method of TripleDESCryptoServiceProvider class.

Summary

In this article we saw how TripleDESCryptoServiceProvider class can be used to encrypt and decrypt string data. With little or no modification you can reuse the class for your own requirements. Some common uses of this algorithm can be - storing passwords in database, string confidential data such as bank account numbers etc. in database. In the example above we used memory stream to put our data but you can also use FileStream to save the data to a disk file. In the next article we will see how to use public-key encryption

6月30日

True Random Number Generation

This one is actually good since , the actual system.Random class on .net framework is not a very viable option , this one uses cryptography classes to generate random number bytes and beleive me it rocks even for a
for (int i=0;i<20;i++) kind of loop , for which the normal random number class would have spitted out same number , may be that much time is not good enouch for our dude to think of a different number .
 
 
code -->
====
 

public class RandomNumber

{

private RandomNumberGenerator rng;

// private static ulong biggestNumber = 18446744073709551615;

 

/// <summary>

/// Constructor which creates the random number object

/// </summary>

public RandomNumber()

{

// Create the random number generator.

rng = RandomNumberGenerator.Create();

}

 

/// <summary>

/// This returns a random number of a particular size

/// </summary>

/// <param name="bits">Size of the random number in bits</param>

/// <returns>Random number</returns>

public ulong GetNumber(byte bits)

{

ulong randomNumber = 1;

// Convert the number of bits to bytes.

byte numBytes = Convert.ToByte(bits / 8);

 

Byte[] ranbuff =

new Byte[numBytes];

 

// This retrieves a random sequence of bytes.

rng.GetBytes(ranbuff);

 

uint randomByte;

 

// Here we convert the random bytes to a number, using byte shifting.

for (byte i = 0; i < numBytes; i++)

{

randomByte = (

uint) ranbuff[i];

randomNumber = randomNumber + (randomByte *

Convert.ToUInt64(System.Math.Pow(2, (i * 8))));

}

 

// Return the generated number.

return randomNumber;

}

 

/// <summary>

/// Generates an 8 bit random number

/// </summary>

/// <returns>Random number</returns>

public ulong GetNumber()

{

return GetNumber(8);

}

 

/// <summary>

/// Returns a random number within a specific range min <= number < max.

/// </summary>

/// <param name="min">minimum number of the range</param>

/// <param name="max">maximum number of the range</param>

/// <returns>random number</returns>

public ulong GetNumberInRange(ulong min, ulong max)

{

byte bits = 32;

 

ulong randomNumber = GetNumber(bits);

ulong biggestNumber = Convert.ToUInt64(System.Math.Pow(2, bits));

 

// Takes the generated number and puts it in the range

// that has been asked for.

ulong randomNumberInRange =

Convert.ToUInt64(System.Math.Floor((Convert.ToDouble(randomNumber) /

Convert.ToDouble(biggestNumber) * Convert.ToDouble(max - min)) +

Convert.ToDouble(min)));

 

return randomNumberInRange;

}

 

/// <summary>

/// Returns a random number within a specific range

/// min less than or equal to number less than max

/// </summary>

/// <param name="min">minimum number of the range</param>

/// <param name="max">maximum number of the range</param>

/// <returns>random number</returns>

public int GetNumberInRange(int min, int max)

{

return Convert.ToInt32(GetNumberInRange(Convert.ToUInt64(min),

Convert.ToUInt64(max)));

}

}

6月23日

Steve Jobs - stay fool , stay hungry

Stanford Report, June 14, 2005 'You've got to find what you love,' Jobs says

This is the text of the Commencement address by Steve Jobs, CEO of Apple Computer and of Pixar Animation Studios, delivered on June 12, 2005.

I am honored to be with you today at your commencement from one of the finest universities in the world. I never graduated from college. Truth be told, this is the closest I've ever gotten to a college graduation. Today I want to tell you three stories from my life. That's it. No big deal. Just three stories.

The first story is about connecting the dots.

I dropped out of Reed College after the first 6 months, but then stayed around as a drop-in for another 18 months or so before I really quit. So why did I drop out?

It started before I was born. My biological mother was a young, unwed college graduate student, and she decided to put me up for adoption. She felt very strongly that I should be adopted by college graduates, so everything was all set for me to be adopted at birth by a lawyer and his wife. Except that when I popped out they decided at the last minute that they really wanted a girl. So my parents, who were on a waiting list, got a call in the middle of the night asking: "We have an unexpected baby boy; do you want him?" They said: "Of course." My biological mother later found out that my mother had never graduated from college and that my father had never graduated from high school. She refused to sign the final adoption papers. She only relented a few months later when my parents promised that I would someday go to college.

And 17 years later I did go to college. But I naively chose a college that was almost as expensive as Stanford, and all of my working-class parents' savings were being spent on my college tuition. After six months, I couldn't see the value in it. I had no idea what I wanted to do with my life and no idea how college was going to help me figure it out. And here I was spending all of the money my parents had saved their entire life. So I decided to drop out and trust that it would all work out OK. It was pretty scary at the time, but looking back it was one of the best decisions I ever made. The minute I dropped out I could stop taking the required classes that didn't interest me, and begin dropping in on the ones that looked interesting.

It wasn't all romantic. I didn't have a dorm room, so I slept on the floor in friends' rooms, I returned coke bottles for the 5¢ deposits to buy food with, and I would walk the 7 miles across town every Sunday night to get one good meal a week at the Hare Krishna temple. I loved it. And much of what I stumbled into by following my curiosity and intuition turned out to be priceless later on. Let me give you one example:

Reed College at that time offered perhaps the best calligraphy instruction in the country. Throughout the campus every poster, every label on every drawer, was beautifully hand calligraphed. Because I had dropped out and didn't have to take the normal classes, I decided to take a calligraphy class to learn how to do this. I learned about serif and san serif typefaces, about varying the amount of space between different letter combinations, about what makes great typography great. It was beautiful, historical, artistically subtle in a way that science can't capture, and I found it fascinating.

None of this had even a hope of any practical application in my life. But ten years later, when we were designing the first Macintosh computer, it all came back to me. And we designed it all into the Mac. It was the first computer with beautiful typography. If I had never dropped in on that single course in college, the Mac would have never had multiple typefaces or proportionally spaced fonts. And since Windows just copied the Mac, its likely that no personal computer would have them. If I had never dropped out, I would have never dropped in on this calligraphy class, and personal computers might not have the wonderful typography that they do. Of course it was impossible to connect the dots looking forward when I was in college. But it was very, very clear looking backwards ten years later.

Again, you can't connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future. You have to trust in something - your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all the difference in my life.

My second story is about love and loss.

I was lucky – I found what I loved to do early in life. Woz and I started Apple in my parents garage when I was 20. We worked hard, and in 10 years Apple had grown from just the two of us in a garage into a $2 billion company with over 4000 employees. We had just released our finest creation - the Macintosh - a year earlier, and I had just turned 30. And then I got fired. How can you get fired from a company you started? Well, as Apple grew we hired someone who I thought was very talented to run the company with me, and for the first year or so things went well. But then our visions of the future began to diverge and eventually we had a falling out. When we did, our Board of Directors sided with him. So at 30 I was out. And very publicly out. What had been the focus of my entire adult life was gone, and it was devastating.

I really didn't know what to do for a few months. I felt that I had let the previous generation of entrepreneurs down - that I had dropped the baton as it was being passed to me. I met with David Packard and Bob Noyce and tried to apologize for screwing up so badly. I was a very public failure, and I even thought about running away from the valley. But something slowly began to dawn on me – I still loved what I did. The turn of events at Apple had not changed that one bit. I had been rejected, but I was still in love. And so I decided to start over.

I didn't see it then, but it turned out that getting fired from Apple was the best thing that could have ever happened to me. The heaviness of being successful was replaced by the lightness of being a beginner again, less sure about everything. It freed me to enter one of the most creative periods of my life.

During the next five years, I started a company named NeXT, another company named Pixar, and fell in love with an amazing woman who would become my wife. Pixar went on to create the worlds first computer animated feature film, Toy Story, and is now the most successful animation studio in the world. In a remarkable turn of events, Apple bought NeXT, I retuned to Apple, and the technology we developed at NeXT is at the heart of Apple's current renaissance. And Laurene and I have a wonderful family together.

I'm pretty sure none of this would have happened if I hadn't been fired from Apple. It was awful tasting medicine, but I guess the patient needed it. Sometimes life hits you in the head with a brick. Don't lose faith. I'm convinced that the only thing that kept me going was that I loved what I did. You've got to find what you love. And that is as true for your work as it is for your lovers. Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle. As with all matters of the heart, you'll know when you find it. And, like any great relationship, it just gets better and better as the years roll on. So keep looking until you find it. Don't settle.

My third story is about death.

When I was 17, I read a quote that went something like: "If you live each day as if it was your last, someday you'll most certainly be right." It made an impression on me, and since then, for the past 33 years, I have looked in the mirror every morning and asked myself: "If today were the last day of my life, would I want to do what I am about to do today?" And whenever the answer has been "No" for too many days in a row, I know I need to change something.

Remembering that I'll be dead soon is the most important tool I've ever encountered to help me make the big choices in life. Because almost everything – all external expectations, all pride, all fear of embarrassment or failure - these things just fall away in the face of death, leaving only what is truly important. Remembering that you are going to die is the best way I know to avoid the trap of thinking you have something to lose. You are already naked. There is no reason not to follow your heart.

About a year ago I was diagnosed with cancer. I had a scan at 7:30 in the morning, and it clearly showed a tumor on my pancreas. I didn't even know what a pancreas was. The doctors told me this was almost certainly a type of cancer that is incurable, and that I should expect to live no longer than three to six months. My doctor advised me to go home and get my affairs in order, which is doctor's code for prepare to die. It means to try to tell your kids everything you thought you'd have the next 10 years to tell them in just a few months. It means to make sure everything is buttoned up so that it will be as easy as possible for your family. It means to say your goodbyes.

I lived with that diagnosis all day. Later that evening I had a biopsy, where they stuck an endoscope down my throat, through my stomach and into my intestines, put a needle into my pancreas and got a few cells from the tumor. I was sedated, but my wife, who was there, told me that when they viewed the cells under a microscope the doctors started crying because it turned out to be a very rare form of pancreatic cancer that is curable with surgery. I had the surgery and I'm fine now.

This was the closest I've been to facing death, and I hope its the closest I get for a few more decades. Having lived through it, I can now say this to you with a bit more certainty than when death was a useful but purely intellectual concept:

No one wants to die. Even people who want to go to heaven don't want to die to get there. And yet death is the destination we all share. No one has ever escaped it. And that is as it should be, because Death is very likely the single best invention of Life. It is Life's change agent. It clears out the old to make way for the new. Right now the new is you, but someday not too long from now, you will gradually become the old and be cleared away. Sorry to be so dramatic, but it is quite true.

Your time is limited, so don't waste it living someone else's life. Don't be trapped by dogma - which is living with the results of other people's thinking. Don't let the noise of other's opinions drown out your own inner voice. And most important, have the courage to follow your heart and intuition. They somehow already know what you truly want to become. Everything else is secondary.

When I was young, there was an amazing publication called The Whole Earth Catalog, which was one of the bibles of my generation. It was created by a fellow named Stewart Brand not far from here in Menlo Park, and he brought it to life with his poetic touch. This was in the late 1960's, before personal computers and desktop publishing, so it was all made with typewriters, scissors, and polaroid cameras. It was sort of like Google in paperback form, 35 years before Google came along: it was idealistic, and overflowing with neat tools and great notions.

Stewart and his team put out several issues of The Whole Earth Catalog, and then when it had run its course, they put out a final issue. It was the mid-1970s, and I was your age. On the back cover of their final issue was a photograph of an early morning country road, the kind you might find yourself hitchhiking on if you were so adventurous. Beneath it were the words: "Stay Hungry. Stay Foolish." It was their farewell message as they signed off. Stay Hungry. Stay Foolish. And I have always wished that for myself. And now, as you graduate to begin anew, I wish that for you.

Stay Hungry. Stay Foolish.

Thank you all very much.

6月21日

.Net Serialization - ISerializable

Original Link - http://www.codeguru.com/columns/DotNet/article.php/c6595/

By Mickey williams

Serialization is a key part of the .NET framework. The remoting infrastructure, including Web Services and SOAP depend on serialization, which is the process of reducing an object instance into a transportable format that represents a high-fidelity representation of the object. What makes this process interesting is that you may also take the serialized representation, transport it to another context such as a different machine, and rebuild your original object. Given an effective serialization framework, objects may be persisted to storage by simply serializing object representation to disk. Given an efficient serialization framework, objects may be remoted by simply serializing an object to a stream of bytes stored in memory, and transmitting the stream to a cooperating machine that understands your serialization format.

In .NET, serialization is often used with streams, which are the abstractions used to read and write to sources such as files, network endpoints, and memory sinks. Richard Grimes wrote an earlier column on .NET streams for CodeGuru, which you can read here.

How Do You Use Serialization?

Serialization is handled primarily by classes and interfaces in the System.Runtime.Serialization namespace. To serialize an object, you need to create two things:

  • a stream to contain the serialized objects
  • a formatter to serialize the objects into the stream

The code required to perform serialization in .NET is very simple. Most serialization code is similar to the boilerplate code shown below, which serializes an object into a file stream using the BinaryFormatter class:

public static void WriteToFile(BaseballPlayer bp, String filename) { Stream str = File.OpenWrite(filename); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(str, bp); str.Close(); }

Using the BinaryFormatter for serialization results in a compact representation on disk, although it is not a form that is easily read using a text editor. If you would like a more human-friendly representation, you can use the SOAP formatter, as shown below:

public static void WriteToFile(SerialCircle shape, String filename) { Stream str = File.OpenWrite(filename); SoapFormatter formatter = new SoapFormatter(); formatter.Serialize(str, shape); str.Close(); } Simplified Serialization Using Attributes

The simplest way to make your classes eligible for serialization is to use the Serializable attribute. By decorating your class with this attribute as shown below, your classes are immediately made serializable:

[Serializable] public class BaseballPlayer { [...] }

By default, all members of a class are serialized, including private members. To reduce the amount of data serialized to the stream, you can inhibit serialization of members that are not required to reconstitute the class by attaching the NonSerialized attribute to those members:

[NonSerialized] private Decimal _salary;

The NonSerialized attribute is useful for those member variables that represent calculated values or contain information that is transient rather than persistent, or data that should be hidden and not persisted to a storage medium.

Serialization and Private Members

In order for serialization to work effectively, the serialization mechanism must be able to capture enough information about the state of an object to allow it to properly recreate a true copy of the original object at a later time. This often requires information not available to public clients of a class, but it is a necessary side-effect of the work that the serializer must perform. Improperly serialized objects cannot be deserialized properly—it's as simple as that. An example of failed serialization can be seen in the movie Galaxy Quest, where the transporter mechanism fails its test, effectively deserializing a menacing beast inside-out, with explosive (and messy) results.

Is Exposure Required?

In the MFC class library, objects were responsible for serializing themselves. While this did prevent the sharing of internal class details with formatters, it did require all class authors to write correct serialization code for all classes that might ever require serialization. This requirement leads to the following problems:

  • Many developers who can write usable classes cannot write good serialization code. This leads to problems similar to the exploding space pig in Galaxy Quest.

  • Testing can detect the likely hood that a specific class will result in explosions, but such tests increase the testing effort required for each class that implements serialization support.
  • Embedded serialization code adds to the costs of maintainability and adds to the risk of updating components. Any changes to a class that supports serialization in MFC must be properly reflected in the serialization code. Errors in this code may be, as noted previously, just as catastrophic as code that performs the "real work" of the class.
  • But there is a simple way around this mechanism—you can simply elect to not participate in MFC serialization, which may limit the usefulness of your class. Note that even though your class does not need serialization today, it may need it tomorrow, and software developers are notoriously bad at foretelling the future. In NET, all types are self-describing, and the serialization architecture simply leverages the self-describing nature of .NET objects to perform serialization, without all of the problems inherent in the MFC approach. What do you get out of the improved serialization in .NET?
  • In most cases, you need to write very little serialization code. In this column, the code examples are covering special cases, but much of the time you'll need to write zero (or very little) code.
  • You don't need to maintain the serialization code you don't write—there's somebody at Microsoft doing that for you.
  • You can version your classes as needed—the serialization will occur correctly, as the serialization architecture adapts to changes to your classes.
  • The serialization framework provides several places where you can customize portions of the framework to suit your needs. For example, you can write your own formatter class if you need to format your serialization output in a specific way, using ROT-13 encoded XML, for example.
  • All of your classes can participate in serialization, with no work (other than an attribute tag) required by you.
How does Serialization Work in .NET?

As discussed earlier, .NET objects are serialized to streams, which are discussed in the Richard Grimes article here. To summarize and review, when serializing objects to a stream, you must use a .NET formatter class to control the serialization of the object to and from the stream. In addition to the serialized data, the serialization stream carries information about the object's type, including its assembly name, culture, and version.

The Role of Formatters in .NET Serialization

A formatter is used to determine the serialized format for objects. All formatters expose the IFormatter interface, and two formatters are provided as part of the .NET framework:

  • BinaryFormatter provides binary encoding for compact serialization to storage, or for socket-based network streams. The BinaryFormatter class is generally not appropriate when data must be passed through a firewall.
  • SoapFormatter provides formatting that can be used to enable objects to be serialized using the SOAP protocol. The SoapFormatter class is primarily used for serialization through firewalls or among diverse systems. The .NET framework also includes the abstract Formatter class that may be used as a base class for custom formatters. This class inherits from the IFormatter interface, and all IFormatter properties and methods are kept abstract, but you do get the benefit of a number of helper methods that are provided for you.

When implementing a formatter, you'll need to make use of the FormatterServices and ObjectManager classes. The FormatterServices class provides basic functionality that a formatter requires, such as retrieving the set of serializable members object, discovering their types, and retrieving their values. The ObjectManager class is used during deserialization to assist with recovering objects from the stream. When a type is encountered in the stream, it is sometimes a forward reference, which requires special handling by the ObjectManager class.

Taking Control of Serialization with the ISerializable Interface

While the [Serializable] attribute is fine for classes that don't require fine-grained control of their object state, occasionally you may require a more flexible serialization mechanism. Classes that require more control over the serialization process can implement the ISerializable interface.

When implementing the ISerializable interface, a class must provide the GetObjectData method that is included in the interface, as well as a specialized constructor that is specialized to accept two parameters: an instance of SerializationInfo, and an instance of StreamingContext. A minimal class that implements ISerializable is shown below:

[Serializable] public class SerialCircle: ISerializable { public SerialCircle(double radius) { Console.WriteLine("Normal constructor"); ConfigureCircleFromRadius(radius); } private SerialCircle(SerializationInfo info, StreamingContext context) { Console.WriteLine("Deserialization constructor via ISerializable"); double radius = info.GetDouble("_radius"); ConfigureCircleFromRadius(radius); } public void GetObjectData(SerializationInfo info, StreamingContext context) { Console.WriteLine("Serialization via ISerializable.GetObjectData"); info.AddValue("_radius", _radius); } private void ConfigureCircleFromRadius(double radius) { _radius = radius; _circumference = 2 * 3.14 * radius; _area = 3.14 * radius * radius; } public double Circumference { get {return _circumference;} } public double Radius { get {return _radius;} } public double Area { get {return _area;} } private double _radius; private double _area; private double _circumference; }

A version of SerialCircle that uses default serialization serializes the values of each member variable to the stream. However, the _area and _circumference members can be calculated based on the value of _radius. The SerialCircle class implements the ISerializable interface so that it can control which class members are serialized—it serializes only the _radius member, and calculates that values for other members when deserialized.

The GetObjectData function is used to serialize the object, and the specialized constructor is used to deserialize the object. The constructor and GetObjectData are passed the same parameters: an instance of the SerializationInfo class and an instance of the StreamingContext structure.

The framework calls GetObjectData to notify an object that a serialization is in progress. The object is expected to serialize itself into the SerializationInfo object that is passed as a parameter to GetObjectData:

public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("_radius", _radius); }

SerializationInfo is a final class that holds the serialized representation of an object. During serialization, an instance of this class is populated with data about the serialized object using the AddInfo function. During deserialization, an instance of SerializationInfo is used to construct a new instance of the serialized class, by calling one of the GetXxxx functions to extract data from the SerializationInfo object:

private SerialCircle(SerializationInfo info, StreamingContext context) { double radius = info.GetDouble("_radius"); }

The SerializationInfo.AddInfo member function is overloaded to provide versions for any type that you can serialize. The AddInfo method is used to create a name-value pair that is serialized to the stream. During deserialization the name is used to retrieve the value, using one of the GetXxxx methods, where Xxxx is replaced by the type to be recovered. In the example above, GetDouble is used to return a double; there are similar versions for Strings, integers, and all other .NET types.

Using the StreamingContext Structure

The StreamingContext structure is used to indicate how a serialized object will be used. Classes that implement ISerializable may optionally use this information to determine which fields are relevant for serialization. For example, some objects may use a more compact representation when serialized to disk, with the intention of recreating internal structures when the object is recovered. When cloned into a memory stream in the same process—perhaps for cloning a new object, the serialization policy may preserve internal structures for runtime efficiency. Will every class need to use this sort of advanced serialization Kung Fu? No, but it's there if you need it.

There are two properties that are exposed by the StreamingContext structure:

  • State is a value from the ContextStreamingStates enumeration, which is discussed below. This is the property gives you a hint about the reason for the serialization request.
  • Context an object that is associated with this instance of StreamingContext. This value is generally not used unless you have associated an interesting value with the StreamingContext as part of the serialization process.

ContextStreamingStates is an enumeration that provides a clue about the type of serialization that is occurring. This information is sometimes useful—for example, when a client is on a remote machine, information about process handles should be serialized completely, but if the serialization is occurring within a process, a reference to the handle may be sufficient. The enumeration values for ContextStreamingStates are shown in the table below.

Value

Meaning

All

The serialized data may be used or sent from any context

Clone

The serialized data targets the same process

CrossAppDomain

The serialized data is for a different AppDomain

CrossMachine

The serialized data is for a different computer

CrossProcess

The serialized data is for a different process on the current computer

File

The serialized data is read or written to a file

Other

The context is not known

Persistence

The serialized data is stored in a database, file, or other persistent store

Remoting

The serialized data is for a remote context, which may be a different computer

Of the possible values for ContextStreamingStates, you should pay special attention to the File and Persistence states. These two values indicate that the object is being deserialized into a stream that may be long-lived, and is likely to require special handling. For example, the object may be deserialized days, weeks or years from now—serializing values that are short-lived may not be required.

In the SerialCircle example, ISerializable is implemented in order to remove two fields from the serialization stream; however, you could just as easily add information into the stream, such as authentication hints or optimization instructions. Once you take control of the serialization process for your class, you can manage serialization however you see fit.

When is Deserialization Complete?

Serializing simple objects that have no dependencies on other objects is a simple matter; even a computer book author can do it. In real life, objects are often serialized together, with some objects in the serialization stream depending on other objects. This presents a problem, as during deserialization there is no guarantee on the order that specific objects are reconstituted. If you find that instances of your class depend on other objects that are being deserialized, you can receive a notification when all deserialization is complete by implementing the IDeserializationCallback interface.

IDeserializationCallback has one method: OnDeserialization. This method is implemented by serializable classes, and is invoked by the framework when all objects have been deserialized. Continuing with the SerialCircle example presented earlier, initialization of the circle can be deferred until deserialization is complete by waiting until OnDeserialization is called:

private SerialCircle(SerializationInfo info, StreamingContext context) { _radius = info.GetDouble("_radius"); } public void OnDeserialization(Object sender) { ConfigureCircleFromRadius(_radius); }

In the code fragment above, we have changed the deserialization constructor so that it only initializes the _radius member variable. When the framework invokes OnDeserialization through the IDeserializationCallback interface, the initialization of the object is completed by calling ConfigureCircleFromRadius. The SerialCircle project included with this article includes the OnDeserialization code.

A Word About Final Classes

The .NET framework allows classes such as SerializationInfo and SerializableAttribute to be declared as final, meaning that they cannot be subclassed. Although the framework uses the term final, as in "this is the final form of this type," each language in the runtime seems to use a different term:

  • Visual Basic programmers use the NotInheritable keyword
  • C# programmers use the sealed keyword
  • If you're using the managed C++ compiler, look for __sealed
  • Eiffel users have the frozen keyword

That's all of the languages I know about, but if you're aware of more, send them to me at mw@codevtech.com, and I'll add them to my .NET Rosetta Stone.

Next Column

The next column will discuss memory management in .NET, and how it differs from the memory management you're probably accustomed to. We'll discuss the garbage collector, finalizers, and how to write efficient code in a GC environment.

About the Author

Mickey Williams is the founder of Codev Technologies, a provider of tools and consulting for Windows Developers. He is also on the staff at .NET Experts (www.dotnetexperts.com), where he teaches the .NET Framework course. He has spoken at conferences in the USA and Europe, and has written eight books on Windows programming. Mickey can be reached at mw@codevtech.com.

.NET Serialization, Part 2( XML Serialization)

.NET Serialization, Part 2 ( XML Serialization)

by Wei-Meng Lee

Original Link - http://www.ondotnet.com/pub/a/dotnet/2003/11/03/serializationpt2.html

In my last article, I discussed how to serialize objects into a binary stream, as well as into a SOAP message. A third way to serialize an object is to serialize it into an XML document. There are many advantages to XML serialization -- XML documents are platform-agnostic, since they is in plain text format and that makes cross platform communications very easy. XML documents are also easy to read and modify, which makes XML a very flexible format for data representation.

In this article, I will illustrate XML serialization with an example and show you some of its uses.

Defining Our Sample Class

Let's define a class so that we can see how XML serialization works. For this example, I have defined a Member class that allows you to store information about a person, such as name, addresses, and date of birth. Here is the class definition:

Public Class Member Private age As Integer Public Name As CName Public Addresses() As CAddress Public DOB As Date ReadOnly Property currentAge() Get age = DateDiff(DateInterval.Year, DOB, Now) Return age End Get End Property End Class Public Class CName Private pFirstName, pLastName As String Property FirstName() Get Return pFirstName End Get Set(ByVal Value) pFirstName = Value End Set End Property Property LastName() Get Return pLastName End Get Set(ByVal Value) pLastName = Value End Set End Property End Class Public Class CAddress Public Line1 As String Public Line2 As String Public City As String Public Country As String Public Postal As String End Class

I have deliberately designed my class so that I can illustrate the various aspects of XML serialization. Here are the specifics:

  • The Member class contains both private and public variables. It also contains a READONLY property.
  • The Member class contains a public array containing the addresses of a Member.
  • The Member class contains a variable of Date data type.
  • The CName class contains two private variables and two properties.
  • The CAddress contains only public variables.

To serialize a Member object into a XML document, I used the XMLSerializer class from the System.Xml.Serialization namespace:

Imports System.Xml.Serialization '========XML Serialization========= Sub XMLSerialize(ByVal mem As Member) Dim wri As New StreamWriter("c:\Members.xml") Try Dim ser As New XmlSerializer(GetType(Member)) ser.Serialize(wri, mem) Catch ex As Exception MsgBox(ex.ToString) Finally wri.Close() End Try End Sub

Assuming I have the following object declaration:

Dim mem As New Member Dim memName As New CName memName.FirstName = "Wei-Meng" memName.LastName = "Lee" mem.Name = memName mem.DOB = "5/1/1972" Dim address As New CAddress address.Line1 = "One Way Street" address.Line2 = "Infinite Loop" address.Country = "SINGAPORE" address.Postal = "456123" Dim addresses(1) As CAddress addresses(0) = address addresses(1) = address mem.Addresses = addresses

To serialize the Member object, invoke the XMLSerialize() method, as shown earlier:

XMLSerialize(mem)

The XML document generated looks like this:

<?xml version="1.0" encoding="utf-8"?> <Member xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Name> <FirstName xsi:type="xsd:string">Wei-Meng</FirstName> <LastName xsi:type="xsd:string">Lee</LastName> </Name> <Addresses> <CAddress> <Line1>One Way Street</Line1> <Line2>Infinite Loop</Line2> <Country>SINGAPORE</Country> <Postal>456123</Postal> </CAddress> <CAddress> <Line1>One Way Street</Line1> <Line2>Infinite Loop</Line2> <Country>SINGAPORE</Country> <Postal>456123</Postal> </CAddress> </Addresses> <DOB>1972-05-01T00:00:00.0000000-07:00</DOB> </Member>

As you can see, the object is serialized into an XML document with a format corresponding to the structure of the object. (To de-serialize the XML document, simply use the Deserialize() method from the XMLSerializer class.)

Here are some important points to note:

  • The City information is not persisted in the XML document, as it is not assigned in the object. I will show you later how to ensure that an empty element is inserted, even though a value is not assigned.
  • All READ/WRITE properties in the object are persisted in the XML document, except the READONLY currentAge property in the Member class.
  • Only public variables are persisted; private variables are not persisted in XML serialization.
  • The default name for each element in the XML document takes after the variable (or class) name. In most cases this is desirable, except in the case where the individual address is represented by the <caddress> element (which may not be too obvious to the person reading the XML document).

Despite the fairly automated task performed by the XMLSerializer object, you can customize the way the XML document is generated. Let's modify our classes with a few attributes. Here is the modified class:

<XmlRoot("MemberInformation", _ Namespace:="http://www.mycompany.com", _ IsNullable:=True)> _ Public Class Member Private age As Integer ' specify the element name to be MemberName <XmlElement("MemberName")> _ Public Name As CName ' specify the sub-element(s) of Addresses to be Address <XmlArrayItem("Address")> _ Public Addresses() As CAddress Public DOB As Date ReadOnly Property currentAge() Get age = DateDiff(DateInterval.Year, DOB, Now) Return age End Get End Property End Class Public Class CName Private pFirstName, pLastName As String Property FirstName() Get Return pFirstName End Get Set(ByVal Value) pFirstName = Value End Set End Property Property LastName() Get Return pLastName End Get Set(ByVal Value) pLastName = Value End Set End Property End Class Public Class CAddress Public Line1 As String Public Line2 As String ' empty element if city is not specified <XmlElement(isnullable:=True)> _ Public City As String ' specify country and postal as attribute <XmlAttributeAttribute()> _ Public Country As String <XmlAttributeAttribute()> _ Public Postal As String End Class

When the class is serialized, the XML document looks like this:

<?xml version="1.0" encoding="utf-8"?> <MemberInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.mycompany.com"> <MemberName> <FirstName xsi:type="xsd:string">Wei-Meng</FirstName> <LastName xsi:type="xsd:string">Lee</LastName> </MemberName> <Addresses> <Address Country="SINGAPORE" Postal="456123"> <Line1>One Way Street</Line1> <Line2>Infinite Loop</Line2> <City xsi:nil="true" /> </Address> <Address Country="SINGAPORE" Postal="456123"> <Line1>One Way Street</Line1> <Line2>Infinite Loop</Line2> <City xsi:nil="true" /> </Address> </Addresses> <DOB>1972-05-01T00:00:00.0000000-07:00</DOB> </MemberInformation>

Here are the uses of each attribute:

<XmlRoot("MemberInformation", _ Namespace:="http://www.mycompany.com", _ IsNullable:=True)> _ Public Class Member ...

Sets the root element name of the XML document to be MemberInformation (default element name is Member, which follows the class name), with a specific namespace. The IsNullable attribute indicates if empty elements must be displayed.

<XmlElement("MemberName")> _ Public Name As CName ...

Specifies that the element name MemberName be used in place of the current variable name (as defined in the class as CName).

<XmlArrayItem("Address")> _ Public Addresses() As CAddress ...

Specifies that the following variable is repeating (an array) and that each repeating element be named as Address.

<XmlElement(isnullable:=True)> _ Public City As String ...

Indicates that the document must include the City element even if it is empty.

<XmlAttributeAttribute()> _ Public Country As String

Indicates that the Country information be represented as an attribute.

XML Serialization Needs a Default Constructor

There is one more thing that you need to take note of when doing XML serialization. If your class has a constructor (as the following example shows), then you would also need a default constructor:

Public Class Points Sub New(ByVal x As Single, ByVal y As Single) End Sub Property x() Get End Get Set(ByVal Value) End Set End Property Property y() Get End Get Set(ByVal Value) End Set End Property End Class

The above example will result in an error when you try to perform XML serialization on it. To solve the problem, simply add a default constructor to your class definition:

Public Class Points Sub New() End Sub Sub New(ByVal x As Single, ByVal y As Single) End Sub Property x() Get End Get Set(ByVal Value) End Set End Property Property y() Get End Get Set(ByVal Value) End Set End Property End Class Uses of XML Serialization

Now that we have seen how XML serialization works, what are its uses? For one, it can help you to preserve the state of your object (just like the binary and SOAP serialization that you saw in my last article) and makes transportation easy. More significantly, I often use XML serialization to manage configuration files. I can define a class to store configuration information and use XML serialization to persist it on file. By doing so, I have the flexibility to modify the configuration information easily, since the information is now represented in XML; at the same time, I can programmatically manipulate the configuration information by accessing the object's properties and methods.

Wei-Meng Lee is a technologist and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies. He is also the author of O'Reilly's Windows XP Unwired and the .NET Compact Framework Pocket Guide.

.Net Serialization Part - I

Original Link - http://www.ondotnet.com/pub/a/dotnet/2003/10/13/serializationpt1.html

By : Wei-Meng Lee

Comment - an Extremely good article to understand the basics

Many a time, you may need to persist the value of an object to secondary storage. For example, you may wish to save the values of a couple of Point objects representing the positioning of an item on screen to secondary storage. The act of "flattening" an object into a serial form is known as serialization. In this article, I will discuss serialization as supported in the .NET framework -- Binary and SOAP serialization. In the next article, I will discuss how to serialize an object into an XML document.

Binary Serialization

Consider the following class, BookMark, which is used to stored information about web addresses and their descriptions.

Public Class BookMark Private pURL As String Private pDescription As String Private pNextURL As BookMark Private dateCreated As Date Sub New() dateCreated = Now End Sub Public Sub printIndex() Console.WriteLine(dateCreated) End Sub Property URL() Get Return pURL End Get Set(ByVal Value) pURL = Value End Set End Property Property Description() Get Return pDescription End Get Set(ByVal Value) pDescription = Value End Set End Property Property NextURL() Get Return pNextURL End Get Set(ByVal Value) pNextURL = Value End Set End Property End Class

The BookMark class contains properties as well as private variables. The NextURL property is used to link up multiple BookMark objects, much like a linked list.

Let's create two BookMark objects and link them up:

Dim BM1 As New BookMark Dim BM2 As New BookMark BM1.URL = "http://www.amazon.com" BM1.Description = "Amazon.com Web site" BM1.NextURL = BM2 BM2.URL = "http://www.oreilly.com" BM2.Description = "O'Reilly Web Site" BM2.NextURL = Nothing

I will serialize the objects into a binary stream by writing the Serialize() function:

Imports System.IO Imports System.Runtime.Serialization.Formatters.Binary '========Binary Serialization========= Function Serialize(ByVal BkMk As BookMark) _ As MemoryStream Dim ms As New MemoryStream Dim fs As New FileStream("c:\BookMarks.dat", _ FileMode.Create, _ FileAccess.Write) Dim formatter As New BinaryFormatter ' serialize to memory stream formatter.Serialize(ms, BkMk) ' serialize to file stream formatter.Serialize(fs, BkMk) ms.Position = 0 Return ms End Function

Before you serialize an object, you need to prefix the class name with the <Serializable()> attribute:

<Serializable()> Public Class BookMark

I used the BinaryFormatter class from the System.Runtime.Serialization.Formatters.Binary namespace to serialize the BookMark object into a memory stream, as well as into a file stream. The function then returns a memory stream object representing the serialized BookMark object.

'========Binary Serialization========= '---serializing an object graph into a memory stream Dim ms As MemoryStream = Serialize(BM1)

To prove that the object is serialized correctly, I will de-serialize the memory stream and assign it back to a BookMark object:

'---deserializing a memory stream into an object graph Dim newBM As BookMark newBM = Deserialize(ms)

Here is the DeSerialize() function:

Function Deserialize(ByVal ms As MemoryStream) _ As BookMark Dim formatter As New BinaryFormatter Return formatter.Deserialize(ms) End Function

To display the values of the de-serialized BookMark object, I use the Print() subroutine:

Sub Print(ByVal BM As BookMark) Do BM.printIndex() Console.WriteLine(BM.URL.ToString & " - " & BM.Description) BM = BM.NextURL Loop Until BM Is Nothing End Sub

You should see the following in the output window:

9/29/2003 1:11:47 AM http://www.amazon.com - Amazon.com Web site 9/29/2003 1:12:06 AM http://www.oreilly.com - O'Reilly Web Site

But how does the binary stream look like? To answer this question, let's take a look at the c:\BookMarks.dat file that we have created in the process.

To view the binary file, simply drag-and-drop it onto Visual Studio .NET. You should see something similar to what is shown in Figure 1:

Figure 1. Examining the serialized binary file

Some Observations

A few observations are worth noting at this point:

  • Private variables and properties are all serialized. In binary serialization, both the private variables and properties are serialized. This is known as deep serialization, as opposed to shallow serialization in XML serialization (which only serializes the public variables and properties). I will discuss XML serialization in the next article.
  • Object graphs are serialized. In our example, two BookMark objects are linked, and the serialization process takes care of the relationships between the two objects.

There are times that you do not want to serialize all of the data in your object. For example, if you do not wish to persist the date and time that the BookMark objects have been created, you can prefix the variable name (that you do not wish to serialize) with the <NonSerialized()> attribute:

<NonSerialized()> Private dateCreated As Date

The dateCreated variable will not be serialized.

SOAP Serialization

Besides binary serialization, you can also serialize objects into a platform-agnostic format: you can serialize it into a SOAP message.

The SOAPSerialize() subroutine serializes a BookMark object into an XML document (when building this code, you need a reference to the System.Runtime.Serialization.Formatters.Soap.dll assembly):

Imports System.Runtime.Serialization.Formatters.Soap '========SOAP Serialization========= Sub SOAPSerialize(ByVal BkMk As BookMark) Dim fs As New FileStream("c:\BookMarks.xml", _ FileMode.Create, FileAccess.Write) Dim formatter As New SoapFormatter formatter.Serialize(fs, BkMk) ' serialize to file stream fs.Close() End Sub

So, instead of using the BinaryFormatter class, I have replaced it with the SoapFormatter class.

The SOAPDeserialize() function reads the XML document (containing the SOAP message), de-serializes it, and returns a BookMark object:

Function SOAPDeserialize(ByVal filename As String) As BookMark Dim fs As New FileStream(filename, FileMode.Open, _ FileAccess.Read) Dim formatter As New SoapFormatter Return formatter.Deserialize(fs) ' serialize to file stream End Function

Here is how you can call the previous two methods:

'========SOAP Serialization========= SOAPSerialize(BM1) newBM = SOAPDeserialize("c:\ BookMarks.xml") '---printing the object graph Print(newBM)

And the SOAP message generated would look something like this:

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <a1:BookMark id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/WindowsApplication1 /WindowsApplication1%2C%20Version%3D1.0.1125.1874%2C%20Culture%3Dneutral %2C%20PublicKeyToken%3Dnull"> <pURL id="ref-3">http://www.amazon.com</pURL> <pDescription id="ref-4">Amazon.com Web site</pDescription> <pNextURL href="#ref-5"/> </a1:BookMark> <a1:BookMark id="ref-5" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/WindowsApplication1 /WindowsApplication1%2C%20Version%3D1.0.1125.1874%2C%20Culture%3Dneutral%2C %20PublicKeyToken%3Dnull"> <pURL id="ref-6">http://www.oreilly.com</pURL> <pDescription id="ref-7">O'Reilly Web Site</pDescription> <pNextURL xsi:null="1"/> </a1:BookMark> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Uses of Serialization

Serialization is one good way to preserve the state of an object. It is commonly used for network communications, where you need to pass an object from one machine to another. Another good use of serialization is to use it to clone an object -- serialize an object, de-serialize it, and assign to another object. Voilà! You have an identical copy of the object.

In the next article, I will show you how to serialize an object into an XML document.

Wei-Meng Lee is a technologist and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies. He is also the author of O'Reilly's Windows XP Unwired and the .NET Compact Framework Pocket Guide.

Cryptography and .NET Framework - Part 1

Original Link : http://www.dotnetbips.com/e9cb31ca-409e-44bd-98f7-8b901f4d2bcf.aspx?articleid=297

Original Article By : Dotnet bips ( Bipin Joshi )

Introduction

Security is key consideration for many applications. Providing authentication and authorization services to your application is just one part of the overall security. What about the data that is being used and transferred in the application? That is where cryptography comes into picture. Cryptography is a huge topic by itself. In this series of articles I am going to confined our discussion only to .NET Framework and cryptographic classes provided by it.

Why use Cryptography?

Many times application provide security features such as login forms and role based security. However, what if someone intercepts the data that is being flown over the network? What if someone plays with the data that is being transmitted over the network? What if someone opens SQL Server database that is storing passwords? Cryptography provides solution to such questions. Using .NET Cryptographic classes you can encrypt the data that is being flown in your system or network and then decrypt when you want authenticated user to modify or read it. In short Cryptography provides following features:

  • Protect data being transferred from reading by third parties
  • Protect data being transferred from any modification
  • Make sure that data is arriving from the intended location
Types of Cryptographic classes

The overall Cryptographic classes available in .NET framework can be classified in four categories:

  • Classes that deal with secret key encryption (also called as Symmetric Cryptography)
  • Classes that deal with public key encryption (also called Asymmetric Cryptography )
  • Classes that deal with digital signatures (also called cryptographic signatures)
  • Classes that deal with cryptographic hashes

All the cryptography related classes can be found in System.Security.Cryptography namespace.

Secret Key Encryption

In Secret Key Cryptography the data being protected is encrypted using a single secret key. This key is known only to sender and receiver. The sender encrypts the data using the secret key. The receiver decrypts the data using the same secret key. It is very important to keep the key secret otherwise anybody having the key can decrypt the data.

.NET Framework provides following classes to work with Secret Key Cryptography:

  • DESCryptoServiceProvider
  • RC2CryptoServiceProvider
  • RijndaelManaged
  • TripleDESCryptoServiceProvider
Public Key Encryption

Unlike secret key encryption, public key encryption uses two keys. One is called public key and the other is called as private key. The public key is not kept secret at all where as private key is kept confidential by the owner of that key. The data encrypted by private key can be decrypted only using its corresponding public key and data encrypted using public key can be decrypted using its private key. Naturally, in order to encrypt the data being transmitted you need to use public key. This data can be decrypted only with the corresponding private key.

.NET Framework provides following classes to work with public key encryption:

  • DSACryptoServiceProvider
  • RSACryptoServiceProvider
Digital Signatures

Digital signatures are used to verify identity of the sender and ensure data integrity. They are often used along with public key encryption. Digital signature work as follows:

  1. Sender applies hash algorithm to the data being sent and creates a message digest. Message digest is compact representation of the data being sent.
  2. Sender then encrypts the message digest with the private key to get a digital signature
  3. Sender sends the data over a secure channel
  4. Receiver receives the data and decrypts the digital signature using public key and retrieves the message digest
  5. Receiver applies the same hash algorithm as the sender to the data and creates a new message digest
  6. If sender's digest and receiver's digest match then it means that the message really came from the said sender.

The classes DSACryptoServiceProvider and RSACryptoServiceProvider are used to create digital signatures.

Hashes

Hash algorithms create a fixed length output for a given variable length data. If somebody changes the original data even slightly then the hash generated will be different than original hash. They are often used with digital signatures.

Some of the classes in .NET that deal with hashes are:

  • SHA1Managed
  • MD5CryptoServiceProvider
  • MACTripleDES
Random Number Generators

While working with cryptography classes many times you need to generate cryptographic keys. Random number generators are used for this purpose. .NET provides a class called RNGCryptoServiceProvider to generate such random numbers.

In the next article we will see how the secret key encryption can be done using the relevant classes.

 

About the author

Name :

Bipin Joshi

Email :

webmaster at dotnetbips.com

Profile :

Bipin Joshi is the webmaster of DotNetBips.com. He is the founder of BinaryIntellect Consulting (www.binaryintellect.com) - a company providing training and consulting services on .NET framework. He conducts intensive training programs in Thane/Mumbai for developers. He is also a Microsoft MVP (ASP.

Basic Instincts ( Creating and Managing Secondary Threads )

Original Link : http://msdn.microsoft.com/msdnmag/issues/04/06/BasicInstincts/

By : Ted Pattison .

In my January 2004 column I showed you how to use delegates to execute a method in an asynchronous fashion. There you learned how to dispatch an asynchronous method call by simply calling BeginInvoke on a delegate object. Executing methods asynchronously using delegates is easy because the common language runtime (CLR) creates and manages a pool of worker threads for you behind the scenes. When you call BeginInvoke, the CLR takes care of dispatching your request to one of these worker threads from its built-in thread pool.

I recommend that you use asynchronous delegates and the programming techniques shown in my January 2004 column in the majority of cases where you need to execute code asynchronously from a desktop application. However, there are certain occasions when using asynchronous delegates doesn't provide as much flexibility or efficiency as you need.

This month I'll show you how to create and manage your own threads using the Thread class of the CLR. I'll also discuss the scenarios in which it's better to create and manage a secondary thread than to execute a method asynchronously with delegates.


Creating a Thread

When you want to create a new thread, you create an instance of the Thread class defined in the System.Threading namespace. The constructor of the Thread class accepts a reference to a ThreadStart delegate object. You can see two examples of how to create a new thread in the code in Figure 1.

As you can see, there is a longhand syntax and a shorthand syntax for creating a new thread object. The technique for creating ThreadA in Figure 1 demonstrates how to explicitly create a ThreadStart delegate object that is bound to the method named MyAsyncTask. The technique for creating ThreadB accomplishes the same goal with less typing. That's because the Visual Basic® .NET compiler will implicitly create a ThreadStart delegate object when you write the following line of code: Dim ThreadB As New Thread(AddressOf TedsCode.MyAsyncTask)

With version 1.0 and version 1.1 of the CLR, each Thread object is associated with its own physical Win32® thread. However, creating an object from the Thread class doesn't actually create a physical thread. Instead, you must call the Thread object's Start method for the CLR to call to the Windows® OS and create a physical thread. Note that future versions of the CLR are likely to provide an optimization whereby it will not be necessary to create a separate physical thread for each Thread object.

Once the CLR has created the physical thread, it uses it to execute the target method bound to the ThreadStart delegate object. The lifetime of this physical thread is controlled by the target method's execution. When execution of the method completes, the CLR gives control of the physical thread back to Windows. At this point, the OS destroys the physical thread.

You should realize that there is measurable overhead involved in creating and destroying physical threads. This overhead isn't all that significant in a desktop application where a thread is typically created in response to a user's action. However, creating new threads is something you should avoid in server-side code that's written for performance and scalability.

Remember that executing methods asynchronously using delegates leverages the built-in thread pool of the CLR. Therefore, achieving asynchronous execution using delegates scales better in a server-side application because it doesn't require the continual creation and destruction of physical threads.


Passing Parameters to a Secondary Thread

When you create a new Thread object to execute a method asynchronously, you must use a method that matches the calling signature of the ThreadStart delegate. That means you must create a method that is a Sub procedure that accepts no parameters (see the MyAsyncTask sub that is shown in Figure 1). This makes it a bit tricky to pass parameters to a method that is going to execute on a newly created thread.

There is a common technique you can use for passing parameters to a secondary thread; it involves creating a custom thread class. Examine the class definition for TedsThreadClass, shown in Figure 2. You can see how it has been designed with a custom set of instance fields and a parameterized constructor. When you create an object from a custom thread class such as TedsThreadClass, you can initialize it with whatever parameter values are required in your particular situation.

Note that TedsThreadClass is different from the example shown in Figure 1 because in Figure 2 the MyAsyncTask method is defined as an instance method instead of a shared method. That means that the MyAsyncTask method in Figure 2 can access the custom instance fields x and y. The key point of this technique is that it provides the means for passing a customized set of parameters to a method executing on a new secondary thread.

TedsThreadClass contains a protected field named InnerThread, which holds a Thread object that's bound to the instance method MyAsyncTask and a public Start method. This allows the custom thread class to encapsulate the implementation details for creating and managing Thread objects. To use this custom thread class, simply instantiate an object and call its Start method, like this: Dim ThreadA As New TedsThreadClass(1, "Bob") ThreadA.Start()

You have just seen what's involved with a custom thread class that's been designed to pass parameters to an asynchronous method call. Remember that delegates make passing parameters in an asynchronous method call much easier because you can define a custom delegate type with whatever parameter list you like. Note that making an asynchronous method call by creating and managing a thread usually requires more work during design and coding.

You should also consider that executing a method asynchronously with delegates provides an easy way to harvest the return value and output parameters: the delegate's EndInvoke method. Executing methods asynchronously with a new Thread object is not as convenient. You must devise a custom scheme to pass data from secondary threads back to the application's primary thread.

When you are creating and managing secondary threads, it also takes more effort to coordinate thread synchronization. For example, what should you do when you need the application's primary thread to wait until a secondary thread has completed its work? You should call the Join method supplied by the Thread class, as shown in the following code: Dim ThreadA As Thread ThreadA = New Thread(AddressOf TedsCode.MyAsyncTask) '*** do some work on primary thread '*** now block until secondary thread is done ThreadA.Join()

The Join method is a blocking call. The thread that calls Join is blocked until the other thread has finished its work. In other words, the Join method is used to take two threads representing parallel paths of execution and join them together into a single path.


When to Create New Threads

I have already outlined several reasons why executing a method asynchronously on a new Thread object is more difficult and not as efficient as using an asynchronous delegate. Because asynchronous delegates are easier to use and they provide the efficiency of using the built-in thread pool, I recommend you use them when you have to make asynchronous method calls.

There are, however, a few design situations in which delegates should not be used. The following is a list of circumstances in which you should most likely use secondary threads rather than delegates for asynchronous execution.

  • You need to execute a long-running task
  • You need to adjust a thread's priority
  • You need a foreground thread that will keep a managed desktop application alive
  • You need a single-threaded apartment (STA) thread to work with apartment-threaded COM objects

When you need to dedicate a thread to a task that's going to take a long time, you should create a new thread. For example, imagine you need to dedicate a secondary thread to watch for updates to a file or to listen for incoming data on a network socket, and you need it for the lifetime of the application. It would be considered bad style to use delegates because you would effectively be taking a thread out of the CLR thread pool and never returning it. Asynchronous method execution using delegates should only be used for relatively short-running tasks.

When you need to change a thread's priority, you should create a new thread. The Thread class exposes a public Priority property that allows you to increase or decrease the priority of a thread. However, you should not change the priority of threads from the CLR thread pool. You should only adjust the priority of the threads you have created by calling New on the Thread class.

Let's look at a simple example involving a desktop application. Imagine you want to run an asynchronous method on a secondary thread with a lower priority to reduce its impact on the responsiveness of the application's user interface. You can adjust the Thread object's Priority property before calling the Start method: Dim ThreadA As Thread ThreadA = New Thread(AddressOf TedsCode.MyAsyncTask) ThreadA.Priority = ThreadPriority.BelowNormal ThreadA.Start()

The settings for a thread's priority level are Highest, AboveNormal, Normal, BelowNormal, and Lowest. You should generally only lower thread priorities and try to refrain from raising them. Be careful of choosing the Highest and AboveNormal settings because they can have unpredictable effects on the application and the system as a whole.

Creating a new thread is also a good idea when you want to keep a managed desktop application alive while a secondary thread is running. Imagine a scenario in a Windows Forms application where the user closes the main form while a secondary thread is performing a task in the background. Is the fact that this secondary thread is still running important enough to keep the application alive? If the secondary thread is a background thread, the answer is no. The application will shut down right away. However, if the secondary thread is a not a background thread, the app will keep running.

Each Thread object has an IsBackground property that indicates whether it is a background thread. All the threads in the CLR thread pool are background threads and should not be modified in this respect. That means a task executing asynchronously as a result of a call to BeginInvoke on a delegate is never important enough by itself to keep an application alive.

When you create a new Thread object, it is by default a foreground thread because its IsBackground property is set to false. That means your application will continue to run while a secondary thread is executing. If you would like to create a new thread and make it a background thread, you assign a value of True to its IsBackground property before you call the Start method, like so: Dim ThreadA As Thread ThreadA = New Thread(AddressOf TedsCode.MyAsyncTask) ThreadA.IsBackground = True ThreadA.Start()

Remember that whether a Thread object is a foreground or background thread is really only important when writing managed EXE-based applications such as a console application or a Windows Forms application. The IsBackground property of a Thread object has no effect on applications that have been started using a non-managed EXE such as the ASP.NET worker process.

Finally, when you need to initialize a thread for COM interoperability to run within a single-threaded apartment you should create a new thread. To explain why this is important, I'll provide a little background on COM.

In COM, there are STAs and multithreaded apartment (MTA) threads. The majority of COM components, including all those created with Visual Basic 5.0 and Visual Basic 6.0, are apartment-threaded. Apartment-threaded components are restricted to running on STA threads due to issues related to thread safety and affinity. A small percentage of performance-oriented COM components have been written to run safely on MTA threads.

Before code written with Visual Basic .NET can create and interact with a COM object, the CLR must first initialize the calling thread for COM interoperability. In particular, the CLR must make a system call to initialize the thread as either MTA or STA.

If you create apartment-threaded objects using an MTA thread, you will experience thread switching. Thread switching involves a measurable performance hit because each call to the apartment-threaded COM object must be marshaled from the MTA thread over to the object's STA thread. Thread switching can be avoided by using an STA thread instead of an MTA thread. Therefore, you should always use STA threads when creating objects from apartment-threaded COM components.

By default, the primary thread for an application created with Visual Basic .NET will initialize to an STA thread. When you compile a Windows Forms app or a console app, the Visual Basic .NET compiler automatically adds the STAThread attribute to the Main method that serves as the application's entry point: Class MyApp <System.STAThread()> Shared Sub Main() '*** application code here End Sub End Class

The presence of the STAThread attribute forces the application's primary thread to initialize as an STA thread the first time the application does any interoperability work with COM. This is what you want when working with COM components because it is likely that they will be apartment-threaded. In rare cases when you need to write a Visual Basic .NET-based application that uses COM components that are all freethreaded, you can force the application's primary thread to initialize to an MTA thread by explicitly adding the MTAThread attribute to the application's Main method: Class MyApp <System.MTAThread()> _ Shared Sub Main() '*** application code here End Sub End Class

I've just discussed the issues that affect whether an application's primary thread gets initialized as an STA or an MTA thread. Now it's time to look into how things work with secondary threads. The first important point to understand is that you have no control over the threads from the CLR thread pool. They are always initialized as MTA threads. For this reason, you should avoid using asynchronous delegates to execute code which interoperates with apartment-threaded COM components due to the performance degradation that occurs with thread switching.

When you create and manage a secondary thread that is going to interoperate with COM components, you can control whether it is initialized as an STA thread or an MTA thread. After you create an object from the Thread class, you can explicitly set its ApartmentState property to STA before calling Start, as you see here: Dim ThreadA As Thread ThreadA = New Thread(AddressOf TedsCode.MyAsyncTask) ThreadA.ApartmentState = ApartmentState.STA ThreadA.Start() '*** When you create a COM object, the CLR '*** will initialize ThreadA as an STA thread.

You now have a secondary thread which can create and make calls to apartment-threaded COM objects without incurring the overhead of thread switching. This makes it possible to interact with apartment-threaded COM components from a secondary thread in a more efficient manner.


Conclusion

This month I have examined why and how you would create secondary threads. You saw that creating and managing secondary threads to execute methods asynchronously is something you should do only when you cannot use delegates. Such situations include handling long-running tasks, adjusting thread priority, using foreground threads, and using STA threads for more efficient interoperability with apartment-threaded COM components.

My last three columns have examined how to use asynchronous delegates and how to create secondary threads. In short, I've taught you how to get in trouble by introducing multithreaded behavior in your apps. In the next installment of Basic Instincts, I'll show you how to stay out of trouble by designing and writing thread-safe code that is robust in the face of concurrency and that can run dependably in a multithreaded world.


Send your questions and comments for Ted to  instinct@microsoft.com.

Ted Pattison is a cofounder of Barracuda .NET, a developer education company that assists companies building collaborative applications using Microsoft technologies. Ted is the author of several books including Building Applications and Components with Visual Basic .NET (Addison-Wesley, 2003).

From the June 2004 issue of MSDN Magazine.
Get it at your local newsstand, or better yet, subscribe

5月30日

Oracle - Putting strings together and Pulling apart

 
By : Oracle Expert - Scott Sephens
 
Putting them together or pulling them apart, this article from Oracle expert Scott Stephens covers it all.

A common task when selecting data from a database is to take a set of values a query returns and format it as a comma delimited list. Another task that's almost as common is the need to do the reverse: Take a comma delimited list of values in a single string and use it as a table of values.

Many scripting languages, such as Perl and Python, provide functions that do this with their own language-specific list of values; so it's surprising that, as of yet, this functionality isn't a standard part of SQL functions. I've seen some pretty ugly looking code that involved complex declarations with MAX and DECODE, but that solution usually only returns a limited set of values. With some of the new Oracle9i and above features, it's possible to do this yourself.

I'd like to use a "join" functionality to specify a query that returns a single column and a delimiter, and then receive a simple string that contains a list of those values separated by my delimiter. The query part can be passed to the function as a REF CURSOR using the new SQL CURSOR function. The delimiter should default to a comma, since that is the most commonly used delimiter. So, the syntax should be:

SQL> select join(cursor(select ename from emp)) from dual;

SMITH,ALLEN,WARD,JONES,MARTIN,BLAKE,CLARK,SCOTT, KING,TURNER,ADAMS,JAMES,FORD, MILLER

The following code will perform this function:

create or replace function join
(
    p_cursor sys_refcursor,
    p_del varchar2 := ','
) return varchar2
is
    l_value   varchar2(32767);
    l_result  varchar2(32767);
begin
    loop
        fetch p_cursor into l_value;
        exit when p_cursor%notfound;
        if l_result is not null then
            l_result := l_result || p_del;
        end if;
        l_result := l_result || l_value;
    end loop;
    return l_result;
end join;
/
show errors;

The PL/SQL User's Guide says you always have to declare a package that defines a ref cursor; however, the database already defines this as SYS_REFCURSOR in the STANDARD package. The PL/SQL code should be fairly straightforward. There is a limit of 32,767 characters on the output string and the input column.

Since all datatypes can be automatically converted to character strings, you can use any datatype in the cursor--as long as it's one column. For example:

SQL> select join(cursor(select trunc(hiredate,'month') from emp),'|') from
dual;

01-DEC-80|01-FEB-81|01-FEB-81|01-APR-81|01-SEP-81|01-MAY-81|01-JUN-81|01-APR-87|01-NOV-81|01-SEP-81|01-MAY-87|01-DEC-81|01-DEC-81|01-JAN-82

There's another extra benefit. Since the cursor is part of the SQL statement, you can easily join the query inside the join with the outer query. Here is a query that returns each table and a list of the columns that make up its primary key:

SQL> select table_name,join(cursor(select column_name from user_cons_columns where constraint_name = user_constraints.constraint_name
order by position)) columns from user_constraints where constraint_type = 'P';
 
TABLE_NAME              COLUMNS
----------              -------
DEPT                    DEPTNO
EMP                     EMPNO

You can also use this "join" function to compare two sets of ordered data. For example, the following query will check that an index has been created on a foreign key (which helps prevent locking the table and aids master-detail queries):

column status format a7
column table_name format a30
column columns format a40 word_wrapped

select decode(indexes.table_name,null,'missing','ok') status,
       constraints.table_name,
       constraints.columns
  from
    (select table_name,
            constraint_name,
            join(cursor
            (
                select column_name
                  from user_cons_columns
                 where constraint_name = user_constraints.constraint_name
            )) columns
        from user_constraints
       where constraint_type = 'R'
       ) constraints,
    (select table_name, index_name,
            join(cursor
            (
                select column_name
                  from user_ind_columns
                 where index_name = user_indexes.index_name
            )) columns
      from user_indexes) indexes
    where constraints.table_name = indexes.table_name (+)
      and constraints.columns = indexes.columns (+);

This query works by executing two subqueries: one that queries foreign keys and another that queries indexes. The join between these two queries is on the table name and the list of columns used in creating the foreign key and the index, taken as an ordered list of values.

We'd also like the reverse functionality: to have the ability to take a single comma-delimited value and treat it as if it were a column in a table. We can take advantage of the TABLE SQL function and PL/SQL function tables to do this quite easily, but first, we must define the result type to be a TABLE type of the largest possible string.

create or replace type split_tbl as table of varchar2(32767);
/
show errors;

create or replace function split
(
    p_list varchar2,
    p_del varchar2 := ','
) return split_tbl pipelined
is
    l_idx    pls_integer;
    l_list    varchar2(32767) := p_list;
AA
    l_value    varchar2(32767);
begin
    loop
        l_idx := instr(l_list,p_del);
        if l_idx > 0 then
            pipe row(substr(l_list,1,l_idx-1));
            l_list := substr(l_list,l_idx+length(p_del));

        else
            pipe row(l_list);
            exit;
        end if;
    end loop;
    return;
end split;
/
show errors;

With this function, I can run a query like this:

SQL> select * from table(split('one,two,three'));

one
two
three

The PL/SQL procedure will parse its argument and return each part through a PIPELINE; the TABLE function allows it to be used in the FROM statement, so it appears to SQL as if it is a table with one column and three rows. (Remember that the column being returned is named COLUMN_VALUE if you want to use the value elsewhere.)

Here's an example query, which shows a dynamic IN condition in a query. The split function generates a table of values, which can be used on a row-by-row basis.

SQL> select ename from emp
      where to_char(hiredate,'YY')
         in (select column_value from table(split('81,82')));

ENAME      HIREDATE
---------- ---------
ALLEN      20-FEB-81
WARD       22-FEB-81
JONES      02-APR-81
MARTIN     28-SEP-81
TURNER     08-SEP-81
JAMES      03-DEC-81
FORD       03-DEC-81
KING       17-NOV-81
BLAKE      01-MAY-81
CLARK      09-JUN-81
MILLER     23-JAN-82

If you want, you can join a column and then split it, too:

SQL> select * from table(split(join(cursor(select ename from emp))));

And, you can use this method to merge sets of values:

create table t(a varchar2(200));
insert into t values('81,82');
insert into t values('84,85');

SQL> select * from table(split(join(cursor(select a from t))));

81
82
84
85

These are just simple example functions. You could extend join to enclose values in quotes and escape quotes inside the values. You could extend split to allow a REF CURSOR parameter instead of a single VARCHAR2, so it could split up sets of columns as well.

Scott Stephens worked for Oracle for more than 13 years in technical support, e-commerce, marketing, and software development.

 
Krishna  
全 4 枚中 1 枚目