Blog Home  Home Feed your aggregator (RSS 2.0)  
A Random Walk Around .Net - Saturday, June 07, 2008
 
 Friday, May 02, 2008

Due to the fact my background is in financial markets (trading systems to be exact), I find my self continuously trying to scrounge up milliseconds by code improvements.  My weapon of choice is parallel processing or otherwise called threading.  Over the years it has been both my greatest asset any my most malevolent foe.  Many have commented on the impeding doom of mutable states and many core processors in software design; hence functional programming.

            I have aspiration to neither speak about functional programming nor give a class on threading best practices.  Instead, I am interested in providing an easier ReaderWriterLock schematic; most likely to the joy of my team.

            The “lock{}” keyword (or “SyncLock” keyword for VB.NET) is very useful and concise in its usage; though anyone trying to squeeze milliseconds knows the performance benefits of a ReaderWriterLock in many cases.  (Stop here if the previous statement doesn’t make sense to you and go Google the ReaderWriterLock.)  However, the implementation of a ReaderWriterLock requires much more code and can cause dead locks if implemented incorrectly.

            Thus, I came up with the attached solution.  It offers improvements on two fronts.  One, it allows a user to retry a function N number of times before raising an exception.  Second, it ensures the locks are acquired and released correctly.

            I am not exactly thrilled with this design because the use of anonymous methods makes for a non simple solution.  Nevertheless, I think it is better then writing the internalized code in ever method that needs to be locked.  Finally, I have not performance tested this yet; but I will post later with results.

public class ClassThanNeedsLocking
    {
        ReTryReaderWriterLock _rw = new ReTryReaderWriterLock();
        private Dictionary<double, double> _valueMap;

        public ClassThanNeedsLocking()
        {
            this._valueMap = new Dictionary<double, double>();
        }

        public void AddSomething(double key, double value)
        {
            ReTryReaderWriterLock.FunctionalityToLock temp = delegate
            {
                this._valueMap.Add(key, value);
            };
            this._rw.WriterLockFunction(temp, 100, 5, 10);
        }

        public double GetSomething(double key)
        {
            double value = 0;
            ReTryReaderWriterLock.FunctionalityToLock temp = delegate
            {
                if (this._valueMap.TryGetValue(key, out value))
                {
                    throw new ArgumentException("Key Does Not Exist.", "key");
                }
            };
            this._rw.ReaderLockFunction(temp, 100, 5, 10);
            return value;
        }

    }

    public class ReTryReaderWriterLock
    {
        public delegate void FunctionalityToLock();

        private delegate void RepeatTryLock(int timesTried);
        private ReaderWriterLock _rw = new ReaderWriterLock();
        private ILock _reader = new ReaderLock();
        private ILock _writer = new WriterLock();

        public void ReaderLockFunction(FunctionalityToLock function, int timeOutPerTry, int timesToTry, int timeToWaitBeforeTryingAgain)
        {
            LockFunction(function, timeOutPerTry, timesToTry, timeToWaitBeforeTryingAgain, this._reader);
        }

        public void WriterLockFunction(FunctionalityToLock function, int timeOutPerTry, int timesToTry, int timeToWaitBeforeTryingAgain)
        {
            LockFunction(function, timeOutPerTry, timesToTry, timeToWaitBeforeTryingAgain, this._writer);
        }

        private void LockFunction(FunctionalityToLock function, int timeOutPerTry, int timesToTry, int timeToWaitBeforeTryingAgain, ILock typeOfLock)
        {
            RepeatTryLock repeater = null;
            repeater = delegate(int timesTried)
            {
                try
                {
                    typeOfLock.Acquire(this._rw, timeOutPerTry);
                    function();
                }
                catch (ApplicationException)
                {
                    if (timesTried < timesToTry)
                    {
                        Thread.Sleep(timeToWaitBeforeTryingAgain);
                        timesTried += 1;
                        repeater(timesTried);
                        return;
                    }
                    throw;
                }
                finally
                {
                    typeOfLock.Release(this._rw);
                }
            };

            repeater(0);
        }

        private interface ILock
        {
            void Acquire(ReaderWriterLock rw, int timeOutPerTry);
            void Release(ReaderWriterLock rw);
        }

        private class ReaderLock : ILock
        {
            public void Acquire(ReaderWriterLock rw, int timeOutPerTry)
            {
                rw.AcquireReaderLock(timeOutPerTry);
            }

            public void Release(ReaderWriterLock rw)
            {
                if (rw.IsReaderLockHeld == true)
                {
                    rw.ReleaseReaderLock();
                }
            }
        }

        private class WriterLock : ILock
        {
            public void Acquire(ReaderWriterLock rw, int timeOutPerTry)
            {
                rw.AcquireWriterLock(timeOutPerTry);
            }

            public void Release(ReaderWriterLock rw)
            {
                if (rw.IsWriterLockHeld == true)
                {
                    rw.ReleaseWriterLock();
                }
            }
        }
    }
Friday, May 02, 2008 9:24:10 PM (Central Standard Time, UTC-06:00)  #    Comments [0]    | 
 Monday, April 28, 2008

            I am sure I have said this before; has anyone else noticed how little code I have written?  I have quite a bit to talk about, so tonight I will just drop all my code and screen shots unaccompanied.  Thereafter, we will spend the next few evening talking about exactly what was done.

First, I created the data contracts.

 

Second, I created the service contracts.

 

Third, I added a Silverlight browser project.

 

Fourth, I added the WPF XAML for the Silverlight front end.

 

<UserControl x:Class="DBinsor.Svc.WCF.Browser.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:grid ="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
    <Grid x:Name="LayoutRoot" Background="White" ShowGridLines="False">
        <Grid.RowDefinitions>
            <RowDefinition Height="10" />
            <RowDefinition Height="90" />
            <RowDefinition Height="50*" />
            <RowDefinition Height="50*" />
            <RowDefinition Height="10" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="50*" />
            <ColumnDefinition Width="50*" />
            <ColumnDefinition Width="10" />
        </Grid.ColumnDefinitions>
        <grid:DataGrid x:Name="CastleGrid" AlternatingRowBackground="Beige" 
                       AutoGenerateColumns="True" Grid.Row="1" Grid.Column="2" 
                       MouseLeftButtonDown="CastleGrid_MouseLeftButtonDown" />
        <grid:DataGrid x:Name="ContractGrid" AlternatingRowBackground="Beige" 
                       AutoGenerateColumns="True" Grid.Row="1" Grid.Column="1" 
                       MouseLeftButtonDown="ContractGrid_MouseLeftButtonDown"/>
        <grid:DataGrid x:Name="ComponentGrid" AlternatingRowBackground="Beige" 
                       AutoGenerateColumns="True" Grid.Row="2" Grid.Column="2" 
                       MouseLeftButtonDown="ComponentGrid_MouseLeftButtonDown" />
        <grid:DataGrid x:Name="ImplementationGrid" AlternatingRowBackground="Beige" 
                       AutoGenerateColumns="True" Grid.Row="2" Grid.Column="1" />
        <grid:DataGrid x:Name="ComponentParametersGrid" AlternatingRowBackground="Beige" 
                       AutoGenerateColumns="True" Grid.Row="3" Grid.Column="2" 
                       CanUserResizeColumns="True" />
        <grid:DataGrid x:Name="ContractParametersGrid" AlternatingRowBackground="Beige" 
                       AutoGenerateColumns="True" Grid.Row="3" Grid.Column="1" 
                       CanUserResizeColumns="True" />
    </Grid>
</UserControl>

Fifth, I hooked the WCF Service to the Silverlight browser.

 

using System;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using DBinsor.Svc.WCF.Browser.DatabaseProxy;

namespace DBinsor.Svc.WCF.Browser
{
    public partial class Page : UserControl
    {
        DatabaseServiceContractClient _dscc;
        Castle _selectedCastle;
        Contract _selectedContract;
        Component _selectedComponent;

        public Page()
        {
            InitializeComponent();
            this._dscc = new DatabaseServiceContractClient();
            this._dscc.DemandCastlesCompleted 
                += new EventHandler<DemandCastlesCompletedEventArgs>(_dscc_DemandCastlesCompleted);
            this._dscc.DemandComponentParametersCompleted
                += new EventHandler<DemandComponentParametersCompletedEventArgs>(_dscc_DemandComponentParametersCompleted);
            this._dscc.DemandComponentsCompleted
                += new EventHandler<DemandComponentsCompletedEventArgs>(_dscc_DemandComponentsCompleted);
            this._dscc.DemandContractParametersCompleted
                += new EventHandler<DemandContractParametersCompletedEventArgs>(_dscc_DemandContractParametersCompleted);
            this._dscc.DemandContractsCompleted
                += new EventHandler<DemandContractsCompletedEventArgs>(_dscc_DemandContractsCompleted);
            this._dscc.DemandImplementationsCompleted
                += new EventHandler<DemandImplementationsCompletedEventArgs>(_dscc_DemandImplementationsCompleted);

            LoadPrimaryTables();
        }

        private void LoadPrimaryTables()
        {
            this._dscc.DemandCastlesAsync();
            this._dscc.DemandContractsAsync();
        }

        private void _dscc_DemandCastlesCompleted(object sender, DemandCastlesCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                HtmlPage.Window.Alert(e.Error.Message);
                return;
            }

            if (e.Result.Count == 0)
            {
                return;
            }

            this.CastleGrid.ItemsSource = e.Result;
        }       
        
        private void _dscc_DemandComponentParametersCompleted(object sender, DemandComponentParametersCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                HtmlPage.Window.Alert(e.Error.Message);
                return;
            }

            if (e.Result.Count == 0)
            {
                return;
            }

            this.ComponentParametersGrid.ItemsSource = e.Result;
        }
        
        private void _dscc_DemandComponentsCompleted(object sender, DemandComponentsCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                HtmlPage.Window.Alert(e.Error.Message);
                return;
            }

            if (e.Result.Count == 0)
            {
                return;
            }

            this.ComponentGrid.ItemsSource = e.Result;
        }

        private void _dscc_DemandContractParametersCompleted(object sender, DemandContractParametersCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                HtmlPage.Window.Alert(e.Error.Message);
                return;
            }

            if (e.Result.Count == 0)
            {
                return;
            }

            this.ContractParametersGrid.ItemsSource = e.Result;
        }

        private void _dscc_DemandContractsCompleted(object sender, DemandContractsCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                HtmlPage.Window.Alert(e.Error.Message);
                return;
            }

            if (e.Result.Count == 0)
            {
                return;
            }

            this.ContractGrid.ItemsSource = e.Result;
        }

        private void _dscc_DemandImplementationsCompleted(object sender, DemandImplementationsCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                HtmlPage.Window.Alert(e.Error.Message);
                return;
            }

            if (e.Result.Count == 0)
            {
                return;
            }

            this.ImplementationGrid.ItemsSource = e.Result;
        }

        private void CastleGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            object temp = CastleGrid.SelectedItem;

            if (temp == null)
            {
                return;
            }

            this._selectedCastle = temp as Castle;

            this._dscc.DemandComponentsAsync(this._selectedCastle);
        }

        private void ContractGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            object temp = ContractGrid.SelectedItem;

            if (temp == null)
            {
                return;
            }

            this._selectedContract = temp as Contract;

            this._dscc.DemandImplementationsAsync(this._selectedContract);
            this._dscc.DemandContractParametersAsync(this._selectedContract);
        }

        private void ComponentGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            object temp = ComponentGrid.SelectedItem;

            if (temp == null)
            {
                return;
            }

            this._selectedComponent = temp as Component;

            this._dscc.DemandComponentParametersAsync(this._selectedComponent);
        }
    }
}

Sixth, I used LINQ to Extract Data from the Entity Framework.

 

using System.Linq;


namespace DBinsor.Svc.WCF.BusinessLogic
{
    public static class DatabaseToDataContractGenerator
    {
        public static DataContracts.Castles GetCastles()
        {
            using (DataAccess.Model.Entities db =
                   new DataAccess.Model.Entities())
            {
                DataContracts.Castles ret = new DataContracts.Castles();
                var dataCastles = from castle in
                                      db.Castle
                                  select castle;

                foreach (DataAccess.Model.Castle dataCastle in dataCastles)
                {
                    DataContracts.Castle serviceCastle =
                        new DataContracts.Castle();
                    serviceCastle.id = dataCastle.Id;
                    serviceCastle.name = dataCastle.Name;
                    ret.Add(serviceCastle);
                }

                return ret;
            }
        }

        public static DataContracts.Components GetComponents(DataContracts.Castle castle)
        {
            using (DataAccess.Model.Entities db =
                   new DataAccess.Model.Entities())
            {
                int temp;
                DataContracts.Components ret = new DataContracts.Components();
                var dataComponents = from component in
                                         db.Components
                                     where component.Castle.Id == castle.id
                                     select component;

                foreach (DataAccess.Model.Components dataComponent in dataComponents)
                {
                    DataContracts.Component serviceComponent =
                        new DataContracts.Component();
                    serviceComponent.id = dataComponent.Id;
          
                    int.TryParse(dataComponent.InitialPoolSize.ToString(), out temp);
                    serviceComponent.initialPoolSize = temp;
                    serviceComponent.inspectionBehavior = dataComponent.InspectionBehavior;
                    serviceComponent.lifestyle = dataComponent.Lifestyle;
                    int.TryParse(dataComponent.MaxPoolSize.ToString(), out temp);
                    serviceComponent.maxPoolSize = temp;
                    serviceComponent.Castle = castle;
                    serviceComponent.Implementation = new DataContracts.Implementation();
                    //todo: Add Implementation Name
                    ret.Add(serviceComponent);
                }

                return ret;
            }
        }

        public static DataContracts.ComponentParameters GetComponentParameters(DataContracts.Component component)
        {
            using (DataAccess.Model.Entities db =
                   new DataAccess.Model.Entities())
            {
                DataContracts.ComponentParameters ret = new DataContracts.ComponentParameters();

                var dataComponentParameters = from componentParameter in
                                                 db.ComponentParameters
                                             where componentParameter.Components.Id == component.id
                                             select componentParameter;

                foreach (DataAccess.Model.ComponentParameters dataComponentParameter in dataComponentParameters)
                {
                    DataContracts.ComponentParameter serviceComponentParameter =
                        new DataContracts.ComponentParameter();
                    serviceComponentParameter.Component = component;
                    serviceComponentParameter.overrideValue = dataComponentParameter.OverrideValue;
                    //todo: Add Contract Parameter Name
                    ret.Add(serviceComponentParameter);
                }

                return ret;
            }
        }


        public static DataContracts.Contracts GetContracts()
        {
            using (DataAccess.Model.Entities db =
                   new DataAccess.Model.Entities())
            {
                DataContracts.Contracts ret = new DataContracts.Contracts();
                var dataContracts = from contract in
                                      db.Contracts
                                  select contract;

                foreach (DataAccess.Model.Contracts dataContract in dataContracts)
                {
                    DataContracts.Contract serviceContract =
                        new DataContracts.Contract();
                    serviceContract.id = dataContract.Id;
                    serviceContract.contractNamespace = dataContract.Namespace;
                    serviceContract.contractInterface = dataContract.Interface;
                    ret.Add(serviceContract);
                }

                return ret;
            }
        }

        public static DataContracts.Implementations GetImplementations(DataContracts.Contract contract)
        {
            using (DataAccess.Model.Entities db =
                   new DataAccess.Model.Entities())
            {
                DataContracts.Implementations ret = new DataContracts.Implementations();

                var dataImplementations = from implementation in
                                              db.Implementations
                                          where implementation.Contracts.Id == contract.id
                                          select implementation;

                foreach (DataAccess.Model.Implementations dataImplementation in dataImplementations)
                {
                    DataContracts.Implementation serviceImplementation =
                        new DataContracts.Implementation();
                    serviceImplementation.name = dataImplementation.Name;
                    serviceImplementation.Contract = contract;
                    ret.Add(serviceImplementation);
                }

                return ret;
            }
        }

        public static DataContracts.ContractParameters GetContractParameters(DataContracts.Contract contract)
        {
            using (DataAccess.Model.Entities db =
                   new DataAccess.Model.Entities())
            {
                DataContracts.ContractParameters ret = new DataContracts.ContractParameters();

                var dataContractParameters = from contractParameter in
                                              db.ContractParameters
                                          where contractParameter.Contracts.Id == contract.id
                                          select contractParameter;

                foreach (DataAccess.Model.ContractParameters dataContractParameter in dataContractParameters)
                {
                    DataContracts.ContractParameter serviceContractParameter =
                        new DataContracts.ContractParameter();
                    serviceContractParameter.name = dataContractParameter.Name;
                    serviceContractParameter.defaultValue = dataContractParameter.DefaultValue;
                    serviceContractParameter.Contract = contract;
                    ret.Add(serviceContractParameter);
                }

                return ret;
            }
        }

    }
}

Seventh, I had to add the CSDL, MSL and SSDL files to my host project to make things work.  Still need to think about a better way to do this:

 

  

<connectionStrings>
     <add name="DBinsor.Svc.WCF.DataAccess.Properties.Settings.WindsorDataBaseConnectionString"
         connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\WindsorDataBase.mdf;Integrated Security=True;User Instance=True"
         providerName="System.Data.SqlClient" />
 </connectionStrings>

Finally, Here is the End Product:

Monday, April 28, 2008 8:55:50 PM (Central Standard Time, UTC-06:00)  #    Comments [0]    | 
 Sunday, April 27, 2008

            Both of these technologies are very powerful ways of implementing object to relational mapping.  With LINQ to SQL, I feel it should be built on top of “views” so when one makes table changes the whole system doesn’t come crashing down.  The Entity Framework seems to cover such scenarios in its mapping functionality.

            However, neither seems to place nice in the n-tier model.  That is, in which DLL should the EDMX or the DBML files belong?  In one sense they do data access and in another they define business entities.  On the one hand, I suppose one could put them in the data access layer and use business logic to convert those entities to ones defined in the business tier.  Yet, that seems like a lot of work and bit un-refactored.  On the other hand, we could put them in the business layer, but then we are doing data access from the business layer.

            I would like to see a system where the data access is decoupled from the entities.  For now, I am going to add these files to the data access layer.  Furthermore, I am going to add the Data Contracts from my service layer to my business layer: not really happy about that.  However, this will allow me the ability to use my business layer as a translator to expose my entities to the Silverlight frontend.

            I could add the data access to my service implementation project, but I think it is better to do such translations in the business layer.  Obviously, we could build duplicate entities in the business layer and translate twice, then again to much work and not that refactored.

Sunday, April 27, 2008 7:00:28 PM (Central Standard Time, UTC-06:00)  #    Comments [0]    | 
 Saturday, April 26, 2008

I am using Windows XP Professional, Visual Studio 2008 Professional, IE 7.0 and Silverlight 2.0.  The weird thing is I must delete my history every time in IE before I can view changes to my Silverlight application.  I am assuming that is caching the XAP file in the browser and not reloading it when I make changes.  I am sure there is a work around, but I have not had time to look for it.  Any ideas?

Saturday, April 26, 2008 6:33:42 PM (Central Standard Time, UTC-06:00)  #    Comments [0]    | 
 Friday, April 25, 2008

It has been a couple weeks since my last post.  As with many juggling family, career, socializing and hobbies can be quite a circus act.  Nonetheless, the DBinsor solution has not yet reached a critical mass for usability.

It is great that one can pull the configuration from the database, but how does one put it there in the first place.  Moreover, this process of insertion should be intuitive as well as allow for a holistic view of the data.

The end user of choice for DBinsor would be a system which utilized a plug in methodology meshed with a SOA topology.  More specifically, one who utilizes services contracts where the implementation is defined by configuration settings.  Thus utilizing DBinsor as a centralized configuration store should be quite appealing.

With this type of user in mind, a web user interface is the only sensible approach.  For example, an administrator could seamlessly change configurations of any service from any computer with accessibility to the DBinsor server without installing a windows client.

We could have chosen web forms or the new model view controller framework; however Silverlight 2.0 seems the most intriguing.  Moreover, we get the chance to work with XAML instead of HTML and Java Script.  The “Learn” section has been quite helpful in the process of learning Silverlight.

We will post something once we have basic functionality working.

Friday, April 25, 2008 5:15:16 PM (Central Standard Time, UTC-06:00)  #    Comments [0]    | 
 Sunday, April 13, 2008

            We uploaded the working code to the Code Gallery Site.  This should allow readers of this blog the ability to see exactly what is happening underneath the hood.  One very interesting use of this application is a centralized configuration repository.  That is because of the parameters feature of the Windsor Library, a user should use those instead of a configuration file.

If anyone is interested in contributing to this project, please send me an email.  The next features will include:

·         A web GUI to access the database

·         A windows application using reflection to auto generate data from an assembly

·         Using card space to add security

·         Exposing all the features of the container.

·         Performance Enhancements

·         And others.

We have also added Code Gallery to Navigation Section.

Sunday, April 13, 2008 6:07:53 PM (Central Standard Time, UTC-06:00)  #    Comments [0]    | 
 Saturday, April 12, 2008

To test this, we decided to setup an interface and two derived classes.  Then we added corresponding data to the database (we will build an intuitive graphical user interface eventually).  Finally, we used the Container Singleton class to resolve our types and print out the results.

 

            Class Diagram:

Database:

 

            Windsor Component View

Lookup Name

Namespace

Contract

Implementation

Component Id

Contract Id

Test1

DBinsor.Svc.WCF.Client

IMath

Add

1844d2e0-455e-4d44-a9ff-1c63f78e407b

0aa71152-91d4-4e8f-a4a0-4124a98e2851

Test1

DBinsor.Svc.WCF.Client

IMath

Subtract

5c3ee79a-926c-4438-8391-44a437bd8f47

0aa71152-91d4-4e8f-a4a0-4124a98e2851