I’ve noticed that – despite a fair bit of discussion on the topic – many folks wind
up using atomic scopes simply to avoid serialization requirements for .Net types within
an orchestration.  It isn’t surprising this is the past of least resistance –
after all, the relevant compiler error sort of suggests this as a fix:

error X2141: a non-serializable object type 'SomeAssembly.SomeComponent yourComponent'
can only be declared within an atomic scope or service

Recall that persistence will occur when messages are sent, when another orchestration
is started asynchronously (like via the Start Orchestration shape), when an orchestration
instance is suspended, when a host instance does a controlled shutdown, when a “wait”
state occurs (like a blocking receive or delay shape that makes the schedule a candidate
for dehydration), or when the orchestration completes. 

It will also occur at the end of a transactional scope to assist with resuming in
an unambiguous state (and executing compensation logic.)

So…although the introduction of an atomic scope prevents serialization within the
scope, it introduces serialization at the end of the scope.  This is
often a persistence point (read: database hit) you wouldn’t have had to live with
— if an atomic scope was introduced purely to get around the compiler error
above.

Now…sometimes the .Net component you are using indeed requires state – and you should
go ahead and implement a serialization strategy for that case.  If the component
can be stateless, then you might consider making the methods you access “static”
to avoid the compiler-enforced requirement altogether.

There is a third case, however – where you know that serialization is not required
(given how your orchestration is structured) – but you don’t own the code for it,
either.  For instance, you might want to use an XmlNode to hold the result of
a SelectSingleNode call on an XmlDocument.  If your use of the XmlNode instance is
confined to a single expression shape…no state actually needs to be preserved. 
So, in this case, consider wrapping the class as shown below.  Here, we honor
the serialization requirement – but we don’t, in fact, do any serialization work. 
Now, no atomic scope is needed (avoiding the associated performance hit).  Use
this technique with care – the state management facilities in BizTalk are usually
a great asset.

      
/// <summary>
/// It can be helpful when dealing with xpath expressions within orchestrations to
/// make use of a System.Xml.XmlNode (or derivations) without having to deal 
/// with the fact that XmlNode is not serializable.  If usage is confined to a single
/// expression shape, we actually won't have any serialization requirements, and so they
/// have empty implementation here.
/// </summary>
[Serializable]
public class BizTalkXmlNode : ISerializable
{
	private XmlNode _xmlNode;

	public BizTalkXmlNode()
	{

	}

	public XmlNode XmlNode
	{
		get{return _xmlNode;}
		set{_xmlNode = value;}
	}

	public string InnerText
	{
		get{return _xmlNode.InnerText;}
		set{_xmlNode.InnerText = value;}
	}

	// This is helpful to use as a static helper method because the xpath expression in 
	// biztalk returns a XmlNode - so direct comparisons to string literals won't work.
	// (And the expression editor won't let you get the InnerText property...)
	public static string GetInnerText(XmlNode node)
	{
		return node.InnerText;
	}

	private BizTalkXmlNode(SerializationInfo info, StreamingContext context)
	{
		// no state intended...
	}

	public void GetObjectData(SerializationInfo info, StreamingContext context)
	{
		// no state intended...
	}

}