<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>All Free Tech &#187; .NET</title>
	<atom:link href="http://www.allfreetech.com/tag/net/feed" rel="self" type="application/rss+xml" />
	<link>http://www.allfreetech.com</link>
	<description>For developers</description>
	<lastBuildDate>Tue, 01 Feb 2011 13:45:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Asp .net 3.5</title>
		<link>http://www.allfreetech.com/microsoft-net/asp-net/asp-net-3-5-245.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/asp-net/asp-net-3-5-245.html#comments</comments>
		<pubDate>Tue, 02 Feb 2010 14:23:38 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=245</guid>
		<description><![CDATA[The asp.net reporting is so easy to use. Do not be overwhelmed by the terms that you might encounter. Just know the basics and you are good to go. If ever it is taking some time for you to make your report using asp.net reporting, try to crack what exactly it asks from you. The [...]]]></description>
			<content:encoded><![CDATA[<p>The asp.net reporting is so easy to use. Do not be overwhelmed by the terms that you might encounter. Just know the basics and you are good to go. If ever it is taking some time for you to make your report using asp.net reporting, try to crack what exactly it asks from you. The minute you get the hang of it, you will see that it can definitely make your preparing for reports easier.You can work on your designer skills too &ndash; when you use the asp.net reporting. All you would have to do is to embed this within your application. As long as you have strong data, then the system will generate the presentation for you. At run time, the data can automatically populate the information that you want presented. So you can choose the ReportViewer control. By clicking on this, you will see in your very eyes the information that you were able to gather from previous reports which you have also incorporated with your own.The New Data Controls include the listview and Datapager. The listview enables the user to create, read, update and delete the functions, it is also known as the CRUP operations. &nbsp;The listview allows the user to page and sort the data. It is a flexible and elastic control function which makes the user list controls such as repeater, Gridview, Dataview etc. The datapager was included in the ASP. NET 3.5 hosting platform to ensure that the page functioning was integrated into the date controls without any complexities.ASP.NET 3.5 hosting also allows the web hosters to create such websites that enable Ajax for .NET. The user is also allowed to create such web pages which enable ASMX and WCF by making use of the Ajax library.The ASP.NET 3.5 hosting also includes features like Management, Membership, profiles and authentication etc. there are the first and foremost ASP. NET application tools and services.The other feature included into this hosting solution is the ASP.NET AJAX Control Toolkit. This application utilizes a SDK and use of samples. Its major benefit is to allow the web-hosters to make their website more appealing and visually attractive within no time. This tool enables the user to add in more aesthetic and artistic appeal to their website without facing much problems and difficulties.The web-pages get delivered at a faster rate, the system memory is not put into overload situation, the language neutrality has been introduced, the web-page updates are based on real time updates, the user interface is ultimately richer and extremely responsive, the unnecessary and round trip web server hits have been decreased and lessened.The Ajax support is now included into the ASP. NET 3.5 platform, which allows the users to make use of the following benefits and advantages;The merger tool added to this platform is known as the ASP .NET Merger tool which is one of the new features. This allows the web-hosters to merge the assemblies and files which have been compiled previously. Other improvements and features included are as; improved design, time saver, new data controls, and support for LINQ, integrated AJAX support, IntelliSense for ASP .NET java and Ajax, the LinqDataSource control etc.ASP.NET 1.1 and ASP.NET 2.0 has offered the programmers with a number of features and facilities but ASP.NET 3.5 offers such features and applications which has increased its ratings and popularity as a development platform.Web designing and development has taken a significant and noteworthy step forward by including new controls, ASP. NET Ajax into the runtime, the LINQ data functionalities, support for JavaScript, CSS and othersVisual Studio 2008 and ASP.NET 3.5 together bring enormous latest functionalities around Web designing and development that makes the building standards based, next generation Web-site development easier than ever before.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/asp-net/asp-net-3-5-245.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working with Microsoft Dynamics AX and .NET: Part 2</title>
		<link>http://www.allfreetech.com/microsoft-net/working-with-microsoft-dynamics-ax-and-net-part-2-134.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/working-with-microsoft-dynamics-ax-and-net-part-2-134.html#comments</comments>
		<pubDate>Sun, 24 Jan 2010 08:09:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=134</guid>
		<description><![CDATA[Add a reference to .NET Business Connector In the next example, we create a new project in Visual Studio and add the reference to the project. You can skip this step if you already have a project where you would like to use the .NET Business Connector. Open Visual Studio and create a new project [...]]]></description>
			<content:encoded><![CDATA[<h1>Add a reference to .NET Business Connector</h1>
<p>In the next example, we create a new project in Visual Studio and add the reference to the project. You can skip this step if you already have a project where you would like to use the .NET Business Connector.</p>
<p>Open Visual Studio and create a new project as shown in the next screenshot:</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image05.png" /></p>
<p>When you click on <b>OK</b>, you will have a new C# file called <i>Program.cs</i>. Before we start writing any code in the file, we have to add the .NET Business Connector as a reference.</p>
<p>In the Solution Explorer right-click on the <b>References</b> node and select <b>Add Reference</b>.</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image06.png" /></p>
<p>In the form that opens select <b>Microsoft.Dynamics.BusinessConnectorNet.dll</b> under the Browse tab.</p>
<p>The file is found in the <i>ClientBin</i> catalog of your AX installation. The default path is:</p>
<p><i>C:Program FilesMicrosoft Dynamics Ax50ClientBin</i></p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image07.png" /></p>
<p>Click on <b>OK</b> and note that the reference has now been added under the <b>References</b> node in the <b>Solution Explorer</b>.</p>
<h1>Using the .NET Business Connector in .NET classes</h1>
<p>In the next sections of this article we will look at some examples that show how we can use methods in the .NET Business Connector to call AX methods, insert data into AX tables, and read data from AX tables.</p>
<h2>Calling a static class method in AX</h2>
<p>You now have to go back to AX, open the AOT and find the <b>Global</b> class. Add the following method to the <b>Global</b> class:</p>
<pre style="margin-left: 40px;">static str AxHelloWorld()
{
    return &quot;HelloWorld!&quot;;
}
</pre>
<p>In the Visual Studio project we open the <i>Program.cs</i> file again and enter the following code that will create a connection to AX through the .NET Business Connector. We then call the method we created in the Global class before it prints the result to the console:</p>
<p>
	&nbsp;</p>
<pre style="margin-left: 40px;">using System;
using Microsoft.Dynamics.BusinessConnectorNet;
namespace GetAxInfo1
{
    class Program
    {
        /// &lt;summary&gt;
        /// This class connects to AX throught the
        /// .NET Business Connector and call the static method
        /// AxHelloWorld in the Global class in AX.
        /// The result is sent to the console (command prompt).
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;args&quot;&gt;&lt;/param&gt;
        static void Main(string[] args)
        {
            Axapta ax;
            Object axObject;
            try
            {
                // Create a new Axapta object.
                ax = new Axapta();
                // Logon using the default settings
                // in the AX configuration for the .NET
                // Business Connector
                ax.Logon(null, null, null, null);
                // Call the static method and return the
                // result to the axObject variable
                axObject =
                  ax.CallStaticClassMethod(&quot;Global&quot;, &quot;AxHelloWorld&quot;);
                // Print the result to the console
                Console.WriteLine(&quot;The message from AX is {0}&quot;,
                  axObject.ToString());
                ax.Logoff();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }
    }
}
</pre>
<p>Execute the program by pressing <i>Ctrl + F5</i>. You should now see the following result in the console (command prompt) that opens up:</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image08.png" /></p>
<p>If you get a different result it might be because you haven&#39;t set up the .NET Business Connector correctly. If so, please refer to the installation guide to set it up properly. Also, check the Windows Event Viewer to see if there are any error messages that can lead you in the right direction.</p>
<h2>Insert data into an AX table</h2>
<p>As mentioned earlier in this article, you can use the methods in some of the marshaled classes in the .NET Business Connector to manipulate data. However, it is better to avoid this and instead have AX handle all data selection and manipulation. It would be even better to have your .NET application call a method in AX that does the job and returns the results back to the .NET application again. However, this is not always feasible, for instance, when you would like to insert records from your .NET application to an AX table. The next section will guide you through the steps needed to achieve this.</p>
<p>First, you should create a new project in Visual Studio as we did earlier in this article. In this example, we will call the new project &quot;InsertAxRecord&quot;.</p>
<p>Then you have to add a reference to the .NET Business Connector.</p>
<p>In the <i>Program.cs</i> file (or whatever you call your file), you write something like this:</p>
<pre style="margin-left: 40px;">using System;
using Microsoft.Dynamics.BusinessConnectorNet;
namespace InsertAxRecord
{
    class Program
    {
        static void Main(string[] args)
        {
            Axapta ax;
            AxaptaRecord record;
            try
            {
                // Create AX object and logon to AX
                ax = new Axapta();
                ax.Logon(null, null, null, null);
                // Create a new AxaptaRecord object with
                // the name of the table as input parameter
                using (record = ax.CreateAxaptaRecord(&quot;CarTable&quot;))
                {
                    // Remember to clear the tablebuffer if
                    // you are inserting inside a loop
                    record.Clear();
                    record.InitValue();
                    // Set the fields in the table
                    record.set_Field(&quot;CARID&quot;, &quot;XXX1&quot;);
                    record.set_Field(&quot;MODELYEAR&quot;, 1998);
                    record.set_Field(&quot;CARBRAND&quot;, &quot;FORD&quot;);
                    record.set_Field(&quot;MODEL&quot;, &quot;F1&quot;);
                    record.set_Field(&quot;MILEAGE&quot;, 89378);
                    // Insert the record
                    record.Insert();
                }
                // End the AX session
                ax.Logoff();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}
</pre>
<p>
	&nbsp;</p>
<p>If you open the table browser and look at the contents of <b>CarTable</b> in AX now (find the table in the AOT and pressing <i>Ctrl + O</i> to open the table browser) you should see that the record has been added.</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image09.png" /></p>
<h2>Read data from an AX table</h2>
<p>For our next example we will repeat the procedure from the previous example, except that now we will read data from the table instead of writing to the table.</p>
<p>Start off by creating a new project and add the .NET Business Connector as&nbsp; a reference to the solution.</p>
<p>Enter the following code into the <i>Program.cs</i> file (or whatever you call your program):</p>
<pre style="margin-left: 40px;">using System;
using Microsoft.Dynamics.BusinessConnectorNet;
namespace ReadAxRecord
{
    class Program
    {
        static void Main(string[] args)
        {
            Axapta ax;
            AxaptaRecord record;
            Object carId, carBrand, model, modelYear, mileage;
            try
            {
                // Create AX object and logon to AX
                ax = new Axapta();
                ax.Logon(null, null, null, null);
                // Create an AxaptaRecord object from the
                // table that will be used
                using (record = ax.CreateAxaptaRecord(&quot;CarTable&quot;))
                {
                    // Execute the statement entered as parameter
                    record.ExecuteStmt(&quot;select * from %1
                      where %1.CarBrand like &#39;BMW&#39;&quot;);
                    // Loop through the result of the statement.
                    while (record.Found)
                    {
                        // Set our local variables to be
                        // equal to the fields in the table
                        // for the current record.
                        carId = record.get_Field(&quot;CARID&quot;);
                        carBrand = record.get_Field(&quot;CARBRAND&quot;);
                        model = record.get_Field(&quot;MODEL&quot;);
                        modelYear = record.get_Field(&quot;MODELYEAR&quot;);
                        mileage = record.get_Field(&quot;MILEAGE&quot;);
                        // Write the result to the console
                        Console.WriteLine(carId + &quot;t&quot; +
                                          carBrand + &quot;t&quot; +
                                          model + &quot;t&quot; +
                                          modelYear + &quot;t&quot; +
                                          mileage);
                        // Go to the next record in the result set
                        record.Next();
                    }
                    // End the AX session
                    ax.Logoff();
                    // Make sure the console stays up
                    // until a key is pressed
                    Console.ReadKey();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}
</pre>
<p>Execute the program by pressing <i>Ctrl + F5</i> and take a look at the result. It should look something like this:</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image10.png" /></p>
<h2>Exception classes</h2>
<p>The .NET Business Connector also consists of a number of exceptions that AX can raise. These exceptions are controlled by exception classes that will help you determine further actions if an exception occurs. In the previous example I have only used the standard .NET exception class, but if you would like to write solid code you should consider using the exceptions from the .NET Business Connector instead.</p>
<p>
	&nbsp;</p>
<p>
<style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style>
</p>
<table align="center" border="1" bordercolor="#000000" cellpadding="7" cellspacing="0" style="page-break-before: always;" width="639">
<col width="304" />
<col width="305" />
<tbody>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2"><b>Exception </b></font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2"><b>Description</b></font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AlreadyLoggedOnException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when logon to AX fails because the </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">user is already logged on.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxBufferNotValidException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the AX buffer being referenced is </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">not valid.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxContainerNotValidException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the AX container being </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">referenced is not valid.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxObjectNotValidException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the AX object being referenced is </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">not valid.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxRecordNotValidException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the AX record being referenced </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">is not valid.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">BusinessConnectorException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when an unexpected error has </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">occurred with the Business Connector.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">ConnectionLostException</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">Thrown when the connection to the AOS is lost.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">DebuggerStopException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the AX debugger has been </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">stopped.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">ExecutionErrorException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when an unexpected system exception </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">has occurred.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">FatalErrorLoggedOffException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the AX session is closed due to </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">an error.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">InitializationFailedException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the .NET Business Connector </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">fails to initialize.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">InvalidReturnValueException</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">Thrown when a return value is invalid.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">LogonAsGuestNotSupportedException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when trying to logon as Guest from a </font></font></p>
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">non-web (IIS) scenario, for example, directly </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">through .NET Business Connector.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">LogonFailedException</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">Thrown during an AX logon failure.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">LogonSystemChangedException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when logon to AX fails due to logon </font></font></p>
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">parameters not matching those currently in use </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">for the Business Connector.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">LogonUserLockedOutException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the user attempting a logon is </font></font></p>
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">locked out due to exceeding the maximum </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">number of logon attempts.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">MethodUnknownException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the method being referenced is </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">not known by the system.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">NoIISRightsException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when logon to AX fails because the </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">user has not been granted the proper IIS rights.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">NoSecurityKeyException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when a requested operation fails </font></font></p>
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">because the required security key does not </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">exist.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">NotLoggedOnException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when a requested operation cannot be </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">performed because the user is not logged on.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">PermissionDeniedException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when permission to execute an </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">operation is denied.</font></font></p>
</td>
</tr>
</tbody>
</table>
<p>
	&nbsp;</p>
<table cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td valign="top">
<style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style>
<table align="center" border="1" bordercolor="#000000" cellpadding="7" cellspacing="0" style="page-break-before: always;" width="639">
<col width="304" />
<col width="305" />
<tbody>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">ServerCommunicationErrorException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when communication between the </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">client computer and the server fails.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">ServerOutOfReachException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when communication with the server </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">cannot be established.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">ServerOutOfResourcesException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the server terminates the session </font></font></p>
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">due to the server not having enough free </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">resources.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">ServerUnavailableException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the server is unavailable. AX will </font></font></p>
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">attempt to connect to other servers listed in the </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">client confguration.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">SessionTerminatedException</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">Thrown when the server terminates the session.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">UnknownClassHandleException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the class being referenced does </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">not exist.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">UnknownRecordException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when the record being referenced does </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">not exist.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">UnknownTextException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when an unknown text exception has </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">occurred.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">UnknownXPPClassException</font></font></p>
</td>
<td width="305">
<p style="margin-bottom: 0in;"><font face="Verdana, sans-serif"><font size="2">Thrown when an unknown X++ exception has </font></font></p>
<p><font face="Verdana, sans-serif"><font size="2">occurred.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">XppException</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">Thrown when an X++ exception has occurred.</font></font></p>
</td>
</tr>
</tbody>
</table>
<h1>Summary</h1>
<p>You should now be able to use .NET classes in AX and also use AX code in&nbsp; .NET classes.</p>
<p>When using .NET classes in AX you had to add the reference to the .NET class first and then use the code in the .NET class from X++ code. AX makes this possible by using a bridge to the Common Language Runtime.</p>
<p>When you want to use AX functionality in your .NET classes you first had to add a reference to the .NET Business Connector. Then you had to use the marshalled classes that the .NET Business Connector consists of in your .NET code in order to call class methods, manipulate data or read data from AX.</p>
<p>For more examples on how to use the .NET Business Connector to create cool features in other programs, take a look at the Microsoft Dynamics Snap for AX:<a href="http://www.codeplex.com/axsnap" target="_blank">http://www.codeplex.com/axsnap</a></p>
<p>The Microsoft Dynamics Snap for AX are free applications that exemplifies how Microsoft Office applications like Excel, Word, and Outlook can be used to integrate with AX.</p>
<p>One of the applications is Business Data Lookup. It enables users that work in Word, Excel, and Outlook to lookup information in AX and paste data back to the Microsoft Offce application.</p>
</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/working-with-microsoft-dynamics-ax-and-net-part-2-134.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working with Microsoft Dynamics AX and .NET: Part 1</title>
		<link>http://www.allfreetech.com/microsoft-net/working-with-microsoft-dynamics-ax-and-net-part-1-131.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/working-with-microsoft-dynamics-ax-and-net-part-1-131.html#comments</comments>
		<pubDate>Sun, 24 Jan 2010 08:07:54 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=131</guid>
		<description><![CDATA[This article by Erlend Dalen, explains how you can use .NET classes in AX with the Common Language Runtime and how you can write .NET code that uses AX classes by using the .NET Business Connector for AX. The topics covered in this article are: A brief description of Common Language Runtime (CLR) Adding .NET [...]]]></description>
			<content:encoded><![CDATA[<p>This article by <b>Erlend Dalen</b>, explains how you can use .NET classes in AX with the Common Language Runtime and how you can write .NET code that uses AX classes by using the .NET Business Connector for AX.<span id="more-131"></span></p>
<p>The topics covered in this article are:</p>
<ul>
<li>A brief description of Common Language Runtime (CLR)</li>
<li>Adding .NET references to classes in AX</li>
<li>Using a .NET class in X++</li>
<li>Adding references to the .NET Business Connector</li>
<li>Using the .NET Business Connector in .NET classes</li>
</ul>
<p>When you are done with this article, you should be able to use .NET classes as reference classes in AX through the <b>Common Language Runtime</b> (<b>CLR</b>). The article will also guide you through the process of creating a .NET class in Visual Studio, and how to use it in AX. You will also learn how to use AX logic from external applications by using the .NET Business Connector.</p>
<p style="margin-left: 40px; margin-right: 40px;"><em>All the Visual Studio examples in this article are written in C#.</em></p>
<h1>Common Language Runtime</h1>
<p>You might have done some .NET development before looking into X++ right? Maybe you&#39;re even a .NET expert? If so, you must have heard of CLR before. The CLR is a component of .NET that enables objects written in different languages to communicate with each other. CLR can be used in AX to combine functionality from .NET classes and libraries, including the ones you have yourself created in .NET. However, you cannot consume AX objects in .NET by using the CLR. Instead, you will then have to use the .NET Business Connector.</p>
<p>To learn more about the CLR, check out the following link: <a href="http://msdn.microsoft.com/en-us/library/ddk909ch%28VS.71%29.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/ddk909ch(VS.71).aspx</a></p>
<p>One very useful feature in AX when dealing with integration between AX and .NET is the way AX implicitly converts the most common data types. For the data types listed in the next table you do not need to convert the data manually. For all other data types, you will have to convert them manually.</p>
<p>
<style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style>
</p>
<table align="center" border="1" bordercolor="#000000" cellpadding="7" cellspacing="0" style="page-break-before: always;" width="639">
<col width="304" />
<col width="305" />
<tbody>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2"><b>.NET Common Language Runtime</b></font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2"><b>X++</b></font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.String</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">str</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.Int32</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">int</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.Int64</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">int64</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.Single</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">real</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.Double</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">real</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.Boolean</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">Boolean</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.DateTime</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">date</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">System.Guid</font></font></p>
</td>
<td width="305">
<p><font face="Verdana, sans-serif"><font size="2">guid</font></font></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p style="margin-left: 40px; margin-right: 40px;"><em>Enums are stored as integers in AX and are treated as integers when they are implicitly converted between .NET and AX.</em>&nbsp;&nbsp; &nbsp;</p>
<p>We prove this by executing the next example that shows the conversion between <i>System.String</i> and <i>str</i>. The same can be done for any of the other data types in the above table.</p>
<pre style="margin-left: 40px;"><b> </b>static void ImplicitDataConversion(Args _args)
{
    System.String netString;
    str xppString;
    ;

    // Converting from System.String to str
    netString = &quot;Hello AX!&quot;;
    xppString = netString;
    info(xppString);
    // Converting from str to System.String
    xppString = &quot;Hello .NET!&quot;;
    netString = xppString;
    info(netString);
}
</pre>
<p style="margin-left: 40px; margin-right: 40px;"><em>X++ is case insensitive, except when dealing with CLR. This means that writing <i>System.string</i> in the previous example will result in &nbsp;&nbsp; &nbsp;a compile error, whereas writing <i>Str</i> instead of <i>str</i> will not.</em></p>
<p>The result will look like this:</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image01.png" /></p>
<h1>Adding a reference to a .NET class in AX</h1>
<p>To be able to use .NET classes in AX you have to make sure that the .NET assembly that you would like to use in AX exists under the <b>References</b> node in the AOT. If you can&#39;t find it there, you have to add it by adding a reference to the DLL file that contains the assembly in the AOT under <b>References</b>.</p>
<p style="margin-left: 40px; margin-right: 40px;"><em>When adding a reference node in the AOT you have to make sure that the DLL exists on all client computers. If there is a client computer in which the DLL does not exist, it will result in compile errors when compiling code on that client computer.</em></p>
<h2>Assembly exist in the Global Assembly Cache</h2>
<p>Follow these steps to add a reference that exists in the Global Assembly Cache:</p>
<ol>
<li>If the DLL has been added to the Global Assembly Cache, you can right-click on the <b>Reference</b> node in the AOT and select <b>Add Reference</b>.</li>
<li>In the form that opens (see next screenshot), you should be able to find the desired <i>DLL</i>. Add it by clicking on the <b>Select</b> button.</li>
<li>When you have selected the desired reference, click on the <b>OK</b> button. The assembly has now been added to the AOT, and can be used when writing X++ code.</li>
<p>	&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;</ol>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image02.png" /></p>
<h2>Assembly not in Global Assembly Cache</h2>
<p>If the file does not exist in the Global Assembly Cache follow these steps:</p>
<ol>
<li>Click on the <b>Browse</b> button in the <b>Add Reference</b> form shown above and find the <i>DLL</i> file.</li>
<li>Click on <b>Open</b>. If the <i>DLL</i> is a valid assembly it will be added to the AOT under <b>References</b>.</li>
</ol>
<p>Another option is to add the DLL to the Global Assembly Cache first and select it as described in the previous section, <i>Assembly exist in the Global Assembly Cache</i>.</p>
<h1>Using a .NET class in X++</h1>
<p>After having added a reference to the .NET assembly you want to use in AX, you can start writing the X++ code that will use the assembly.</p>
<p>When referencing the classes in the assembly you will need to write the whole namespace and class name. In my example I&#39;m using an assembly that has been added to the AOT in the SYS layer. The example shows a nice feature that enables AX to send info messages to the Windows Event Log.</p>
<p>This can be particularly useful when you would like to use the Windows Event Log to monitor AX batch Jobs.</p>
<p>First, we add a new static method called <i>writeLogEntry</i> to the Global class:</p>
<div style="margin-left: 40px;">
<pre>static void writeLogEntry(Exception e, str caller, int line, str text)
{
    // Use the standard .NET class EventLog from
    // the System.Diagnostics assembly
    System.Diagnostics.EventLog     eventLog;
    // Also use a .NET enumeration from the
    // System.Diagnostics assembly
    System.Diagnostics.EventLogEntryType    entryType;
    System.Exception    clrException;
    str stack;
    Batch batch;
    str batchInfo;
    ;
    try
    {
        // Create a new object of the EventLog class
        eventLog = new System.Diagnostics.EventLog();
        eventLog.set_Source(&quot;Dynamics AX&quot;);
        // Set the enumeration value based on the Exception
        // type in AX
        switch (e)
        {
            case Exception::Info :
                entryType =
                  System.Diagnostics.EventLogEntryType::Information;
                break;
            case Exception::Warning :
                entryType =
                  System.Diagnostics.EventLogEntryType::Warning;
                break;
            case Exception::Error :
                entryType =
                  System.Diagnostics.EventLogEntryType::Error;
                break;
        }
        // If the current user is running a batch job
        // we can assume that the info message came
        // from the batch job and add additional information
        // to the event log

        while select batch
            where batch.Status == BatchStatus::Executing &amp;&amp;
                  batch.ExecutedBy == curuserid()
        {
            batchInfo += batch.GroupId + &#39;: &#39;+
              classid2name(batch.ClassNumber) + &#39;n&#39;;
        }
        if (batchInfo)
            eventLog.WriteEntry(strfmt(&quot;Batch info from AX: %1 nn
              The message originated from :%2 nat line %3 nn
              Message: %4&quot;, batchInfo, caller, line, text),
              entryType);
        else
            eventLog.WriteEntry(strfmt(&quot;Info from AX: nn
              The message originated from :%1 nat line %2 nn
              Message: %3&quot;, caller, line, text), entryType);
    }
    catch(Exception::CLRError)
    {
        // If not able to write the info to the eventlog
        // print an error in the print window instead.
        print &quot;EventWriter:
          Unable to write entry to the windows eventlog&quot;;
    }
}</pre>
</div>
<p>
	&nbsp;</p>
<p>Then we add a line of code at the end of the <i>add</i> method in the <i>Info</i> class so that the end of the method will look like this:</p>
<pre style="margin-left: 40px;">       writeLogEntry(_exception, conpeek(packedAction,2) ,
          conpeek(packedAction,3), _txt);
        this.addSysInfoAction(_helpUrl, actionClassId, packedAction);
    }
    return super(_exception, (buildprefix?getprefix():&#39;&#39;)+_txt);
}
</pre>
<p>To test the feature, simply create a new Job that prints something to the infolog:</p>
<pre style="margin-left: 40px;">static void TestEventLog(Args _args)
{
    ;
    info(&quot;This is a test&quot;);
}
</pre>
<p>You will now see an infolog message in AX, and if you open the Windows <b>Event Viewer</b> you should see the following message in the list:</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image03.png" /></p>
<p>Double-clicking on the event will bring up information about the origin of the info and the message that was printed to the infolog in AX.</p>
<p style="text-align: center;"><img src="http://www.packtpub.com/files/images/msax-article1-image04.png" /></p>
<p>This example could easily be extended so you can enable or disable the feature for different users and select the level of messages to be sent to the EventLog.</p>
<h1>.NET Business Connector</h1>
<p>If you have external applications that need to integrate directly to AX logic you can easily achieve this by using the .NET Business Connector. A typical scenario can be that you would like your .NET application to execute some code in AX and have the result sent back to the .NET application.</p>
<p style="margin-left: 40px; margin-right: 40px;"><em>The .NET Business Connector requires additional licenses. Make sure that the AX installation in which you want to make use&nbsp; of the .NET Business Connector has the necessary licenses before you start developing the solution.</em></p>
<p>In standard AX, the .NET Business Connector is also used by the Enterprise Portal through the Web Parts in SharePoint so that they can expose AX data and logic directly to the Web. It is also used by the standard <b>Application Integration Framework</b> (<b>AIF</b>).</p>
<p>The way that the .NET Business Connector works is that it offers a set of .NET managed classes that .NET applications use in order to log on to AX and execute methods in AX classes.</p>
<p>Here is a list of the different managed classes that can be used in .NET when you want to integrate to AX through the .NET Business Connector. The list is taken from the Dynamics AX SDK.</p>
<p>
	&nbsp;</p>
<table cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td valign="top">
<style type="text/css">
<!--
@page { margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</style>
<table align="center" border="1" bordercolor="#000000" cellpadding="7" cellspacing="0" style="page-break-before: always;" width="640">
<col width="304" />
<col width="306" />
<tbody>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2"><b>Class name </b></font></font></p>
</td>
<td width="306">
<p><font face="Verdana, sans-serif"><font size="2"><b>Description</b></font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">Axapta</font></font></p>
</td>
<td width="306">
<p><font face="Verdana, sans-serif"><font size="2">The Axapta class contains methods that enable you to connect to AX, create AX objects, and execute transactions.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxaptaBuffer</font></font></p>
</td>
<td width="306">
<p><font face="Verdana, sans-serif"><font size="2">The AxaptaBuffer class contains methods that enable you to add data to, and retrieve data from an AX buffer.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxaptaContainer</font></font></p>
</td>
<td width="306">
<p><font face="Verdana, sans-serif"><font size="2">The AxaptaContainer class contains methods that enable you to read data from, and write data to, AX containers.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxaptaRecord</font></font></p>
</td>
<td width="306">
<p><font face="Verdana, sans-serif"><font size="2">The AxaptaRecord class contains methods that enable you to read, update, insert, and delete AX records. It also enables you to call table methods in AX.</font></font></p>
</td>
</tr>
<tr valign="TOP">
<td width="304">
<p><font face="Verdana, sans-serif"><font size="2">AxaptaObject</font></font></p>
</td>
<td width="306">
<p><font face="Verdana, sans-serif"><font size="2">The AxaptaObject class contains methods that enable you to call class methods in AX.</font></font></p>
</td>
</tr>
</tbody>
</table>
<p>				<a href="http://www.packtpub.com/article/working-with-microsoft-dynamics-ax-and-net-2?utm_source=sb_msax_abr1_1209&amp;utm_medium=content&amp;utm_campaign=santi" target="_blank"><br />
				</a></td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/working-with-microsoft-dynamics-ax-and-net-part-1-131.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Writing Reliable .NET Code</title>
		<link>http://www.allfreetech.com/microsoft-net/writing-reliable-net-code-76.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/writing-reliable-net-code-76.html#comments</comments>
		<pubDate>Sat, 23 Jan 2010 04:10:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/microsoft-net/writing-reliable-net-code-76.html</guid>
		<description><![CDATA[When we talk about something being reliable, we&#39;re referring to it being dependable and predictable. When it comes to software, however, there are other key attributes that must also be present for the code to be considered reliable. Software needs to be resilient, meaning that it will continue to function in the face of internal [...]]]></description>
			<content:encoded><![CDATA[<div class="ArticleNormalPara">When we talk about something being reliable, we&#39;re referring to it being dependable and predictable. When it comes to software, however, there are other key attributes that must also be present for the code to be considered reliable.<span id="more-76"></span></div>
<div class="ArticleNormalPara">Software needs to be resilient, meaning that it will continue to function in the face of internal and external disruptions. It must be recoverable, such that it knows how to restore itself to a previously known, consistent state. The software needs to be predictable, so it will provide timely and expected service. It must be undisruptable, meaning that changes and upgrades won&#39;t affect its service. And, finally, the software must be production-ready, meaning that it contains a minimal number of bugs and will require only a limited number of updates. When these criteria are met, then the software can be considered truly reliable.</div>
<div class="ArticleNormalPara">These key attributes of reliable code depend on various factors&mdash;some depend on the overall architecture of the software, some depend upon the OS on which the software will run, and others depend on the tools used to develop the application and the framework on which it is built. Resilience is an attribute that relies on every layer, and an application will only be as resilient as its weakest link.</div>
<div class="ArticleNormalPara">Now consider Microsoft<span class="superscript">&reg;</span> .NET Framework-based applications. These apps delegate to the runtime certain operations that in a native environment either did not exist (such as just-in-time compilation of IL code) or were under the direct control of the developer (such as memory management). In terms of reliability, the platform itself can introduce its own points of failure that impact the reliability of the applications that run on top of it. It&#39;s important to understand where these breakdowns can occur and what techniques you can use to create more reliable .NET-based apps.</div>
<p><strong><br />
	</strong></p>
<div class="ArticleTypeTitle" id="S1"><strong>A Look at Runtime Failure</strong></div>
<div class="ArticleNormalPara">There are certain exceptional events that can occur at any time and in any code section. These events, which we will call asynchronous exceptions, are resource exhaustions (out of memory and stack overflows), thread aborts, and access violations. (In the execution of managed code, access violations occur in the runtime.)</div>
<div class="ArticleNormalPara">This last case is not very interesting&mdash;if this event does actually occur, it means that a serious bug in the implementation of the common language runtime (CLR) is being exposed and should be fixed. The first two cases, however, deserve deeper analysis.</div>
<div class="ArticleNormalPara">In theory, we would imagine that resource exhaustions would be gracefully managed by the runtime and that they would never affect the ability of application code to continue running. That&#39;s just theory, though&mdash;reality is more complex.</div>
<div class="ArticleNormalPara">To explain, we&#39;ll start by taking a look at how some popular server applications deal with out-of-memory (OOM) events. Server applications, such as ASP.NET and Exchange Server 2007, that require very high availability have achieved this through AppDomain and process recycling. The operating system provides a very powerful mechanism to clean up memory and most other resources used by a process&mdash;all this is done for you when the process terminates.</div>
<div class="ArticleNormalPara">In a client scenario, when memory pressure gets to the point that even small allocations fail, the overall system reaches such a level of unresponsiveness due to extensive thrashing and paging that the user is much more likely to reach for the reset button or the task manager than to allow any recovery code to run. In a sense, the user&#39;s initial reaction is to perform the same action manually that ASP.NET or Exchange 2007 will do automatically.</div>
<div class="ArticleNormalPara">Some OOMs may not even be caused by any particular issue with the running code. Another process running on the machine or another AppDomain running in the process may be hogging the available resource pool and causing allocations to fail. In this sense, you should consider resource exhaustions to be asynchronous in that they can occur at any time in the execution of code and they may depend on environmental factors external to and independent from the running code.</div>
<div class="ArticleNormalPara">This problem is exacerbated by the fact that the runtime may allocate memory to perform operations related to its own workings. Here are a few examples of allocations that happen in the runtime that could fail in a constrained resource environment:</div>
<div class="ArticleNormalPara">
<ul>
<li>boxing and unboxing</li>
<li>delayed class loading until the first use of the class</li>
<li>remoted operations on MarshalByRef objects</li>
<li>certain operations on strings</li>
<li>security checks</li>
<li>JITing methods</li>
</ul>
</div>
<div class="ArticleNormalPara">This is just a partial list of the many internal operations in the runtime that may need to allocate resources, but it should give you an idea of why it is not really practical to predict and mitigate the consequences of any specific allocation failure.</div>
<div class="ArticleNormalPara">In the family of the asynchronous exceptions, thread aborts have a special role. Thread aborts are not errors due to resource exhaustions (like OOMs and SOs), but they too can happen at any time. If you abort a thread from a different thread, the point on the aborted thread where the exception will be raised is completely random.</div>
<div class="ArticleNormalPara">Stack overflows also have their own idiosyncrasies. Stack space is reserved per thread and committed eagerly, so it should always be possible to avoid any competition for the resource. But there are problems with this. It is a guessing game to predict how much stack is enough for every application. The OS limits the amount of stack space per thread. There are issues with presenting an exception via Structured Exception Handling (SEH) when the thread is low on stack space due to unwinding issues. And reentrancy and recursion rule out computing a finite upper bound on the stack space required by a method.</div>
<div class="ArticleNormalPara">In a nutshell: it is practically impossible to forecast when OutOfMemoryException, StackOverflowException, and ThreadAbortException might occur. Thus, writing backout code to attempt to recover from asynchronous exceptions is not practical on a large scale.</div>
<div class="ArticleNormalPara">You may be wondering whose responsibility it is to make the application reliable if the runtime cannot guarantee resilience to asynchronous exceptions. The ASP.NET example we just discussed hinted at the answer. While the application code is responsible for handling the common synchronous exceptions, it cannot handle asynchronous ones; this must be handled by the host process. In the case of ASP.NET, this is where the logic is contained that triggers process recycling when memory consumption goes beyond a known threshold.</div>
<div class="ArticleNormalPara">In other more sophisticated cases, hosts like SQL Server<span class="superscript">TM</span> 2005 utilize the CLR&#39;s hosting APIs to decide whether to abort the managed thread running a transaction and roll it back, unload an AppDomain, or even suspend the execution of all managed code on the server. The default policy for an application is that the host process will be killed, but there are several techniques you can use to embrace and extend this approach or to override this behavior. For further reading on the CLR&#39;s hosting APIs, see the August 2006 CLR Inside Out column (<a href="http://msdn.microsoft.com/msdnmag/issues/06/08/CLRInsideOut">msdn.microsoft.com/msdnmag/issues/06/08/CLRInsideOut</a>).</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S2"><strong>Dealing with Failure</strong></div>
<div class="ArticleNormalPara">By now, you&#39;ve probably identified the key to solving this problem. A resilient application is one that isolates the work in units that can independently fail without affecting the other units. So far, three models have been proven successful at creating resilient, managed applications.</div>
<div class="ArticleNormalPara">The first model is to make the process itself the unit of failure and isolate the managed code execution in one or more worker processes that can die and spawn liberally.</div>
<div class="ArticleNormalPara">The second is to keep two redundant processes working in parallel doing the processing, with one active and the other dormant. On failure, the dormant process takes over and spawns another dormant process to act as a backup in case of another failure.</div>
<div class="ArticleNormalPara">The third model is to make the AppDomain the unit of failure and ensure that the process is never affected by any failure occurring in managed code or in the runtime.</div>
<div class="ArticleNormalPara">We&#39;ll look at these three approaches in more depth, analyzing the cost of implementation and the different ways that there are to approach the design.</div>
<p><strong><br />
	</strong></p>
<div class="ArticleTypeTitle" id="S3"><strong>Recycling the Host Process</strong></div>
<div class="ArticleNormalPara">Say we accept the fact that resource exhaustion could tear down the process hosting the CLR. And say the system is built in such a way that the work is isolated in one or more child processes supervised by a master process whose job it is to manage the lifetime of the worker processes. Under these circumstances, we have a cheap and effective solution with which to provide a reliable system. The system will not be resilient, but it will be fully recoverable and predictable in its behavior.</div>
<div class="ArticleNormalPara">This approach is ideal for whenever you are handling a large number of independent stateless requests, such as Web requests in ASP.NET, and you want to isolate the execution of their processing. If an asynchronous exception is raised, a worker process dies and the requests being worked on will simply not be serviced&mdash;they need to be resubmitted. This, however, makes the approach ill-suited for long and expensive operations in which the cost of resubmitting the job may be too high.</div>
<div class="ArticleNormalPara">Still, this is the cheapest way to provide a reliable service running managed code. You are effectively making use of the runtime&#39;s default behavior.</div>
<p><strong><br />
	</strong></p>
<div class="ArticleTypeTitle" id="S4"><strong>Mirrored Processes</strong></div>
<div class="ArticleNormalPara">IT shops make extensive use of redundancy for everything from local disk drives to entire servers. If a disk or server fails, a second one that is in sync with the first quickly takes over.</div>
<div class="ArticleNormalPara">A similar approach can be taken with a process. You can design software that runs two copies of a process on the same machine, each receiving the same input and producing the same output. Under circumstances where the main process fails due to a temporary fault in that specific process (as opposed to a reproducible bug that will affect all instances of the process), this model will provide some resiliency. You should also use a transacted store in this scenario to ensure that any failed requests can be safely rolled back.</div>
<div class="ArticleNormalPara">The National Aeronautics and Space Administration (NASA) uses a model like this for the computers on the space shuttle. When life-and-death operations depend on a computer, some degree of redundancy is a must.</div>
<div class="ArticleNormalPara">NASA actually ran into a problem when using just two computers in this scenario: a situation occurred where the two computers disagreed on the result of a computation. Which one was right? With only two computers, you can&#39;t know which is correct in the event of a single unit failure. So, NASA added a third machine, and if two computers agree but the third returns a different result, the third is considered to be broken.</div>
<div class="ArticleNormalPara">This level of redundancy is nice&mdash;unless one of your three boxes fails, because then you&#39;re back in the scenario where only two are available and you don&#39;t know which is correct in the event of a second failure. So NASA added a fourth, then talked itself into adding a fifth. Clearly, resolving non-crashing failures in a pair of mirrored processes is not simple.</div>
<div class="ArticleNormalPara">Another problem with this approach is that if you run multiple processes on the same machine and one of them exhausts a system-level resource, there&#39;s a reasonable chance that the other process will need the same resource simultaneously. And this may cause the reserve process to fail in the same manner as the first. In fact, they may even both be competing with one another for the same resource.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S5"><strong>Recycling a Portion of the Process</strong></div>
<div class="ArticleNormalPara">For a high level of resiliency, tearing down a process and restarting it or failing over to another process just won&#39;t do. What you really need to do is find the part of the application that failed and recycle that part. This requires isolating various parts of your application&#39;s process into recyclable chunks. Operations must either be stateless or they must use a transactional system to ensure that no writes occur or that they get backed out. Additionally, all resource usage must be freed when you recycle a part of the process.</div>
<div class="ArticleNormalPara">When thinking about long-living servers, think about state corruption and lack of consistency. Consistency can apply to several different layers. While a simple linked list might be consistent, a complex data structure will require additional invariants. If a consumer has an invariant that all elements in a linked list also must be stored as values in a hash table, then consistency in the linked list doesn&#39;t mean the application is consistent. For this reason, you must treat the slightest possibility of corruption that breaks invariants to be a problem. If an asynchronous exception occurs, how much of the state may potentially be corrupted and how can a server be resilient to this corruption?</div>
<div class="ArticleNormalPara">To carve an application into recyclable chunks, you must isolate operations from one another. When an asynchronous exception occurs, it may have caused state corruption. To avoid recycling the entire process, you need to have encapsulated a smaller portion of your process, including the set of failed operations and all relevant state information.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S6"><strong>What Is an AppDomain?</strong></div>
<div class="ArticleNormalPara">An application domain, or AppDomain for short, is a sub-process unit of isolation for managed code. Most assemblies can be loaded into an AppDomain. When the AppDomain is unloaded, the assemblies can often be unloaded as well.</div>
<div class="ArticleNormalPara">Each AppDomain gets its own copy of static variables. While threads can cross AppDomain boundaries, it is (almost) impossible to initiate communication across an AppDomain boundary without using .NET remoting or a similar technique. AppDomains give you a relatively firm boundary to contain code.</div>
<div class="ArticleNormalPara">If an asynchronous exception occurs on a thread, you must decide how much corruption might be present and how to be resilient to that specific level of corruption.</div>
<p><strong><br />
	</strong></p>
<div class="ArticleTypeTitle" id="S7"><strong>State Corruption</strong></div>
<div class="ArticleNormalPara">There are three buckets that state corruption may fall into. The first is local state, which includes local variables and heap objects that are only used by a particular thread. The second is shared state, which includes anything shared across threads within the AppDomain, such as objects stored in static variables. Caches often fall into this category. The third is process-wide, machine-wide, and cross-machine shared state&mdash;files, sockets, shared memory, and distributed lock managers fall into this camp.</div>
<div class="ArticleNormalPara">The amount of state that can be corrupted by an async exception is the maximum amount of state a thread is currently modifying. If a thread allocates a few temporary objects and doesn&#39;t expose them to other threads, only those temporary objects can be corrupted. But if a thread is writing to shared state, that shared resource may be corrupted, and other threads may potentially encounter this corrupted state. You must not let that happen. In this case, you abort all the other threads in the AppDomain and then unload the AppDomain. In this way, an asynchronous exception escalates to an AppDomain, causing it to unload and ensuring that any potentially corrupted state is thrown away. Given a transacted store like a database, this AppDomain recycling provides resiliency to corruption of local and shared state.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S8"><strong>Detecting Shared State</strong></div>
<div class="ArticleNormalPara">Figuring out whether a thread is modifying shared state is not the easiest problem. It&#39;s not obvious in most code whether the value of a local variable on the stack was initialized locally, whether it was passed in as a parameter to the method, or whether it simply refers to an object that is stored in a static variable (or is reachable from a static variable).</div>
<div class="ArticleNormalPara">A subtle demand about modifying shared state comes from the concurrency space: whenever you edit a static variable, your code almost inevitably holds a lock. So keeping a lock count on each thread informs our escalation policy as to whether a thread may potentially be editing shared state. It&#39;s true that locks are often taken while reading from shared state and no state corruption occurs while reading from shared state (assuming there is no lazy initialization), but this pessimistic heuristic is the tightest we have found, without requiring an unacceptable additional level of discipline from users.</div>
<div class="ArticleNormalPara">You can safely use interlocked operations, as they are only safe for editing one piece of shared state atomically. And knowing whether they succeed is easy&mdash;they either do or they do not.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S9"><strong>Escalation Policy</strong></div>
<div class="ArticleNormalPara">The CLR&#39;s escalation policy goes a bit further. We&#39;d like to attempt to give user code a chance to clean up when aborting threads. So the CLR attempts to run finally blocks and finalizers when aborting threads and before the AppDomain is unloaded. But there is tension caused by the user&#39;s desire to run arbitrary cleanup code and the host&#39;s availability needs. You can impose some timeout on running finally blocks and finalizers and simply abort them if they do not finish within a reasonable time.</div>
<div class="ArticleNormalPara">A harder question, though, is how to be resilient if an asynchronous exception occurs while accessing a process-wide, machine-wide, or cross-machine piece of state. We&#39;ll discuss this in more detail later.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S10"><strong>Resiliency to Escalation</strong></div>
<div class="ArticleNormalPara">Escalation policy also imposes limits on code, both when written by users and library authors. For SQL Server, the CLR allows stored procedures to be written in managed code, with some very high restrictions on what it can express. For scalability, reliability, and security concerns, user code in SQL Server should not launch or terminate threads, it should minimize or completely avoid shared state, and it should not be allowed to access certain types of OS resources. However, trusted libraries such as the .NET Framework must access these resources, often on behalf of this relatively untrusted user code.</div>
<div class="ArticleNormalPara">The CLR provides code access security as a first line of defense to tweak the set of permissions given to user code. However, the CLR does not include permissions for all interesting resource types. For this purpose, the CLR defines the HostProtectionAttribute attribute, which can be used to mark methods that raise programming model concerns, such as by having the ability to kill threads.</div>
<div class="ArticleNormalPara">These limitations on user code are actually a very good thing because by restricting user code from accessing OS resources directly (along with other limitations), user code is freed from the responsibility of tracking its use of these resources.</div>
<div class="ArticleNormalPara">In the process recycling world, whenever a process is killed, the OS frees all of the machine-wide resources used by the process. For AppDomain recycling to truly provide resiliency, AppDomain unloading must provide the same level of guarantees. Since an AppDomain is just a unit within the process, managed libraries that provide access to resources must fill the gap between the operating system&#39;s ability to clean up on process exit and the demands of AppDomain unloading.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S11"><strong>Writing Reliable Code</strong></div>
<div class="ArticleNormalPara">AppDomain unloading must be clean. This is the guiding principle for writing libraries resilient to async exceptions. For a transacted host like SQL Server that guarantees its own consistency, all other concerns about user and library code (like correctness, performance, and maintainability) are secondary to the host&#39;s ability to guarantee its availability. If user code has a bug that occasionally causes a crash, the server will live on as long as it can make forward progress and doesn&#39;t degrade over time.</div>
<div class="ArticleNormalPara">Clean AppDomain unloading and careful resource management allow your code to fight against the CLR&#39;s escalation policy, enabling you to identify code that must have an opportunity to run to ensure consistency of a resource or to ensure that no resources are leaked. In most cases, an asynchronous exception will have already happened or will be unpreventable&mdash;these are the tools your code will need to become resilient to failure. The most important advice for library writers is to use SafeHandle, and it&#39;s critical that you understand several other available features so you can fully grasp why to use SafeHandle.</div>
<p><strong><br />
	</strong></p>
<div class="ArticleTypeTitle" id="S12"><strong>Choosing a Reliability Bar</strong></div>
<div class="ArticleNormalPara">Not all code is equally critical. You should think about what level of reliability is required from a certain block of code. The techniques we describe can increase development costs, so a good engineer should determine how much resiliency is necessary for a block of code.</div>
<div class="ArticleNormalPara">First, ask yourself what your code should do when a power failure occurs. As a starting point, all code obviously must be able to restart and work correctly after a power failure. Even if client applications will lose work and encounter data corruption, they still must, at a bare minimum, be able to start back up.</div>
<div class="ArticleNormalPara">Designing mail servers to ensure they don&#39;t lose e-mail when a power failure occurs is a significantly harder problem. Similarly, software controlling a nuclear power plant must be able to tolerate such failures with greater resilience than, say, a basic productivity app. Figuring out where your application falls on this continuum should be trivial, and it will help inform your decisions on how much to invest in resiliency.</div>
<div class="ArticleNormalPara">For most client applications, the surprising answer is to do very little. Surviving an async exception is overkill for most client apps. Killing the process and restarting is often sufficient. And when using the Windows Vista<span class="superscript">&reg;</span> Restart Manager APIs, this approach can help limit how much state is lost when the client app crashes. Outlook<span class="superscript">&reg;</span> offers a great example. If Outlook 2007 crashes on Windows Vista, it can recover and reopen all windows to the right spot. If you were composing a message when Outlook crashed, you might lose only the last minute or two of typing, rather than the entire message.</div>
<div class="ArticleNormalPara">For libraries, the reliability bar is determined by the most aggressive host in which your code will run. If your library is used by hosts that recycle processes, your reliability needs are less than for a host that recycles AppDomains. However, if your library allows accesses to resources without using some of the techniques we describe, and your code is used in a host that recycles AppDomains, your library can eventually cause that host to fail.</div>
<p><strong><br />
	</strong></p>
<div class="ArticleTypeTitle" id="S13"><strong>Clean Up Code</strong></div>
<div class="ArticleNormalPara">You should use try/finally blocks and finalizers to clean up resources. As a first approximation, these tools give developers a simple way to restore state to a reasonable level of consistency. Try/finally blocks (and language-specific keywords like the C# &quot;using&quot; statement) will improve correctness and performance by ensuring that resources are cleaned up or disposed of at deterministic points in your code.</div>
<div class="ArticleNormalPara">The problem with this approach, though, is that the CLR cannot easily guarantee that the code in your finally block will complete. While the CLR attempts to avoid aborting threads while running in finally blocks, resource exhaustion and thus async exceptions can occur at any time.</div>
<div class="ArticleNormalPara">Likewise, we have no way of ensuring that any given finalizer will complete. Additionally, the CLR&#39;s escalation policy allows a host to abort threads in finally blocks and finalizers in case a finally block goes into an infinite loop or blocks indefinitely.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S14"><strong>Constrained Execution Regions</strong></div>
<div class="ArticleNormalPara">A constrained execution region, or CER, is a reliability primitive that helps enable code to maintain consistency. This is best for when you are willing to work extremely hard to guarantee some limited amount of forward progress or ability to undo changes to an object. Constrained execution regions are a best-effort attempt from the runtime to run your code. With CERs, the runtime will hoist any CLR-induced failures to predictable locations. This doesn&#39;t guarantee that your code will run&mdash;you can&#39;t sprinkle CERs like fairy dust and expect your code to magically work&mdash;but if you&#39;re writing code with some rigid constraints, there is a good chance your code will run to completion.</div>
<div class="ArticleNormalPara">CERs are exposed in three forms:</div>
<div class="ArticleNormalPara">
<ul>
<li>With ExecuteCodeWithGuaranteedCleanup, which is a stack-overflow safe form of a try/finally.</li>
<li>As a try/finally block preceded immediately by a call to RuntimeHelpers.PrepareConstrainedRegions. In this case, the try block isn&#39;t constrained, but all catch, finally, and fault blocks for that try are constrained.</li>
<li>As a critical finalizer. Here, any subclass of CriticalFinalizerObject has a finalizer that is eagerly prepared before an instance of the object is allocated.</li>
</ul>
</div>
<div class="ArticleNormalPara">(Note that there is a special case: SafeHandle&#39;s ReleaseHandle method, a virtual method that is eagerly prepared before the subclass is allocated and called from SafeHandle&#39;s critical finalizer.)</div>
<div class="ArticleNormalPara">To give your code an opportunity to execute, the CLR will eagerly prepare your code, meaning it will JIT the statically discoverable call graph for your method. If you use delegates within a CER, the target method of the delegate must be eagerly prepared, preferably by calling RuntimeHelpers.PrepareMethod() on the method. Additionally, if you use ngen, you can mark the method with the PrePrepareMethodAttribute to eliminate some need to pull in the JIT. This eager preparation will eliminate CLR-induced out-of-memory exceptions.</div>
<div class="ArticleNormalPara">With regard to thread aborts, the CLR will disable these over CERs. The CLR will also probe for some stack, if and only if the CLR&#39;s host (for example, any native app that uses the CLR&#39;s COM hosting interfaces to launch the CLR) wants to survive stack overflow. Barring bugs in the runtime itself, heap corruption, and hardware problems, this should eliminate all CLR-induced asynchronous exceptions caused by your code.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S15"><strong>Reliability Contracts</strong></div>
<div class="ArticleNormalPara">You may have noticed that I keep drawing a line between CLR-induced failures and all other failures. Failures can occur at all levels of the system since each layer of the system has a different view of consistency. Consider an application that wants to maintain a list of items in sorted order. If you use an unsorted collection like List&lt;T&gt;, your code may look like this:</div>
<div class="ArticleNormalPara">
<div class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl03_">
<div class="CodeSnippetTitleBar">
<div class="CodeDisplayLanguage">&nbsp;</div>
</p></div>
<div dir="ltr" style="background-color: rgb(221, 221, 221);">
<pre class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl03_code" space="preserve" style="white-space: pre-wrap;"><span id="ctl00_MTContentSelector1_mainContentContainer_ctl03" xmlns:msxsl="urn:schemas-microsoft-com:xslt">public static void InsertItem&lt;T&gt;(List&lt;T&gt; list, T item)
{
    // List&lt;T&gt; isn&#39;t sorted, but the app relies on it being sorted.
    list.Add(item);
    list.Sort();
}
</span></pre>
</div></div>
</div>
<div class="ArticleNormalPara">Now imagine that all the methods on List&lt;T&gt; magically succeeded all the time. We&#39;ll use the hypothetical ReliableList&lt;T&gt; to imply this behavior. Imagine that Add never needs to grow the size of the list and the Sort routine always works (even with its indirect calls into comparers and CompareTo methods on the generic type T). If a ThreadAbortException occurs in InsertItem after the call to Add completed but before the call to Sort, we still run into a consistency problem.</div>
<div class="ArticleNormalPara">From the perspective of ReliableList&lt;T&gt;, the list is fully consistent. The internal data structures in the list are in a perfectly fine state in that there is no extra item half-added to the collection. And we can continue to use the list without any problems. But, from the perspective of the application (remember that it required the list to be sorted), this invariant has been broken and the method hasn&#39;t been written to recover from this problem.</div>
<div class="ArticleNormalPara">This scenario illustrates that consistency exists at various levels in the system. This is indicated to users via reliability contracts&mdash;a very coarse-grained mechanism for stating the extent of corruption if an asynchronous exception occurs. In this case, the method corrupted the list, and if we admit the possibility of an OutOfMemoryException during the Add method call, then we have to mark this method as potentially failing, like this:</div>
<div class="ArticleNormalPara">
<div class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl04_">
<div class="CodeSnippetTitleBar">
<div class="CodeDisplayLanguage">&nbsp;</div>
</p></div>
<div dir="ltr" style="background-color: rgb(221, 221, 221);">
<pre class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl04_code" space="preserve" style="white-space: pre-wrap;"><span id="ctl00_MTContentSelector1_mainContentContainer_ctl04" xmlns:msxsl="urn:schemas-microsoft-com:xslt">[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static void InsertItem&lt;T&gt;(ReliableList&lt;T&gt; list, T item)
</span></pre>
</div></div>
</div>
<div class="ArticleNormalPara">Reliability contracts, which are required on all code called within CERs, serve primarily as documentation to the developer about whether to expect the possibility of a failure. Here, reliability contracts could do a better job of indicating corruption of parameters versus a &quot;this&quot; pointer, but these are really meant to start a reliability discussion between the author of the InsertItem method and the person calling it. In this case, someone calling InsertItem&lt;T&gt; will notice that it may cause corruption of an instance if it fails, so they will know that they need a mitigation strategy.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S16"><strong>Mitigating Failures the Hard Way</strong></div>
<div class="ArticleNormalPara">Constrained execution regions offer some ways to mitigate failures in code like InsertItem. The options vary in complexity and some techniques may not work well if the code changes significantly from one version to another.</div>
<div class="ArticleNormalPara">The most obvious technique is to try to understand the failure and avoid it. In this sample, it may be possible to hoist allocations to a place where you can recover from the failure, such as allocating the list with sufficient capacity to begin with. This would hoist any allocation failures. However, this requires that you understand InsertItem&lt;T&gt;, List&lt;T&gt;, and how they both fail.</div>
<div class="ArticleNormalPara">Additionally, this technique doesn&#39;t solve the thread abort problem. The list may still not be sorted. Here, a CER could be used to ensure that the finally block is sorted all the time. Regardless of whether Add fails or not, we ensure consistency of the list by guaranteeing that it is sorted. This requires a strong reliability guarantee on our fictitious ReliableList&lt;T&gt;&#39;s Sort method. But with that in place, we could write our code as shown in <strong>Figure 1</strong>, offering a stronger consistency guarantee in InsertItem&#39;s reliability contract.</div>
<div class="MTPS_CollapsibleRegion">
<div class="CollapseRegionLink"><!-- ApplyClick with current id --><span><img class="LibC_o" src="http://i.msdn.microsoft.com/Global/Images/clear.gif" style="border-width: 0px; vertical-align: middle;" /> &nbsp;Figure&nbsp;1&nbsp;A Stronger Consistency Guarantee </span></div>
<div class="MTPS_CollapsibleSection" style="display: block;">
<div class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl12_ctl00_ctl00_">
<div class="CodeSnippetTitleBar">
<div class="CodeDisplayLanguage">&nbsp;</div>
</p></div>
<div dir="ltr" style="background-color: rgb(221, 221, 221);">
<pre class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl12_ctl00_ctl00_code" space="preserve" style="white-space: pre-wrap;"><span><span id="ctl00_MTContentSelector1_mainContentContainer_ctl12_ctl00_ctl00" xmlns:msxsl="urn:schemas-microsoft-com:xslt">[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 public static void InsertItem&lt;T&gt;(ReliableList&lt;T&gt; list, T item)
 {
     RuntimeHelpers.PrepareConstrainedRegions();  // CER marker
     try
     {
         // Add can fail with an OutOfMemoryException.
         // That&#39;s fine, since the list didn&#39;t change.
         list.Add(item);
         // Consider a failure here, perhaps from calling a second method.
     }
     finally
     {
         // Restore consistency by guaranteeing the list is sorted.
         list.Sort();
     }
 }

</span></span></pre>
</div></div>
</p></div>
</div>
<div class="ArticleNormalPara">Keep in mind that these techniques don&#39;t work in a real-world implementation of this example since ReliableList&lt;T&gt; doesn&#39;t really exist. It would be particularly difficult to write due to the nature of sort algorithms&mdash;you need any comparer used by Sort and most likely T&#39;s CompareTo method to also be reliable.</div>
<div class="ArticleNormalPara">But there&#39;s another technique similar to the recycling model. If you can live with the performance hit, you can copy the data, make your changes on your copy, and then expose your consistent data structure to the world. Here&#39;s one way to do this, complete with compromises to the method signature:</div>
<div class="ArticleNormalPara">
<div class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl07_">
<div class="CodeSnippetTitleBar">
<div class="CodeDisplayLanguage">&nbsp;</div>
</p></div>
<div dir="ltr" style="background-color: rgb(221, 221, 221);">
<pre class="libCScode" id="ctl00_MTContentSelector1_mainContentContainer_ctl07_code" space="preserve" style="white-space: pre-wrap;"><span id="ctl00_MTContentSelector1_mainContentContainer_ctl07" xmlns:msxsl="urn:schemas-microsoft-com:xslt">[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static void InsertItem&lt;T&gt;(ref List&lt;T&gt; list, T item)
{
    // Forward progress
    List&lt;T&gt; copy = new List&lt;T&gt;(list);  // expensive copy operation
    copy.Add();
    copy.Sort();

    // Expose the results
    list = copy;
}
</span></pre>
</div></div>
</div>
<div class="ArticleNormalPara">Here, we can use the real List&lt;T&gt;, but be sure to note that we take a significant performance hit by copying the data. Additionally, using a ref parameter here isn&#39;t really a preferable solution. However, a strong reliability contract saying &quot;will not corrupt state&quot; is often highly desirable.</div>
<div class="ArticleNormalPara">Another technique is to try to make forward progress and provide backout code in case of a failure. This is similar to constructing a transaction around your changes and providing code to roll back the changes made in the transaction.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S17"><strong>When to Use a Strong Reliability Contract</strong></div>
<div class="ArticleNormalPara">The previous examples show that a strong reliability contract is difficult to implement efficiently. Using CERs is like rocket science, since you need to be prepared for failures that can occur anywhere. Note that for CERs exposed as an annotated try/finally block, the try block is not a CER, so even multiple assignment operations may be interrupted by an async exception. For this reason, CERs are not for most people&mdash;better choices are to rely on a host&#39;s escalation policy, or for client applications, recycling the entire application.</div>
<div class="ArticleNormalPara">That said, CERs are truly required in places that manipulate machine or process-wide state, such as a shared memory segment. And in these cases, business needs often require that these applications are written to recover from power failures anywhere in the code, so you not only have to write CERs, but you also have to be very careful about consistency throughout significant parts of the application. This complexity is why you don&#39;t want your summer intern writing control software for a nuclear power plant.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S18"><strong>SafeHandle</strong></div>
<div class="ArticleNormalPara">You might be wondering whether you can safely return values from a method in the presence of asynchronous exceptions. You cannot safely do this! When you call an unhardened P/Invoke method like CreateFile that returns an IntPtr and then assign the return value to a local variable, two distinct machine instructions are generated, and threads can be aborted between any two machine instructions. In situations like this, using IntPtr to represent OS handles is fundamentally unreliable. But there is a solution.</div>
<div class="ArticleNormalPara">When you access an OS resource, such as a file, socket, or event, you get a handle for that resource, and that resource must eventually be freed. SafeHandle ensures that if you can allocate a resource, you can free that resource. To provide this guarantee, SafeHandle aggregates multiple CLR features.</div>
<div class="ArticleNormalPara">You define a subclass of SafeHandle and provide an implementation of the ReleaseHandle method. This method is a CER, called from SafeHandle&#39;s critical finalizer. Assuming that your ReleaseHandle method obeys all the CER rules, you are guaranteed that if you can successfully allocate an instance of a native resource, your ReleaseHandle method will get a chance to run.</div>
<div class="ArticleNormalPara">SafeHandle also offers some key security features. It prevents handle recycling attacks by ensuring that no thread can free a handle while another thread is actively using it. It also prevents a subtle race condition between a class using a handle and its own finalizer. SafeHandle is also integrated with the P/Invoke marshaling layer. For any method that returns or consumes a handle, you can replace that handle with a subclass of SafeHandle. CreateFile for example, would return a SafeFileHandle, and WriteFile would take a SafeFileHandle as its first parameter.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S19"><strong>Using Locks</strong></div>
<div class="ArticleNormalPara">Locks must be taken on the right types of objects. Consider the C# lock keyword, which expands into calling Monitor.Enter(Object), followed in a finally block by Monitor.Exit(Object). Locks should have a strong sense of identity&mdash;unboxed value types do not fit the bill, as they would get boxed each time you pass them as an Object. But the CLR also shares certain types across AppDomain boundaries in certain cases. Taking locks on Strings, Type objects, CultureInfo instances, and byte[]&#39;s may end up taking a lock across AppDomain boundaries. Similarly, taking locks on any subclass of a MarshalByRefObject from outside of that class&#39;s implementation may lock on a transparent proxy instead of the real object in the correct appdomain, meaning you might not take the right lock! In na&iuml;vely written code, if an async exception occurs, the finally block to release the lock will not run and you may cause other threads to block indefinitely.</div>
<div class="ArticleNormalPara">Do not define your own locks unless you are a true expert when it comes to memory models and concurrency and you have demonstrated a need for a better lock. Beyond the obvious pitfalls like alertable waits and how to spin on hyper-threaded CPUs, your lock must also cooperate with the CLR&#39;s escalation policy, which needs to keep track of whether each thread is holding a lock. Thread.BeginCriticalRegion and EndCriticalRegion can help the CLR identify when third-party locks are acquired and released.</div>
<p>&nbsp;</p>
<div class="ArticleTypeTitle" id="S20"><strong>Hard and Soft OOM Conditions</strong></div>
<div class="ArticleNormalPara">There is another mitigation technique besides AppDomain unloading for out-of-memory errors. The MemoryFailPoint class will attempt to predict whether a memory allocation will fail. You allocate a MemoryFailPoint for X megabytes of memory, where X is an upper bound on the expected additional working set for processing one request. You then process the request and call Dispose on the MemoryFailPoint.</div>
<div class="ArticleNormalPara">If there is not enough memory available, the constructor throws an InsufficientMemoryException, which is a different exception type used to express the concept of a soft OOM. Apps can use this to throttle their own performance based on available memory. The exception is thrown before memory is actually allocated, when no corruption has occurred yet. Thus, this implies that there is no corruption of shared state and therefore there is no need for an escalation policy to kick in.</div>
<div class="ArticleNormalPara">MemoryFailPoint does not reserve memory in the sense of reserving or committing physical pages of memory, so this technique is not iron-clad&mdash;you can get into races with other heap allocations in the process. But this technique does maintain an internal process-wide reservation count to keep track of all threads using a MemoryFailPoint in the process. And we believe this can reduce the frequency of hard OOMs requiring invocation of the framework&#39;s escalation policy.</div>
<div class="ArticleNormalPara">&nbsp;</div>
<div class="ArticleNormalPara"><span class="CodeDownloadText">Code download available at: </span> <a href="http://download.microsoft.com/download/f/2/7/f279e71e-efb0-4155-873d-5554a0608523/CLRInsideOut2007_12.exe">CLRInsideOut2007_12.exe</a> <span class="CodeDownloadText"> (156 KB) </span></div>
<div class="ArticleNormalPara">&nbsp;</div>
<div class="ArticleNormalPara"><strong>Alessandro Catorcini and Brian Grunkemeyer</strong></div>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/writing-reliable-net-code-76.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Build a .NET Application on the Oracle Database with Visual Studio 2005 or 2008</title>
		<link>http://www.allfreetech.com/microsoft-net/build-a-net-application-on-the-oracle-database-with-visual-studio-2005-or-2008-115.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/build-a-net-application-on-the-oracle-database-with-visual-studio-2005-or-2008-115.html#comments</comments>
		<pubDate>Wed, 20 Jan 2010 07:31:20 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[visual studio]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=115</guid>
		<description><![CDATA[With the popularity of Microsoft&#39;s .NET Framework, many developers are hungry for information about the best means of integrating .NET applications with Oracle&#8212;not only in terms of basic connectivity, but also in relationship to effective and efficient application development using Visual Studio 2005 or 2008. In this article, I&#39;ll explain the basic yet essential processes [...]]]></description>
			<content:encoded><![CDATA[<p>With the popularity of Microsoft&#39;s .NET Framework, many developers are hungry for information about the best means of integrating .NET applications with Oracle&mdash;not only in terms of basic connectivity, but also in relationship to effective and efficient application development using Visual Studio 2005 or 2008.</p>
<p>In this article, I&#39;ll explain the basic yet essential processes involved in building a .NET application that uses an Oracle database, including:</p>
<ul type="square">
<li>How to add project references to support Oracle class libraries in your .NET project</li>
<li>How to create Oracle Database connection strings</li>
<li>How to work with Connection, Command, and DataReader objects</li>
</ul>
<p>You will have the opportunity to apply what you have learned in three <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab1">practice labs</a>, ranging in difficulty from the relatively simple to the more complex. The article&#39;s screenshots are taken from Visual Studio 2008, but the experience is very similar in Visual Studio 2005.</p>
<p>For information and labs about how to secure your application, see my article &quot;<a class="bodylink" href="http://www.oracle.com/technology/pub/articles/mastering_dotnet_oracle/cook_masteringdotnet.html">Securing a .NET Application on the Oracle Database</a>&quot;. (Also, see the OTN <a class="bodylink" href="http://www.oracle.com/technology/tech/dotnet/index.html">.NET Developer Center</a> for technical articles covering a range of Oracle.NET application lifecycle issues.)</p>
<p>Note that the free <a class="bodylink" href="http://www.oracle.com/technology/tech/dotnet/tools/index.html">Oracle Developer Tools for Visual Studio</a>, available for <a class="bodylink" href="http://www.oracle.com/technology/tech/dotnet/tools/index.html">download</a> from OTN, provides a Visual Studio add-in that makes the development of .NET apps on Oracle much easier and more intuitive. That subject is beyond our scope here, however.</p>
<h2>.NET Data Provider</h2>
<p>In addition to basic Oracle client connectivity software, .NET applications require the use of what is known as a <em>managed data provider</em> (where &quot;managed&quot; refers to code managed by the .NET framework). The data provider is the layer between the .NET application code and the Oracle client connectivity software. In almost every case, the best performance is achieved by using a provider optimized for a specific database platform instead of the generic .NET OLE DB data provider.</p>
<p>Oracle, Microsoft, and third-party vendors all offer .NET data providers optimized for Oracle. Oracle and Microsoft make their Oracle data providers available for free. (Microsoft&#39;s provider for the .NET Framework 2.0 is included in the framework, but it still requires Oracle client software installation.) In this article, we will use of the Oracle Data Provider for .NET (ODP.NET), which is included with the Oracle Database or as a separate <a class="bodylink" href="http://www.oracle.com/technology/software/tech/windows/odpnet/index.html">download</a>.</p>
<p>ODP.NET provides standard ADO.NET data access, while exposing Oracle database-specific features, such as XML DB, data access performance optimizations, and Real Application Clusters connection pooling.</p>
<p>When ODP.NET and Oracle client software are installed, application development using Visual Studio can begin. It&#39;s a good idea to confirm client connectivity before starting development. If you can connect to Oracle using Oracle client software such as SQL*Plus on the same machine as Visual Studio, then you know that your Oracle client-side software is properly installed and configured.</p>
<p>If you are new to Oracle, see the section &quot;Installing .NET Products&quot; in the <a class="bodylink" href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28843/toc.htm"><em>Oracle Database 2 Day Developer&#39;s Guide</em></a> for background information regarding installing and configuring ODP.NET specifically, or to the <a class="bodylink" href="http://www.oracle.com/technology/documentation/database.html">Oracle Database Documentation Library</a> for general information about Oracle Database.</p>
<h2>Creating a Project in Visual Studio 2005 or 2008</h2>
<p>Let&#39;s create an ODP.NET application that retrieves data from an Oracle database. Later, we&#39;ll see how to perform error handling with ODP.NET and handle an additional data retrieval scenario.</p>
<p>After starting Visual Studio, the first task is to create a project. You can either select <strong>File | New | Project</strong> as shown below or click the <strong>New Project</strong> button located directly under <strong>File</strong>.</p>
<div align="center">
<p><img alt="Figure 1" src="http://www.oracle.com/technology/pub/images/cook-vs08-f1.gif" /><br />
		<em><strong>Figure 1</strong> Creating a new project in Visual Studio 2008 Service Pack 1</em></p>
</div>
<p>A <strong>New Project</strong> dialog box appears. On the left side of the dialog box under <strong>Project Types</strong>, select the programming language of your choice. In our example, &quot;Visual Basic&quot; was chosen. On the right side under <strong>Visual Studio installed templates</strong>, choose a project template. To keep things simple, a &quot;Windows Forms Application&quot; is selected.</p>
<div align="center">
<p><img alt="Figure 2" src="http://www.oracle.com/technology/pub/images/cook-vs08-f2.gif" /><br />
		<em><strong>Figure 2</strong> Using the <strong>New Project</strong> dialog</em></p>
</div>
<p>You&#39;ll want to specify meaningful names for the project name (we used OraWinApp) and the solution name (we used OraWinApp). A solution contains one or more projects. When a solution contains only one project, many people use the same name for both.</p>
<h2>Adding a Reference</h2>
<p>Because our project must connect to an Oracle database, it is necessary to add a reference to the ODP.NET DLL containing the data provider of our choice. Within the Solution Explorer, select the project name, right click and select <strong>Add Reference</strong>. Alternatively, you can go to the menu bar and select <strong>Project</strong> and then select <strong>Add Reference</strong>.</p>
<div align="center">
<p><img alt="Figure 3" src="http://www.oracle.com/technology/pub/images/cook-vs08-f3.gif" /><br />
		<em><strong>Figure 3</strong> Adding a reference</em></p>
</div>
<p>The <strong>Add Reference</strong> dialog box appears.</p>
<div align="center">
<p><img alt="Figure 4" src="http://www.oracle.com/technology/pub/images/cook-vs08-f4.gif" /><br />
		<strong><em>Figure 4</em></strong><em> Selecting the ODP.NET Managed Data Provider</em></p>
</div>
<p>ODP.NET is found under the Oracle.DataAccess component name. Select <strong>Oracle.DataAccess</strong> from the list, then click <strong>OK</strong> to make the ODP.NET data provider known to your project.</p>
<h2>Visual Basic/C# Statements</h2>
<p>After adding references, it is standard practice to add Visual Basic Imports statements or C# using statements. Technically, these statements are not required but they do allow you to refer to database objects without using lengthy, fully qualified names.</p>
<p>By convention, these statements appear at or near the top of a code file, before the namespace or class declaration.</p>
<pre>Imports Oracle.DataAccess.Client &#39; Visual Basic ODP.NET Oracle managed provider

using Oracle.DataAccess.Client; // C# ODP.NET Oracle managed provider
</pre>
<p>If you added the reference, Intellisense will help you complete the addition of an Imports or using statement as shown in Figure 5.</p>
<div align="center">
<p><img alt="Figure 5" src="http://www.oracle.com/technology/pub/images/cook-vs08-f5.gif" /><br />
		<strong><em>Figure 5</em></strong><em> Adding an Imports statement in Visual Basic</em></p>
</div>
<h2>Connection Strings and Objects</h2>
<p>An Oracle connection string is inseparable from Oracle names resolution. Suppose you had a database alias of OraDb defined in a tnsnames.ora file as follows:</p>
<pre>OraDb=
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521))
    )
    (CONNECT_DATA=
      (SERVER=DEDICATED)
      (SERVICE_NAME=ORCL)
    )
  )
</pre>
<p>The OraDb alias defines the database address connection information for the client. To use the OraDb alias defined in the tnsnames.ora file shown above, you would use the following syntax:</p>
<pre>Dim oradb As String = &quot;Data Source=OraDb;User Id=scott;Password=tiger;&quot; &#39; Visual Basic

string oradb = &quot;Data Source=OraDb;User Id=scott;Password=tiger;&quot;; // C#
</pre>
<p>You can modify the connection string to obviate the need for the tnsnames.ora file, however. Simply replace the name of the alias with how it would be defined in a tnsnames.ora file.</p>
<pre>&#39; Visual Basic
Dim oradb As String = &quot;Data Source=(DESCRIPTION=&quot; _
           + &quot;(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot; _
           + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot; _
           + &quot;User Id=scott;Password=tiger;&quot;

// C#
string oradb = &quot;Data Source=(DESCRIPTION=&quot;
             + &quot;(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot;
             + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot;
             + &quot;User Id=scott;Password=tiger;&quot;;
</pre>
<p>As you can see above, the username and password are embedded in the connection string in clear text. This is the simplest approach to creating a connection string. However, the clear text approach is undesirable from a security perspective. In particular, you must understand that compiled .NET application code is only marginally more secure than the clear text source code files. It is very easy to decompile .NET DLL and EXE files and view the original clear text contents. (Encryption is in fact the appropriate solution, but that subject would be a quite lengthy digression from our discussion here.)</p>
<p>Next, you must instantiate a connection object from the connection class. The connection string must be associated with the connection object.</p>
<pre>Dim conn As New OracleConnection(oradb) &#39; Visual Basic

OracleConnection conn = new OracleConnection(oradb); // C#
</pre>
<p>Notice that the connection string is associated with the connection object by being passed through the object&#39;s constructor, which is overloaded. The constructor&#39;s other overload allows the following alternative syntax:</p>
<pre>Dim conn As New OracleConnection() &#39; Visual Basic
conn.ConnectionString = oradb

OracleConnection conn = new OracleConnection(); // C#
conn.ConnectionString = oradb;
</pre>
<p>After associating a connection string with a connection object, use the Open method to make the actual connection.</p>
<pre>conn.Open() &#39; Visual Basic

conn.Open(); // C#
</pre>
<p>We&#39;ll cover error handling later.</p>
<h2>Command Object</h2>
<p>The Command object is used to specify the SQL command text that is executed, either a SQL string or a stored procedure. Similar to the Connection object, it must be instantiated from its class and it has an overloaded constructor. In this sample, ODP.NET will perform a SQL query to return the department name (DNAME) from the departments table (DEPT) where the department number (DEPTNO) is 10.</p>
<pre>Dim sql As String = &quot;select dname from dept where deptno = 10&quot; &#39; Visual Basic
Dim cmd As New OracleCommand(sql, conn)
cmd.CommandType = CommandType.Text

string sql = &quot;select dname from dept where deptno = 10&quot;; // C#
OracleCommand cmd = new OracleCommand(sql, conn);
cmd.CommandType = CommandType.Text;
</pre>
<p>Using different overloads, the syntax can be structured slightly differently. The Command object has methods for executing the command text, which will be seen in the next section. Different methods are appropriate for different types of SQL commands.</p>
<h2>Retrieving a Scalar Value</h2>
<p>Retrieving data from the database can be accomplished by instantiating an OracleDataReader object and using the ExecuteReader method, which returns an OracleDataReader object. Returned data is accessible by passing either the column name or zero-based column ordinal to the OracleDataReader.</p>
<pre>Dim dr As OracleDataReader = cmd.ExecuteReader() &#39; Visual Basic
dr.Read()

Label1.Text = dr.Item(&quot;dname&quot;) &#39; retrieve by column name
Label1.Text = dr.Item(0) &#39; retrieve the first column in the select list
Label1.Text = dr.GetString(0) &#39; return a .NET data type
Label1.Text = dr.GetOracleString(0) &#39; return an Oracle data type
</pre>
<p>There are typed accessors for returning .NET native data types and others for returning native Oracle data types, all of which are available in C#, Visual Basic, or any other .NET language. Zero-based ordinals are passed to the accessors to specify which column to return.</p>
<pre>OracleDataReader dr = cmd.ExecuteReader(); // C#
dr.Read();

label1.Text = dr[&quot;dname&quot;].ToString(); // C# retrieve by column name
label1.Text = dr.GetString(0).ToString();  // return a .NET data type
label1.Text = dr.GetOracleString(0).ToString();  // return an Oracle data type
</pre>
<p>In this simplified example, the returned value of DNAME is a string and is used to set the value of the label control&#39;s text property, which is also a string. But if DEPTNO, which is not a string, had been retrieved instead, there would be a data type mismatch. The .NET runtime attempts to implicitly convert from one data type to another when the source and destination data types don&#39;t match. Sometimes the data types are incompatible and the implicit conversion fails, throwing an exception. But even when it works, it&#39;s still better to use explicit data type conversions instead of implicit data type conversion.</p>
<p>An explicit cast to integer is shown below:</p>
<pre>Label1.Text = CStr(dr.Item(&quot;deptno&quot;)) &#39; Visual Basic integer to string cast

C# is not as forgiving as Visual Basic on implicit conversions. You&#39;ll find yourself doing explicit conversions: 

label1.Text = dr.GetInt16(&quot;deptno&quot;).ToString(); // C#
</pre>
<p>You can explicitly cast scalar values as well as arrays.</p>
<h2>Close and Dispose</h2>
<p>Either the connection object&#39;s <tt>Close</tt> or the <tt>Dispose</tt> method should be called to close the connection to the database. The <tt>Dispose</tt> method calls the <tt>Close</tt> method.</p>
<pre>conn.Close()   &#39; Visual Basic
conn.Dispose() &#39; Visual Basic

conn.Close();   // C#
conn.Dispose(); // C#
</pre>
<p>You don&#39;t have to explicitly call <tt>Close</tt> or <tt>Dispose</tt> if you use VB&#39;s <tt>Using</tt> keyword or C#&#39;s <tt>using</tt> keyword.</p>
<pre>using (OracleConnection conn = new OracleConnection(oradb)) // C#
{
    conn.Open();

    OracleCommand cmd = new OracleCommand();
    cmd.Connection = conn;
    cmd.CommandText = &quot;select dname from dept where deptno = 10&quot;;
    cmd.CommandType = CommandType.Text;

    OracleDataReader dr = cmd.ExecuteReader();
    dr.Read();

    label1.Text = dr.GetString(0);
}
</pre>
<p>In addition, OracleCommand includes a Dispose method; OracleDataReader includes a <tt>Close</tt> and <tt>Dispose</tt> method. Closing and disposing .NET objects free up system resources, ensuring more efficient application performance, which is especially important under high load conditions. You can experiment with some of the concepts we&#39;ve learned here in <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab1">Lab 1</a> (Retrieving Data from the Database) and <a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab2">Lab 2</a> (Adding Interactivity).</p>
<h2>Error Handling</h2>
<p>When an error occurs, .NET applications should gracefully handle the error and inform the user with a meaningful message. Try-Catch-Finally structured error handling is a part of .NET languages; here is a relatively minimalist example of using the Try-Catch-Finally syntax:</p>
<pre>&#39; Visual Basic
Try
    conn.Open()

    Dim cmd As New OracleCommand
    cmd.Connection = conn
    cmd.CommandText = &quot;select dname from dept where deptno = &quot; + TextBox1.Text
    cmd.CommandType = CommandType.Text

    If dr.Read() Then
        Label1.Text = dr.Item(&quot;dname&quot;) &#39; or use dr.Item(0)
    End If
Catch ex As Exception &#39; catches any error
    MessageBox.Show(ex.Message.ToString())
Finally
    &#39; In a real application, put cleanup code here.
End Try

// C#
try
{
    conn.Open();

    OracleCommand cmd = new OracleCommand();
    cmd.Connection = conn;
    cmd.CommandText = &quot;select dname from dept where deptno = &quot; + textBox1.Text;
    cmd.CommandType = CommandType.Text;

    if (dr.Read()) // C#
    {
        label1.Text = dr[&quot;dname&quot;].ToString();
                   // or use dr.GetOracleString(0).ToString()
    }
}
catch (Exception ex) // catches any error
{
    MessageBox.Show(ex.Message.ToString());
}
finally
{
    // In a real application, put cleanup code here.
}
</pre>
<p>Although this approach will gracefully capture any errors in attempting to get data from the database, it is not user friendly. For example, look at the following message displayed when the database is unavailable:</p>
<div align="center">
<p><img alt="Figure 6" src="http://www.oracle.com/technology/pub/images/cook-vs08-f6.gif" /><br />
		<strong><em>Figure 6</em></strong><em> An ORA-12545 error caught and displayed to the user</em></p>
</div>
<p>An ORA-12545 is quite meaningful for an Oracle DBA or developer, but not for an end user. A better solution is to add an additional <tt>Catch</tt> statement to trap for the most common database errors and provide user-friendly messages.</p>
<pre>Catch ex As OracleException &#39; catches only Oracle errors
    Select Case ex.Number
        Case 1
            MessageBox.Show(&quot;Error attempting to insert duplicate data.&quot;)
        Case 12545
            MessageBox.Show(&quot;The database is unavailable.&quot;)
        Case Else
            MessageBox.Show(&quot;Database error: &quot; + ex.Message.ToString())
    End Select
Catch ex As Exception &#39; catches any error
    MessageBox.Show(ex.Message.ToString())

catch (OracleException ex) // catches only Oracle errors
{
    switch (ex.Number)
    {
        case 1:
            MessageBox.Show(&quot;Error attempting to insert duplicate data.&quot;);
            break;
        case 12545:
            MessageBox.Show(&quot;The database is unavailable.&quot;);
            break;
        default:
            MessageBox.Show(&quot;Database error: &quot; + ex.Message.ToString());
            break;
    }
}
catch (Exception ex) // catches any error not previously caught
{
    MessageBox.Show(ex.Message.ToString());
}
</pre>
<p>Notice the two <tt>Catch</tt> statements in the code sample above. If there aren&#39;t any Oracle errors to catch, the first statement branch is skipped, leaving any other non-Oracle error to be caught by the second statement. <tt>Catch</tt> statements must be ordered in the code from most specific to most general. After implementing the user-friendly exception handling code, the ORA-12545 error message appears as follows:</p>
<div align="center">
<p><img alt="Figure 7" src="http://www.oracle.com/technology/pub/images/cook-vs08-f7.gif" /><br />
		<strong><em>Figure 7</em></strong><em> A user-friendly error message for an ORA-12545 error</em></p>
</div>
<p>The <tt>Finally</tt> code block is always executed regardless of whether or not an error occurred. It is where cleanup code belongs. If you don&#39;t use <tt>Using</tt> or <tt>using</tt>, you should dispose your connection and other objects in the <tt>Finally</tt> code block.</p>
<h2>Retrieving Multiple Values Using a DataReader</h2>
<p>So far our examples have only showed how to retrieve a single value. An OracleDataReader can retrieve values for multiple columns and multiple rows. First consider a multiple column, single row query:</p>
<pre>select deptno, dname, loc from dept where deptno = 10
</pre>
<p>To obtain the values of the columns, either zero-based ordinals or column names can be used. Ordinals are relative to the order in the query. Thus, the LOC column&#39;s value can be retrieved in Visual Basic by using either dr.Item(2) or dr.Item(&quot;loc&quot;).</p>
<p>Here is a code snippet that concatenates the DNAME and LOC columns from the previous query:</p>
<pre>Label1.Text = &quot;The &quot; + dr.Item(&quot;dname&quot;) + &quot; department is in &quot; + dr.Item(&quot;loc&quot;) &#39; VB

label1.Text = &quot;The &quot; + dr[&quot;dname&quot;].ToString() + &quot; department is in &quot; +
              dr[&quot;loc&quot;].ToString();  // C#
</pre>
<p>Now consider a query that returns multiple rows:</p>
<pre>select deptno, dname, loc from dept
</pre>
<p>To process multiple rows returned from an OracleDataReader, some type of looping construct is needed. Furthermore, a control that can display multiple rows is desirable. An OracleDataReader is a forward-only, read-only cursor, so it can&#39;t be bound to an updateable or fully scrollable control such as a Windows Forms DataGrid control. An OracleDataReader is compatible with a ListBox control, as the following code snippet illustrates:</p>
<pre>While dr.Read() &#39; Visual Basic
   ListBox1.Items.Add(&quot;The &quot; + dr.Item(&quot;dname&quot;) + &quot; department is in &quot; + dr.Item(&quot;loc&quot;))
End While

while (dr.Read()) // C#
{
    listBox1.Items.Add(&quot;The &quot; + dr[&quot;dname&quot;].ToString() + &quot; department is in &quot; +
                       dr[&quot;loc&quot;].ToString());
}
</pre>
<p><a class="bodylink" href="http://www.oracle.com/technology/pub/articles/cook-vs08.html#lab3">Lab 3</a> (Retrieve Multiple Columns and Rows with an OracleDataReader) highlights some of these concepts.</p>
<h2>Building and Running on x64</h2>
<p>When running Visual Studio 2008 on an x64 operating system, the <strong>Active solution platform</strong> defaults to <strong>Any CPU</strong>. Change that to x86 before building your project.</p>
<div align="center">
<p><img alt="Figure 8" src="http://www.oracle.com/technology/pub/images/cook-vs08-f8.gif" /><br />
		<strong><em>Figure 8</em></strong><em> Change from <strong>Any CPU</strong> to x86 when building on a 64-bit platform</em></p>
</div>
<h2>Conclusion</h2>
<p>This article has introduced you to the process of accessing Oracle databases using .NET programming languages. You should now have the capability to connect to the database and retrieve multiple columns and rows.</p>
<p>&nbsp;</p>
<table bgcolor="#cccccc" border="0" cellpadding="4" class="bodycopy" width="100%">
<tbody>
<tr>
<td><a name="lab1"></a></p>
<h3>Lab 1: Retrieving Data from the Database</h3>
<p>We begin with the requirement that you&#39;ve created a project and added a reference as shown previously in this article.</p>
<ol>
<li>Continue by adding a button control and a label control to the Windows form. Be sure to leave room above the controls to allow additions that will be made in Lab 2.
<div align="center">
<p><img alt="Figure 9" src="http://www.oracle.com/technology/pub/images/cook-vs08-f9.gif" /><br />
								<strong><em>Figure 9</em></strong><em> Lab 1 form with button and label controls</em></p>
</p></div>
</li>
<li>Add code to retrieve data from the Oracle database and display the results on the form. Put the code in a click event handler for the button. The easiest way to get started with this task is to double click the button because it will create a stub for the event handler.
<div align="center">
<p><img alt="Figure 10" src="http://www.oracle.com/technology/pub/images/cook-vs08-f10.gif" /><br />
								<strong><em>Figure 10</em></strong><em> Click event handler stub</em></p>
</p></div>
</li>
<li>Add Visual Basic Imports statements before the Public Class declaration or C# using statements before the namespace declaration.
<pre>Imports Oracle.DataAccess.Client &#39; Visual Basic, ODP.NET Oracle managed provider

using Oracle.DataAccess.Client; // C#, ODP.NET Oracle managed provider
</pre>
</li>
<li>Add the Visual Basic version of the click event handler code between the Private Sub and End Sub statements (be sure to replace ORASRVR with your server&#39;s host name):
<pre>Dim oradb As String = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot; _
                    + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot; _
                    + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot; _
                    + &quot;User Id=scott;Password=tiger;&quot;

Dim conn As New OracleConnection(oradb) &#39; Visual Basic
conn.Open()

Dim cmd As New OracleCommand
cmd.Connection = conn
cmd.CommandText = &quot;select dname from dept where deptno = 10&quot;
cmd.CommandType = CommandType.Text

Dim dr As OracleDataReader = cmd.ExecuteReader()
dr.Read()  &#39; replace this statement in next lab
Label1.Text = dr.Item(&quot;dname&quot;) &#39; or dr.Item(0), remove in next lab

dr.Dispose()
cmd.Dispose()
conn.Dispose()
</pre>
<p>Add the following C# code to the click event handler between the { and } curly braces for the button&#39;s click event handler (be sure to replace ORASRVR with your server&#39;s host name):
<pre>string oradb = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot;
		 + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot;
		 + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot;
		 + &quot;User Id=scott;Password=tiger;&quot;;

OracleConnection conn = new OracleConnection(oradb); // C#
conn.Open();

OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = &quot;select dname from dept where deptno = 10&quot;;
cmd.CommandType = CommandType.Text;

OracleDataReader dr = cmd.ExecuteReader();
dr.Read();  // replace this statement in next lab
label1.Text = dr[&quot;dname&quot;].ToString();  // remove in next lab

dr.Dispose();
cmd.Dispose();
conn.Dispose();</pre>
</li>
<li>Run the application. Click the button. You should see the following:
<div align="center">
<p><img alt="Figure 11" src="http://www.oracle.com/technology/pub/images/cook-vs08-f11.gif" /><br />
								<strong><em>Figure 11</em></strong><em> Data successfully retrieved.</em></p>
</p></div>
</li>
</ol>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table bgcolor="#cccccc" border="0" cellpadding="4" class="bodycopy" width="100%">
<tbody>
<tr>
<td><a name="lab2"></a></p>
<h3>Lab 2: Adding Interactivity</h3>
<p>Now that the basics of database access are implemented in the code, the next step is to add interactivity to the application. Instead of running the hard coded query, a textbox control can be added to accept a user input for the department number (i.e., DEPTNO).</p>
<ol>
<li>Add a textbox control and another label control to the form as shown below. Set the text property of the <tt>Label2</tt> control to <tt>Enter Deptno:</tt> and make sure that the <tt>Text</tt> property of <tt>TextBox1</tt> isn&#39;t set to anything.
<div align="center">
<p><img alt="Figure 12" src="http://www.oracle.com/technology/pub/images/cook-vs08-f12.gif" /><br />
								<strong><em>Figure 12</em></strong><em> Lab 2 form with button and label controls</em></p>
</p></div>
</li>
<li>Modify the code that defines the select string:
<pre>cmd.CommandText = &quot;select dname from dept where deptno = &quot; + TextBox1.Text &#39;VB

cmd.CommandText = &quot;select dname from dept where deptno = &quot; + textBox1.Text; // C#&gt;</pre>
</li>
<li>Run the application. Test the application by entering 10 for the DEPTNO. Retest the application by entering an invalid DEPTNO (e.g., 50). The application will abort.
<div align="center">
<p><img alt="Figure 13" src="http://www.oracle.com/technology/pub/images/cook-vs08-f13.gif" /><br />
								<strong><em>Figure 13</em></strong><em> An unhandled exception</em></p>
</p></div>
</li>
<li>Modify your code to prevent an error when an invalid DEPTNO is entered. Recall that the ExecuteReader method actually returns an object. Replace the line containing dr.Read with all of the following statements.
<pre>If dr.Read() Then &#39; Visual Basic
    Label1.Text = dr.Item(&quot;dname&quot;).ToString()
Else
    Label1.Text = &quot;deptno not found&quot;
End If

if (dr.Read()) // C#
{
    label1.Text = dr[&quot;dname&quot;].ToString();;
}
else
{
    label1.Text = &quot;deptno not found&quot;;
}
</pre>
<p>Test the application by entering a DEPTNO that does not exist. Now the application no longer aborts. Enter the letter A instead of a number and click the button. The application aborts. Clearly, our application needs a better approach to handling errors.</p>
<p>Although it could be argued that the application should not allow the user to make invalid inputs that would cause an error, ultimately the application must have robust error handling added. Not all errors are preventable, so error handling must be implemented.</p>
</li>
</ol>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table bgcolor="#cccccc" border="0" cellpadding="4" class="bodycopy" width="100%">
<tbody>
<tr>
<td><a name="lab3"></a></p>
<h3>Lab 3: Retrieve Multiple Columns and Rows with an OracleDataReader</h3>
<p>Now that a single value has been retrieved, the next step is to retrieve multiple columns and rows with an OracleDataReader. A ListBox control is added to the form to display the results.</p>
<ol>
<li>Add a ListBox control to the form. Resize the control to fill most of the width of the form as shown below.
<div align="center">
<p><img alt="Figure 14" src="http://www.oracle.com/technology/pub/images/cook-vs08-f14.gif" /><br />
								<strong><em>Figure 14</em></strong><em> Form with ListBox added</em></p>
</p></div>
</li>
<li>Remove the where clause from the query and add the additional columns:
<pre>cmd.CommandText = &quot;select deptno, dname, loc from dept&quot; &#39; Visual Basic

cmd.CommandText = &quot;select deptno, dname, loc from dept&quot;; // C#</pre>
</li>
<li>The query results will be read in a while loop and will populate the ListBox control. Modify your Visual Basic code to look like this:
<pre>Dim oradb As String = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot; _
            + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot; _
            + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot; _
            + &quot;User Id=scott;Password=tiger;&quot;

Dim conn As New OracleConnection(oradb) &#39; Visual Basic
conn.Open()

Dim cmd As New OracleCommand
cmd.Connection = conn
cmd.CommandText = &quot;select deptno, dname, loc from dept&quot;
cmd.CommandType = CommandType.Text

Dim dr As OracleDataReader = cmd.ExecuteReader()
While dr.Read()
    ListBox1.Items.Add(&quot;The &quot; + dr.Item(&quot;dname&quot;) + _
                       &quot; department is in &quot; + dr.Item(&quot;loc&quot;))
End While

dr.Dispose()
cmd.Dispose()
conn.Dispose()
Modify your C# code to look like this:
string oradb = &quot;Data Source=(DESCRIPTION=(ADDRESS_LIST=&quot;
                + &quot;(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))&quot;
                + &quot;(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));&quot;
                + &quot;User Id=scott;Password=tiger;&quot;;

OracleConnection conn = new OracleConnection(oradb); // C#
conn.Open();

OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = &quot;select deptno, dname, loc from dept&quot;;
cmd.CommandType = CommandType.Text;

OracleDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
   listBox1.Items.Add(&quot;The &quot; + dr[&quot;dname&quot;].ToString() +
                      &quot; department is in &quot; + dr[&quot;loc&quot;].ToString());
}

dr.Dispose();
cmd.Dispose();
conn.Dispose();</pre>
</li>
<li>Run the application. The ListBox should be populated with all of the department names and locations from the DEPT table. The code downloads have error handling implemented.</li>
</ol>
</td>
</tr>
</tbody>
</table>
<hr />
<p><strong>John Paul Cook</strong> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/build-a-net-application-on-the-oracle-database-with-visual-studio-2005-or-2008-115.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Write messaging applications with ODP.NET and Oracle Streams Advanced Queuing</title>
		<link>http://www.allfreetech.com/microsoft-net/write-messaging-applications-with-odp-net-and-oracle-streams-advanced-queuing-119.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/write-messaging-applications-with-odp-net-and-oracle-streams-advanced-queuing-119.html#comments</comments>
		<pubDate>Tue, 19 Jan 2010 07:39:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=119</guid>
		<description><![CDATA[Applications frequently need to pass messages to each other, and they need to do so reliably and often asynchronously. This goal is typically achieved with queuing: producer applications enqueue messages, and consumer applications dequeue messages. A message stays in the queue until a consumer application dequeues it or the message expires. Oracle Streams Advanced Queuing [...]]]></description>
			<content:encoded><![CDATA[<p><span class="bodycopy">Applications frequently need to pass messages to each other, and they need to do so reliably and often asynchronously. This goal is typically achieved with queuing: producer applications enqueue messages, and consumer applications dequeue messages. A message stays in the queue until a consumer application dequeues it or the message expires.<span id="more-119"></span></span></p>
<p><span class="bodycopy">Oracle Streams Advanced Queuing provides database-integrated message queuing functionality. Because Oracle Streams Advanced Queuing is implemented in database tables, queue data enjoys the Oracle Database benefits of high availability, scalability, and reliability. </span></p>
<p><span class="bodycopy">Oracle Data Provider for .NET (ODP.NET), Oracle&rsquo;s ADO.NET-compliant data provider, includes Oracle Streams Advanced Queuing classes to expose the messaging capabilities of Oracle Streams Advanced Queuing. Oracle Developer Tools for Visual Studio, a plug-in for Microsoft Visual Studio 2008 and Visual Studio 2005, includes administration tools that assist with tasks such as creating and modifying queues and queue tables.</span></p>
<p><span class="bodycopy">This article guides you through creating a set of .NET applications that make up a stock ticker system that demonstrates many Oracle Streams Advanced Queuing features. You will first create a queue in Oracle Database that holds stock ticker symbols and the corresponding stock prices. Every time a stock price changes, it will be loaded onto this queue by the StockQueueLoader application that you create next. You will also create the StockTickerListener application that receives notifications whenever a new stock price arrives in the queue and then retrieves the stock information and displays it on a ticker screen. StockTickerListener can receive notifications for all stocks that are loaded in the queue, but the queue can also be configured with rules specifying that StockTickerListener receives notifications only when specific stocks and, optionally, price ranges for specific stocks are loaded in the queue. To make it easy for a user to dynamically modify these rules, you will also run a helper application called StockQueueSubscriberAdmin.</span></p>
<p><strong><span class="parahead1">Setup</span> </strong></p>
<p><span class="bodycopy">To follow along with the steps in this article, you will need the following:</span></p>
<p>&nbsp;</p>
<ul>
<li><span class="bodycopy">SYSDBA privileges for Oracle Database Release 9.2 or later, which may be required to grant some of the Oracle Streams Advanced Queuing privileges</span></li>
<li><span class="bodycopy">Microsoft Visual Studio 2008 or Visual Studio 2005</span></li>
<li><span class="bodycopy">Oracle Developer Tools for Visual Studio and Oracle Data Provider for .NET Release 11.1.7.10 or later</span></li>
</ul>
<p><span class="bodycopy">Before you build the sample applications, you will create connections to Oracle Database from Visual Studio and grant the appropriate privileges to enable the use of queuing.</span></p>
<p><span class="bodycopy">To connect to Oracle Database from Visual Studio, create a new connection in </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy">, the top-level node of Server Explorer. (If Server Explorer is not yet visible, select </span><span class="boldbodycopy">View</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Server Explorer</span><span class="bodycopy"> from the main menu.)</span></p>
<p><span class="bodycopy">Right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy">, and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">. In the dialog box that appears, confirm that </span><span class="boldbodycopy">Oracle Database (Oracle ODP.NET)</span><span class="bodycopy"> appears in the </span><span class="boldbodycopy">Data source</span><span class="bodycopy"> field. If you do not see </span><span class="boldbodycopy">Oracle Database (Oracle ODP.NET)</span><span class="bodycopy">, click the </span><span class="boldbodycopy">Change</span><span class="bodycopy"> button and select </span><span class="boldbodycopy">Oracle Data Provider for .NET</span><span class="bodycopy"> from the list of providers. Select the database you want to connect to from the </span><span class="boldbodycopy">Datasource name</span><span class="bodycopy"> list. Click </span><span class="boldbodycopy">Use a specific user name and password</span><span class="bodycopy">. In the </span><span class="boldbodycopy">User name</span><span class="bodycopy"> field, enter SYS. In the </span><span class="boldbodycopy">Password</span><span class="bodycopy"> field, enter the password for SYS, and ensure that </span><span class="boldbodycopy">Role</span><span class="bodycopy"> is set to </span><span class="boldbodycopy">SYSDBA</span><span class="bodycopy">. Click </span><span class="boldbodycopy">Test connection</span><span class="bodycopy"> to verify that you can connect, and click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to complete the connection setup.</span></p>
<p><span class="bodycopy">To create and modify queues and queue tables and to enqueue and dequeue from them, you need the EXECUTE privilege on the DBMS_AQ and DBMS_AQADM PL/SQL packages. (If you wanted to modify queues you did not create, you would also require privileges on the AQ_ADMINISTRATOR_ROLE role.) You will grant the required privileges, using the Grant/Revoke Privilege dialog box in Visual Studio.</span></p>
<p><span class="bodycopy">Right-click the </span><span class="boldbodycopy">SYS</span><span class="bodycopy"> connection node, and choose </span><span class="boldbodycopy">Privileges</span><span class="bodycopy"> from the context menu. In the Grant/Revoke Privileges dialog box that appears, set </span><span class="boldbodycopy">Object Type</span><span class="bodycopy"> to </span><span class="boldbodycopy">Package</span><span class="bodycopy">. Leave </span><span class="boldbodycopy">Schema</span><span class="bodycopy"> set to </span><span class="boldbodycopy">SYS</span><span class="bodycopy">. Click the first radio button, labeled </span><span class="boldbodycopy">Grant/Revoke privileges to a user/role on one or more database object(s)</span><span class="bodycopy">. Hold down the Ctrl key, and in the </span><span class="boldbodycopy">Object Names</span><span class="bodycopy"> list, highlight both </span><span class="boldbodycopy">DBMS_AQ</span><span class="bodycopy"> and </span><span class="boldbodycopy">DBMS_AQADM</span><span class="bodycopy">. From the </span><span class="boldbodycopy">User/Role</span><span class="bodycopy"> list, select </span><span class="boldbodycopy">User</span><span class="bodycopy"> and choose </span><span class="boldbodycopy">HR</span><span class="bodycopy"> or some other username. In the list of privileges, in the Grant column, check the check box next to the </span><span class="boldbodycopy">EXECUTE</span><span class="bodycopy"> privilege. Click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to accept the changes, and close the dialog box.</span></p>
<p><span class="bodycopy">Now connect to Oracle Database as HR (or whichever user you just granted the Oracle Streams Advanced Queuing package privileges). In Server Explorer, right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy"> and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">. Follow the same steps to connect as HR that you used to connect as SYS, except to set </span><span class="boldbodycopy">Role</span><span class="bodycopy"> to </span><span class="boldbodycopy">Default</span><span class="bodycopy">.</span></p>
<p><strong><span class="parahead1">Creating the STOCK User-Defined Type</span> </strong></p>
<p><span class="bodycopy">Oracle Database queues typically hold objects of a single type (unless they are defined as ANYTYPE queues) and can be an XMLType, a user-defined type (UDT), or a RAW type. For more information on Oracle Streams Advanced Queuing queue types, including the benefits and limitations of each, see the <a href="http://download.oracle.com/docs/cd/B28359_01/server.111/b28420/toc.htm" target="_blank"><span class="bodylink"><i>Oracle Streams Advanced Queuing User&rsquo;s Guide</i></span></a>.</span></p>
<p><span class="bodycopy">The queue for this article will be made up of a user-defined type called STOCK, whose definition will include a stock symbol name as well as the price of the stock. (For a deep dive into Oracle user-defined types with Visual Studio and .NET, see &ldquo;<a href="http://www.oracle.com/technology/oramag/oracle/08-may/o38net.html" target="_blank"><span class="bodylink">It Takes All Types</span></a>&rdquo; in the May/June 2008 issue of </span><span class="italicbodycopy">Oracle Magazine</span><span class="bodycopy">).</span></p>
<p><span class="bodycopy">To create the user-defined type, in Server Explorer, under the HR data connection, right-click the </span><span class="boldbodycopy">User Defined Types</span><span class="bodycopy"> node and choose </span><span class="boldbodycopy">New Object Type</span><span class="bodycopy"> from the menu. This will launch Object Designer. In the </span><span class="boldbodycopy">Type name</span><span class="bodycopy"> field, enter </span><tt>STOCK</tt><span class="bodycopy">. Click the </span><span class="boldbodycopy">Add</span><span class="bodycopy"> button to add an attribute, and in the Attribute Properties </span><span class="boldbodycopy">Name</span><span class="bodycopy"> field, enter </span><tt>SYMBOL</tt><span class="bodycopy">. From the </span><span class="boldbodycopy">Type</span><span class="bodycopy"> list, choose </span><span class="boldbodycopy">VARCHAR2</span><span class="bodycopy">. Click the </span><span class="boldbodycopy">Add</span><span class="bodycopy"> button again to add another attribute. In the </span><span class="boldbodycopy">Name</span><span class="bodycopy"> field for this new attribute, enter </span><tt>PRICE</tt><span class="bodycopy"> and choose </span><span class="boldbodycopy">NUMBER</span><span class="bodycopy"> from the </span><span class="boldbodycopy">Type</span><span class="bodycopy"> list. Click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to create the type. The type will now be visible in Server Explorer under the </span><span class="boldbodycopy">User Defined Types</span><span class="bodycopy"> node and will also be available in datatype lists in various Oracle designers, such as Queue Designer. </span></p>
<p><span class="parahead1">Creating the Queue and the Queue Table</span></p>
<p><span class="bodycopy">Next, create a queue named STOCK_Q and its queue table, STOCK_QTAB. Under the </span><span class="boldbodycopy">HR</span><span class="bodycopy"> data connection node in Server Explorer, expand the </span><span class="boldbodycopy">Advanced Queues</span><span class="bodycopy"> node, which will expose the </span><span class="boldbodycopy">Queues</span><span class="bodycopy"> and </span><span class="boldbodycopy">Queue Tables</span><span class="bodycopy"> collection nodes (see Figure 1). Right-click the </span><span class="boldbodycopy">Queues</span><span class="bodycopy"> node, and select </span><span class="boldbodycopy">New Queue</span><span class="bodycopy"> from the menu. This will launch Queue Designer (see Figure 2).</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 1" border="0" height="511" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f1.gif" width="481" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 1: Server Explorer Advanced Queues and User-Defined Types nodes (left); Queues node context menu (right) </span></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 2" border="0" height="595" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f2.gif" width="473" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 2: Queue Designer </span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">In the </span><span class="boldbodycopy">Queue name</span><span class="bodycopy"> field, enter </span><tt>STOCK_Q</tt><span class="bodycopy">. From the </span><span class="boldbodycopy">Queue type</span><span class="bodycopy"> list, choose </span><span class="boldbodycopy">Normal Queue</span><span class="bodycopy">. For </span><span class="boldbodycopy">Payload Type</span><span class="bodycopy">, click the </span><span class="boldbodycopy">Complex</span><span class="bodycopy"> radio button, and then from the list next to it, choose the </span><span class="boldbodycopy">STOCK</span><span class="bodycopy"> user-defined type. </span></p>
<p><span class="bodycopy">Click the </span><span class="boldbodycopy">Queue Table</span><span class="bodycopy"> tab in the lower half of the designer. In the </span><span class="boldbodycopy">Queue Table</span><span class="bodycopy"> area, click the </span><span class="boldbodycopy">New</span><span class="bodycopy"> radio button and enter </span><tt>STOCK_QTAB</tt><span class="bodycopy"> as the name of the queue table. Leave the rest of the default settings as they are. (The most important settings are the </span><span class="boldbodycopy">Multi-Consumer</span><span class="bodycopy"> and </span><span class="boldbodycopy">Secure</span><span class="bodycopy"> check boxes, which must be checked, because multiple stock ticker applications can be run at the same time and all of them will need access to the contents of the queue.)</span></p>
<p><span class="bodycopy">Still in the Queue Designer, click the </span><span class="boldbodycopy">Subscribers</span><span class="bodycopy"> tab. Click the grid in the lower half of the designer, which will cause </span><tt>SUBSCRIBER1</tt><span class="bodycopy"> to be entered for </span><span class="boldbodycopy">Consumer Name</span><span class="bodycopy">. Leave the </span><span class="boldbodycopy">Rule</span><span class="bodycopy"> field blank. Click a new line in the grid to create another subscriber entry. Change the name of this one from </span><tt>SUBSCRIBER2</tt><span class="bodycopy"> to </span><tt>DEFAULT</tt><span class="bodycopy">. Leave the rule for this subscriber entry blank. </span></p>
<p><span class="bodycopy">Click </span><span class="boldbodycopy">Save</span><span class="bodycopy"> to create the queue and the queue table. The STOCK_Q queue and the STOCK_QTAB queue table will now be visible in Server Explorer (see Figure 1). The designer automatically starts the queue after creating it. </span></p>
<p><span class="bodycopy">Note that an exception queue named AQ$_STOCK_QTAB_E has been automatically created for you and that the exceptions will be stored in the STOCK_QTAB queue table. Oracle Streams Advanced Queuing exceptions are generated in a variety of circumstances, such as when a message expires before it is dequeued. For more information on Oracle Streams Advanced Queuing exceptions, see </span><span class="italicbodycopy">Oracle Streams Advanced Queuing User&rsquo;s Guide. </span></p>
<p><strong><span class="parahead1">Building the StockQueueLoader Application</span> </strong></p>
<p><span class="bodycopy">With the queue and the queue table created, you will now build the StockQueueLoader application that generates fictional stock price fluctuations in a fantasy stock market consisting of 10 ticker symbols and loads these stock prices (using a STOCK user-defined type) into the STOCK_Q queue you just created. (In a real-world scenario, actual stock price updates could be obtained via Web services and then inserted into an Oracle queue.) </span></p>
<p><span class="bodycopy">(Note that all of the applications created and used in this article&mdash;StockQueueLoader, StockTickerListener, and QueueSubscriberAdmin&mdash;are available prebuilt in the article&rsquo;s <a href="http://www.oracle.com/technology/oramag/oracle/09-nov/o69odt.zip"><span class="bodylink">application download</span></a>.)</span></p>
<p><span class="bodycopy">To begin construction of the queue loader application (StockQueueLoader), choose </span><span class="boldbodycopy">File</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">New</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Project</span><span class="bodycopy"> from the main menu. In the dialog box that appears, under Project type Visual C#, choose </span><span class="boldbodycopy">Windows</span><span class="bodycopy">, and then on the right side of the dialog box, choose the </span><span class="boldbodycopy">Console Application</span><span class="bodycopy"> template. In the </span><span class="boldbodycopy">Name</span><span class="bodycopy"> field, enter </span><tt>StockQueueLoader.</tt></p>
<p><span class="bodycopy">In the newly opened project, go to Solution Explorer; right-click the </span><span class="boldbodycopy">ConsoleApplication</span><span class="bodycopy"> project; and from the menu, choose </span><span class="boldbodycopy">Add Reference</span><span class="bodycopy">. On the </span><span class="boldbodycopy">.NET</span><span class="bodycopy"> tab in the Add Reference dialog box, scroll down until you see the Oracle.DataAccess assembly. You may see multiple versions, but select version 2.111.7.10&mdash;the version in which Oracle Streams Advanced Queuing support was first introduced&mdash;or later.</span></p>
<p><span class="bodycopy">Next, download the sample applications at <a href="http://www.oracle.com/technology/oramag/oracle/09-nov/o69odt.zip"><span class="bodylink">otn.oracle.com/oramag/oracle/09-nov/o69odt.zip</span></a>, unzip the file, and copy the contents of the AQ_ORAMAG\CodeListings\aqloader.txt file on top of the default template code. (Excerpts of the new code appear in Listing 1.) Notice that the key ODP.NET classes being used are OracleAQQueue and OracleAQMessage. Furthermore, note that the payload for the OracleAQMessage class is another .NET class called STOCK. STOCK is the .NET custom class for the STOCK Oracle user-defined type. (Custom classes enable .NET code to pass user-defined type values to and from Oracle Database.)</span></p>
<p><span class="boldbodycopy">Code Listing 1:</span><span class="bodycopy"> StockQueueLoader application code excerpt</span></p>
<p>&nbsp;</p>
<pre>OracleAQQueue queue = new OracleAQQueue(&quot;HR.STOCK_Q&quot;, con);
queue.MessageType = OracleAQMessageType.Udt;
queue.EnqueueOptions.Visibility = OracleAQVisibilityMode.Immediate;
OracleAQMessage enqMsg = new OracleAQMessage();

Console.WriteLine(&quot;Connected to Oracle.... Will start enqueuing in 10 seconds&quot;);
System.Threading.Thread.Sleep(10000);

string[] symbols = new string[10] { &quot;ORCL&quot;, &quot;MSFT&quot;, &quot;INTC&quot;, &quot;CSCO&quot;, &quot;ADBE&quot;, &quot;GOOG&quot;, &quot;AAPL&quot;, &quot;AMZN&quot;, &quot;EBAY&quot;, &quot;JAVA&quot; };

double[] prices = new double[10] { 19.5, 19, 18.25, 15, 24, 383.25, 121, 79.75, 15, 9 };

Random rand = new Random();
while (true)
{
    for (int i = 0; i &lt; 10; i++)
    {
        //...code to randomly increase or decrease prices[i] goes here
        }

        //We don&#39;t want multiple copies of the same stock on the queue
        //at the same time, so the message will expire after 5 seconds
        enqMsg.Expiration = 5;

        enqMsg.SenderId = new OracleAQAgent(&quot;QUEUELOADER&quot;);
        enqMsg.Payload = new STOCK(symbols[i], (decimal)prices[i]);
        queue.Enqueue(enqMsg);
</pre>
<p><span class="bodycopy">Now generate the STOCK custom class from the STOCK user-defined type, by using a wizard. To start the wizard, in Server Explorer, under the HR data connection, expand the </span><span class="boldbodycopy">User-Defined Types</span><span class="bodycopy"> node (see Figure 1). Find and right-click the </span><span class="boldbodycopy">STOCK</span><span class="bodycopy"> node. From the menu, choose </span><span class="boldbodycopy">Generate Custom Class</span><span class="bodycopy">. In the wizard, click </span><span class="boldbodycopy">Next</span><span class="bodycopy"> to move past the splash screen. In the next screen, uncheck the </span><span class="boldbodycopy">Inherit from Project</span><span class="bodycopy"> check box, directly above the </span><span class="boldbodycopy">Namespace</span><span class="bodycopy"> field. Then change </span><tt>Namespace</tt><span class="bodycopy"> to </span><tt>Stock</tt><span class="bodycopy">, click </span><span class="boldbodycopy">Next</span><span class="bodycopy"> until you get to the final screen, and click the </span><span class="boldbodycopy">Finish</span><span class="bodycopy"> button. This will generate a Stock.cs file and place it in your project.</span></p>
<p><span class="bodycopy">Now add the following constructor to the Stock class, below the automatically generated constructors: </span></p>
<p>&nbsp;</p>
<pre>public STOCK(string sym, decimal pr)
{
   SYMBOL = sym;
   PRICE = pr;
}
</pre>
<p><span class="bodycopy">Finally, build the application, by selecting </span><span class="boldbodycopy">Build</span><span class="bodycopy"> from the Visual Studio main menu and then selecting </span><span class="boldbodycopy">Rebuild Solution</span><span class="bodycopy">. Run the application, by choosing </span><span class="boldbodycopy">Debug</span><span class="bodycopy"> from the main menu, and then select </span><span class="boldbodycopy">Run Without Debugging</span><span class="bodycopy">.</span></p>
<p><span class="bodycopy">As you see messages appear in the console indicating that stock prices are being loaded into the queue, you can inspect the STOCK_QTAB table in Oracle Database to see these values being added there. In Server Explorer, under the </span><span class="boldbodycopy">HR</span><span class="bodycopy"> data connection, expand the </span><span class="boldbodycopy">Tables</span><span class="bodycopy"> node and double-click the </span><span class="boldbodycopy">STOCK_QTAB</span><span class="bodycopy"> node to open the data window. If you right-click the data window and choose </span><span class="boldbodycopy">Refresh</span><span class="bodycopy"> from the context menu, you can watch this queue table grow and notice that after five seconds, each entry in this table is replaced with an advanced queuing exception. Because the StockQueueLoader .NET code sets an expiration of five seconds for each item loaded into the queue, these exceptions indicate that the item was not dequeued before this expiration.</span></p>
<p><strong><span class="parahead1">Building the StockTickerListener Application</span> </strong></p>
<p><span class="bodycopy">Consumer applications have several options for finding out if there is something in a queue they are interested in. They can poll a queue by inspecting it from time to time to see if there is a message they need; they can listen to the queue with a dedicated thread; or they can register a </span><span class="italicbodycopy">callback</span><span class="bodycopy">, a subroutine that gets called and is passed a notification when a message that meets certain criteria is put into the queue.</span></p>
<p><span class="bodycopy">There are various ways a consumer application can choose whether a message is of interest. Messages can be addressed to specific recipients or recipient groups. Messages can also be assigned </span><span class="italicbodycopy">correlations</span><span class="bodycopy">, which are ad hoc identifiers assigned by the producing applications. Messages also have priorities for filtering. Finally, messages can be inspected via </span><span class="italicbodycopy">rules</span><span class="bodycopy">, which are essentially WHERE clauses added to SELECT statements that query against the queue. </span></p>
<p><span class="bodycopy">A consumer application can specify an interest in certain messages in a queue by becoming a subscriber. Each subscriber can define a named rule. You will now build an application&mdash;StockTickerListener&mdash;that receives callbacks whenever stock prices appear in the queue that match a subscriber rule. These stock prices will be output to a window much like a stock ticker. </span></p>
<p><span class="bodycopy">To build the StockTickerListener application, in a new instance of Visual Studio, first create a new console application, including an Oracle.DataAccess reference (in the same way you did in the previous section). Now add the Stock.cs custom class file (from the StockQueueLoader application) to your new project, by right-clicking the new project name in Solution Explorer, choosing </span><span class="boldbodycopy">Add an Existing Item</span><span class="bodycopy">, and then browsing to the file. Visual Studio will then make a local copy of that file in your project, saving you the trouble of re-creating it.</span></p>
<p><span class="boldbodycopy">Code Listing 2:</span><span class="bodycopy"> StockTickerListener application code excerpt</span></p>
<p>&nbsp;</p>
<pre>OracleAQQueue queue = new OracleAQQueue(&quot;HR.STOCK_Q&quot;, con);
queue.MessageType = OracleAQMessageType.Udt;
queue.NotificationConsumers = new string[1] { &quot;SUBSCRIBER1&quot; };

queue.MessageAvailable +=
  new OracleAQMessageAvailableEventHandler(QueueCallback.MsgReceived);
.....

static void MsgReceived(object src, OracleAQMessageAvailableEventArgs arg)
{
    try
    {
        Console.WriteLine(&quot;Notification Received...&quot;);
        byte[] notifiedMsgId = arg.MessageId[0];

        OracleConnection con = new OracleConnection(constr);
        con.Open();

        // Prepare to dequeue message by its MessageID
        OracleAQQueue queue = new OracleAQQueue(&quot;HR.STOCK_Q&quot;, con);
        queue.MessageType = OracleAQMessageType.Udt;
        queue.UdtTypeName = &quot;HR.STOCK&quot;;
        queue.DequeueOptions.MessageId = notifiedMsgId;
        queue.DequeueOptions.ConsumerName = &quot;SUBSCRIBER1&quot;; 

        queue.DequeueOptions.DequeueMode = OracleAQDequeueMode.Browse;

        //Dequeue
        OracleAQMessage deqMsg = queue.Dequeue();
        STOCK st = (deqMsg.Payload as STOCK);

        Console.WriteLine(st.SYMBOL + &quot;: &quot; + st.PRICE);
</pre>
<p><span class="bodycopy">From the sample applications you downloaded earlier, copy the contents of the AQ_ORAMAG\CodeListings\stocktickerlistener.txt file on top of the console template code. (Excerpts of this code appear in Listing 2.) The main part of the code contains two key methods. The first is </span></p>
<p>&nbsp;</p>
<pre>queue.NotificationConsumers
</pre>
<p><span class="bodycopy">which is set to SUBSCRIBER1. This indicates that callbacks should be received only when the SUBSCRIBER1 subscription rules are satisfied. The second key method is</span></p>
<p>&nbsp;</p>
<pre>
queue.MessageAvailable += new
OracleAQMessageAvailableEventHandler
(QueueCallback.MsgReceived);
</pre>
<p><span class="bodycopy">This registers the MsgReceived method as a callback.</span></p>
<p><span class="bodycopy">In the code for the MsgReceived callback, note that the advanced queuing AQ MessageID is included as part of the arguments that are passed to the method. This ID is set to </span></p>
<p>&nbsp;</p>
<pre>queue.DequeueOptions.MessageId
</pre>
<p><span class="bodycopy">to specify the message you want. Finally, </span></p>
<p>&nbsp;</p>
<pre>queue.DequeueOptions.DequeueMode = OracleAQDequeueMode.Browse
</pre>
<p><span class="bodycopy">indicates that the message should not be removed from the queue after viewing, because other client applications may need to view that stock.</span></p>
<p><span class="bodycopy">Build this application, by selecting </span><span class="boldbodycopy">Build</span><span class="bodycopy"> from the Visual Studio main menu and then selecting </span><span class="boldbodycopy">Rebuild Solution</span><span class="bodycopy">. Run the application, by choosing </span><span class="boldbodycopy">Debug</span><span class="bodycopy"> from the main menu, and then select </span><span class="boldbodycopy">Run Without Debugging</span><span class="bodycopy">. </span></p>
<p><span class="bodycopy">Now go back to the earlier instance of Visual Studio, rerun the StockQueueLoader application, and place both console application windows side by side. You should see the StockTickerListener application display every stock price that is loaded by the StockQueueLoader application (see Figure 3). This is because SUBSCRIBER1&rsquo;s rule is currently set to null. Because these rules are essentially WHERE clauses in a query over the queue contents, a null rule means that every item on the queue will be included. Keep both applications running while you move on to the next section.</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 3" border="0" height="584" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f3.gif" width="393" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 3: StockQueueLoader (top) and StockTickerListener (bottom) </span></td>
</tr>
</tbody>
</table>
<p><strong><span class="parahead1">Modifying a SUBSCRIBER Rule at Runtime</span> </strong></p>
<p><span class="bodycopy">Earlier, you saw a subscriber rule in the Queue Designer in Visual Studio. This rule selects specific STOCK user-defined type stock symbols and enables users to specify a range of stock prices in which they are interested. Now you will run a helper application that makes it easier to change this rule at runtime while the stock ticker application is running. </span></p>
<p><span class="bodycopy">The download provided with this article includes a Windows Forms application called StockQueueSubscriberAdmin.This application presents a user interface (see Figure 4) that includes a list of stock symbols; an optional field for providing a stock price; and a list of conditions that enables the user to set up a subscriber rule for receiving stock prices that are less than, greater than, or equal to the provided value. </span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 4" border="0" height="455" src="http://www.oracle.com/technology/oramag/oracle/09-nov/images/o69net_f4.gif" width="650" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 4: StockQueueSubscriberAdmin user interface </span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">Run the StockQueueSubscriberAdmin application. Select the </span><span class="boldbodycopy">ORCL</span><span class="bodycopy"> symbol from the stock list, and click </span><span class="boldbodycopy">Add to Rule</span><span class="bodycopy">. In the text box, you will see </span></p>
<p>&nbsp;</p>
<pre>tab.user_data.SYMBOL=&#39;&#39;ORCL&#39;&#39;
</pre>
<p><span class="bodycopy">This rule will cause your stock ticker to receive notifications only when ORCL stock values are placed in the queue. Next, select the </span><span class="boldbodycopy">JAVA</span><span class="bodycopy"> symbol from the list and enter </span><tt>3</tt><span class="bodycopy"> in the </span><span class="boldbodycopy">Price</span><span class="bodycopy"> field. Choose &gt; (greater than) from the </span><span class="boldbodycopy">Condition</span><span class="bodycopy"> list. Click </span><span class="boldbodycopy">Add to Rule</span><span class="bodycopy">. Now the text box contains</span></p>
<p>&nbsp;</p>
<pre>tab.user_data.SYMBOL=&#39;&#39;ORCL&#39;&#39; OR
(tab.user_data.SYMBOL=&#39;&#39;JAVA&#39;&#39; AND
tab.user_data.PRICE&gt;3)
</pre>
<p><span class="bodycopy">This rule will cause your stock ticker to receive notifications when all ORCL stock prices as well as any JAVA prices above $3 are loaded into the queue.</span></p>
<p><span class="bodycopy">Finally, click </span><span class="boldbodycopy">Alter Subscription!</span><span class="bodycopy">. This will execute the DBMS_AQADM.ALTER_SUBSCRIBER procedure and pass the rule you have created. (The code that calls this procedure is shown in Listing 3.) To see the new rule, in Server Explorer right-click the </span><span class="boldbodycopy">STOCK_Q</span><span class="bodycopy"> node, choose </span><span class="boldbodycopy">Design Queue</span><span class="bodycopy">, and then click the </span><span class="boldbodycopy">Subscribers</span><span class="bodycopy"> tab.</span></p>
<p><span class="boldbodycopy">Code Listing 3:</span><span class="bodycopy"> StockQueueSubscriber</span></p>
<p>&nbsp;</p>
<pre>private void button2_Click_1(object sender, EventArgs e)
{
//Executes DBMS_AQADM.ALTER_SUBSCRIBER to modify the SUBSCRIBER1 subscription
string conString = &quot;User Id=hr;Password=hr;Data Source=;&quot;;
OracleConnection con = new OracleConnection();
con.ConnectionString = conString;
con.Open();

OracleCommand cmd = con.CreateCommand();

string cmdtxt = &quot;DECLARE &quot; +
    &quot;SUBSCRIBER SYS.AQ$_AGENT; &quot; +
    &quot;BEGIN &quot; +
    @&quot;SUBSCRIBER := SYS.AQ$_AGENT(&#39;&quot;&quot;SUBSCRIBER1&quot;&quot;&#39;, NULL, 0); &quot; +
    &quot;DBMS_AQADM.ALTER_SUBSCRIBER(&quot; +
    @&quot;queue_name =&gt; &#39;&quot;&quot;STOCK_Q&quot;&quot;&#39;,&quot; +
    &quot;subscriber =&gt; SUBSCRIBER,&quot; +
    &quot;rule =&gt; &#39;&quot; + textBox2.Text +&quot;&#39;,&quot; +
    &quot;transformation =&gt; &#39;&#39;&quot; +
    &quot;); &quot; +
    &quot;END;&quot;;

OracleCommandBuilder oc = new OracleCommandBuilder();
cmd.CommandText = cmdtxt;

//Execute batched statement
cmd.ExecuteNonQuery();
}
</pre>
<p><span class="bodycopy">If both of the earlier applications are still running, you should notice that your stock ticker application is now displaying only ORCL and JAVA ticker symbols. Each time the rule is modified, your running stock ticker will immediately reflect the change. </span></p>
<p><span class="bodycopy">Now go back to the Queue Subscription GUI application, click </span><span class="boldbodycopy">Clear Rule</span><span class="bodycopy">, and click </span><span class="boldbodycopy">Alter Subscription!</span><span class="bodycopy">. This will set the rule to null. Watch as the stock ticker immediately resumes displaying all the stock symbols that are loaded into the queue. </span></p>
<p><strong><span class="parahead1">Summary</span> </strong></p>
<p><span class="bodycopy">This article showed you how you can leverage Oracle Streams Advanced Queuing database-integrated messaging from .NET applications. You loaded a queue from one application, subscribed to that queue from another application, and received callback notifications based on subscription rules you modified by using the DBMS_AQADM package.</span></p>
<p><strong><span class="boldbodycopy">Christian Shay</span><span class="bodycopy"> </span></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/write-messaging-applications-with-odp-net-and-oracle-streams-advanced-queuing-119.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using an ActionScript code generator to enable Flex and .NET integration</title>
		<link>http://www.allfreetech.com/microsoft-net/using-an-actionscript-code-generator-to-enable-flex-and-net-integration-86.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/using-an-actionscript-code-generator-to-enable-flex-and-net-integration-86.html#comments</comments>
		<pubDate>Sun, 10 Jan 2010 04:23:54 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=86</guid>
		<description><![CDATA[Code generators have long been used to automate creation of the code solving common programming problems. For instance, there are popular code generators automating data access code generation like CodeSmith, LLCoolGen, and NHibernate. Flex and .NET integration using Flex Remoting is not an exception. In fact, ActionScript code invoking different methods of a .NET class [...]]]></description>
			<content:encoded><![CDATA[<p>Code generators have long been used to automate creation of the code solving common programming problems. For instance, there are popular code generators automating data access code generation like CodeSmith, LLCoolGen, and NHibernate. Flex and .NET integration using Flex Remoting is not an exception. In fact, ActionScript code invoking different methods of a .NET class would have the same structure with the difference being method names, argument and return value types. As a result, using an ActionScript code generator can result in significant productivity boost and increased quality of code (with the assumption that the generated code is bug free).<span id="more-86"></span></p>
<p>The solution demonstrated in this article uses WebORB for .NET, a free product by <a href="http://www.themidnightcoders.com/" target="_blank">Midnight Coders</a> that facilitates connectivity between Flex and .NET. WebORB functions as a gateway between Flex clients and .NET objects. Using WebORB, your Flex applications can use the standard remoting API to communicate with .NET applications. WebORB includes a code generator enabling integration between Flex and .NET applications.</p>
<h3>Requirements</h3>
<h4>Flex Builder 3</h4>
<ul class="link-list compact">
<li><a class="icon<br />
download" href="http://www.adobe.com/go/tryflex">Try</a></li>
<li><a class="icon buy" href="http://www.adobe.com/go/buyflexbuilder">Buy</a></li>
</ul>
<h4>Microsoft Internet Information Services Server (version 5.x or later)</h4>
<ul class="link-list compact">
<li><a href="http://www.microsoft.com/technet/prodtechnol/windows2000serv/technologies/iis/default.mspx" target="_blank">Learn more</a></li>
</ul>
<h4>Microsoft .NET version 2.0 or later (installed on the system and integrated into IIS)</h4>
<ul class="link-list">
<li><a href="http://msdn2.microsoft.com/en-us/netframework/default.aspx" target="_blank">Learn more</a></li>
</ul>
<h4>Visual Studio 2003 or 2005</h4>
<ul class="link-list">
<li><a href="http://msdn2.microsoft.com/en-us/vstudio/default.aspx" target="_blank">Learn more</a></li>
</ul>
<h4>WebORB for .NET (version 3.3 or later)</h4>
<ul class="link-list">
<li><a href="http://www.themidnightcoders.com/weborb/dotnet/" target="_blank">Learn more</a></li>
</ul>
<p>The code generator described in this article produces ActionScript code enabling remoting invocations for the methods for a given class. Code generation uses XSLT-style sheets which describe the structure and the content for the generated code.</p>
<p>To get started, review the class shown below. The class is already included into the WebORB distribution and is provided here for the reference and to establish the context:</p>
<h4>C# class:</h4>
<pre>using System;
using System.Collections;
using System.Text;
using System.Data;
using System.Data.OleDb;
namespace Weborb.Examples
{
    public class DataBinding
    {
        private static string connectionString = &quot;..Skipped for brevity...&quot;;
        public DataSet getCustomers()
        {
            DataSet dataSet = new DataSet();
            OleDbConnection connection = new OleDbConnection( connectionString );
            OleDbDataAdapter adapter = new OleDbDataAdapter();
            adapter.SelectCommand = new OleDbCommand( &quot;SELECT * FROM Customers order by CustomerID&quot;, connection );
            try
            {
                adapter.Fill( dataSet );
            }
            finally
            {
                connection.Close();
            }
            return dataSet;
        }
    }
}</pre>
<h4>VB.NET class:</h4>
<pre>Imports System
Imports System.Collections
Imports System.Text
Imports System.Data
Imports System.Data.OleDb

Namespace Weborb.Examples
   Public Class DataBinding
      Private Shared connectionString As String =  &quot;..Skipped for brevity...&quot; 

       Public Function getCustomers() As DataSet
         Dim dataSet As DataSet =  New DataSet()
         Dim connection As OleDbConnection =  New OleDbConnection(connectionString)
         Dim adapter As OleDbDataAdapter =  New OleDbDataAdapter()
         adapter.SelectCommand = New OleDbCommand(&quot;SELECT * FROM Customers order by CustomerID&quot;, connection)

         Try
             adapter.Fill(dataSet)
         Finally
             connection.Close()
         End Try

         Return dataSet
     End Function

    End Class
End Namespace</pre>
<p>You can see and inspect the class in the service browser which is a part of the WebORB management console. You can access the console at the following URL after installing the product: <kbd>http://localhost/weborb30</kbd></p>
<p>Open the Management tab and navigate to the following path (see Figure 1):</p>
<pre>weborb.dll &gt; Weborb &gt; Examples &gt; DataBinding </pre>
<p><img alt="Navigation path" class="border" height="256" src="http://www.adobe.com/devnet/flex/articles/code_generator/fig01.jpg" width="236" /></p>
<p class="caption"><strong>Figure 1.</strong> Navigation path</p>
<p>When you select the class, the console automatically generates and displays the code which can be used to invoke class methods using the Flex Remoting API (RemoteObject). The structure of the generated code is very simple. It consists of the &#39;service&#39; and &#39;model&#39; classes (plus any DTO (data transfer object) classes representing the complex types used in the method signatures) (see Figure 2):</p>
<p><img alt="Generated code structure" class="border" height="237" src="http://www.adobe.com/devnet/flex/articles/code_generator/fig02.jpg" width="204" /></p>
<p class="caption"><strong>Figure 2.</strong> Generated code structure</p>
<p>The generated &#39;service&#39; class (has the same name as the selected .NET class) contains the logic for setting up an instance of RemoteObject and invoking the remote methods. The &#39;model&#39; class aggregates server responses and can be used for data binding in the user interface. The diagram below illustrates the relationship between the generated classes and a View component created by developer (see Figure 3):</p>
<p><img alt="Relationship between the generated classes and a<br />
View component" class="border" height="262" src="http://www.adobe.com/devnet/flex/articles/code_generator/fig03.jpg" width="566" /></p>
<p class="caption"><strong>Figure 3.</strong> Relationship between the generated classes and a View component</p>
<p>Create a project in Flex Builder for your application as described in <a href="http://www.adobe.com/devnet/flex/articles/flextodotnet_remoteobject_03.html">this article</a>.</p>
<p>To keep the naming consistency with this article, name your project DataBindingProject.</p>
<p>Click the Download Code button in the WebORB management console to download a zip file with the generated code. Extract the contents of the zip file into the created Flex Builder project. If you are using Flex Builder 3, make sure to extract the code into the /src folder in the project structure. The image below demonstrates the project structure in Flex Builder 3 after the generated code has been added to the project (see Figure 4):</p>
<p><img alt="Project structure in Flex Builder 3" class="border" height="173" src="http://www.adobe.com/devnet/flex/articles/code_generator/fig04.jpg" width="228" /></p>
<p class="caption"><strong>Figure 4.</strong> Project structure in Flex Builder 3</p>
<p>Open the MXML Application file and add the following code:</p>
<pre>&lt;mx:Script&gt;
 &lt;![CDATA[
  import weborb.examples.DataBindingModel;
  import weborb.examples.DataBinding; 

  [Bindable]
  private var model:DataBindingModel;
  private var dataBindingService:DataBinding;
  private function init():void
  {
    // create the model object
    model = new DataBindingModel();
    // create the service proxy - responsible for carrying out
    // remote method invocations and updating the model
    dataBindingService = new DataBinding( model );
    // invoke remote method
    dataBindingService.getCustomers();
  }
]]&gt;
&lt;/mx:Script&gt;</pre>
<p>Modify the root mx:Application element to invoke the init() method shown above on the creationComplete event:</p>
<pre>&lt;mx:Application xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot; layout=&quot;absolute&quot; <strong>creationComplete=&quot;init()&quot;</strong>&gt; </pre>
<p>Place a data grid component into the application by adding the following MXML code:</p>
<pre>&lt;mx:DataGrid x=&quot;10&quot; y=&quot;37&quot; width=&quot;467&quot; height=&quot;143&quot; dataProvider=&quot;{<strong>model.getCustomersResult</strong>}&quot;&gt;
&lt;/mx:DataGrid&gt;</pre>
<p>Notice the mx:columns declaration is not present, as a result, the data grid will render all columns in the returned resultset. The datagrid uses data binding by setting its data provider to be a bindable property from the model. The property in the model is automatically updated by the generated code when a response from the remote method invocation is available.</p>
<p>Save the file and run the application. When the application is loaded, it makes a remote method invocation which runs a query. The query results are displayed in the data grid.</p>
<h3>Conclusion</h3>
<p>Code generation is a very efficient and productive way to start Flex and .NET integration. Proven code generators provide less error-prone, high quality code. The technique described in this article additionally provides support for complex type generation which saves a lot of time for more complex projects.</p>
<p><strong>Mark Piller</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/using-an-actionscript-code-generator-to-enable-flex-and-net-integration-86.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ten ways to unit test your .NET code</title>
		<link>http://www.allfreetech.com/microsoft-net/ten-ways-to-unit-test-your-net-code-63.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/ten-ways-to-unit-test-your-net-code-63.html#comments</comments>
		<pubDate>Tue, 05 Jan 2010 03:40:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/microsoft-net/ten-ways-to-unit-test-your-net-code-63.html</guid>
		<description><![CDATA[You know you have to write unit tests. You have the tools, and your team is committed to the idea. Somehow, though, despite your best intentions, the tests just never get written. Or you write them, but never run them. They always fail anyway. For one reason or another, your project is resisting the will [...]]]></description>
			<content:encoded><![CDATA[<p>You know you have to write unit tests. You have the tools, and your team is committed to the idea. Somehow, though, despite your best intentions, the tests just never get written. Or you write them, but never run them. They always fail anyway. For one reason or another, your project is resisting the will of the unit test. Usually, this means that your code needs a good solid refactoring, to make it more accepting of the way of the test. <span id="more-63"></span></p>
<p>Many people have observed that <a href="http://searchsoftwarequality.techtarget.com/sDefinition/0,290660,sid92_gci1243425,00.html">unit testing</a> fits the mold of Heisenberg&#39;s Uncertainty Principle which says, among other things, that at the quantum level, the act of observing an event changes the nature of that event. Unit tests often have the same effect, but it extends beyond the runtime event being tested. It affects the design of the code that is to be tested, as well.</p>
<p>In this column, we&#39;ll examine 10 different ways you can change your .NET code to make it ready to be tested. By doing so, you will be creating a more loosely coupled, flexible and transparent architecture, which will benefit you not only in testing but in documentation, maintenance and, eventually, modification. With a little forethought and some careful implementation, the unit tests can drive more than the QA process; it can help you design a more robust application in the first place.</p>
<p><b>Use Interfaces</b></p>
<p>Those of us who came through the COM days with our registries intact remember that most strident of admonitions: &quot;it&#39;s the interfaces, stupid.&quot; To write COM code, you had to employ interfaces as the primary coupling mechanism. For the un- (or under-)initiated, interfaces are lightweight constructs which define the publicly accessible method signatures exposed by a class; they contain no implementation details whatsoever. Instantiated objects can be referred to by references of the interface type, but the interface can never be instantiated itself.</p>
<p>Here is a simple interface example: we&#39;ll define an interface for interacting with different kinds of agents. The interface is called IAgent:</p>
<p>Agents all have a name, and can attempt to accomplish a mission in a given amount of time.</p>
<p>&nbsp;</p>
<p><span class="a3">We&#39;ll implement two different kinds of agents, SecretAgents and AirlineAgents. Airline agents perform their mission by getting people on planes, and secret agents have clandestine rendezvous points. In addition, the SecretAgent, if in undercover mode, won&#39;t reveal her name.</span></p>
<p><span class="a3">In projects based entirely on concrete types, you may often hear complaints about the amount of time it takes to write the unit tests. This is due to the fact that test cases are meant to exercise the methods of a type; as long as each class is defined only by its own instantiable self, then unit tests are not reusable. There is a one-to-one correlation between the classes and the test cases.</span></p>
<p><span class="a3">Using interfaces, though, can allow you to reuse your unit tests. When you employ this architectural strategy, you are defining a common subset of available functionality that your concrete classes can implement. Unit tests, since they target methods on a type, can be written to exercise an implementation of a given interface. For every concrete type that implements that interface, the same test case can be used to exercise and verify the methods. </span></p>
<p><span class="a3">To test these different agents, we will want to run tests against the public interface IAgent. Tests for accomplishMission will all be remarkably identical; test known values for timeLimit and check true or false on the return. We need to create a specific unit test for each concrete type of agent in our application, but we don&#39;t want to rewrite the test for accomplishMission each time. Instead, start by defining a base class for your unit test that can adequately test accomplishMission:</span></p>
<p><span class="a3">Notice that the class is not marked with [TestFixture] though it does contain at least on [Test]. TestAgents will never be instantiated directly by the <a href="http://www.nunit.org/">NUnit</a> test runner because you have not marked it as a TestFixture, which is precisely the behavior you want. The test method itself relies on protected fields that will be filled in by the derived tests.</span></p>
<p><span class="a3">The test for AirlineAgent is only testing the accomplishMission method, since AirlineAgent currently has no other functionality. SecretAgent, on the other hand, has the extra ability to not return its name if it is undercover. The TestSecretAgent class therefore has an extra [Test] method to cover this. The code that actually exercises accomplishMission, though, is written only once, and can be maintained and upgraded in a single place.</span></p>
<p><span class="a3"><b>Define a base test class</b></span></p>
<p><span class="a3">To create a test case for NUnit, you need only define a class and mark it with the TestFixture attribute from the NUnit Framework assembly. This designation provides a marker for the test runner to identify your test cases and run them. It provides no other functionality for your class, and since it is only metadata, your class does not inherit any meaningful functionality or data from it.</span></p>
<p><span class="a3">However, you will find very quickly that there are techniques and strategies you employ again and again for your unit tests. It might be that you have to perform a task to set up a test data store, and run it often to clean out cruft from earlier tests, or that you have to create or destroy session information to enable proper test values. These types of repetitive activities cry out to be centrally located so that you can eliminate the extra work of typing them again and again. In keeping with the principle of &quot;don&#39;t repeat yourself&#39;, it is, in fact, imperative.</span></p>
<p><span class="a3">The solution is to create a base test class that your specific tests can derive from. This base class will host a series of utility methods and data structures that you can call on from any individual test. In addition, if all (or even most) of your tests require some common code in setUp and tearDown, you can implement those methods on the new base class. When your individual tests require the functionality, they can call up the chain and invoke it. </span></p>
<p><span class="a3">For example, with our agents application, perhaps we want our unit tests to be able to validate that the agent&#39;s name matches a certain pattern (no numbers, or if numbers, starts with &quot;00&quot;, or something). We would make a base class for our tests that exposes an isValidNameString method:</span></p>
<p><span class="a3">Simply have your other tests derive from this one. In the case of our example above, we&#39;ll have TestAgents derive from AgentTestBase, thus providing our common testing functionality to all our current tests.</span></p>
<p><span class="a3">Another favorite technique of mine for testing .NET code is to make my mock objects be internal classes in the base test class. This is especially useful when I only have a few mock objects, and most of my tests can share the same versions. See &quot;Mock the data access layer&quot; below for an example of this.</span></p>
<p><span class="a3">Do not decorate the base class as a TestFixture. This just clutters your test runs with ignored tests (since it won&#39;t have any actual [Test] methods on it). </span></p>
<p><span class="a3"><b>As much as feasible, make everything return a value</b></span></p>
<p><span class="a3">This obviously isn&#39;t a hard-and-fast, all-or-nothing rule, but as much as possible, avoid void methods and sub procedures. Unit tests are easier to write when the primary value to test is the return from a method. When a unit test has to scurry off to the database or another object or a text file to verify a simple method, then not only have you created more work for your unit test but you are also testing more than just your business logic; you are testing the infrastructure that leads from your business logic to that external data store. You are additionally adding the exact same infrastructure into your unit test, and if there is a problem, it will be a problem in the test as well as the thing being tested. </span></p>
<p><span class="a3">A method that returns the logical outcome of its processing can clearly enunciate its view of the world to its client, whether that be a user, other process or unit test. It may or may not reflect the true state of things, since obviously the full state of the application will probably be based on more than the code in this single method, but it will reflect what the method thinks is the state of things, which is what you should be unit testing. Testing the full application state is a job for integration testing.</span></p>
<p><span class="a3">Say that AirlineAgents have to be able to submit a timecard at the end of the day. The business rules for the application state that the agent should create the timecard, then save it to the database. Such a method might normally be written as:</span></p>
<p><span class="a3">To test that, you would have to go to the database and look up the timecard and verify its format. This is open to a number of problems, and isn&#39;t really testing the code in your method; it is testing a complex collection of activity, most of which won&#39;t have anything to do with the agent&#39;s ability to create the timecard.</span></p>
<p><span class="a3">A better way to write this method is:</span></p>
<p><span class="a3">Now, you can write a unit test that calls the method then verifies that the string returned matches the known state of the agent and the expected format of the document. You are not testing the database code, since that is orthogonal to the problem at hand.</span></p>
<p><span class="a3">So what happens if your method has more than one logical return value? If your architecture already calls for this, you will already have devised an answer to the problem. But what if you are trying to convert a void method to one with a return value (or values) just for the benefit of your unit tests? In this case, you really have three options:</span></p>
<ol>
<li><span class="a3">pick the most relevant value and return it and nothing else</span></li>
<li><span class="a3">pick the most relevant value and return it as the return value of the method, but make the other values REF parameters</span></li>
<li><span class="a3">package all the values into a strongly typed data transfer object, which is just a fancy description of a <em>struct</em></span></li>
</ol>
<p><span class="a3">Avoid option #2 as much as possible unless your architecture specifically calls for it. Using REF parameters adds complexity to your application, and your unit tests should not force you to add complexity to your code. All of the other suggestions given in this article actually reduce complexity, which is the key to testable code.</span></p>
<p><span class="a3"><b>Separate data access from business logic</b></span></p>
<p><span class="a3">Following from the last suggestion, make sure that your data access code is separated into its own layer. You might be using direct <a href="http://searchoracle.techtarget.com/sDefinition/0,290660,sid41_gci214133,00.html">ODBC</a> calls, or typed datasets, or an O/R mapping tool like <a href="http://www.nhibernate.org/">NHibernate</a>, but whichever method you use, make sure it lives in its own namespace and object model. </span></p>
<p><span class="a3">If your business objects are focused on the actual problem domain (rather than the common, and already solved, problem of storing data) then it is much easier to test whether or not you are solving the real problem. In addition, you can now implement a series of unit tests that exercise the data storage infrastructure for your application without jumping through hoops to ensure that the data you are storing is correctly formatted.</span></p>
<p><span class="a3">Instead of writing the timecard directly to the database inside of AirlineAgent, as in our example above, you would write a new data access class that handles saving and loading timecards.</span></p>
<p><span class="a3">The method submitTimeCard now becomes much cleaner:</span></p>
<p><span class="a3">In addition, now you can write unit tests that exercise just the data access layer.</span></p>
<p><span class="a3"><b>Mock the data layer to test the business logic</b></span></p>
<p><span class="a3">When you are writing the unit tests that target the domain logic, mock the data access layer to ensure the separation of concerns. Just because you have separated the data access code into is own namespace, if the business logic is inseparably dependent on it, you still have the same problem: testing the business logic is dependent on successful data access logic. </span></p>
<p><span class="a3">You can either choose to create your own mock data access classes, or employ a mock object framework like <a href="http://nmock.org/">nmock</a>. We&#39;ll save mock-object frameworks for another column. Today, let&#39;s just create a mock version of TimeCardDA that throws exceptions when it is given a well-known input.</span></p>
<p><span class="a3">This mock version of the data access defines some well-known error-inducing inputs. If the input is anything other than the defined error procuring values, then the methods will return something resembling a real value. When the well-known input is given, the method will error out.</span></p>
<p><span class="a3"><b>Make use of configuration</b></span></p>
<p><span class="a3">If you have followed the advice given so far, then you have an architecture based on interface implementation, with a variety of concrete implementations of your .NET code. Multiple domain objects implementing the same interface, separated domain and persistence layers, and a variety of mock or test objects that can be used in place of the real thing. In order to make full use of all of this, you need to take advantage of the configuration abilities of <a href="http://searchwindevelopment.techtarget.com/sDefinition/0,290660,sid8_gci342248,00.html">.NET</a>.</span></p>
<p><span class="a3">Let&#39;s examine the case of the persistence layer. For normal use, your domain model will rely on the real data access layer to perform its data storage. During testing, though, you will want to use the mock persistence layer. If your domain model is tightly coupled to the real persistence layer, then you will not be able to easily replace it at test-time.</span></p>
<p><span class="a3">Instead of making the domain model directly coupled to the persistence model, employ the indirection pattern. Create some kind of broker or router that your domain model relies on to provide concrete implementations of the persistence layer. This broker will look up the classes that are needed for the storage operations and create instances of those classes reflectively, based on the values in the configuration file. When the application is deployed, it will have a configuration file pointing to all of your real persistence classes. The test environment, though, should have its own copy of the configuration that points to your mock data object layer.</span></p>
<p><span class="a3">For our agents application, we&#39;ll want to have a way to get the real version of the TimeCardDA in a deployment scenario, but the mock version for unit testing. First, let&#39;s add a configuration element to the .config file for our application:</span></p>
<p><span class="a3">Next, we&#39;ll modify TimeCardDA so that you cannot instantiate it directly. Instead, we&#39;ll use the factory pattern (calling a static method on the class to return a new instance). The static method will look in the configuration file to determine whether to return the real or mock object.</span></p>
<p><span class="a3">Finally, we need only change our code to use the new factory method instead of the direct constructor.</span></p>
<p><span class="a3">Now, whenever we run the unit test suite, we make sure that the value of the TimeCardDA key in the config file is set to the mock object instead of the real, and our unit tests will test only the logic of the business model.</span></p>
<p><span class="a3">You could, instead, implement a method or property on the domain objects that tell it whether or not to use the real mock object.</span></p>
<p><span class="a3">This makes it very explicit from the test code&#39;s perspective what is being tested; nobody reading your tests will miss the fact that the data generated during the test will be sent off to some mock objects instead of the real thing. However, it means that your domain objects have to implement some code that is ONLY useful during testing, and this is usually a bad idea. Your domain objects should be devoted to the single purpose of solving your business problem; extraneous testing-specific code at best clutters the interface, and at worst, can have unintended ripple-effects throughout the class and possibly the rest of the code.</span></p>
<p><span class="a3"><b>Make Your Classes Do Only One Thing</b></span></p>
<p><span class="a3">This is a fairly common design principle that deserves its own point. When you write a class, it is the domain model representation of some idea. Too often, we clutter these classes with code that is only tangentially related to the idea. In &quot;Separate data access from business logic&quot;, we examined one of the many ways that programmers clutter their code with extraneous functionality.</span></p>
<p><span class="a3">The rule of thumb is that there should only ever be one reason for you to modify a class. If you find yourself going back to the class to make changes again and again as different requirements change, then the class is probably overcrowded. When this happens, determine what the class was intended to do, and refactor everything else into one or more other classes. If our SecretAgent class was spending too much time in file i/o, or the AirlineAgent kept looking things up via <a href="http://searchmobilecomputing.techtarget.com/sDefinition/0,290660,sid40_gci1128914,00.html">LDAP</a>, then we would want to remove that non-core logic and put it in another class dedicated to that kind of task.</span></p>
<p><span class="a3"><b>Have Domain Object Factories</b></span></p>
<p><span class="a3">Often, the unit of functionality that you are testing is dependent on other parts of your domain model. In general, you will not want to use mock objects to impersonate the objects your functionality relies on. Mock objects are generally used to impersonate external objects from third-party libraries whose internal state you cannot control nor directly observe. </span></p>
<p><span class="a3">Your domain objects might have very convoluted construction requirements. If the object needs more than a single call to a simple constructor to be initialized into a state that is useful for your test, you should think about creating a test factory for that class. The test factory should provide a static method for returning an instance of the class in a ready state for use in your tests. On top of that, it should provide some static constants defining known property values that can be used to verify the state during your tests.</span></p>
<p><span class="a3">For example, we might need to create a series of SecretAgents for testing. We will want to create them in known states with known values. Here is a sample factory for SecretAgents:</span></p>
<p><span class="a3">Whenever one of your tests needs to introduce a SecretAgent into the test, perhaps passing one or more into a method that operates on a collection of IAgents, then you can use the factory to create them. Moreover, when you are handed back a reference to an IAgent in the course of a test, you can compare its data values against known values on the test factory.</span></p>
<p><span class="a3"><b>Think carefully about packaging, assemblies and namespaces</b></span></p>
<p><span class="a3">Eventually, almost all &quot;enterprise level&quot; applications will grow to the point that running the entire suite of unit tests becomes a severe burden on the development team. Since running unit tests often is one of the central tenets of agile development (and it really is a good idea) this problem can quickly lead to fewer runs of the tests (and at worst, fewer tests written). </span></p>
<p><span class="a3">One way to avoid this problem is to plan your application for natural divisions of the codebase. Instead of allowing everything to be part of one monolithic assembly, the application should be built around the idea of multiple, interrelated assemblies. Your tests should follow the same architectural separation. When you work on a specific piece of the application, you can focus on running the tests associated with the assembly you are knee-deep in, and ignore the rest.</span></p>
<p><span class="a3">Don&#39;t be afraid of multiply-nested namespaces. If your application naturally breaks down in a nested tree structure, then let it. The only strong rule for breaking your application up into multiple assemblies and namespaces is to be careful not to overly entwine them. You generally only want dependencies running one direction between any two packages. If classes in one assembly are dependent on classes in a second, the reverse should not be true. This will allow you to replace entire assemblies more easily (for instance, if all your persistence code lives in its own assembly, you could swap it out for a new assembly that targets a different database, or one composed entirely of mock objects). </span></p>
<p><span class="a3"><b>Pick a logging strategy early</b></span></p>
<p><span class="a3">Even given the earlier recommendation to have your methods return values, sometimes you can&#39;t test everything you need to just by examining the return from a method. Since unit tests are usually run from outside your development environment, it makes step through debugging during testing difficult. In truth, most unit tests are run as batches anyways, and even if you could step into the code, you won&#39;t be sitting there and be able to.</span></p>
<p><span class="a3">What you need is an external store of application state that you can examine and correlate back to the test results. You need a logging strategy. It is vital to implement your chosen logging strategy as early as possible in the development effort, so that you don&#39;t have to layer it back into existing code later.</span></p>
<p><span class="a3">Beyond that, logging will be enormously beneficial to your application post-deployment. Since bugs are difficult enough to trace when you have a full development environment available to you, tracing bugs at the customer site is next to impossible. Detailed logging allows you, and your customer, to get a detailed look at application state in both a real-time and historical perspective.</span></p>
<p><span class="a3">You may choose to use the built-in Trace mechanism in the FCL, or move to an external tool like <a href="http://logging.apache.org/log4net/">log4net</a>. Regardless, make sure you learn the basics of categorizing your messages, sorting by priority and, most importantly, routing them to different output stores. The console is a great place to get realtime logging information, but what happens when your unit tests run as a batch overnight? Where is the console tomorrow? You need to be able to store the log information in files or data tables for retrieval and examination later.</span></p>
<p><span class="a3"><b>Summary</b></span></p>
<p><span class="a3">This is by no means an exhaustive treatment on the testability of applications. Entire articles can be written just about the testability of user interfaces and data access layers. Instead, these ten suggestions form a good starting point for re-examining the assumptions inherent in your design, and thinking through the decisions that will affect your code&#39;s testability. Since testability determines how well you can verify your application, it should follow that a testable application is a better application.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/ten-ways-to-unit-test-your-net-code-63.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use Microsoft Visual Studio for the complete .NET and Oracle Database development lifecycle</title>
		<link>http://www.allfreetech.com/microsoft-net/use-microsoft-visual-studio-for-the-complete-net-and-oracle-database-development-lifecycle-117.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/use-microsoft-visual-studio-for-the-complete-net-and-oracle-database-development-lifecycle-117.html#comments</comments>
		<pubDate>Mon, 04 Jan 2010 07:35:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[visual studio]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=117</guid>
		<description><![CDATA[Building a .NET application that accesses Oracle Database involves a variety of tasks besides writing .NET code: creating users and roles, creating tables and table data, generating SQL scripts and checking them into source control, performance tuning, and more. Those of you who use Microsoft Visual Studio will be happy to know that with Oracle [...]]]></description>
			<content:encoded><![CDATA[<p><span class="bodycopy">Building a .NET application that accesses Oracle Database involves a variety of tasks besides writing .NET code: creating users and roles, creating tables and table data, generating SQL scripts and checking them into source control, performance tuning, and more. Those of you who use Microsoft Visual Studio will be happy to know that with Oracle Developer Tools for Visual Studio, you can accomplish almost everything you need in this development lifecycle without having to leave Visual Studio to use another tool. <span id="more-117"></span></span></p>
<p><span class="bodycopy">In this article, I&rsquo;ll build a .NET application with Oracle Database and take you step by step through the development lifecycle. Along the way, you will learn how to</span></p>
<p>&nbsp;</p>
<ul>
<li><span class="bodycopy">Create users and roles and grant privileges to them</span></li>
<li><span class="bodycopy">Import tables and table data from Microsoft Excel spreadsheets (and many third-party databases) </span></li>
<li><span class="bodycopy">Automatically generate .NET code for an ASP.NET Web application</span></li>
<li><span class="bodycopy">Use Microsoft Query Builder to design SQL</span></li>
<li><span class="bodycopy">Generate a SQL script for all the Oracle schema objects your application uses</span></li>
<li><span class="bodycopy">Check your application and related SQL scripts into source control from Visual Studio </span></li>
</ul>
<p><span class="bodycopy">I&rsquo;ll also touch on other aspects of the development lifecycle, including PL/SQL debugging and performance tuning. </span></p>
<p><strong><span class="parahead1">Setup</span> </strong></p>
<p><span class="bodycopy">To follow along with the steps in this article, you will need the following:</span></p>
<p>&nbsp;</p>
<ul>
<li><span class="bodycopy">Oracle9<i>i</i> Database Release 9.2 or later (SYSDBA privileges are required for a few steps) </span></li>
<li><span class="bodycopy">Oracle Developer Tools for Visual Studio Release 11.1.0.7.10 (beta) or later </span></li>
<li><span class="bodycopy">Microsoft Visual Studio 2008 or Visual Studio 2005</span></li>
<li><span class="bodycopy">A source control system with a plug-in for Visual Studio, such as Microsoft SourceSafe, Team Foundation source control, or Subversion</span></li>
</ul>
<p><span class="bodycopy">To connect to Oracle Database from Visual Studio, create a connection in Server Explorer. (If Server Explorer is not yet visible, select </span><span class="boldbodycopy">View</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Server Explorer</span><span class="bodycopy"> from the main menu.) Now create the new connection in </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy">, the top-level node of Server Explorer. Right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy">, and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">. In the dialog box that appears, confirm that </span><span class="boldbodycopy">Oracle Database (Oracle ODP.NET)</span><span class="bodycopy"> appears in the </span><span class="boldbodycopy">Data source</span><span class="bodycopy"> field. If you do not see </span><span class="boldbodycopy">Oracle Database (Oracle ODP.NET)</span><span class="bodycopy">, click the </span><span class="boldbodycopy">Change</span><span class="bodycopy"> button and select </span><span class="boldbodycopy">Oracle Data Provider for .NET</span><span class="bodycopy"> from the list of providers. Select the database you want to connect to from the </span><span class="boldbodycopy">Datasource name</span><span class="bodycopy"> list. Click </span><span class="boldbodycopy">Use a specific user name and password</span><span class="bodycopy">. In the </span><span class="boldbodycopy">User name</span><span class="bodycopy"> field, enter </span><tt>SYS</tt><span class="bodycopy">. In the </span><span class="boldbodycopy">Password</span><span class="bodycopy"> field, enter the password for SYS, and ensure that </span><span class="boldbodycopy">Role</span><span class="bodycopy"> is set to </span><span class="boldbodycopy">SYSDBA</span><span class="bodycopy">. Click </span><span class="boldbodycopy">Test connection</span><span class="bodycopy"> to verify that you can connect, and click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to complete the connection setup. </span></p>
<p><strong><span class="parahead1">Creating a New User with User Designer</span> </strong></p>
<p><span class="bodycopy">Now create an Oracle Database user that you will use during development. In Server Explorer, expand the new </span><span class="boldbodycopy">SYS</span><span class="bodycopy"> connection you just created. You should see two child nodes: </span><span class="boldbodycopy">Schemas</span><span class="bodycopy"> and </span><span class="boldbodycopy">Roles</span><span class="bodycopy">. Right-click </span><span class="boldbodycopy">Schemas</span><span class="bodycopy">, and choose </span><span class="boldbodycopy">New User</span><span class="bodycopy"> from the context menu. This will launch User Designer. </span></p>
<p><span class="bodycopy">I&rsquo;m creating a user named CSHAY, so in User Designer, for </span><span class="boldbodycopy">User name</span><span class="bodycopy">, I enter </span><tt>CSHAY</tt><span class="bodycopy"> (see Figure 1). For </span><span class="boldbodycopy">Profile</span><span class="bodycopy"> I leave the </span><span class="boldbodycopy">&ldquo;DEFAULT&rdquo;</span><span class="bodycopy"> value, and for </span><span class="boldbodycopy">Authentication</span><span class="bodycopy"> I select </span><span class="boldbodycopy">Password</span><span class="bodycopy">. For </span><span class="boldbodycopy">Password</span><span class="bodycopy"> and </span><span class="boldbodycopy">Confirm password</span><span class="bodycopy">, I enter my chosen password. In the Tablespaces section, I select the location of the default and temporary tablespaces for the CSHAY user. When I installed Oracle Database earlier, I let the Oracle installer create a database for me, so for the default tablespace, I select the </span><span class="boldbodycopy">USERS</span><span class="bodycopy"> tablespace, and for the temporary tablespace, I choose </span><span class="boldbodycopy">TEMP</span><span class="bodycopy">. Finally, I click </span><span class="boldbodycopy">Save</span><span class="bodycopy">, which will create my new user account. The SQL that creates the new user account will appear in the output window in Visual Studio.</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 1" border="0" height="458" src="http://www.oracle.com/technology/oramag/oracle/09-jul/images/o49odt_f1.gif" width="458" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 1: Creating a user in User Designer</span></td>
</tr>
</tbody>
</table>
<p><strong><span class="parahead1">Granting Privileges to the New User Account</span> </strong></p>
<p><span class="bodycopy">Before you can do anything with this new user, you will need to provide some basic privileges. Specifically, you will grant the CONNECT and RESOURCE roles. To do this in Server Explorer, first right-click the </span><span class="boldbodycopy">SYS</span><span class="bodycopy"> connection node and choose </span><span class="boldbodycopy">Privileges</span><span class="bodycopy"> from the context menu. In the Grant/Revoke Privileges dialog box that appears, set </span><span class="boldbodycopy">Object Type</span><span class="bodycopy"> to </span><span class="boldbodycopy">Role</span><span class="bodycopy">. Select </span><span class="boldbodycopy">User</span><span class="bodycopy">, and then select </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> from the list of users. At the bottom of the dialog box, there will be a list of roles. Select both the </span><span class="boldbodycopy">CONNECT</span><span class="bodycopy"> and the </span><span class="boldbodycopy">RESOURCE</span><span class="bodycopy"> roles, and then click </span><span class="boldbodycopy">Apply</span><span class="bodycopy">.</span></p>
<p><span class="bodycopy">In Server Explorer, again right-click the </span><span class="boldbodycopy">SYS</span><span class="bodycopy"> connection node and choose </span><span class="boldbodycopy">Privileges</span><span class="bodycopy"> to reopen the Grant/Revoke Privileges dialog box. This time set </span><span class="boldbodycopy">Object Type</span><span class="bodycopy"> to </span><span class="boldbodycopy">System Privileges</span><span class="bodycopy">. Select </span><span class="boldbodycopy">User</span><span class="bodycopy">, and then select </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> from the list of users. At the bottom of the dialog box will be a list of privileges. Select the </span><span class="boldbodycopy">CREATE ROLE</span><span class="bodycopy"> privilege, and click </span><span class="boldbodycopy">Apply</span><span class="bodycopy">. Finally, click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to dismiss the dialog box. </span></p>
<p><span class="bodycopy">Now connect to Oracle Database, using the new CSHAY user in Server Explorer. Right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy">, and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">. Follow the same steps to connect as CSHAY that you used to connect as </span><span class="boldbodycopy">SYS</span><span class="bodycopy">, except set </span><span class="boldbodycopy">Role</span><span class="bodycopy"> to </span><span class="boldbodycopy">Default</span><span class="bodycopy">.</span></p>
<p><strong><span class="parahead1">Importing Tables and Table Data</span> </strong></p>
<p><span class="bodycopy">Now you need some tables and table data for the application to use. There are several ways you can achieve this. If you already have a SQL script, you can run it by choosing </span><span class="boldbodycopy">Tools</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Run SQL Plus Script</span><span class="bodycopy"> from the main menu. Or you can create the tables and table data from scratch, by using the table designer and the data window. Additionally, you can use the Import Table Wizard to import tables and table data from any datasource listed in Server Explorer that is using a data provider for .NET that supports ADO.NET 2.0. This could include any other Oracle Database instance, a Microsoft SQL Server database, Microsoft Access, a Microsoft Excel spreadsheet, or many other datasources.</span></p>
<p><span class="bodycopy">For this article, you will import data from two tables contained within the EMP_DEPT.xls spreadsheet. Download this data via the link in the <a href="http://www.oracle.com/technology/oramag/oracle/09-jul/o49odt.html#next"><span class="bodylink">Next Steps box</span></a> at the end of this article.</span></p>
<p><span class="bodycopy">First, connect to the EMP_DEPT.xls spreadsheet in Server Explorer. Right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy"> and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">. In the dialog box that appears, click the </span><span class="boldbodycopy">Change</span><span class="bodycopy"> button and select </span><span class="boldbodycopy">&lt;other&gt;</span><span class="bodycopy"> from the list. In the </span><span class="boldbodycopy">Data Provider</span><span class="bodycopy"> list, select </span><span class="boldbodycopy">.NET Framework Data Provider for OLEDB</span><span class="bodycopy"> and then click </span><span class="boldbodycopy">OK</span><span class="bodycopy">. In Server Explorer, right-click </span><span class="boldbodycopy">Data Connections</span><span class="bodycopy"> and select </span><span class="boldbodycopy">Add Connection</span><span class="bodycopy">, and in the dialog box, under OLEDB provider, select </span><span class="boldbodycopy">Microsoft Jet 4.0 OLEDB Provider</span><span class="bodycopy">. (Note that if you wanted to use the new Excel 12.0 .xlsx spreadsheet format, you would need to select </span><span class="boldbodycopy">Microsoft Office 12.0 Access Database Engine OLEDB Provider</span><span class="bodycopy">.) In the </span><span class="boldbodycopy">Server or File name</span><span class="bodycopy"> field, enter the full path to EMP_DEPT.xls, and click the </span><span class="boldbodycopy">Advanced</span><span class="bodycopy"> button, which will open a property sheet. For the </span><span class="boldbodycopy">Extended Properties</span><span class="bodycopy"> property, enter </span><tt>Excel 8.0;HDR=YES</tt><span class="bodycopy">. (If you were using the Excel 12.0 .xlsx format, you would enter </span><tt>Excel 12.0;HDR=YES</tt><span class="bodycopy">.) Click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to close the property sheet, click </span><span class="boldbodycopy">Test</span><span class="bodycopy"> to test the connection, and click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> once more to close the Add Connection dialog box. </span></p>
<p><span class="bodycopy">Now import the data from the connected spreadsheet. Right-click the </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> connection node, and select </span><span class="boldbodycopy">Import Table</span><span class="bodycopy">. This will start the Import Table Wizard. Click </span><span class="boldbodycopy">Next</span><span class="bodycopy"> until you see the Choose Data Source Connection screen. For the data connection source, choose the </span><span class="boldbodycopy">emp_dept.xls</span><span class="bodycopy"> connection. Click </span><span class="boldbodycopy">Next</span><span class="bodycopy"> to go to the Select Tables to Import screen. Under Source Table, click the check boxes next to both </span><span class="boldbodycopy">DEPARTMENTS$</span><span class="bodycopy"> and </span><span class="boldbodycopy">EMPLOYEES$</span><span class="bodycopy">. Click each destination table name, and then edit each name to remove the dollar sign at the end (see Figure 2). The </span><span class="boldbodycopy">Import Data</span><span class="bodycopy"> check box is checked by default, which is what you want. </span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 2" border="0" height="406" src="http://www.oracle.com/technology/oramag/oracle/09-jul/images/o49odt_f2.gif" width="650" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 2: Import Table Wizard: Renaming the destination table</span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">Click </span><span class="boldbodycopy">Next</span><span class="bodycopy"> to go to the Customize Columns Settings screen (see Figure 3). For each column of type BINARY_DOUBLE, highlight the row, and in the </span><span class="boldbodycopy">Data Type</span><span class="bodycopy"> list, choose </span><span class="boldbodycopy">NUMBER</span><span class="bodycopy">. For EMPLOYEES.EMPLOYEE_ID, uncheck the </span><span class="boldbodycopy">Allows NULL</span><span class="bodycopy"> check box and then check the </span><span class="boldbodycopy">Primary Key</span><span class="bodycopy"> check box. Do the same for DEPARTMENTS .DEPARTMENT_ID. (Note that you will need to use the </span><span class="boldbodycopy">Select a Table</span><span class="bodycopy"> list at the top of the screen to switch between the two tables.) Click </span><span class="boldbodycopy">Finish</span><span class="bodycopy"> to import the data.</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 3" border="0" height="411" src="http://www.oracle.com/technology/oramag/oracle/09-jul/images/o49odt_f3.gif" width="650" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 3: Import Table Wizard: Choosing the destination column datatype</span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">After the data has been successfully imported, click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> and then go to Server Explorer, right-click the </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> connection, and select </span><span class="boldbodycopy">Refresh</span><span class="bodycopy">. Navigate to the </span><span class="boldbodycopy">Tables</span><span class="bodycopy"> node to view the newly imported tables. </span></p>
<p><strong><span class="parahead1">Automatically Generating the .NET Code for a Web Application</span> </strong></p>
<p><span class="bodycopy">Now, taking advantage of Visual Studio&rsquo;s automatic .NET code generation features, create an ASP.NET Web application to display the data you just imported into Oracle Database. You could just as easily create a client/server Winform application or a Microsoft Office application by using similar steps. </span></p>
<p><span class="bodycopy">From the Visual Studio main menu, select </span><span class="boldbodycopy">File</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">New Project</span><span class="bodycopy">. For </span><span class="boldbodycopy">Visual C# Project Type</span><span class="bodycopy"> select </span><span class="boldbodycopy">Web</span><span class="bodycopy">, and then select the </span><span class="boldbodycopy">ASP.NET Web Application</span><span class="bodycopy"> template. Click the </span><span class="boldbodycopy">Design</span><span class="bodycopy"> button, below the HTML code window. If the toolbox is not already visible, choose </span><span class="boldbodycopy">View</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Toolbox</span><span class="bodycopy"> from the main menu.</span></p>
<p><span class="bodycopy">Scroll down to the Data section of the toolbox, and drag and drop a </span><span class="boldbodycopy">GridView</span><span class="bodycopy"> control onto the design surface. The GridView Tasks window should immediately open, but if it does not, click the small </span><span class="boldbodycopy">&gt;</span><span class="bodycopy"> icon to open it. From the </span><span class="boldbodycopy">Choose Data Source</span><span class="bodycopy"> list, select </span><span class="boldbodycopy">:&lt;New Data Source&gt;</span><span class="bodycopy">. This will open the Data Source Configuration Wizard to the Choose a Data Source Type screen. Select the </span><span class="boldbodycopy">Database</span><span class="bodycopy"> icon, and then click </span><span class="boldbodycopy">OK</span><span class="bodycopy">. On the Choose Your Data Connection screen (the next screen), select </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> for the data connection, and click </span><span class="boldbodycopy">Next</span><span class="bodycopy">. On the Save a Connection String to the Application Configuration File screen, accept the defaults and click </span><span class="boldbodycopy">Next</span><span class="bodycopy">.</span></p>
<p><span class="bodycopy">On the Configure the Select Statement screen, select </span><span class="boldbodycopy">Specify a Custom SQL Statement</span><span class="bodycopy"> and click </span><span class="boldbodycopy">Next</span><span class="bodycopy">. On the Define Custom Statements screen, click the </span><span class="boldbodycopy">Query Builder</span><span class="bodycopy"> button. When Microsoft Query Builder launches and the Add Table dialog box appears, select the </span><span class="boldbodycopy">DEPARTMENTS</span><span class="bodycopy"> and </span><span class="boldbodycopy">EMPLOYEES</span><span class="bodycopy"> tables and click the </span><span class="boldbodycopy">Add</span><span class="bodycopy"> button. In the top section of Query Builder, you will see both tables automatically joined by </span><span class="boldbodycopy">DEPARTMENT_ID</span><span class="bodycopy"> (see Figure 4).</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 4" border="0" height="508" src="http://www.oracle.com/technology/oramag/oracle/09-jul/images/o49odt_f4.gif" width="650" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 4: Microsoft Query Builder </span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">Now you need to decide which columns to select in your query. In the </span><span class="boldbodycopy">EMPLOYEES</span><span class="bodycopy"> table, select the </span><span class="boldbodycopy">EMPLOYEE_ID</span><span class="bodycopy">, </span><span class="boldbodycopy">FIRST_NAME, LAST_NAME</span><span class="bodycopy">, and </span><span class="boldbodycopy">SALARY</span><span class="bodycopy"> columns. In the </span><span class="boldbodycopy">DEPARTMENTS</span><span class="bodycopy"> table, select the </span><span class="boldbodycopy">DEPARTMENT_NAME</span><span class="bodycopy"> column. In the second pane from the top, order the column list by dragging and dropping so that </span><span class="boldbodycopy">EMPLOYEE_ID</span><span class="bodycopy"> is the first </span><span class="boldbodycopy">Select</span><span class="bodycopy"> list item and </span><span class="boldbodycopy">DEPARTMENT_NAME</span><span class="bodycopy"> is last. Click the </span><span class="boldbodycopy">Execute Query</span><span class="bodycopy"> button to test the query. Click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to finish and return to the Define Custom Statements screen of the Data Source Configuration Wizard. Click </span><span class="boldbodycopy">Next</span><span class="bodycopy">; test the query again (if you wish), by clicking the </span><span class="boldbodycopy">Test Query</span><span class="bodycopy"> button; and then click </span><span class="boldbodycopy">Finish</span><span class="bodycopy">.</span></p>
<p><span class="bodycopy">From the main menu, select </span><span class="boldbodycopy">Debug</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Start Without Debugging</span><span class="bodycopy">, which will open your Web browser and display your running application (see Figure 5).</span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 5" border="0" height="451" src="http://www.oracle.com/technology/oramag/oracle/09-jul/images/o49odt_f5.gif" width="610" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 5: The application running in a Web browser</span></td>
</tr>
</tbody>
</table>
<p><strong><span class="parahead1">Creating an Oracle Database Project</span> </strong></p>
<p><span class="bodycopy">You will want to store the SQL scripts for the Oracle Database schema objects the application uses and eventually check them into source control along with the application. This will allow other developers who obtain the application code to also check out and run the SQL scripts to create the Oracle schema objects the application requires.</span></p>
<p><span class="bodycopy">Before you store the SQL and application code, create a project location for the code. To add an Oracle Database project to the Visual Studio solution, first right-click the topmost node in Solution Explorer and select </span><span class="boldbodycopy">Add</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">New Project</span><span class="bodycopy"> from the context menu. Under Project Types, select </span><span class="boldbodycopy">Other Project Types</span><span class="bodycopy"> and then </span><span class="boldbodycopy">Database</span><span class="bodycopy">, and then select the </span><span class="boldbodycopy">Oracle Database Project</span><span class="bodycopy"> template. When asked to select a database reference to be stored with the project, choose the </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> connection and click </span><span class="boldbodycopy">OK</span><span class="bodycopy">.</span></p>
<p><strong><span class="parahead1">Creating a Role for the Application</span> </strong></p>
<p><span class="bodycopy">You may want to create a role that represents the privileges required to access the database objects the application uses. Using Oracle roles is a good way to ensure that application users have the correct privileges. Also, if your application later requires additional privileges, modifying a single role is much easier than making new privilege grants to each individual user. This article&rsquo;s sample application, for example, will need access to the </span><span class="boldbodycopy">EMPLOYEES</span><span class="bodycopy"> and </span><span class="boldbodycopy">DEPARTMENTS</span><span class="bodycopy"> tables.</span></p>
<p><span class="bodycopy">To create the application user role, right-click the </span><span class="boldbodycopy">Roles</span><span class="bodycopy"> node under the </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> connection, and select </span><span class="boldbodycopy">New Role</span><span class="bodycopy"> from the context menu. Enter </span><tt>EMPDEPT_WEBAPP</tt><span class="bodycopy"> in the </span><span class="boldbodycopy">Role Name</span><span class="bodycopy"> field, and then click </span><span class="boldbodycopy">Save</span><span class="bodycopy">.</span></p>
<p><span class="bodycopy">Next, grant privileges to the role you just created. Right-click the </span><span class="boldbodycopy">EMPDEPT_WEBAPP</span><span class="bodycopy"> node under the </span><span class="boldbodycopy">Roles</span><span class="bodycopy"> node, and select </span><span class="boldbodycopy">Privileges</span><span class="bodycopy"> from the context menu. When the Privilege Wizard launches, set </span><span class="boldbodycopy">Object Type</span><span class="bodycopy"> to </span><span class="boldbodycopy">Table</span><span class="bodycopy"> (see Figure 6). The </span><span class="boldbodycopy">Schema</span><span class="bodycopy"> field should be set to </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy">. Select </span><span class="boldbodycopy">Grant/Revoke privileges to a user/role on one or more database object(s)</span><span class="bodycopy">, and then in the </span><span class="boldbodycopy">Object Name(s)</span><span class="bodycopy"> list, select both </span><span class="boldbodycopy">DEPARTMENTS</span><span class="bodycopy"> and </span><span class="boldbodycopy">EMPLOYEES</span><span class="bodycopy"> (by holding down the Shift key while you click). Select </span><span class="boldbodycopy">Role</span><span class="bodycopy">, and then select </span><span class="boldbodycopy">EMPDEPT_WEBAPP</span><span class="bodycopy"> from the list of roles. </span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 6" border="0" height="592" src="http://www.oracle.com/technology/oramag/oracle/09-jul/images/o49odt_f6.gif" width="547" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 6: Granting permissions on tables to the EMPDEPT_WEBAPP role</span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">At the bottom of the dialog box, there will be a list of privileges. Select the </span><span class="boldbodycopy">DELETE</span><span class="bodycopy">, </span><span class="boldbodycopy">INSERT</span><span class="bodycopy">, </span><span class="boldbodycopy">SELECT</span><span class="bodycopy">, and </span><span class="boldbodycopy">UPDATE</span><span class="bodycopy"> privileges. Click the </span><span class="boldbodycopy">Preview SQL</span><span class="bodycopy"> button, and then click </span><span class="boldbodycopy">Add to Project</span><span class="bodycopy">. This will create a SQL script that contains the GRANT statements and will add it to the Oracle Database project. (You will use these GRANT statements in the next section.) Click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to dismiss the Preview SQL window, and then click the </span><span class="boldbodycopy">Apply</span><span class="bodycopy"> button to execute the SQL needed to grant the privileges. Then click </span><span class="boldbodycopy">OK</span><span class="bodycopy"> to dismiss the dialog box. </span></p>
<p><strong><span class="parahead1">Generating SQL Scripts</span> </strong></p>
<p><span class="bodycopy">Now generate the SQL scripts for the tables the application uses, so that you can check them into source control along with the application. In Server Explorer, under the </span><span class="boldbodycopy">CSHAY</span><span class="bodycopy"> node, while holding down the Control key, select the </span><span class="boldbodycopy">DEPARTMENTS</span><span class="bodycopy"> table, the </span><span class="boldbodycopy">EMPLOYEES</span><span class="bodycopy"> table, and the </span><span class="boldbodycopy">EMPDEPT_WEBAPP</span><span class="bodycopy"> role. With all three selected, right-click and select </span><span class="boldbodycopy">Generate Create Script to Project.</span><span class="bodycopy"> Provide a script name, and click </span><span class="boldbodycopy">OK</span><span class="bodycopy">. After the script is added, the Oracle SQL script editor will open and display the script (see Figure 7). </span></p>
<p>&nbsp;</p>
<table align="center" width="100%">
<tbody>
<tr>
<td align="center"><img alt="figure 7" border="0" height="363" src="http://www.oracle.com/technology/oramag/oracle/09-jul/images/o49odt_f7.gif" width="650" /></td>
</tr>
<tr>
<td align="center"><span class="bodycopy">Figure 7: The Oracle SQL script editor (left) and project with source control menu items (right)</span></td>
</tr>
</tbody>
</table>
<p><span class="bodycopy">Under Solution Explorer, in the </span><span class="boldbodycopy">Security</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Permissions</span><span class="bodycopy"> folder, open the script containing GRANT statements that you created earlier. Copy these GRANT statements, and paste them at the end of the just-generated SQL script. Save this script. You can now delete the GRANT script from the Permissions folder. Although it is not necessary to merge these two scripts, it is generally simpler to use one deployment SQL script for each application in source control. </span></p>
<p><strong><span class="parahead1">Adding Application and SQL Scripts into Source Control</span> </strong></p>
<p><span class="bodycopy">The first time you use source control in Visual Studio, you will need to enable it. From the main menu, select </span><span class="boldbodycopy">Tools</span><span class="bodycopy"> -&gt; </span><span class="boldbodycopy">Options</span><span class="bodycopy">, and then select </span><span class="boldbodycopy">Source Control</span><span class="bodycopy">. Under </span><span class="boldbodycopy">Current Source Control Plug-in</span><span class="bodycopy">, select the plug-in corresponding to your source control system. If you don&rsquo;t see it listed here, you will need to obtain it from the vendor and install it.</span></p>
<p><span class="bodycopy">To add your solution into source control, right-click the solution name in Solution Explorer and select </span><span class="boldbodycopy">Add Solution to Source Control</span><span class="bodycopy">. After the solution is added to source control, new icons will appear next to the filenames and source control menu items such as </span><span class="boldbodycopy">Check Out for Edit</span><span class="bodycopy"> will be available (see Figure 7). When users check out SQL scripts from source control, they will be able to run them (using a built-in SQL*Plus execution engine) by right-clicking and selecting </span><span class="boldbodycopy">Run</span><span class="bodycopy"> from the context menu. This will ensure that their database schema matches the one required by the application. </span></p>
<p><strong><span class="parahead1">Debugging Your Application&rsquo;s PL/SQL </span> </strong></p>
<p><span class="bodycopy">Although this application doesn&rsquo;t use PL/SQL, note that you can use all the powerful features of the Visual Studio debugger with your stored functions or procedures. Debugging the PL/SQL your application uses is a very important part of the application lifecycle that was covered extensively in an earlier </span><span class="italicbodycopy">Oracle Magazine</span><span class="bodycopy"> article (&ldquo;<a href="http://www.oracle.com/technology/oramag/oracle/06-sep/o56odp.html" target="_blank"><span class="bodylink">Debugging PL/SQL from .NET</span></a>&rdquo;). </span></p>
<p><strong><span class="parahead1">Performance Tuning</span> </strong></p>
<p><span class="bodycopy">Now you are ready to tune the application and its use of Oracle Database. The main performance tuning feature provided by Oracle Developer Tools for Visual Studio is Oracle Performance Analyzer. You can launch it by clicking a SYSDBA connection in Server Explorer and choosing </span><span class="boldbodycopy">Oracle Performance Analyzer</span><span class="bodycopy"> from the context menu. It monitors the use of the database under load and provides performance-improving recommendations, some of which can be implemented automatically. I&rsquo;ll be deep-diving into Oracle Performance Analyzer and performance tuning tricks in an upcoming article.</span></p>
<p><strong><span class="boldbodycopy">Christian Shay</span><span class="bodycopy"> </span></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/use-microsoft-visual-studio-for-the-complete-net-and-oracle-database-development-lifecycle-117.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Microsoft .NET vs. J2EE: How Do They Stack Up?</title>
		<link>http://www.allfreetech.com/microsoft-net/microsoft-net-vs-j2ee-how-do-they-stack-up-61.html</link>
		<comments>http://www.allfreetech.com/microsoft-net/microsoft-net-vs-j2ee-how-do-they-stack-up-61.html#comments</comments>
		<pubDate>Mon, 23 Apr 2007 03:38:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Microsoft .Net]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[J2EE]]></category>

		<guid isPermaLink="false">http://www.allfreetech.com/?p=61</guid>
		<description><![CDATA[Even if you don&#39;t write code dedicated to Microsoft platforms, you have probably heard by now about Microsoft .NET, Microsoft&#39;s latest volley in their campaign against all things non-Windows. If you&#39;ve read the media spin from Microsoft, or browsed through the scant technical material available on the MSDN site, or even if you attended the [...]]]></description>
			<content:encoded><![CDATA[<p>Even if you don&#39;t write code dedicated to Microsoft platforms, you have probably heard by now about Microsoft .NET, Microsoft&#39;s latest volley in their campaign against all things non-Windows. If you&#39;ve read the media spin from Microsoft, or browsed through the scant technical material available on the MSDN site, or even if you attended the Microsoft Professional Developers&#39; Conference (where the .NET platform was officially &quot;launched&quot;), you&#39;re probably still left with at least two big questions:</p>
<p>&nbsp;</p>
<ul>
<li>What exactly <i>is</i> the .NET platform?</li>
<li>How does the .NET architecture measure up against J2EE?</li>
</ul>
<p>And, if you think more long-term, you might have a third question rattling around your head:</p>
<ul>
<li>What can we learn from the .NET architecture about pushing the envelope of enterprise software development?</li>
</ul>
<p>The .NET framework is at a very early stage in its lifecycle, and deep details are still being eked out by the Microsoft .NET team. But we can, nevertheless, get fairly decent answers to these questions from the information that&#39;s already out there.</p>
<h3>What is it?</h3>
<p>Current ruminations about .NET in various forums are reminiscent of the fable of the three blind men attempting to identify an elephant: It&#39;s perceived as very different things, depending on your perspective. Some see .NET as Microsoft&#39;s next-generation Visual Studio development environment. Some see it as yet another new programming language (C#). Some see it as a new data-exchange and messaging framework, based on XML and SOAP. In reality, .NET wants to be all of these things, and a bit more.</p>
<p>First, let&#39;s get some concrete details. Here&#39;s one cut at an itemized list of the technical components making up the .NET platform:</p>
<ul>
<li><b>C#</b>, a &quot;new&quot; language for writing classes and components, that integrates elements of C, C++, and Java, and adds additional features, like metadata tags, related to component development.</li>
<li>A &quot;<b>common language runtime</b>&quot;, which runs bytecodes in an Internal Language (IL) format. Code and objects written in one language can, ostensibly, be compiled into the IL runtime, once an IL compiler is developed for the language.</li>
<li>A set of <b>base components</b>, accessible from the common language runtime, that provide various functions (networking, containers, etc.).</li>
<li><b>ASP+</b>, a new version of ASP that supports compilation of ASPs into the common language runtime (and therefore writing ASP scripts using any language with an IL binding).</li>
<li><b>Win Forms and Web Forms</b>, new UI component frameworks accessible from Visual Studio.</li>
<li><b>ADO+</b>, a new generation of ADO data access components that use XML and SOAP for data interchange.</li>
</ul>
<h3>How do .NET and J2EE compare?</h3>
<p>As you can see, the .NET platform has an array of technologies under its umbrella. Microsoft is ostensibly presenting these as alternatives to other existing platforms, like J2EE and CORBA, in order to attract developers to the Windows platform. But how do the comparisons play out item-by-item? One way to lay out the alternatives between .NET and J2EE is shown in the following table:</p>
<p>&nbsp;</p>
<p><center></p>
<table cellpadding="7" cellspacing="2">
<tbody>
<tr bgcolor="#666666">
<th><font color="#ffffff" size="-1">Microsoft.NET</font></th>
<th><font color="#ffffff" size="-1">J2EE</font></th>
<th><font color="#ffffff" size="-1">Key differentiators</font></th>
</tr>
<tr bgcolor="#eeeeee">
<td><font size="-1">C# programming language</font></td>
<td><font size="-1">Java programming language</font></td>
<td><font size="-1">C# and Java both derive from C and C++. Most significant features (e.g., garbage collection, hierarchical namespaces) are present in both. C# borrows some of the component concepts from JavaBeans (properties/attributes, events, etc.), adds some of its own (like metadata tags), but incorporates these features into the syntax differently. </font></p>
<p><font size="-1">Java runs on any platform with a Java VM. C# only runs in Windows for the foreseeable future. </font></p>
<p><font size="-1">C# is implicitly tied into the IL common language runtime (see below), and is run as just-in-time (JIT) compiled bytecodes or compiled entirely into native code. Java code runs as Java Virtual Machine (VT) bytecodes that are either interpreted in the VM or JIT compiled, or can be compiled entirely into native code.</font></p>
</td>
</tr>
<tr bgcolor="#eeeeee">
<td><font size="-1">.NET common components (aka the &quot;.NET Framework SDK&quot;)</font></td>
<td><font size="-1">Java core API</font></td>
<td><font size="-1">High-level .NET components will include support for distributed access using XML and SOAP (see ADO+ below).</font></td>
</tr>
<tr bgcolor="#eeeeee">
<td><font size="-1">Active Server Pages+ (ASP+)</font></td>
<td><font size="-1">Java ServerPages (JSP)</font></td>
<td><font size="-1">ASP+ will use Visual Basic, C#, and possibly other languages for code snippets. All get compiled into native code through the common language runtime (as opposed to being interpreted each time, like ASPs). JSPs use Java code (snippets, or JavaBean references), compiled into Java bytecodes (either on-demand or batch-compiled, depending on the JSP implementation).</font></td>
</tr>
<tr bgcolor="#eeeeee">
<td><font size="-1">IL Common Language Runtime</font></td>
<td><font size="-1">Java Virtual Machine and CORBA IDL and ORB</font></td>
<td><font size="-1">.NET common language runtime allows code in multiple languages to use a shared set of components, on Windows. Underlies nearly all of .NET framework (common components, ASP+, etc.). </font></p>
<p><font size="-1">Java&#39;s Virtual Machine spec allows Java bytecodes to run on any platform with a compliant JVM. </font></p>
<p><font size="-1">CORBA allows code in multiple languages to use a shared set of objects, on any platform with an ORB available. Not nearly as tightly integrated into J2EE framework.</font></p>
</td>
</tr>
<tr bgcolor="#eeeeee">
<td><font size="-1">Win Forms and Web Forms</font></td>
<td><font size="-1">Java Swing</font></td>
<td><font size="-1">Similar web components (e.g., based on JSP) not available in Java standard platform, some proprietary components available through Java IDEs, etc. </font></p>
<p><font size="-1">Win Forms and Web Forms RAD development supported through the MS Visual Studio IDE &#8211; no other IDE support announced at this writing. Swing support available in many Java IDEs and tools.</font></p>
</td>
</tr>
<tr bgcolor="#eeeeee">
<td><font size="-1">ADO+ and SOAP-based Web Services</font></td>
<td><font size="-1">JDBC, EJB, JMS and Java XML Libraries (XML4J, JAXP)</font></td>
<td><font size="-1">ADO+ is built on the premise of XML data interchange (between remote data objects and layers of multi-tier apps) on top of HTTP (AKA, SOAP). .NET&#39;s web services in general assume SOAP messaging models. EJB, JDBC, etc. leave the data interchange protocol at the developer&#39;s discretion, and operate on top of either HTTP, RMI/JRMP or IIOP.</font></td>
</tr>
</tbody>
</table>
<p></center></p>
<p>The comparisons in this table only scratch the surface. Here&#39;s an executive summary of .NET vs. J2EE:</p>
<p>Features: .NET and J2EE offer pretty much the same laundry of list of features, albeit in different ways.</p>
<p>Portability: The .NET core works on Windows only but theoretically supports development in many languages (once sub-/supersets of these languages have been defined and IL compilers have been created for them). Also, Net&#39;s SOAP capabilities will allow components on other platforms to exchange data messages with .NET components. While a few of the elements in .NET, such as SOAP and its discovery and lookup protocols, are provided as public specifications, the core components of the framework (IL runtime environment, ASP+ internals, Win Forms and Web Forms component &quot;contracts&quot;, etc.) are kept by Microsoft, and Microsoft will be the only provider of complete .NET development and runtime environments. There has already been some pressure by the development community for Microsoft to open up these specifications, but this would be counter to Microsoft&#39;s standard practices.</p>
<p>&nbsp;</p>
<hr noshade="noshade" size="1" />
<blockquote><p>Read more on the .NET platform in this in-depth interview by O&#39;Reilly Windows editor John Osborn:</p>
<p><a href="http://windows.oreilly.com/news/hejlsberg_0800.html"> <b>Deep Inside C#: An Interview with Microsoft chief architect Anders Hejlsberg</b></a>&#8211;John gets to the bottom of not only Microsoft&#39;s detailed plans for the C# programming language but also the .Net framework.</p>
</blockquote>
<hr noshade="noshade" size="1" />
<p>J2EE, on the other hand, works on any platform with a compliant Java VM and a compliant set of required platform services (EJB container, JMS service, etc., etc.). All of the specifications that define the J2EE platform are published and reviewed publicly, and numerous vendors offer compliant products and development environments. But J2EE is a single-language platform. Calls from/to objects in other languages are possible through CORBA, but CORBA support is not a ubiquitous part of the platform.</p>
<h3>The Bigger Picture</h3>
<p>These last points highlight some of the key differentiators between .NET and J2EE, and point towards Microsoft&#39;s real play here. Microsoft is doing two very notable things with .NET: It is opening up a channel to developers in other programming languages, and it is opening up a channel to non-.NET components by integrating XML and SOAP into their messaging scheme.</p>
<p>By allowing cross-language component interactions, .NET is enfranchising Perl, Eiffel, Cobol, and other programmers by allowing them to play in the Microsoft sandbox. Devotees of these languages are particularly amenable to gestures like this, since for the most part they have felt somewhat disenfranchised and marginalized in the Microsoft/Sun/Open Source wars. And by using XML and SOAP in their component messaging layer, Microsoft is bolstering their diplomatic face and adding an element of openness to their platform, providing ammunition against claims of proprietary behavior.</p>
<h3>What&#39;s the correct response?</h3>
<p><b>For Microsoft developers:</b></p>
<p>.NET is a good thing for those of you committed to Microsoft architectures. ASP+ is better than ASP, ADO+ is better, but different, than ADO and DCOM, C# is better than C and C++. The initial version of .NET won&#39;t be real until sometime in 2001, so you have some time to prepare, but this will undoubtedly become the default development environment for Microsoft platforms. And if you&#39;re developing within the Microsoft development framework now, you will undoubtedly benefit from adopting elements of the .NET framework into your architectures.</p>
<p>However, several of the goals of the .NET platform are fairly lofty and not at all guaranteed to fly, at least not in the short term. The IL common language runtime, for example, has some fairly significant hurdles to overcome before it has any real payoff for developers. Each language that wants to integrate with the component runtime has to define a subset/superset of the language that maps cleanly into and out of the IL runtime, and has to define constructs that provide the component metadata that IL requires. Then compilers (x-to-IL and IL-to-x) will have to be developed to both compile language structures (objects, components, etc.) into IL component bytecodes, and also generate language-specific interfaces to existing IL components.</p>
<p>There is some historical precedence here. Numerous bridges from non-Java languages to the Java VM have been developed, such as <a href="http://www.jpython.org/" target="new"><b>JPython</b></a>, <a href="http://www.legacyj.com/lgcyj_perc1.html" target="new"><b> PERCobol</b></a>, <a href="http://dev.scriptics.com/software/java/" target="new"><b>the Tcl/Java project</b></a>, and interestingly enough, <a href="http://www.progsoc.uts.edu.au/%7Egeldridg/ea3495.html" target="new"> <b>Bertrand Meyer</b></a> and some other Eiffel folks put together an <a href="http://www.progsoc.uts.edu.au/%7Egeldridg/eiffel/liberty/v1/n1/jp/" target="new"><b>Eiffel-to-JavaVM</b></a> system a few years back. With the possible exception of JPython, these tools have not been widely adopted, even within their respective language communities, even though they seem to offer a way to write code for the Java environment (albeit not the entire J2EE framework) using your favorite language. Why this lack of enthusiasm? I believe it&#39;s because people are hesitant to take on the headaches of adding yet another translation step from their development language to the target framework. If the Java environment is the goal, people will generally choose to learn Java. I predict that the same will be true of .NET: People will generally choose to learn C# and write .NET components in that language.</p>
<p>Another caution: Beware of performance issues with .NET&#39;s SOAP-based distributed communications. SOAP essentially means XML over HTTP. HTTP is not a high-performance data protocol, and XML implies an XML parsing layer, which implies more compute overhead. The combination of both could significantly reduce transaction rates relative to alternative messaging/communications channels. XML is a very rich, robust metalanguage for messaging, and HTTP is very portable and avoids many firewall issues. But if transaction rates are a priority for you, keep your options open.</p>
<p><b>For the Java and Open Source communities:</b></p>
<p>It would be easy to dismiss .NET as more Microsoft marketing-ware and continue on your merry way. But don&#39;t. .NET is a sign of a subtle but significant shift in Microsoft&#39;s strategy to evangelize their platforms. They have been fighting alternative frameworks and platforms at the management level pretty well, touting the usual questionable &quot;statistics&quot; about cost of ownership and seamless integration. Now they are fighting Java and open source initiatives on their own terms, putting their own spin on &quot;open&quot; and attempting to directly address the needs of developers, two things that they have been faulted for not doing very well in the past. If you consider yourself an evangelist for Java or open source platforms, then the nature of the war is changing. Be prepared.</p>
<p>Also, Microsoft&#39;s IL runtime has at least one notable, if improbable, goal: eliminate the programming language as a barrier to entry to the framework. Java eliminates the platform barrier (within limits, of course: You can&#39;t make up for missing hardware resources with software, for example), but in order to work in J2EE, you have to work in Java. .NET wants to let you use the language of your choice to build .NET applications. This is admirable, though there are big questions as to whether and when the IL approach in .NET will actually become broadly useful (see above). Regardless, this points to a weakness in the single-language J2EE approach. The importance of this weakness is questionable, but it exists nonetheless, and deserves some consideration by the Java community. If this is really desired by developers, then maybe the efforts in Java bytecode generators for non- Java languages should be organized and consolidated.</p>
<p>Focusing on J2EE, there are a few issues that should be addressed immediately in order to bolster the advantages of that platform compared to what .NET is shooting for. First, XML support needs to be integrated seamlessly into the framework. I&#39;m not talking about bolting an XML SAX/DOM parser to the set of standard services, or extending the use of XML in configuration files. XML messaging and manipulation need to be there, ready to use. Admittedly, you can use XML payloads on top of JMS messaging, but the platform doesn&#39;t facilitate this at all. The XML space is a cluttered mess of standards, de facto standards, APIs and DTDs, which is to be expected when you&#39;re dealing with a meta-language.</p>
<p>But Microsoft has put a stake in the ground with SOAP, and they&#39;re pushing hard to put something understandable and useful in the hands of developers. J2EE proponents need to do the same with their platform. One possibility that comes to mind is to add an XML messaging &quot;provider&quot; layer on top of JMS, along the lines of the pattern followed by <a href="http://java.sun.com/products/jndi" target="new"><b>Java Naming and Directory Interface</b></a>, or JNDI, with LDAP, NIS, COS Naming, etc. This in combination with a standard SOAP/BizTalk provider, an ebXML provider, etc. would be an impressive statement.</p>
<p>&nbsp;</p>
<h3><a name="clarify">Clarifications and Corrections</a></h3>
<p>Since the publication of this article in August 2000, 40 readers have responded with their own thoughts about .Net vs. J2EE. Jim Farley, the author of this article, has sifted through those comments, as well as email he&#39;s received, and added the following clarifications and corrections.</p>
<h4>Clarifications</h4>
<p>The description of C#&#39;s compilation features vs. those of Java seems to have confused some readers. To put it another way: C# code always runs natively. Java code typically runs as interpreted bytecodes, and can run natively. C# is either compiled entirely to native code, or it is compiled into the common language runtime bytecodes and then just-in-time compiled to native code during execution. Java code, on the other hand, typically runs as runtime-interpreted bytecodes (from which its cross-platform abilities spring), and can also run in a just-in-time compiled context. Some Java native-code compilers also exist (Jove, BulletTrain, JET, etc.).</p>
<p>As a side note, Microsoft claims that the default interpretive mode of Java is a liability, in that bytecodes designed for a virtual machine do not lend themselves as well to native optimization. I haven&#39;t seen any hard data to prove or disprove that claim, either generally (bytecodes vs. native-compiled languages) or specifically (Java vs. C#).</p>
<p>Several readers, in response to the call to include XML support in J2EE, mentioned the fact that J2EE 1.3 (currently in public draft) requires that any J2EE-compliant product must include Java XML SAX and DOM parsers. But this is just &quot;bolting an XML SAX/DOM parser&quot; to J2EE, as I mentioned. I was calling for it to be taken a step farther, to incorporate XML support directly in the J2EE support APIs. Ideally, J2EE-based components and services would have XML support (for messaging, interface description exports, etc.) automatically built-in, to some extent.</p>
<p>&nbsp;</p>
<h4>Corrections</h4>
<p>I state in the article that C# &quot;borrows some of the component concepts from JavaBeans.&quot; This statement can&#39;t be proven, and, as several readers pointed out, it&#39;s more likely that Microsoft based the component functionality of C# more on their own COM and VB models, with influences from other pre-existing component models. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.allfreetech.com/microsoft-net/microsoft-net-vs-j2ee-how-do-they-stack-up-61.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

