<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Clemens Vasters - Technology|Enterprise Services</title>
    <link>http://vasters.com/clemensv/</link>
    <description>Cloud Development and Alien Abductions</description>
    <language>en-us</language>
    <copyright>Clemens Vasters</copyright>
    <lastBuildDate>Sun, 05 Dec 2004 15:41:21 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.7067.0</generator>
    <managingEditor>cvasters@guhhome.com</managingEditor>
    <webMaster>cvasters@guhhome.com</webMaster>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=c48dd120-cf19-42b8-ad14-39ad3ec1c3e4</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,c48dd120-cf19-42b8-ad14-39ad3ec1c3e4.aspx</pingback:target>
      <dc:creator>
      </dc:creator>
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,c48dd120-cf19-42b8-ad14-39ad3ec1c3e4.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=c48dd120-cf19-42b8-ad14-39ad3ec1c3e4</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The little series I am currently <a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=3a83d7c0-cded-46f7-a6a6-b6450d66fb56">writing
here</a> on my blog has inspired me to write way too more code than actually necessary
to get my point across ;-) So by now I've got my own MSMQ transport for WSE 2.0
(yes, I know that others have written that already, but I am shooting for
a "enterprise strength" implementation), a WebRequest/WebResponse pair to smuggle
under arbitrary ASMX proxies and I am more than halfway done with a server-side host
for MSMQ-to-ASMX (spelled out: ASP.NET Web Services). 
</p>
        <p>
What bugs me is that WSE 2.0's messaging model is "asynchronous only" and that it <em>always</em> performs
a push/pull translation and that there is no way to push a message through to a service
on the receiving thread. Whenever I grab a message from the queue and put it into
my SoapTransport's "Dispatch()" method, the message gets queued up in an in-memory
queue and that is then, on a concurrent thread, pulled (OnReceiveComplete) by the
SoapReceivers collection and submitted into ProcessMessage() of the SoapReceiver (like
any SoapService derived implementation) matching the target endpoint. So while
I can dequeue from MSMQ within a transaction scope (ServiceDomain), that transaction
scope doesn't make it across onto the thread that will actually execute the action
inside the SoapReceiver/SoapService.
</p>
        <p>
So now I am sitting here, contemplating and trying to figure out a workaround that doesn't
require me to rewrite a big chunk of WSE 2.0 (which I am totally not shy
of if that is what it takes). Transaction marshaling, thread synchronization,
ah, I love puzzles. Once I am know how to solve this and have made the adjustments,
I'll post the queue listener I promised to wrap up the series. The other code I've
written in the process will likely surface in some other way.
</p>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=c48dd120-cf19-42b8-ad14-39ad3ec1c3e4" />
      </body>
      <title>Push/Pull Translation and Transactions</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,c48dd120-cf19-42b8-ad14-39ad3ec1c3e4.aspx</guid>
      <link>http://vasters.com/clemensv/2004/12/05/PushPull+Translation+And+Transactions.aspx</link>
      <pubDate>Sun, 05 Dec 2004 15:41:21 GMT</pubDate>
      <description>&lt;p&gt;
The little series I am currently &lt;a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=3a83d7c0-cded-46f7-a6a6-b6450d66fb56"&gt;writing
here&lt;/a&gt; on my blog has inspired me to write way too more code than actually necessary
to get my point across&amp;nbsp;;-) So by now I've got my own MSMQ transport for WSE 2.0
(yes, I know&amp;nbsp;that others have&amp;nbsp;written that already, but I am shooting for
a "enterprise strength" implementation), a WebRequest/WebResponse pair to smuggle
under arbitrary ASMX proxies and I am more than halfway done with&amp;nbsp;a server-side&amp;nbsp;host
for MSMQ-to-ASMX&amp;nbsp;(spelled out: ASP.NET Web Services). 
&lt;/p&gt;
&lt;p&gt;
What bugs me is that WSE 2.0's messaging model is "asynchronous only" and that&amp;nbsp;it &lt;em&gt;always&lt;/em&gt; performs
a push/pull translation and that there is no way to push a message through to a service
on the receiving thread. Whenever I grab a message from the queue and put it into
my SoapTransport's "Dispatch()" method, the message gets queued up in an in-memory
queue and that is then, on a concurrent thread, pulled (OnReceiveComplete) by the
SoapReceivers collection and submitted into&amp;nbsp;ProcessMessage() of the SoapReceiver&amp;nbsp;(like
any SoapService derived implementation) matching the target endpoint.&amp;nbsp;So while
I can dequeue from MSMQ within a transaction scope (ServiceDomain), that transaction
scope doesn't make it across onto the thread that will actually execute the action
inside the SoapReceiver/SoapService.
&lt;/p&gt;
&lt;p&gt;
So now I am sitting here, contemplating and trying to figure out a workaround that&amp;nbsp;doesn't
require me to&amp;nbsp;rewrite a big chunk of WSE 2.0 (which I am&amp;nbsp;totally not shy
of if that is what it takes).&amp;nbsp;Transaction marshaling, thread synchronization,
ah, I love puzzles. Once I am know how to solve this and have made the adjustments,
I'll post the queue listener I promised to wrap up the series. The other code I've
written in the process will likely surface in some other way.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=c48dd120-cf19-42b8-ad14-39ad3ec1c3e4" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,c48dd120-cf19-42b8-ad14-39ad3ec1c3e4.aspx</comments>
      <category>Technology</category>
      <category>Technology/Enterprise Services</category>
      <category>Technology/MSMQ</category>
      <category>Technology/Web Services</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=bafdbe41-0786-4a7f-a488-8ca447d612eb</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,bafdbe41-0786-4a7f-a488-8ca447d612eb.aspx</pingback:target>
      <dc:creator>
      </dc:creator>
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,bafdbe41-0786-4a7f-a488-8ca447d612eb.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=bafdbe41-0786-4a7f-a488-8ca447d612eb</wfw:commentRss>
      <slash:comments>8</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <div class="Section1">
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">
              <a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=826bc7c9-8b0f-4df6-aabe-e6c5377a9446">See
Part 1</a>
            </span>
          </p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">Before we can do anything about
deadlocks or deal with similar troubles, we first need to be able to tell that we
indeed have a deadlock situation. Finding this out is a matter of knowing the respective
error codes that your database gives you and a mechanism to bubble that information
up to some code that will handle the situation. So before we can think about and write
the handling logic for failed/failing but safely repeatable transactions, we need
to build a few little things. The first thing we’ll need is an exception class
that will wrap the original exception indicating the reason for the transaction failure.
The new exception class’s identity will later serve to filter out exceptions
in a “catch” statement and take the appropriate actions.</span>
          </p>
          <table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #e6e6e6; BORDER-LEFT: medium none; WIDTH: 100%; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" width="100%" border="1">
            <tbody>
              <tr>
                <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top">
                  <p class="MsoNormal">
                    <span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'">using</span>
                    <span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'"> System;<br /><span style="COLOR: blue">using</span> System.Runtime.Serialization;<br /><br /><span style="COLOR: blue">namespace</span> newtelligence.EnterpriseTools.Data<br />
{<br />
   [Serializable]<br />
   <span style="COLOR: blue">public</span><span style="COLOR: blue">class</span> RepeatableOperationException
: Exception<br />
   {<br />
       <span style="COLOR: blue">public</span> RepeatableOperationException():<span style="COLOR: blue">base</span>()<br />
       {<br />
       }<br /><br />
       <span style="COLOR: blue">public</span> RepeatableOperationException(Exception
innerException)<br />
           :<span style="COLOR: blue">base</span>(<span style="COLOR: blue">null</span>,innerException)<br />
       {<br />
       }<br /><br />
       <span style="COLOR: blue">public</span> RepeatableOperationException(<span style="COLOR: blue">string</span> message,
Exception innerException)<br />
           :<span style="COLOR: blue">base</span>(message,innerException)<br />
       {<br />
       }<br /><br />
       <span style="COLOR: blue">public</span> RepeatableOperationException(<span style="COLOR: blue">string</span> message):<span style="COLOR: blue">base</span>(message)<br />
       {<br />
       }<br /><br />
        <span style="COLOR: blue">public</span> RepeatableOperationException(<br />
          SerializationInfo serializationInfo, 
<br />
          StreamingContext streamingContext)<br />
            :<span style="COLOR: blue">base</span>(serializationInfo,streamingContext)<br />
        {<br />
        }<br /><br />
        <span style="COLOR: blue">public</span><span style="COLOR: blue">override</span><span style="COLOR: blue">void</span> GetObjectData(<br />
           System.Runtime.Serialization.SerializationInfo
info,<br />
           System.Runtime.Serialization.StreamingContext
context)<br />
        {<br />
            <span style="COLOR: blue">base</span>.GetObjectData
(info, context);<br />
        }<br />
   }<br />
}</span>
                  </p>
                </td>
              </tr>
            </tbody>
          </table>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">Having an exception wrapper with
the desired semantics, we know need to be able to figure out when to replace the original
exception with this wrapper and re-throw it up on the call stack. The idea is that
whenever you execute a database operation – or, more generally, any operation
that might be repeatable on failure – you will catch the resulting exception
and run it through a factory, which will analyze the exception and wrap it with the
RepeatableOperationException if the issue at hand can be resolved by re-running the
transaction. The (still a little naïve) code below illustrates how to such a
factory in the application code. Later we will flesh out the catch block a little
more, since we will lose the original call stack if we end up re-throwing the original
exception like shown here:</span>
          </p>
          <table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #e6e6e6; BORDER-LEFT: medium none; WIDTH: 100%; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" width="100%" border="1">
            <tbody>
              <tr>
                <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top">
                  <p class="MsoNormal">
                    <span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'">Try<br /></span>
                    <span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'">{<br />
   dbConnection.Open();<br />
   sprocUpdateAndQueryStuff.Parameters["@StuffArgument"].Value = argument;<br />
   result = <span style="COLOR: blue">this</span>.GetResultFromReader( sprocUpdateAndQueryStuff.ExecuteReader()
);<br />
}<br /><span style="COLOR: blue">catch</span>( Exception exception )<br />
{<br /><span style="COLOR: blue">   throw</span> RepeatableOperationExceptionMapper.MapException(
exception );                   
        
<br />
}<br /><span style="COLOR: blue">finally<br /></span>{<br />
   dbConnection.Close();<br />
}</span>
                  </p>
                </td>
              </tr>
            </tbody>
          </table>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">The factory class itself is rather
simple in structure, but a bit tricky to put together, because you have to know the
right error codes for all resource managers you will ever run into. In the example
below I put in what I believe to be the appropriate codes for SQL Server and Oracle
(corrections are welcome) and left the ODBC and OLE DB factories (for which would
have to inspect the driver type and the respective driver-specific error codes) blank.
The factory will check out the exception data type and delegate mapping to a private
method that is specialized for a specific managed provider. </span>
          </p>
          <table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #e6e6e6; BORDER-LEFT: medium none; WIDTH: 100%; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" width="100%" border="1">
            <tbody>
              <tr>
                <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top">
                  <p class="MsoNormal">
                    <span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'">using</span>
                    <span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'"> System;<br /><span style="COLOR: blue">using</span> System.Data.SqlClient;<br /><span style="COLOR: blue">using</span> System.Data.OleDb;<br /><span style="COLOR: blue">using</span> System.Data.Odbc;<br /><span style="COLOR: blue">using</span> System.Data.OracleClient;<br /><br /><span style="COLOR: blue">namespace</span> newtelligence.EnterpriseTools.Data<br />
{<br />
   <span style="COLOR: blue">public</span><span style="COLOR: blue">class</span> RepeatableOperationExceptionMapper<br />
   {<br />
        <span style="COLOR: gray">///</span><span style="COLOR: green"></span><span style="COLOR: gray">&lt;summary&gt;<br /></span>        <span style="COLOR: gray">///</span><span style="COLOR: green"> Maps
the exception to a Repeatable exception, if the error code<br /></span>        <span style="COLOR: gray">///</span><span style="COLOR: green"> indicates
that the transaction is repeatable.<br /></span>        <span style="COLOR: gray">///</span><span style="COLOR: green"></span><span style="COLOR: gray">&lt;/summary&gt;<br /></span>        <span style="COLOR: gray">///</span><span style="COLOR: green"></span><span style="COLOR: gray">&lt;param
name="sqlException"&gt;&lt;/param&gt;<br /></span>        <span style="COLOR: gray">///</span><span style="COLOR: green"></span><span style="COLOR: gray">&lt;returns&gt;&lt;/returns&gt;<br /></span>        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span> Exception
MapSqlException( SqlException sqlException )<br />
        {<br />
            <span style="COLOR: blue">switch</span> (
sqlException.Number )<br />
            {<br />
                <span style="COLOR: blue">case</span> -2: <span style="COLOR: green">/*
Client Timeout */</span><br />
                <span style="COLOR: blue">case</span> 701: <span style="COLOR: green">/*
Out of Memory */</span><br />
                <span style="COLOR: blue">case</span> 1204: <span style="COLOR: green">/*
Lock Issue */</span><br />
                <span style="COLOR: blue">case</span> 1205: <span style="COLOR: green">/*
Deadlock Victim */</span><br />
                <span style="COLOR: blue">case</span> 1222: <span style="COLOR: green">/*
Lock Request Timeout */</span><br />
                <span style="COLOR: blue">case</span> 8645: <span style="COLOR: green">/*
Timeout waiting for memory resource */</span><br />
                <span style="COLOR: blue">case</span> 8651: <span style="COLOR: green">/*
Low memory condition */</span><br />
                    <span style="COLOR: blue">return</span><span style="COLOR: blue">new</span> RepeatableOperationException(sqlException);<br />
                <span style="COLOR: blue">default</span>:<br />
                    <span style="COLOR: blue">return</span> sqlException;<br />
            }<br />
        }<br /><br />
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span> Exception
MapOleDbException( OleDbException oledbException )<br />
        {<br />
            <span style="COLOR: blue">switch</span> (
oledbException.ErrorCode )<br />
            {<br />
                <span style="COLOR: blue">default</span>:<br />
                    <span style="COLOR: blue">return</span> oledbException;<br />
            }<br />
        }<br /><br />
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span> Exception
MapOdbcException( OdbcException odbcException )<br />
        {<br />
            <span style="COLOR: blue">return</span> odbcException;            
<br />
        }<br /><br />
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span> Exception
MapOracleException( OracleException oracleException )<br />
        {<br />
            <span style="COLOR: blue">switch</span> (
oracleException.Code )<br />
            {<br />
                <span style="COLOR: blue">case</span> 104:  <span style="COLOR: green">/*
ORA-00104: Deadlock detected; all public servers blocked waiting for resources */<br /></span>                <span style="COLOR: blue">case</span> 1013: <span style="COLOR: green">/*
ORA-01013: User requested cancel of current operation */<br /></span>                <span style="COLOR: blue">case</span> 2087: <span style="COLOR: green">/*
ORA-02087: Object locked by another process in same transaction */<br /></span>                <span style="COLOR: blue">case</span> 60:   <span style="COLOR: green">/*
ORA-00060: Deadlock detected while waiting for resource */</span><br />
              
     <span style="COLOR: blue">return</span><span style="COLOR: blue">new</span> RepeatableOperationException(
oracleException );<br />
                <span style="COLOR: blue">default</span>:<br />
                    <span style="COLOR: blue">return</span> oracleException;<br />
            }<br />
        }<br /><br />
        <span style="COLOR: blue">public</span><span style="COLOR: blue">static</span> Exception
MapException( Exception exception )<br />
        {<br />
            <span style="COLOR: blue">if</span> (
exception <span style="COLOR: blue">is</span> SqlException )<br />
            {<br />
                <span style="COLOR: blue">return</span> MapSqlException(
exception <span style="COLOR: blue">as</span> SqlException );<br />
            }<br />
            <span style="COLOR: blue">else</span><span style="COLOR: blue">if</span> (
exception <span style="COLOR: blue">is</span> OleDbException )<br />
            {<br />
                <span style="COLOR: blue">return</span> MapOleDbException(
exception <span style="COLOR: blue">as</span> OleDbException );<br />
            }<br />
            <span style="COLOR: blue">else</span><span style="COLOR: blue">if</span> (exception <span style="COLOR: blue">is</span> OdbcException
)<br />
            {<br />
                <span style="COLOR: blue">return</span> MapOdbcException(
exception <span style="COLOR: blue">as</span> OdbcException );<br />
            }<br />
            <span style="COLOR: blue">else</span><span style="COLOR: blue">if</span> (exception <span style="COLOR: blue">is</span> OracleException
)<br />
            {<br />
                <span style="COLOR: blue">return</span> MapOracleException(
exception <span style="COLOR: blue">as</span> OracleException );<br />
            }<br />
            <span style="COLOR: blue">else</span><br />
            {<br />
                <span style="COLOR: blue">return</span> exception;<br />
            }<br />
        }<br />
   }<br />
}<br /><br /></span>
                  </p>
                </td>
              </tr>
            </tbody>
          </table>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">With that little framework of two
classes, we can now selectively throw exceptions that convey whether a failed/failing
transaction is worth repeating. Next step: How do we do actually run such repeats
and make sure we neither lose data nor make the user unhappy in the process? Stay
tuned.</span>
          </p>
        </div>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=bafdbe41-0786-4a7f-a488-8ca447d612eb" />
      </body>
      <title>Dealing with Deadlocks and Other Unfortunate Events on the Application Level: Part 2</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,bafdbe41-0786-4a7f-a488-8ca447d612eb.aspx</guid>
      <link>http://vasters.com/clemensv/2004/11/30/Dealing+With+Deadlocks+And+Other+Unfortunate+Events+On+The+Application+Level+Part+2.aspx</link>
      <pubDate>Tue, 30 Nov 2004 11:02:27 GMT</pubDate>
      <description>&lt;div class=Section1&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;&lt;a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=826bc7c9-8b0f-4df6-aabe-e6c5377a9446"&gt;See
Part 1&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;Before we can do anything about
deadlocks or deal with similar troubles, we first need to be able to tell that we
indeed have a deadlock situation. Finding this out is a matter of knowing the respective
error codes that your database gives you and a mechanism to bubble that information
up to some code that will handle the situation. So before we can think about and write
the handling logic for failed/failing but safely repeatable transactions, we need
to build a few little things. The first thing we&amp;#8217;ll need is an exception class
that will wrap the original exception indicating the reason for the transaction failure.
The new exception class&amp;#8217;s identity will later serve to filter out exceptions
in a &amp;#8220;catch&amp;#8221; statement and take the appropriate actions.&lt;/span&gt;
&lt;/p&gt;
&lt;table class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #e6e6e6; BORDER-LEFT: medium none; WIDTH: 100%; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing=0 cellpadding=0 width="100%" border=1&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign=top&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'"&gt;using&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'"&gt; System;&lt;br&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Runtime.Serialization;&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: blue"&gt;namespace&lt;/span&gt; newtelligence.EnterpriseTools.Data&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp; [Serializable]&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; RepeatableOperationException
: Exception&lt;br&gt;
&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; RepeatableOperationException():&lt;span style="COLOR: blue"&gt;base&lt;/span&gt;()&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; RepeatableOperationException(Exception
innerException)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;:&lt;span style="COLOR: blue"&gt;base&lt;/span&gt;(&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;,innerException)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;public&lt;/span&gt; RepeatableOperationException(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; message,
Exception innerException)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&lt;span style="COLOR: blue"&gt;base&lt;/span&gt;(message,innerException)&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; RepeatableOperationException(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; message):&lt;span style="COLOR: blue"&gt;base&lt;/span&gt;(message)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; RepeatableOperationException(&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SerializationInfo serializationInfo, 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StreamingContext streamingContext)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; :&lt;span style="COLOR: blue"&gt;base&lt;/span&gt;(serializationInfo,streamingContext)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;override&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; GetObjectData(&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.Runtime.Serialization.SerializationInfo
info,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.Runtime.Serialization.StreamingContext
context)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;base&lt;/span&gt;.GetObjectData
(info, context);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;Having an exception wrapper with
the desired semantics, we know need to be able to figure out when to replace the original
exception with this wrapper and re-throw it up on the call stack. The idea is that
whenever you execute a database operation &amp;#8211; or, more generally, any operation
that might be repeatable on failure &amp;#8211; you will catch the resulting exception
and run it through a factory, which will analyze the exception and wrap it with the
RepeatableOperationException if the issue at hand can be resolved by re-running the
transaction. The (still a little na&amp;#239;ve) code below illustrates how to such a
factory in the application code. Later we will flesh out the catch block a little
more, since we will lose the original call stack if we end up re-throwing the original
exception like shown here:&lt;/span&gt;
&lt;/p&gt;
&lt;table class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #e6e6e6; BORDER-LEFT: medium none; WIDTH: 100%; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing=0 cellpadding=0 width="100%" border=1&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign=top&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'"&gt;Try&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'"&gt;{&lt;br&gt;
&amp;nbsp;&amp;nbsp; dbConnection.Open();&lt;br&gt;
&amp;nbsp; &amp;nbsp;sprocUpdateAndQueryStuff.Parameters["@StuffArgument"].Value = argument;&lt;br&gt;
&amp;nbsp;&amp;nbsp; result = &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.GetResultFromReader( sprocUpdateAndQueryStuff.ExecuteReader()
);&lt;br&gt;
}&lt;br&gt;
&lt;span style="COLOR: blue"&gt;catch&lt;/span&gt;( Exception exception )&lt;br&gt;
{&lt;br&gt;
&lt;span style="COLOR: blue"&gt;&amp;nbsp;&amp;nbsp; throw&lt;/span&gt; RepeatableOperationExceptionMapper.MapException(
exception );&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; 
&lt;br&gt;
}&lt;br&gt;
&lt;span style="COLOR: blue"&gt;finally&lt;br&gt;
&lt;/span&gt;{&lt;br&gt;
&amp;nbsp; &amp;nbsp;dbConnection.Close();&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;The factory class itself is rather
simple in structure, but a bit tricky to put together, because you have to know the
right error codes for all resource managers you will ever run into. In the example
below I put in what I believe to be the appropriate codes for SQL Server and Oracle
(corrections are welcome) and left the ODBC and OLE DB factories (for which would
have to inspect the driver type and the respective driver-specific error codes) blank.
The factory will check out the exception data type and delegate mapping to a private
method that is specialized for a specific managed provider. &lt;/span&gt;
&lt;/p&gt;
&lt;table class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #e6e6e6; BORDER-LEFT: medium none; WIDTH: 100%; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing=0 cellpadding=0 width="100%" border=1&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign=top&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'"&gt;using&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'"&gt; System;&lt;br&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Data.SqlClient;&lt;br&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Data.OleDb;&lt;br&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Data.Odbc;&lt;br&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Data.OracleClient;&lt;br&gt;
&lt;br&gt;
&lt;span style="COLOR: blue"&gt;namespace&lt;/span&gt; newtelligence.EnterpriseTools.Data&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; RepeatableOperationExceptionMapper&lt;br&gt;
&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;summary&amp;gt;&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; Maps
the exception to a Repeatable exception, if the error code&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; indicates
that the transaction is repeatable.&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;/summary&amp;gt;&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;param
name="sqlException"&amp;gt;&amp;lt;/param&amp;gt;&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; Exception
MapSqlException( SqlException sqlException )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;switch&lt;/span&gt; (
sqlException.Number )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; -2: &lt;span style="COLOR: green"&gt;/*
Client Timeout */&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 701: &lt;span style="COLOR: green"&gt;/*
Out of Memory */&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 1204: &lt;span style="COLOR: green"&gt;/*
Lock Issue */&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 1205: &lt;span style="COLOR: green"&gt;/*
Deadlock Victim */&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 1222: &lt;span style="COLOR: green"&gt;/*
Lock Request Timeout */&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 8645: &lt;span style="COLOR: green"&gt;/*
Timeout waiting for memory resource */&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 8651: &lt;span style="COLOR: green"&gt;/*
Low memory condition */&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; RepeatableOperationException(sqlException);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;default&lt;/span&gt;:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; sqlException;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; Exception
MapOleDbException( OleDbException oledbException )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;switch&lt;/span&gt; (
oledbException.ErrorCode )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;default&lt;/span&gt;:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; oledbException;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; Exception
MapOdbcException( OdbcException odbcException )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; odbcException;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; Exception
MapOracleException( OracleException oracleException )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;switch&lt;/span&gt; (
oracleException.Code )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 104:&amp;nbsp; &lt;span style="COLOR: green"&gt;/*
ORA-00104: Deadlock detected; all public servers blocked waiting for resources */&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 1013: &lt;span style="COLOR: green"&gt;/*
ORA-01013: User requested cancel of current operation */&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 2087: &lt;span style="COLOR: green"&gt;/*
ORA-02087: Object locked by another process in same transaction */&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;case&lt;/span&gt; 60:&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;/*
ORA-00060: Deadlock detected while waiting for resource */&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; RepeatableOperationException(
oracleException );&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;default&lt;/span&gt;:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; oracleException;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; Exception
MapException( Exception exception )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (
exception &lt;span style="COLOR: blue"&gt;is&lt;/span&gt; SqlException )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; MapSqlException(
exception &lt;span style="COLOR: blue"&gt;as&lt;/span&gt; SqlException );&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;else&lt;/span&gt; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (
exception &lt;span style="COLOR: blue"&gt;is&lt;/span&gt; OleDbException )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; MapOleDbException(
exception &lt;span style="COLOR: blue"&gt;as&lt;/span&gt; OleDbException );&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;else&lt;/span&gt; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (exception &lt;span style="COLOR: blue"&gt;is&lt;/span&gt; OdbcException
)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; MapOdbcException(
exception &lt;span style="COLOR: blue"&gt;as&lt;/span&gt; OdbcException );&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;else&lt;/span&gt; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (exception &lt;span style="COLOR: blue"&gt;is&lt;/span&gt; OracleException
)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; MapOracleException(
exception &lt;span style="COLOR: blue"&gt;as&lt;/span&gt; OracleException );&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;else&lt;/span&gt; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; exception;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;With that little framework of two
classes, we can now selectively throw exceptions that convey whether a failed/failing
transaction is worth repeating. Next step: How do we do actually run such repeats
and make sure we neither lose data nor make the user unhappy in the process? Stay
tuned.&lt;/span&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=bafdbe41-0786-4a7f-a488-8ca447d612eb" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,bafdbe41-0786-4a7f-a488-8ca447d612eb.aspx</comments>
      <category>Architecture</category>
      <category>Architecture/SOA</category>
      <category>Technology/Enterprise Services</category>
      <category>Technology/MSMQ</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=826bc7c9-8b0f-4df6-aabe-e6c5377a9446</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,826bc7c9-8b0f-4df6-aabe-e6c5377a9446.aspx</pingback:target>
      <dc:creator>
      </dc:creator>
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,826bc7c9-8b0f-4df6-aabe-e6c5377a9446.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=826bc7c9-8b0f-4df6-aabe-e6c5377a9446</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <div class="Section1">
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">Deadlocks and other locking conflicts
that cause transactional database operations to fail are things that puzzle many application
developers. Sure, proper database design and careful implementation of database access
(and appropriate support by the database engine) <i>should</i> take care of that problem,
but it cannot do so in all cases. Sometimes, especially under stress and other situations
with high lock contention, a database just has not much of a choice but picking at
least one of the transactions competing for the same locks as the victim in resolving
the deadlock situation and then aborts the chosen transaction. Generally speaking,
transactions that abort and roll back are a good thing, because this behavior guarantees
data integrity. In the end, we use transaction technology for those cases where data
integrity is at risk. What’s interesting is that even though transactions are
a technology that is explicitly about things going wrong, the strategy for dealing
with failing transaction is often not much more than to bubble the problem up to the
user and say “We apologize for the inconvenience. Please press OK”.</span>
          </p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">The appropriate strategy for handling
a deadlock or some other recoverable reason for a transaction abort on the application
level is to back out of the entire operation and to retry the transaction. Retrying
is a gamble that the next time the transaction runs, it won’t run into the same
deadlock situation again or that it will at least come out victorious when the database
picks its victims. Eventually, it’ll work. Even if it takes a few attempts.
That’s the idea. It’s quite simple.</span>
          </p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">What is not really all that simple
is the implementation. Whenever you are using transactions, you must make your code
aware that such “good errors” may occur at any time. Wrapping your transactional
ODBC/OLEDB/ADO/ADO.NET code or calls to transactional Enterprise Services or COM+
components with a try/catch block, writing errors to log-files and showing message
boxes to users just isn’t the right thing to do. The right thing is to simply
do the same batch of work again and until it succeeds.</span>
          </p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">The problem that some developers
seem to have with “just retry” is that it’s not so clear what should
be retried. It’s a problem of finding and defining the proper transaction scope.
Especially when user interaction is in the picture, things easily get very confusing.
If a user has filled in a form on a web page or some dialog window and all of his/her
input is complete and correct, should the user be bothered with a message that the
update transaction failed due to a locking issue? Certainly not. Should the user know
when the transaction fails because the database is currently unavailable? Maybe, but
not necessarily. Should the user be made aware that the application he/she is using
is for some sudden reason incompatible with the database schema of the backend database?
Maybe, but what does Joe in the sales department do with that valuable piece of information?</span>
          </p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">If stuff fails, should we just
forget about Joe’s input and tell him to come back when the system is happier
to serve him? So, in other words, do we have Joe retry the job? That’s easy
to program, but that sort of strategy doesn’t really make Joe happy, does it? </span>
          </p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">So what’s the right thing
to do? One part of the solution is a proper separation between the things the user
(or a program) does and the things that the transaction does. This will give us two
layers and “a job” that can be handed down from the presentation layer
down to the “transaction layer”. Once this separation is in place, we
can come up with a mechanism that will run those jobs in transactions and will automate
how and when transactions are to be retried. Transactional MSMQ queues turn out to
be a brilliant tool to make this very easy to implement. More tomorrow. Stay tuned.</span>
          </p>
        </div>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=826bc7c9-8b0f-4df6-aabe-e6c5377a9446" />
      </body>
      <title>Dealing with Deadlocks and Other Unfortunate Events on the Application Level: Part 1</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,826bc7c9-8b0f-4df6-aabe-e6c5377a9446.aspx</guid>
      <link>http://vasters.com/clemensv/2004/11/29/Dealing+With+Deadlocks+And+Other+Unfortunate+Events+On+The+Application+Level+Part+1.aspx</link>
      <pubDate>Mon, 29 Nov 2004 23:26:11 GMT</pubDate>
      <description>&lt;div class=Section1&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;Deadlocks and other locking conflicts
that cause transactional database operations to fail are things that puzzle many application
developers. Sure, proper database design and careful implementation of database access
(and appropriate support by the database engine) &lt;i&gt;should&lt;/i&gt; take care of that problem,
but it cannot do so in all cases. Sometimes, especially under stress and other situations
with high lock contention, a database just has not much of a choice but picking at
least one of the transactions competing for the same locks as the victim in resolving
the deadlock situation and then aborts the chosen transaction. Generally speaking,
transactions that abort and roll back are a good thing, because this behavior guarantees
data integrity. In the end, we use transaction technology for those cases where data
integrity is at risk. What&amp;#8217;s interesting is that even though transactions are
a technology that is explicitly about things going wrong, the strategy for dealing
with failing transaction is often not much more than to bubble the problem up to the
user and say &amp;#8220;We apologize for the inconvenience. Please press OK&amp;#8221;.&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;The appropriate strategy for handling
a deadlock or some other recoverable reason for a transaction abort on the application
level is to back out of the entire operation and to retry the transaction. Retrying
is a gamble that the next time the transaction runs, it won&amp;#8217;t run into the same
deadlock situation again or that it will at least come out victorious when the database
picks its victims. Eventually, it&amp;#8217;ll work. Even if it takes a few attempts.
That&amp;#8217;s the idea. It&amp;#8217;s quite simple.&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;What is not really all that simple
is the implementation. Whenever you are using transactions, you must make your code
aware that such &amp;#8220;good errors&amp;#8221; may occur at any time. Wrapping your transactional
ODBC/OLEDB/ADO/ADO.NET code or calls to transactional Enterprise Services or COM+
components with a try/catch block, writing errors to log-files and showing message
boxes to users just isn&amp;#8217;t the right thing to do. The right thing is to simply
do the same batch of work again and until it succeeds.&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;The problem that some developers
seem to have with &amp;#8220;just retry&amp;#8221; is that it&amp;#8217;s not so clear what should
be retried. It&amp;#8217;s a problem of finding and defining the proper transaction scope.
Especially when user interaction is in the picture, things easily get very confusing.
If a user has filled in a form on a web page or some dialog window and all of his/her
input is complete and correct, should the user be bothered with a message that the
update transaction failed due to a locking issue? Certainly not. Should the user know
when the transaction fails because the database is currently unavailable? Maybe, but
not necessarily. Should the user be made aware that the application he/she is using
is for some sudden reason incompatible with the database schema of the backend database?
Maybe, but what does Joe in the sales department do with that valuable piece of information?&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;If stuff fails, should we just
forget about Joe&amp;#8217;s input and tell him to come back when the system is happier
to serve him? So, in other words, do we have Joe retry the job? That&amp;#8217;s easy
to program, but that sort of strategy doesn&amp;#8217;t really make Joe happy, does it? &lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma"&gt;So what&amp;#8217;s the right thing
to do? One part of the solution is a proper separation between the things the user
(or a program) does and the things that the transaction does. This will give us two
layers and &amp;#8220;a job&amp;#8221; that can be handed down from the presentation layer
down to the &amp;#8220;transaction layer&amp;#8221;. Once this separation is in place, we
can come up with a mechanism that will run those jobs in transactions and will automate
how and when transactions are to be retried. Transactional MSMQ queues turn out to
be a brilliant tool to make this very easy to implement. More tomorrow. Stay tuned.&lt;/span&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=826bc7c9-8b0f-4df6-aabe-e6c5377a9446" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,826bc7c9-8b0f-4df6-aabe-e6c5377a9446.aspx</comments>
      <category>Architecture</category>
      <category>Architecture/SOA</category>
      <category>Technology/Enterprise Services</category>
      <category>Technology/MSMQ</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=2639bfcf-a32a-4326-b49e-0ebd919d1675</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,2639bfcf-a32a-4326-b49e-0ebd919d1675.aspx</pingback:target>
      <dc:creator>
      </dc:creator>
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,2639bfcf-a32a-4326-b49e-0ebd919d1675.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=2639bfcf-a32a-4326-b49e-0ebd919d1675</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Microsoft urgently needs to consolidate all the APIs that are required for provisioning
services or sites. The amount of knowledge you need to have and the number APIs you
need to use in order to lock down a Web service or Enterprise Services application
programmatically at installation time in order to have it run under an isolated
user account (with a choice of local or domain account) that has the precise rights
to do what it needs to do (but nothing else) is absolutely insane. 
</p>
        <p>
You need to set ACLs on the file system and the registry, you need to modify the local
machine's security policy, you need to create accounts and add them to local groups,
you must adhere to password policies with your auto-generated passwords, you need
to conbfigure identities on Enterprise Services applications and IIS application pools,
you need to set ACLs on Message Queues (if you use them), and you need to write WS-Policy
documents to secure your WS front. Every single of these tasks uses a different API
(and writing policies has none) and most of these jobs require explicit Win32
or COM interop. I have a complete wrapper for that functionality for my app now (which
took way too long to write), but that really needs to be fixed on a platform level.
</p>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=2639bfcf-a32a-4326-b49e-0ebd919d1675" />
      </body>
      <title>Secure deployment is just too hard, Microsoft</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,2639bfcf-a32a-4326-b49e-0ebd919d1675.aspx</guid>
      <link>http://vasters.com/clemensv/2004/06/07/Secure+Deployment+Is+Just+Too+Hard+Microsoft.aspx</link>
      <pubDate>Mon, 07 Jun 2004 09:45:52 GMT</pubDate>
      <description>&lt;p&gt;
Microsoft urgently needs to consolidate all the APIs that are required for provisioning
services or sites. The amount of knowledge you need to have and the number APIs you
need to use in order to lock down a Web service or Enterprise Services application
programmatically at installation time&amp;nbsp;in order to&amp;nbsp;have it run under an isolated
user account (with a choice of local or domain account) that has the precise rights
to do what it needs to do (but nothing else) is absolutely insane.&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
You need to set ACLs on the file system and the registry, you need to modify the local
machine's security policy, you need to create accounts and add them to local groups,
you must adhere to password policies with your auto-generated passwords, you need
to conbfigure identities on Enterprise Services applications and IIS application pools,
you need to set ACLs on Message Queues (if you use them), and you need to write WS-Policy
documents to secure your WS front. Every single of these tasks uses a different API
(and writing policies has none) and most of these jobs&amp;nbsp;require explicit Win32
or COM interop. I have a complete wrapper for that functionality for my app now (which
took way too long to write), but that really needs to be fixed on a platform level.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=2639bfcf-a32a-4326-b49e-0ebd919d1675" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,2639bfcf-a32a-4326-b49e-0ebd919d1675.aspx</comments>
      <category>Technology</category>
      <category>Technology/ASP.NET</category>
      <category>Technology/Enterprise Services</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=4fc00140-3a4e-4db0-8474-79c05e50ee96</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,4fc00140-3a4e-4db0-8474-79c05e50ee96.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,4fc00140-3a4e-4db0-8474-79c05e50ee96.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=4fc00140-3a4e-4db0-8474-79c05e50ee96</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of the reasons why I run Windows Server 2003 on my notebook is that "<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cossdk/htm/pgservices_serviceswithoutcomponents_7u5v.asp">Services
without Components</a>" (managed incarnation is <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystementerpriseservicesservicedomainclasstopic.asp">System.EnterpriseServices.ServiceDomain</a>)
didn't work on XP. If you just touch the ServiceConfig or ServiceDomain classes on
XP, you get rewarded with a <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemplatformnotsupportedexceptionclasstopic.asp">PlatformNotSupportedException</a>,
because the unmanaged implementation of that feature was present, but not
quite-as-perfect-as-it-should-be on XP. That will soon be history. Windows XP
SP2 and the COM+ 1.5 Rollup Package 6 will fix that and will bring COM+ 1.5 pretty
much on par with Windows Server 2003.
</p>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=4fc00140-3a4e-4db0-8474-79c05e50ee96" />
      </body>
      <title>Enterprise Services &amp; XP SP2: "Services without Components" works</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,4fc00140-3a4e-4db0-8474-79c05e50ee96.aspx</guid>
      <link>http://vasters.com/clemensv/2004/05/16/Enterprise+Services+XP+SP2+Services+Without+Components+Works.aspx</link>
      <pubDate>Sun, 16 May 2004 18:55:11 GMT</pubDate>
      <description>&lt;p&gt;
One of the reasons why I run Windows Server 2003 on my notebook is that "&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cossdk/htm/pgservices_serviceswithoutcomponents_7u5v.asp"&gt;Services
without Components&lt;/a&gt;" (managed incarnation is &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystementerpriseservicesservicedomainclasstopic.asp"&gt;System.EnterpriseServices.ServiceDomain&lt;/a&gt;)
didn't work on XP. If you just touch the ServiceConfig or ServiceDomain classes on
XP, you get rewarded with a &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemplatformnotsupportedexceptionclasstopic.asp"&gt;PlatformNotSupportedException&lt;/a&gt;,
because the unmanaged implementation of that&amp;nbsp;feature&amp;nbsp;was present,&amp;nbsp;but&amp;nbsp;not
quite-as-perfect-as-it-should-be on XP. That will soon be history.&amp;nbsp;Windows XP
SP2 and the COM+ 1.5 Rollup Package 6 will fix that and will bring COM+ 1.5 pretty
much on par with Windows Server 2003.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=4fc00140-3a4e-4db0-8474-79c05e50ee96" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,4fc00140-3a4e-4db0-8474-79c05e50ee96.aspx</comments>
      <category>Technology/Enterprise Services</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=64000a9a-567f-46e3-8c34-54f8414464a2</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,64000a9a-567f-46e3-8c34-54f8414464a2.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,64000a9a-567f-46e3-8c34-54f8414464a2.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=64000a9a-567f-46e3-8c34-54f8414464a2</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I am writing a very, very, very big application at the moment and I am totally swamped
in a 24/7 coding frenzy that’s going to continue for the next week or so, but
here’s one little bit to think about and for which I came up with a solution.
It’s actually a pretty scary problem.
</p>
        <p>
Let’s say you have a transactional serviced component (or make that a transactional
EJB) and you call an HTTP web service from it that forwards any information to another
service. What happens if the transaction fails for any reason? You’ve just produced
a phantom record. The web service on the other end should never have seen that information.
In fact, that information doesn’t exist from the viewpoint of your rolled back
local transaction. And of course, as of yet, there is no infrastructure in place that
gives you interoperable transaction flow. And if that were the case, the other web
service may not support it. What should you do? Panic?
</p>
        <p>
There is help right in the platform (Enterprise Services that is). Your best friend
for that sort of circumstance is System.EnterpriseServices.CompensatingResourceManager.
</p>
        <p>
The use case here is to call another service to allocate some items from an inventory
service. The call is strictly asynchronous and I the remote service will eventually
turn around and call an action on my service (they have a “duplex” conversation
using asynchronous calls going back and forth). Instead of calling the service form
within my transactional method, I am deferring the call until the transaction is being
resolved. Only when DTC is sure that the local transaction will go through, the web
service call will be made. There is no way to guarantee that the remote call succeeds,
but it does at least eliminate the very horrible side effects on overall system consistency
caused by phantom calls. It is in fact quite impossible to implement “Prepare”
correctly here, since the remote service may fail processing the (one-way) call on
a different thread and hence I might never get a SOAP fault indicating failure. Because
that’s so and because I really don’t know what the other service does,
I am not writing any specific recovery code in the “Commit” phase. Instead,
my local state for the conversation indicates the current progress of the interaction
between the two services and logs an expiration time. Once that expiration time has
passed without a response from the remote service, a watchdog will pick up the state
record, create a new message for the remote service and replay the call. 
</p>
        <p>
For synchronous call scenarios, you could implement (not shown here) a two-step call
sequence to the remote service, which the remote service needs to support, of course.
In “Prepare” (or in the “normal code”) you would pass the
data to the remote service and hold a session state cookie. If that call succeeds,
you vote “true”. In “Commit” you would issue a call to commit
that data on the remote service for this session, on “Abort” (remember
that the transaction may fail for any reason outside the scope of the web service
call), you will call the remote service to cancel the action and discard the data
of the session. What if the network connection fails between the “Prepare”
phase call and the “Commit” phase call? That’s the tricky bit. You
could log the call data and retry the “Commit” call at a later time or
keep retrying for a while in the “Commit” phase (which will cause the
transaction to hang). There’s no really good solution for that case, unless
you have transaction flow. In any event, the remote service will have to default to
an “Abort” once the session times out, which is easy to do if the data
is kept in a volatile session store over there. It just “forgets” it.
</p>
        <p>
However, all of this is much, much better than making naïve, simple web service
calls that fan out intermediate data from within transactions. Fight the phantoms.
</p>
        <p class="MsoNormal">
At the call location, write the call data to the CRM transaction log using the Clerk:
</p>
        <p class="MsoNormal" style="MARGIN-BOTTOM: 12pt">
          <span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'">AllocatedItemsMessage
aim = <span style="COLOR: blue">new</span> AllocatedItemsMessage();<br />
aim.allocatedAllocation = &lt;&lt;&lt; copy that data from elsewhere&gt;&gt;&gt;<br />
Clerk clerk = <span style="COLOR: blue">new</span> Clerk(<span style="COLOR: blue">typeof</span>(SiteInventoryConfirmAllocationRM),"SiteInventoryConfirmAllocationRM",CompensatorOptions.AllPhases);<br />
SiteInventoryConfirmAllocationRM.ConfirmAllocationLogRecord rec = <span style="COLOR: blue">new</span> RhineBooks.ClusterInventoryService.SiteInventoryConfirmAllocationRM.ConfirmAllocationLogRecord();<br />
rec.allocatedItemsMessage = aim;<br />
clerk.WriteLogRecord( rec.XmlSerialize() );<br />
clerk.ForceLog();</span>
        </p>
        <p>
Write a compensator that picks up the call data from the log and forwards it to the
remote service. In the “Prepare” phase, the minimum work that can be done
is to check whether the proxy can be constructed. You could also make sure that the
call URL is valid, the server name resolves and you could even try a GET on the service’s
documentation page or call a “Ping” method the remote service may provide.
That all serves to verify as good as you can that the “Commit” call has
a good chance of succeeding: 
</p>
        <p class="MsoNormal">
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">
            <br />
using System.EnterpriseServices.CompensatingResourceManager;<br /></span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">using
…</span>
        </p>
        <p class="MsoNormal">
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">
          </span> 
</p>
        <p class="MsoNormal" style="MARGIN-BOTTOM: 12pt">
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">///</span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'">
          </span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">
            <SUMMARY>
              <br />
///
</SUMMARY>
          </span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"> This
class is a CRM compensator that will invoke the allocation confirmation 
<br /></span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">///</span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"> activity
on the site inventory service if, and only if, the local transaction<br /></span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">///</span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"> enlisting
it is succeeding. Using the technique is a workaround for the lack<br /></span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">///</span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"> of
transactional I/O with HTTP web services. While the compensator cannot make<br /></span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">///</span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"> sure
that the call will succeed, it can at least guarantee that we do not produce 
<br /></span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">///</span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"> phantom
calls to external services.<br /></span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">///</span>
          <span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'">
          </span>
          <span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'">
            <br />
          </span>
          <span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'">public</span>
          <span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'">
            <span style="COLOR: blue">class</span> SiteInventoryConfirmAllocationRM
: Compensator<br />
{<br />
  <span style="COLOR: blue">private</span><span style="COLOR: blue">bool</span> vote
= <span style="COLOR: blue">true</span>;<br /><br />
  [Serializable]<br />
  <span style="COLOR: blue">public</span><span style="COLOR: blue">class</span> ConfirmAllocationLogRecord<br />
  {<br />
    <span style="COLOR: blue">public</span> SiteInventoryInquiries.AllocatedItemsMessage
allocatedItemsMessage;            
<br /><br />
    <span style="COLOR: blue">internal</span><span style="COLOR: blue">string</span> XmlSerialize() 
<br />
    {<br />
      StringWriter sw = <span style="COLOR: blue">new</span> StringWriter();<br />
      XmlSerializer xs = <span style="COLOR: blue">new</span> XmlSerializer(<span style="COLOR: blue">typeof</span>(ConfirmAllocationLogRecord));<br />
      xs.Serialize(sw,<span style="COLOR: blue">this</span>);<br />
      sw.Flush();<br />
      <span style="COLOR: blue">return</span> sw.ToString();<br />
    }<br /><br />
    <span style="COLOR: blue">internal</span><span style="COLOR: blue">static</span> ConfirmAllocationLogRecord
XmlDeserialize(<span style="COLOR: blue">string</span> s) 
<br />
    {<br />
      StringReader sr = <span style="COLOR: blue">new</span> StringReader(s);<br />
      XmlSerializer xs = <span style="COLOR: blue">new</span> XmlSerializer(<span style="COLOR: blue">typeof</span>(ConfirmAllocationLogRecord));<br />
      <span style="COLOR: blue">return</span> xs.Deserialize(sr) <span style="COLOR: blue">as</span> ConfirmAllocationLogRecord;<br />
    }<br />
  }<br /><br /><b>  <span style="COLOR: blue">public</span><span style="COLOR: blue">override</span><span style="COLOR: blue">bool</span> PrepareRecord(LogRecord
rec)<br /></b>  {<br />
    <span style="COLOR: blue">try<br /></span>    {<br />
      SiteInventoryInquiriesWse sii;<br />
      ConfirmAllocationLogRecord calr  = ConfirmAllocationLogRecord.XmlDeserialize((<span style="COLOR: blue">string</span>)rec.Record); 
<br />
      sii = InventoryInquiriesInternal.GetSiteInventoryInquiries(
calr.allocatedItemsMessage.allocatedAllocation.warehouseName );<br />
      vote = sii != <span style="COLOR: blue">null</span>; 
  <br />
      <span style="COLOR: blue">return</span><span style="COLOR: blue">false</span>;<br />
    }<br />
    <span style="COLOR: blue">catch</span>( Exception ex )<br />
    {<br />
      ExceptionManager.Publish( ex );<br />
      vote = <span style="COLOR: blue">false</span>;<br />
      <span style="COLOR: blue">return</span><span style="COLOR: blue">true</span>;<br />
    }<br />
  }<br /><br />
  <span style="COLOR: blue">public</span><span style="COLOR: blue">override</span><span style="COLOR: blue">bool</span> EndPrepare()<br />
  {<br />
    <span style="COLOR: blue">return</span> vote;<br />
  }<br /><br /><br /><b>  <span style="COLOR: blue">public</span><span style="COLOR: blue">override</span><span style="COLOR: blue">bool</span> CommitRecord(LogRecord
rec)</b><br />
  {<br />
    SiteInventoryInquiriesWse sii;<br />
    ConfirmAllocationLogRecord calr  = ConfirmAllocationLogRecord.XmlDeserialize((<span style="COLOR: blue">string</span>)rec.Record); 
<br />
    sii = InventoryInquiriesInternal.GetSiteInventoryInquiries( calr.allocatedItemsMessage.allocatedAllocation.warehouseName
);<br />
  
<br />
    <span style="COLOR: blue">try<br /></span>    {<br />
      sii.ConfirmAllocation( calr.allocatedItemsMessage );<br />
    }<br />
    <span style="COLOR: blue">catch</span>( Exception ex )<br />
    {<br />
      ExceptionManager.Publish( ex );<br />
    }<br />
    <span style="COLOR: blue">return</span><span style="COLOR: blue">true</span>;<br />
  }<br />
}</span>
        </p>
        <p class="MsoNormal">
          <span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">
          </span> 
</p>
        <p class="MsoNormal">
          <span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">
          </span> 
</p>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=64000a9a-567f-46e3-8c34-54f8414464a2" />
      </body>
      <title>Dealing with distributed transaction anomalies caused by web service calls from within transactions</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,64000a9a-567f-46e3-8c34-54f8414464a2.aspx</guid>
      <link>http://vasters.com/clemensv/2004/04/23/Dealing+With+Distributed+Transaction+Anomalies+Caused+By+Web+Service+Calls+From+Within+Transactions.aspx</link>
      <pubDate>Fri, 23 Apr 2004 08:27:54 GMT</pubDate>
      <description>&lt;p&gt;
I am writing a very, very, very big application at the moment and I am totally swamped
in a 24/7 coding frenzy that&amp;#8217;s going to continue for the next week or so, but
here&amp;#8217;s one little bit to think about and for which I came up with a solution.
It&amp;#8217;s actually a pretty scary problem.
&lt;/p&gt;
&lt;p&gt;
Let&amp;#8217;s say you have a transactional serviced component (or make that a transactional
EJB) and you call an HTTP web service from it that forwards any information to another
service. What happens if the transaction fails for any reason? You&amp;#8217;ve just produced
a phantom record. The web service on the other end should never have seen that information.
In fact, that information doesn&amp;#8217;t exist from the viewpoint of your rolled back
local transaction. And of course, as of yet, there is no infrastructure in place that
gives you interoperable transaction flow. And if that were the case, the other web
service may not support it. What should you do? Panic?
&lt;/p&gt;
&lt;p&gt;
There is help right in the platform (Enterprise Services that is). Your best friend
for that sort of circumstance is System.EnterpriseServices.CompensatingResourceManager.
&lt;/p&gt;
&lt;p&gt;
The use case here is to call another service to allocate some items from an inventory
service. The call is strictly asynchronous and I the remote service will eventually
turn around and call an action on my service (they have a &amp;#8220;duplex&amp;#8221; conversation
using asynchronous calls going back and forth). Instead of calling the service form
within my transactional method, I am deferring the call until the transaction is being
resolved. Only when DTC is sure that the local transaction will go through, the web
service call will be made. There is no way to guarantee that the remote call succeeds,
but it does at least eliminate the very horrible side effects on overall system consistency
caused by phantom calls. It is in fact quite impossible to implement &amp;#8220;Prepare&amp;#8221;
correctly here, since the remote service may fail processing the (one-way) call on
a different thread and hence I might never get a SOAP fault indicating failure. Because
that&amp;#8217;s so and because I really don&amp;#8217;t know what the other service does,
I am not writing any specific recovery code in the &amp;#8220;Commit&amp;#8221; phase. Instead,
my local state for the conversation indicates the current progress of the interaction
between the two services and logs an expiration time. Once that expiration time has
passed without a response from the remote service, a watchdog will pick up the state
record, create a new message for the remote service and replay the call. 
&lt;/p&gt;
&lt;p&gt;
For synchronous call scenarios, you could implement (not shown here) a two-step call
sequence to the remote service, which the remote service needs to support, of course.
In &amp;#8220;Prepare&amp;#8221; (or in the &amp;#8220;normal code&amp;#8221;) you would pass the
data to the remote service and hold a session state cookie. If that call succeeds,
you vote &amp;#8220;true&amp;#8221;. In &amp;#8220;Commit&amp;#8221; you would issue a call to commit
that data on the remote service for this session, on &amp;#8220;Abort&amp;#8221; (remember
that the transaction may fail for any reason outside the scope of the web service
call), you will call the remote service to cancel the action and discard the data
of the session. What if the network connection fails between the &amp;#8220;Prepare&amp;#8221;
phase call and the &amp;#8220;Commit&amp;#8221; phase call? That&amp;#8217;s the tricky bit. You
could log the call data and retry the &amp;#8220;Commit&amp;#8221; call at a later time or
keep retrying for a while in the &amp;#8220;Commit&amp;#8221; phase (which will cause the
transaction to hang). There&amp;#8217;s no really good solution for that case, unless
you have transaction flow. In any event, the remote service will have to default to
an &amp;#8220;Abort&amp;#8221; once the session times out, which is easy to do if the data
is kept in a volatile session store over there. It just &amp;#8220;forgets&amp;#8221; it.
&lt;/p&gt;
&lt;p&gt;
However, all of this is much, much better than making na&amp;#239;ve, simple web service
calls that fan out intermediate data from within transactions. Fight the phantoms.
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
At the call location, write the call data to the CRM transaction log using the Clerk:
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN-BOTTOM: 12pt"&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'"&gt;AllocatedItemsMessage
aim = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; AllocatedItemsMessage();&lt;br&gt;
aim.allocatedAllocation = &amp;lt;&amp;lt;&amp;lt; copy that data from elsewhere&amp;gt;&amp;gt;&amp;gt;&lt;br&gt;
Clerk clerk = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; Clerk(&lt;span style="COLOR: blue"&gt;typeof&lt;/span&gt;(SiteInventoryConfirmAllocationRM),"SiteInventoryConfirmAllocationRM",CompensatorOptions.AllPhases);&lt;br&gt;
SiteInventoryConfirmAllocationRM.ConfirmAllocationLogRecord rec = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; RhineBooks.ClusterInventoryService.SiteInventoryConfirmAllocationRM.ConfirmAllocationLogRecord();&lt;br&gt;
rec.allocatedItemsMessage = aim;&lt;br&gt;
clerk.WriteLogRecord( rec.XmlSerialize() );&lt;br&gt;
clerk.ForceLog();&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Write a compensator that picks up the call data from the log and forwards it to the
remote service. In the &amp;#8220;Prepare&amp;#8221; phase, the minimum work that can be done
is to check whether the proxy can be constructed. You could also make sure that the
call URL is valid, the server name resolves and you could even try a GET on the service&amp;#8217;s
documentation page or call a &amp;#8220;Ping&amp;#8221; method the remote service may provide.
That all serves to verify as good as you can that the &amp;#8220;Commit&amp;#8221; call has
a good chance of succeeding: 
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;
&lt;br&gt;
using System.EnterpriseServices.CompensatingResourceManager;&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;using
&amp;#8230;&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p class=MsoNormal style="MARGIN-BOTTOM: 12pt"&gt;
&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;///&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; &lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;
&lt;SUMMARY&gt;
&lt;br&gt;
///
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; This
class is a CRM compensator that will invoke the allocation confirmation 
&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;///&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; activity
on the site inventory service if, and only if, the local transaction&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;///&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; enlisting
it is succeeding. Using the technique is a workaround for the lack&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;///&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; of
transactional I/O with HTTP web services. While the compensator cannot make&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;///&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; sure
that the call will succeed, it can at least guarantee that we do not produce 
&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;///&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; phantom
calls to external services.&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;///&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Lucida Console'"&gt; &lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Lucida Console'"&gt;&gt;
&lt;br&gt;
&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Lucida Console'"&gt;public&lt;/span&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: 'Lucida Console'"&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; SiteInventoryConfirmAllocationRM
: Compensator&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; vote
= &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;;&lt;br&gt;
&lt;br&gt;
&amp;nbsp; [Serializable]&lt;br&gt;
&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; ConfirmAllocationLogRecord&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;public&lt;/span&gt; SiteInventoryInquiries.AllocatedItemsMessage
allocatedItemsMessage;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;internal&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; XmlSerialize() 
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringWriter sw = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; StringWriter();&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;XmlSerializer xs = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; XmlSerializer(&lt;span style="COLOR: blue"&gt;typeof&lt;/span&gt;(ConfirmAllocationLogRecord));&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xs.Serialize(sw,&lt;span style="COLOR: blue"&gt;this&lt;/span&gt;);&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.Flush();&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;return&lt;/span&gt; sw.ToString();&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;internal&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; ConfirmAllocationLogRecord
XmlDeserialize(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; s) 
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringReader sr = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; StringReader(s);&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;XmlSerializer xs = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; XmlSerializer(&lt;span style="COLOR: blue"&gt;typeof&lt;/span&gt;(ConfirmAllocationLogRecord));&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;return&lt;/span&gt; xs.Deserialize(sr) &lt;span style="COLOR: blue"&gt;as&lt;/span&gt; ConfirmAllocationLogRecord;&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&lt;b&gt;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;override&lt;/span&gt; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; PrepareRecord(LogRecord
rec)&lt;br&gt;
&lt;/b&gt;&amp;nbsp; {&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;try&lt;br&gt;
&lt;/span&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SiteInventoryInquiriesWse sii;&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ConfirmAllocationLogRecord calr&amp;nbsp; = ConfirmAllocationLogRecord.XmlDeserialize((&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;)rec.Record); 
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sii = InventoryInquiriesInternal.GetSiteInventoryInquiries(
calr.allocatedItemsMessage.allocatedAllocation.warehouseName );&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vote = sii != &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: blue"&gt;false&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;catch&lt;/span&gt;( Exception ex )&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExceptionManager.Publish( ex );&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vote = &lt;span style="COLOR: blue"&gt;false&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;override&lt;/span&gt; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; EndPrepare()&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;return&lt;/span&gt; vote;&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;b&gt;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;override&lt;/span&gt; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; CommitRecord(LogRecord
rec)&lt;/b&gt;
&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;SiteInventoryInquiriesWse sii;&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;ConfirmAllocationLogRecord calr&amp;nbsp; = ConfirmAllocationLogRecord.XmlDeserialize((&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;)rec.Record); 
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;sii = InventoryInquiriesInternal.GetSiteInventoryInquiries( calr.allocatedItemsMessage.allocatedAllocation.warehouseName
);&lt;br&gt;
&amp;nbsp; 
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;try&lt;br&gt;
&lt;/span&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sii.ConfirmAllocation( calr.allocatedItemsMessage );&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;catch&lt;/span&gt;( Exception ex )&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExceptionManager.Publish( ex );&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=64000a9a-567f-46e3-8c34-54f8414464a2" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,64000a9a-567f-46e3-8c34-54f8414464a2.aspx</comments>
      <category>Architecture</category>
      <category>Technology/Enterprise Services</category>
      <category>Technology/Web Services</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=2e27b7d3-8567-4cee-86ee-6b3e23e86d5d</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,2e27b7d3-8567-4cee-86ee-6b3e23e86d5d.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,2e27b7d3-8567-4cee-86ee-6b3e23e86d5d.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=2e27b7d3-8567-4cee-86ee-6b3e23e86d5d</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://weblogs.asp.net/bmore/posts/33113.aspx">Brad More</a> is asking whether
and why he should use Enterprise Services.
</p>
        <p>
Brad, if you go to the PDC, you can get the definitive, strategic answer on that question
in this talk:
</p>
        <p>
          <strong>“Indigo”: Connected Application Technology Roadmap<br /></strong>
          <font style="FONT-SIZE: 8pt">
            <strong>Track: </strong>Web/Services   <strong>Code: </strong>WSV203<br /><strong>Room: </strong>Room 409AB   <strong>Time Slot: </strong>Wed,
October 29 11:30 AM-12:45 PM<br /><strong>Speakers: 
<SPEAKER></SPEAKER></strong><a>Angela Mills</a>
, 
<SPEAKER><a>Joe Long</a></SPEAKER></font>
        </p>
        <p>
Joe Long is Product Unit Manager for Enterprise Services at Microsoft, a product unit
that is part of the larger Indigo group. The Indigo team owns Remoting, ASP.NET
Web Services, Enterprise Services, all of COM/COM+ and everything that has to do with
Serialization. 
</p>
        <p>
And if you want to hear the same song sung by the technologyspeakmaster,
go and hear Don:
</p>
        <p>
          <strong>“Indigo": Services and the Future of Distributed Applications<br /></strong>
          <font style="FONT-SIZE: 8pt">
            <strong>Track: </strong>Web/Services   <strong>Code: </strong>WSV201<br /><strong>Room: </strong>Room 150/151/152/153   <strong>Time Slot: </strong>Mon,
October 27 4:45 PM-6:00 PM<br /><strong>Speaker: </strong><SPEAKER><a>Don Box</a></SPEAKER></font>
        </p>
        <p>
If you want to read the core message right now, just <a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=97f80d05-73bc-4e59-b2f1-c748d7eed43b">scroll
down here</a>. I've been working directly with the Indigo folks on the messaging
for my talks at TechEd in Dallas earlier this year as part of the effort of setting
the stage for Indigo's debut at the PDC.
</p>
        <p>
I'd also suggest that you don't implement your own ES clone using custom
channel sinks, context sinks, or formatters and ignore the entire context model of
.NET Remoting if you want to play in Indigo-Land without having to rewrite a large
deal of your apps. The lack of security support of Remoting is not a missing feature;
Enterprise Services is layered on top of Remoting and provides security. The very
limited scalability of Remoting on any transport but cross-appdomain is not a
real limitation; if you want to scale use Enterprise Services. Check out this <a href="http://radio.weblogs.com/0108971/2002/09/12.html">page
from my old blog</a> for a few intimate details on transport in Enterprise Services. 
</p>
        <p>
ASMX is the default, ES ist the fall-back strategy if you need the features or the
performance and Remoting the the cheap, local ORPC model. 
</p>
        <p>
If you rely on ASMX and ES today, you'll have a pretty smooth upgrade path. Take that
expectation with you and go to Joe's session.
</p>
        <p>
[PS: What I am saying <a href="http://radio.weblogs.com/0108971/2002/09/12.html">there </a>about
ES marshaling not using COM/Interop is true except for two cases that I found later:
Queued Components and calls with isomorphic call signatures where the binary
representation of COM and the CLR is identical - like with a function that passes
and returns only ints. The reason why COM/Interop is used in those cases is very simple:
it's a lot faster.]<em> </em></p>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=2e27b7d3-8567-4cee-86ee-6b3e23e86d5d" />
      </body>
      <title>PDC Countdown: Use ASMX and Enterprise Services Now For Tomorrow</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,2e27b7d3-8567-4cee-86ee-6b3e23e86d5d.aspx</guid>
      <link>http://vasters.com/clemensv/2003/10/24/PDC+Countdown+Use+ASMX+And+Enterprise+Services+Now+For+Tomorrow.aspx</link>
      <pubDate>Fri, 24 Oct 2003 06:54:46 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://weblogs.asp.net/bmore/posts/33113.aspx"&gt;Brad More&lt;/a&gt; is asking whether
and why he should use Enterprise Services.
&lt;/p&gt;
&lt;p&gt;
Brad, if you go to the PDC, you can get the definitive, strategic answer on that question
in this talk:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;“Indigo”: Connected Application Technology Roadmap&lt;br&gt;
&lt;/strong&gt;&lt;font style="FONT-SIZE: 8pt"&gt;&lt;strong&gt;Track: &lt;/strong&gt;Web/Services&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;Code: &lt;/strong&gt;WSV203&lt;br&gt;
&lt;strong&gt;Room: &lt;/strong&gt;Room 409AB&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;Time Slot: &lt;/strong&gt;Wed,
October 29 11:30 AM-12:45 PM&lt;br&gt;
&lt;strong&gt;Speakers: 
&lt;SPEAKER&gt;
&lt;/strong&gt;&lt;a&gt;Angela Mills&lt;/a&gt;&gt;
, 
&lt;SPEAKER&gt;
&lt;a&gt;Joe Long&lt;/a&gt;
&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
Joe Long is Product Unit Manager for Enterprise Services at Microsoft, a product unit
that is&amp;nbsp;part of the larger Indigo group. The Indigo team owns Remoting, ASP.NET
Web Services, Enterprise Services, all of COM/COM+ and everything that has to do with
Serialization. 
&lt;/p&gt;
&lt;p&gt;
And if you want to hear&amp;nbsp;the same song sung&amp;nbsp;by the technologyspeakmaster,
go and hear Don:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;“Indigo": Services and the Future of Distributed Applications&lt;br&gt;
&lt;/strong&gt;&lt;font style="FONT-SIZE: 8pt"&gt;&lt;strong&gt;Track: &lt;/strong&gt;Web/Services&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;Code: &lt;/strong&gt;WSV201&lt;br&gt;
&lt;strong&gt;Room: &lt;/strong&gt;Room 150/151/152/153&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;Time Slot: &lt;/strong&gt;Mon,
October 27 4:45 PM-6:00 PM&lt;br&gt;
&lt;strong&gt;Speaker: &lt;/strong&gt;
&lt;SPEAKER&gt;
&lt;a&gt;Don Box&lt;/a&gt;
&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
If you want to read the&amp;nbsp;core message right now, just&amp;nbsp;&lt;a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=97f80d05-73bc-4e59-b2f1-c748d7eed43b"&gt;scroll
down here&lt;/a&gt;. I've been working directly with&amp;nbsp;the Indigo folks on the messaging
for my talks at TechEd in Dallas earlier this year as part of the effort&amp;nbsp;of setting
the stage for Indigo's debut at the PDC.
&lt;/p&gt;
&lt;p&gt;
I'd also suggest that you don't&amp;nbsp;implement your own ES clone&amp;nbsp;using custom
channel sinks, context sinks, or formatters and ignore the entire context model of
.NET Remoting if you want to play in Indigo-Land without having to rewrite a large
deal of your apps. The lack of security support of Remoting is not a missing feature;
Enterprise Services is layered on top of Remoting and provides security. The very
limited scalability of Remoting&amp;nbsp;on any transport but cross-appdomain is not a
real limitation; if you want to scale use Enterprise Services. Check out this &lt;a href="http://radio.weblogs.com/0108971/2002/09/12.html"&gt;page
from my old blog&lt;/a&gt;&amp;nbsp;for a few intimate details on transport in Enterprise Services. 
&lt;/p&gt;
&lt;p&gt;
ASMX is the default, ES ist the fall-back strategy if you need the features or the
performance and Remoting the the&amp;nbsp;cheap, local&amp;nbsp;ORPC model.&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
If you rely on ASMX and ES today, you'll have a pretty smooth upgrade path. Take that
expectation with you and go to Joe's session.
&lt;/p&gt;
&lt;p&gt;
[PS: What I am saying &lt;a href="http://radio.weblogs.com/0108971/2002/09/12.html"&gt;there &lt;/a&gt;about
ES marshaling not using COM/Interop is true except for two cases that I found later:
Queued Components and calls with isomorphic call signatures&amp;nbsp;where&amp;nbsp;the binary
representation of COM and the CLR is identical - like with a function that passes
and returns only ints. The reason why COM/Interop is used in those cases is very simple:
it's a lot faster.]&lt;em&gt;&amp;nbsp;&lt;/em&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=2e27b7d3-8567-4cee-86ee-6b3e23e86d5d" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,2e27b7d3-8567-4cee-86ee-6b3e23e86d5d.aspx</comments>
      <category>PDC 03</category>
      <category>Technology</category>
      <category>Technology/COM</category>
      <category>Technology/Enterprise Services</category>
      <category>Technology/Indigo</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=d4530741-3a50-4423-be66-804383adf328</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,d4530741-3a50-4423-be66-804383adf328.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,d4530741-3a50-4423-be66-804383adf328.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=d4530741-3a50-4423-be66-804383adf328</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <div class="Section1">
          <p>
Steve Swartz, who is one of my very good personal friends and who is, that “personal
function” aside, Program Manager in Microsoft’s Indigo team and also was
the lead architect for a lot of the new functionality that we got in the Windows Server
2003 version of Enterprise Services (COM+ 1.5 for the old fashioned folks), wrote
a comment on my <a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d">previous
post</a> on this topic, where I explained how you can get the XML configuration story
of the Framework to work with Enterprise Services using the .NET Framework 1.1.
</p>
          <p>
In response to what I wrote, someone asked whether this would also work on Windows
XP, because I was explicitly talking about Windows Server 2003. Steve’s answer
to that question completes the picture and therefore it shouldn’t be buried
in the comments. Steve writes:
</p>
          <p style="margin-left:36.0pt">
            <i>In fact, this will work on XP and Windows Server 2003 so long as you have NETFX
1.1. The field has been there since XP; in NETFX 1.1, we set the current directory
for the managed app domain. 
<br /><br />
This field was originally added to configure unmanaged fusion contexts. In that capacity,
the field works with library and server apps alike. In its capacity as a setter of
current appdomain directory, it works less well with library apps (natch).</i>
          </p>
        </div>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=d4530741-3a50-4423-be66-804383adf328" />
      </body>
      <title>The official word on the solution of the "dllhost.exe.config dilemma" or "How to use XML config with Enterprise Services"</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,d4530741-3a50-4423-be66-804383adf328.aspx</guid>
      <link>http://vasters.com/clemensv/2003/09/27/The+Official+Word+On+The+Solution+Of+The+Dllhostexeconfig+Dilemma+Or+How+To+Use+XML+Config+With+Enterprise+Services.aspx</link>
      <pubDate>Sat, 27 Sep 2003 15:33:35 GMT</pubDate>
      <description>

&lt;div class=Section1&gt;
&lt;p&gt;
Steve Swartz, who is one of my very good personal friends and who is, that &amp;#8220;personal
function&amp;#8221; aside, Program Manager in Microsoft&amp;#8217;s Indigo team and also was
the lead architect for a lot of the new functionality that we got in the Windows Server
2003 version of Enterprise Services (COM+ 1.5 for the old fashioned folks), wrote
a comment on my &lt;a href="http://staff.newtelligence.net/clemensv/PermaLink.aspx?guid=0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d"&gt;previous
post&lt;/a&gt; on this topic, where I explained how you can get the XML configuration story
of the Framework to work with Enterprise Services using the .NET Framework 1.1.
&lt;/p&gt;
&lt;p&gt;
In response to what I wrote, someone asked whether this would also work on Windows
XP, because I was explicitly talking about Windows Server 2003. Steve&amp;#8217;s answer
to that question completes the picture and therefore it shouldn&amp;#8217;t be buried
in the comments. Steve writes:
&lt;/p&gt;
&lt;p style='margin-left:36.0pt'&gt;
&lt;i&gt;In fact, this will work on XP and Windows Server 2003 so long as you have NETFX
1.1. The field has been there since XP; in NETFX 1.1, we set the current directory
for the managed app domain. 
&lt;br&gt;
&lt;br&gt;
This field was originally added to configure unmanaged fusion contexts. In that capacity,
the field works with library and server apps alike. In its capacity as a setter of
current appdomain directory, it works less well with library apps (natch).&lt;/i&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=d4530741-3a50-4423-be66-804383adf328" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,d4530741-3a50-4423-be66-804383adf328.aspx</comments>
      <category>Technology/Enterprise Services</category>
    </item>
    <item>
      <trackback:ping>http://vasters.com/clemensv/Trackback.aspx?guid=0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d</trackback:ping>
      <pingback:server>http://vasters.com/clemensv/pingback.aspx</pingback:server>
      <pingback:target>http://vasters.com/clemensv/PermaLink,guid,0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://vasters.com/clemensv/CommentView,guid,0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d.aspx</wfw:comment>
      <wfw:commentRss>http://vasters.com/clemensv/SyndicationService.asmx/GetEntryCommentsRss?guid=0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d</wfw:commentRss>
      <slash:comments>6</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <div class="Section1">
          <p>
            <img height="399" hspace="12" src="http://staff.newtelligence.net/clemensv/content/binary/image0011234.jpg" width="341" align="left" vspace="11" />A
long while back, <a href="http://radio.weblogs.com/0108971/2002/07/16.html#a13">I
wrote about</a> a hack to fix the dllhost.exe.config dilemma of Enterprise Services.
That hack no longer works due to changes in the Framework, but the good news is there
is an “official” and very easy solution for this now. Unfortunately there is no documentation
on this (or at least it’s not easy enough to find that I could locate it) and Google
only yields a few hints if you know exactly what you are looking for. So, index this,
Google!
</p>
          <p>
What I call the “config dilemma” of Enterprise Services is that because all out-of-process
ES applications are executed using the surrogate process provided by <i>%SystemRoot%\System32\dllhost.exe</i> and
the runtime is loaded into that process, the default application configuration file
is dllhost.exe.config, must reside just next to dllhost.exe (in System32) and is therefore
shared across all out-of-process Enterprise Services applications.
</p>
          <p>
That makes using the XML configuration infrastructure for Enterprise Services very
unattractive, to say the least.
</p>
          <p>
Now, with COM+ 1.5 (Windows Server 2003) and the .NET Framework 1.1, things did change
in a big way. 
</p>
          <p>
To use per-application application configuration files, all you have to do is to create
an (possibly otherwise empty) “application root directory” for your application in
which you place two files: An <b><i>application.manifest</i></b> file (that exact
name) and an <b><i>application.config</i></b> file. Once your application is registered
(lazy or using the <i>RegistrationHelper</i> class or through regsvcs.exe), you will
have to configure the application’s root directory in the catalog – that can be done
either programmatically using the <a href="http://msdn.microsoft.com/library/en-us/cossdk/htm/comadmincollections 2ram.asp?frame=true# cos applications applicationdirectory">catalog
admin API</a> (ApplicationDirectory property) or through the Component Services explorer
as shown above.
</p>
          <p>
The picture shows that the example that you can download using the link below is installed
at “c:\Development\ES\ConfigTest\ESTest” on my machine and has these two said files
sitting right there. 
</p>
          <p>
The <b><i>application.manifest</i></b> file content is embarrassingly simple
</p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">&lt;?<span style="COLOR: maroon">xml</span><span style="COLOR: fuchsia"></span><span style="COLOR: red">version</span>="1.0"<span style="COLOR: fuchsia"></span><span style="COLOR: red">encoding</span>="UTF-8"<span style="COLOR: fuchsia"></span><span style="COLOR: red">standalone</span>="yes"?&gt;<br />
&lt;<span style="COLOR: maroon">assembly</span><span style="COLOR: fuchsia"></span><span style="COLOR: red">xmlns</span>="urn:schemas-microsoft-com:asm.v1"<span style="COLOR: fuchsia"></span><span style="COLOR: red">manifestVersion</span>="1.0"&gt;<br />
&lt;/<span style="COLOR: maroon">assembly</span>&gt;</span>
          </p>
          <p>
and the <b><i>application.config</i></b> isn’t complicated either:
</p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 8pt; COLOR: blue; FONT-FAMILY: 'Courier New'">&lt;?</span>
            <span style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">xml<span style="COLOR: fuchsia"></span><span style="COLOR: red">version</span><span style="COLOR: blue">="1.0"?&gt;<br />
&lt;</span>configuration<span style="COLOR: blue">&gt;<br /></span>  <span style="COLOR: blue">&lt;</span>appSettings<span style="COLOR: blue">&gt;<br /></span>     <span style="COLOR: blue">&lt;</span>add<span style="COLOR: fuchsia"></span><span style="COLOR: red">key</span><span style="COLOR: blue">="configBit"</span><span style="COLOR: fuchsia"></span><span style="COLOR: red">value</span><span style="COLOR: blue">="This
rocks!"/&gt;<br /></span>  <span style="COLOR: blue">&lt;/</span>appSettings<span style="COLOR: blue">&gt;<br />
&lt;/</span>configuration<span style="COLOR: blue">&gt;</span></span>
          </p>
          <p>
These two files, placed into the same directory and properly configured as shown in
the above picture, let this class
</p>
          <p class="MsoNormal">
            <span style="FONT-SIZE: 8pt; COLOR: blue; FONT-FAMILY: 'Courier New'">      
public</span>
            <span style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'">
              <span style="COLOR: blue">class</span> SimpleComponent
: ServicedComponent<br />
       {<br />
        p<span style="COLOR: blue">ublic</span><span style="COLOR: blue">string</span> GetConfigBit()<br />
        {<br />
            <span style="COLOR: blue">return</span> ConfigurationSettings.AppSettings["configBit"];<br />
        }<br />
       }</span>
          </p>
          <p>
yield the expected result for GetConfigBit(): “This rocks!”
</p>
          <p>
 
</p>
          <p>
 
</p>
        </div>
        <p>
Download: <a href="http://staff.newtelligence.net/clemensv/content/binary/ESTest.zip">ESTest.zip</a><br /></p>
        <img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d" />
      </body>
      <title>dllhost.exe.config dilemma fixed, at last -- by Microsoft.</title>
      <guid isPermaLink="false">http://vasters.com/clemensv/PermaLink,guid,0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d.aspx</guid>
      <link>http://vasters.com/clemensv/2003/09/26/dllhostexeconfig+Dilemma+Fixed+At+Last+By+Microsoft.aspx</link>
      <pubDate>Fri, 26 Sep 2003 11:37:36 GMT</pubDate>
      <description>&lt;div class=Section1&gt;
&lt;p&gt;
&lt;img height=399 hspace=12 src="http://staff.newtelligence.net/clemensv/content/binary/image0011234.jpg" width=341 align=left vspace=11&gt;A
long while back, &lt;a href="http://radio.weblogs.com/0108971/2002/07/16.html#a13"&gt;I
wrote about&lt;/a&gt; a hack to fix the dllhost.exe.config dilemma of Enterprise Services.
That hack no longer works due to changes in the Framework, but the good news is there
is an “official” and very easy solution for this now. Unfortunately there is no documentation
on this (or at least it’s not easy enough to find that I could locate it) and Google
only yields a few hints if you know exactly what you are looking for. So, index this,
Google!
&lt;/p&gt;
&lt;p&gt;
What I call the “config dilemma” of Enterprise Services is that because all out-of-process
ES applications are executed using the surrogate process provided by &lt;i&gt;%SystemRoot%\System32\dllhost.exe&lt;/i&gt; and
the runtime is loaded into that process, the default application configuration file
is dllhost.exe.config, must reside just next to dllhost.exe (in System32) and is therefore
shared across all out-of-process Enterprise Services applications.
&lt;/p&gt;
&lt;p&gt;
That makes using the XML configuration infrastructure for Enterprise Services very
unattractive, to say the least.
&lt;/p&gt;
&lt;p&gt;
Now, with COM+ 1.5 (Windows Server 2003) and the .NET Framework 1.1, things did change
in a big way. 
&lt;/p&gt;
&lt;p&gt;
To use per-application application configuration files, all you have to do is to create
an (possibly otherwise empty) “application root directory” for your application in
which you place two files: An &lt;b&gt;&lt;i&gt;application.manifest&lt;/i&gt;&lt;/b&gt; file (that exact
name) and an &lt;b&gt;&lt;i&gt;application.config&lt;/i&gt;&lt;/b&gt; file. Once your application is registered
(lazy or using the &lt;i&gt;RegistrationHelper&lt;/i&gt; class or through regsvcs.exe), you will
have to configure the application’s root directory in the catalog – that can be done
either programmatically using the &lt;a href="http://msdn.microsoft.com/library/en-us/cossdk/htm/comadmincollections 2ram.asp?frame=true# cos applications applicationdirectory"&gt;catalog
admin API&lt;/a&gt; (ApplicationDirectory property) or through the Component Services explorer
as shown above.
&lt;/p&gt;
&lt;p&gt;
The picture shows that the example that you can download using the link below is installed
at “c:\Development\ES\ConfigTest\ESTest” on my machine and has these two said files
sitting right there. 
&lt;/p&gt;
&lt;p&gt;
The &lt;b&gt;&lt;i&gt;application.manifest&lt;/i&gt;&lt;/b&gt; file content is embarrassingly simple
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"&gt;&amp;lt;?&lt;span style="COLOR: maroon"&gt;xml&lt;/span&gt;&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;version&lt;/span&gt;="1.0"&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;encoding&lt;/span&gt;="UTF-8"&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;standalone&lt;/span&gt;="yes"?&amp;gt;&lt;br&gt;
&amp;lt;&lt;span style="COLOR: maroon"&gt;assembly&lt;/span&gt;&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;xmlns&lt;/span&gt;="urn:schemas-microsoft-com:asm.v1"&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;manifestVersion&lt;/span&gt;="1.0"&amp;gt;&lt;br&gt;
&amp;lt;/&lt;span style="COLOR: maroon"&gt;assembly&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
and the &lt;b&gt;&lt;i&gt;application.config&lt;/i&gt;&lt;/b&gt; isn’t complicated either:
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 8pt; COLOR: blue; FONT-FAMILY: 'Courier New'"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"&gt;xml&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;version&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="1.0"?&amp;gt;&lt;br&gt;
&amp;lt;&lt;/span&gt;configuration&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;appSettings&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;add&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;key&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="configBit"&lt;/span&gt;&lt;span style="COLOR: fuchsia"&gt; &lt;/span&gt;&lt;span style="COLOR: red"&gt;value&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="This
rocks!"/&amp;gt;&lt;br&gt;
&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;appSettings&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;br&gt;
&amp;lt;/&lt;/span&gt;configuration&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
These two files, placed into the same directory and properly configured as shown in
the above picture, let this class
&lt;/p&gt;
&lt;p class=MsoNormal&gt;
&lt;span style="FONT-SIZE: 8pt; COLOR: blue; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
public&lt;/span&gt;&lt;span style="FONT-SIZE: 8pt; FONT-FAMILY: 'Courier New'"&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; SimpleComponent
: ServicedComponent&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;p&lt;span style="COLOR: blue"&gt;ublic&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; GetConfigBit()&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; ConfigurationSettings.AppSettings["configBit"];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
yield the expected result for GetConfigBit(): “This rocks!”
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Download: &lt;a href="http://staff.newtelligence.net/clemensv/content/binary/ESTest.zip"&gt;ESTest.zip&lt;/a&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vasters.com/clemensv/aggbug.ashx?id=0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d" /&gt;</description>
      <comments>http://vasters.com/clemensv/CommentView,guid,0615b3cc-0fbf-4cf5-9d49-ae95b50f7e8d.aspx</comments>
      <category>Technology/CLR</category>
      <category>Technology/Enterprise Services</category>
    </item>
  </channel>
</rss>