in

ASP.NET Weblogs

Keith 'StarPilot' Barrows (Tech Blog)

Musings on Microsoft Technologies and other technical things
  • Missed my High School Reunion :(

    Wish I had thought to google for this.  Another classmate just left me a message on MySpace and the link to my HS Reunion site.  <sigh/>

    With all of this technology at hand it is still hard to know when periodic events like this happen.  How does everyone else stay abreast of events like this?
    Cross posted from my blog at http://schema.sol3.net/kbarrows
    Posted Oct 10 2008, 12:59 PM by StarPilot with no comments
    Filed under:
  • Loading XML with accented characters breaks System.XmlDocument.Load()

    It took me a bit of time but I finally found a solution for loading a XML file that has accented characters (like áéíóúâä) into a UTF-8 format.  I'm loading data for a client and it ended up having a name in it with an accented e character.  For the first time on this project System.XmlDocument.Load() was blowing up.  With a lot of Googling I finally found a link that gave me, what I hope, is the solution for this problem.  For now it is working so I'll go with it.  The link to the article I found is in the code sample below as well as the image to the left.  The magic happens by reading in while enforcing a double-byte encoding then saving out in an encoding that gives the visual representation we, in the US, would expect.

    Hope this helps someone else.


       1:  #region Fix Character Encodings
       2:  // Need to drop accented characters back to normal characters...
       3:  // reference:  http://www.codeproject.com/KB/cs/EncodingAccents.aspx //
       4:  StreamReader sr = new StreamReader(_pfInfo.WorkingFile, Encoding.GetEncoding("iso-8859-1"));
       5:  string fileContents = sr.ReadToEnd();
       6:  sr.Close();
       7:  sr = null;
       8:   
       9:  StreamWriter sw = new StreamWriter(_pfInfo.WorkingFile, false, Encoding.GetEncoding("iso-8859-8"));
      10:  sw.Write(fileContents);
      11:  sw.Flush();
      12:  sw.Close();
      13:  sw = null;
      14:  #endregion
    Cross posted from my blog at http://schema.sol3.net/kbarrows
  • Managed Extensibility Framework (MEF) is on CodePlex

    The Managed Extensibility Framework (MEF) is a new library in .NET that enables greater reuse of applications and components. Using MEF, .NET applications can make the shift from being statically compiled to dynamically composed. If you are building extensible applications, extensible frameworks and application extensions, then MEF is for you.

    I've been doing a few projects with a plug-in architecture and am going to be playing with this to see how I can benefit from it. Hopefully, I'll post some stuff out here as well on this new journey.

    Cross posted from my blog at http://schema.sol3.net/kbarrows
  • SQL Not In Revisited

    I always seem to struggle with a NOT IN clause when there are more than one column to compare.  This, of course, comes up when I am trying to get records from one set that are NOT IN another set and the comparison has to be done across multiple columns.  For instance, if I want to compare table 1 (users) against table 2 (importedUsers) and I want to see if the mandatory fields are there and *NOT* work with those that fail I usually ended up doing a cursor.  But - there is a much easier way to do it and it does need a cursor!  Thanks to David Penton for pointing me in this direction!

    DECLARE @impUsers TABLE(empID VARCHAR(50), hireDate SMALLDATETIME, userNew BIT, userChange BIT, userTerm BIT)

    INSERT INTO @impEmpTbl
    ( [empID]
    , [hireDate]
    , [userNew]
    , [userChange]
    , [userTerm]
    )
    SELECT i.empID, i.hireDate, 0, 1, 0
      FROM [ImportUsers] i
    INNER JOIN Users u ON i.[empID] = u.[empID]
    WHERE NOT EXISTS (SELECT 1
                         FROM [Users] u2
                        WHERE u2.[empID]         = i.[empID]
                          AND u2.[lastName]      = i.[lastName]
                          AND u2.[firstName]     = i.[firstName]
                          AND t2.[countryInfo]   = i.[countryInfo]
                          AND t2.[emailAddress]  = i.[emailAddress]
                          AND t2.[region]        = i.[region])

    Sweet, simple and elegant.  The above query will produce a new record in the temp table for each record that has one or more changes across the 6 fields I am comparing in the NOT EXISTS clause.  What is happening inside the parenthesis is the elegant part.  The SQL Query Engine is comparing one row from the Import table to all rows in the Users (2) table.  If it finds a match then it returns 1 - which means it does exist.  This negates the overall WHERE clause and does not insert it into the temp table.  When doing this in a cursor it was taking 30-45 seconds.  As a T-SQL query it takes less than 3 seconds.  That's an order of magnitude faster!

    Cross posted from my blog at http://schema.sol3.net/kbarrows
    Posted Aug 27 2008, 11:52 AM by StarPilot with no comments
    Filed under:
  • SQL XML - TreeView

    I sometimes forget how to do an XML output formed in a tree when dealing with a single table parent/child relationship.  There is a great explanation on SQL Server Central on *how* to do this.  I am mainly capturing the link and the SQL I just generated to do this.  This query will drill down 12 levels at the most.  Just alter the case statement (pivot) to go deeper.

    ALTER PROC getOrgUnitTreeAsXml
    AS
    BEGIN
        ;WITH OrgUnit1
        AS
        (
            SELECT
                0 AS [Level],
                [OrgUnitId],
                [orgUnitParentID],
                [orgUnit],
                CAST( [orgUnitID] AS VARBINARY(MAX)) AS Sort
            FROM [orgUnit]
            WHERE [orgUnitParentID] IS NULL
            UNION ALL
            SELECT
                [Level] + 1,
                p.[OrgUnitId],
                p.[orgUnitParentID],
                p.[orgUnit],
                CAST( SORT + CAST(p.[orgUnitID] AS BINARY(4)) AS VARBINARY(MAX))
            FROM [orgUnit] p
            INNER JOIN OrgUnit1 c ON p.[orgUnitParentID] = c.[OrgUnitId]
        )
        ,  OrgUnit2 AS
        (
            SELECT
                [Level] + 1 AS Tag,
                [OrgUnitId],
                [orgUnitParentID],
                [orgUnit],
                sort
            FROM OrgUnit1
        )
        , OrgUnit3 AS
        (
            SELECT
                *,
                (SELECT Tag FROM OrgUnit2 r2 WHERE r2.[OrgUnitId] = r1.[orgUnitParentID]) AS ParentTag
            FROM OrgUnit2 r1
        )
        SELECT Tag, ParentTag as Parent,
        CASE WHEN tag = 1 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!1!id',
            CASE WHEN tag = 1 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!1!name',
        CASE WHEN tag = 2 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!2!id',
            CASE WHEN tag = 2 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!2!name',
        CASE WHEN tag = 3 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!3!id',
            CASE WHEN tag = 3 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!3!name',
        CASE WHEN tag = 4 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!4!id',
            CASE WHEN tag = 4 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!4!name',
        CASE WHEN tag = 5 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!5!id',
            CASE WHEN tag = 5 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!5!name',
        CASE WHEN tag = 6 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!6!id',
            CASE WHEN tag = 6 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!6!name',
        CASE WHEN tag = 7 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!7!id',
            CASE WHEN tag = 7 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!7!name',
        CASE WHEN tag = 8 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!8!id',
            CASE WHEN tag = 8 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!8!name',
        CASE WHEN tag = 9 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!9!id',
            CASE WHEN tag = 9 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!9!name',
        CASE WHEN tag = 10 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!10!id',
            CASE WHEN tag = 10 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!10!name',
        CASE WHEN tag = 11 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!11!id',
            CASE WHEN tag = 11 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!11!name',
        CASE WHEN tag = 12 THEN [OrgUnitId] ELSE NULL END AS 'OrgUnit!12!id',
            CASE WHEN tag = 12 THEN [orgUnit] ELSE NULL END AS 'OrgUnit!12!name'
        FROM OrgUnit3
        ORDER BY sort
        FOR XML EXPLICIT
    END
    GO

    Cross posted from my blog at http://schema.sol3.net/kbarrows
    Posted Aug 25 2008, 04:52 PM by StarPilot with no comments
    Filed under: ,
  • Microsoft's Velocity - Caching turned up a notch

    velocity

    Microsoft just released it's CTP-1 of a new caching product code named Velocity.  It is a distributed caching technology that should add extra velocity to your ASP.NET applications.

    Summary: “Velocity” is a distributed in-memory application cache platform for developing scalable, available, and high-performance applications. “Velocity” fuses memory across multiple computers to give a single unified cache view to applications. Applications can store any serializable CLR object without worrying about where the object gets stored. Scalability can be achieved by simply adding more computers on demand. “Velocity” also allows for copies of data to be stored across the cluster, thus protecting data against failures. “Velocity” can be configured to run as a service accessed over the network or can be run embedded with the distributed application. “Velocity” includes an ASP.NET session provider object that enables ASP.NET session objects to be stored in the distributed cache without having to write to databases. This increases the performance and scalability of ASP.NET applications (17 printed pages)

    Some more resources:

    Cross posted from my blog at http://schema.sol3.net/kbarrows
  • VS 2008 and .NET FX 3.5 SP1 (Beta)

    The beta has been released.  Scott Guthrie has a huge list of what to expect.

    (The image should link you directly to the download page.)

     
    Cross posted from my blog at http://schema.sol3.net/kbarrows
  • ALT.NET?

    alt.net-Big

    Do you know what happens when you read blogs?  You mine expands, dude!  Like Woaoooo...

    Something Scott Hanselman posted caught my attention.  He posted about Alt.Net.  I am now searching out all things ALT.NET to make sure my head was wrapped around the ideas in a way that makes sense to me.  Pass the word...

    Cross posted from my blog at http://schema.sol3.net/kbarrows
    Posted Apr 25 2008, 05:29 PM by StarPilot with no comments
    Filed under:
  • Using multiple config files in one application

    I'm supporting an ASP (Application Service Provider) style application for my company.  Instead of putting each client's settings into a single config file, I wanted to have the main config file point to each clients configuration.  After a bit of digging, I came up with a solution that works.  I don't know if it is the best solution but it does work.  My main config file now looks like:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <configSections>
            <section name="FeedProvider"
                     type="Sol3.Feed.Provider.FeedProviderConfiguration, Sol3.Feed.Provider"
                     allowDefinition="MachineToApplication" />
        </configSections>
        <FeedProvider defaultProvider="FeedProvider01">
            <providers>
                <add name="FeedProvider01"
                     type="Sol3.Feed.FeedProvider01, Sol3.Feed"
                     connectionStringName="ConnString"
                     description="Client 01 Feed Provider" />
                <add name="FeedProvider02"
                     type="Sol3.Feed.FeedProvider02, Sol3.Feed"
                     connectionStringName="connString"
                     description="Client 02 Feed Provider" />
            </providers>
        </FeedProvider>
        <appSettings>
            <add key="EnvironmentName" value="dev"/>
            <!-- add key="EnvironmentName" value="qa"/ -->
            <!-- add key="EnvironmentName" value="uat"/ -->
            <!-- add key="EnvironmentName" value="prod"/ -->
            <add key="Clients" value="3"/>
            <add key="Client 1" value="Client Name 01"/>
            <add key="Client 2" value="Client Name 02"/>
            <add key="Client 3" value="Client Name 03"/>
        </appSettings>
    </configuration>
    A client config file now looks like:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <connectionStrings>
            <clear />
            <add name="connString" connectionString="[client connection string]" />
        </connectionStrings>
    
        <appSettings>
            <add key="WatchPath" value="C:\Feeds\ClientN"/>
            <add key="FileName" value="sample.csv"/>
            <add key="FileType" value="*.csv;*.txt"/>
            <add key="StartTime" value="05:00"/>
            <add key="EndTime" value="05:00"/>
            <add key="ArchiveDays" value="30"/>
        </appSettings>
    </configuration>
    I have a service that will iterate through the appSettings and setup a file handler for each client.  The service creates a new ClientInfo object for each client:
            #region Constructor
            public Service()
            {
                _clientInfo = new Dictionary<string, ClientInfo>();
                _clientList = new List<string>();
    
                _clientCount = Convert.ToInt32(ConfigurationManager.AppSettings.Get("Clients").ToString());
                _environmentName = ConfigurationManager.AppSettings.Get("EnvironmentName").ToString();
                for (int i = 0; i < _clientCount; i++)
                {
                    string appKey = String.Format("Client {0}", i+1);
                    string clientName = ConfigurationManager.AppSettings.Get(appKey).ToString();
                    ClientInfo thisInfo = new ClientInfo(clientName, _environmentName);
                    _clientList.Add(clientName);
                    _clientInfo.Add(clientName, thisInfo);
                }
            }
            #endregion
    

    This is the ClientInfo Class and contains the code to read from another config file:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Configuration;
    using ITMS.Feed;
    using System.IO;
    using System.Diagnostics;
    
    namespace TestHarness
    {
        public class ClientInfo
        {
            #region Declarations
            private Dictionary<string, object> _config;
            private Handler _handler;
            #endregion
    
            #region Constructor
            public ClientInfo(string clientName, string environmentName)
            {
                clientName = clientName.Replace(" ", "_");
                ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
                fileMap.ExeConfigFilename = String.Format("{0}_{1}.config", clientName, environmentName);  // relative path names possible
    
                if (!File.Exists(Environment.CurrentDirectory + "\\" + fileMap.ExeConfigFilename))
                {
                    EventLog.WriteEntry("TestHarness.ClientInfo"
                        , String.Format("{0} was not found!", fileMap.ExeConfigFilename)
                        , EventLogEntryType.Information);
                    return;
                }
    
                // Open another config file
                Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
                // Get the app settings section...
                AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings");
    
                // Get configuration settings and start file watcher for this client...
                _config = new Dictionary<string, object>();
    
                // read/write from it as usual
                _config.Add("connString", config.ConnectionStrings.ConnectionStrings[0].ConnectionString);
                _config.Add("WatchPath", section.Settings["WatchPath"].Value.ToString());
                _config.Add("FileType", section.Settings["FileType"].Value.ToString());
                _config.Add("StartTime", Convert.ToDateTime(section.Settings["StartTime"].Value.ToString()));
                _config.Add("EndTime", Convert.ToDateTime(section.Settings["EndTime"].Value.ToString()));
    
                _handler = new Handler(_config);
                _handler.Start();
            }
            #endregion
        }
    }

    There is still a lot I can do to this but this is the basics of handling a config file that is not your app or web config.  Enjoy.

    Cross posted from my blog at http://schema.sol3.net/kbarrows
  • Latest build of the ASP.NET MVC source on CodePlex

      
     

    Come and get it!  If you are a MVC developer and really want to dig into the core of MVC then go directly to CodePlex and get the codeScott Guthrie has a LOT more details on his blog.

    Cross posted from my blog at http://schema.sol3.net/kbarrows
More Posts Next page »