Sunday, June 29, 2014

Proxy Class For Consuming RESTful Services

About 2 years ago, I wrote a blog post about using generics to create an easy-to-use WCF proxy class (click here: A Generic WCF Proxy Class).

A few months ago, I had the need to consume several RESTful web services that made use of JSON. Wanting to make is as easy to use as ProxyBase, the generic WCF proxy class that I posted 2 years ago, I decided to write another base class for RESTful web service access. I call it ProxyBaseREST.

There are several things you will need to add to your project references that aren't normally added when you create a new class library project (and also remember to put using statements for them at the top of your class). One is System.Net, because we'll need to make use of the WebClient, which lives in that namespace. Since we'll also be dealing with JSON, you need a JSON library. I've made use of Json.NET (the assembly is called NewtonSoft.Json.DLL), which is widely used. It's free open-source and you can download it here: https://json.codeplex.com/ And, two more, System.Xml and System.Xml.Linq, since we'll be converting JSON to either XNode or XmlNode.

So, here's the class I wrote:

public class ProxyBaseREST
{
    #region Declarations and Constructor

    protected string BaseAddress;
    protected string Parameters = "";

    public ProxyBaseREST(string baseAddress)
    {
        this.BaseAddress = baseAddress;
    }

    #endregion

    #region Methods

    protected string GetJSON()
    {
        try
        {
            WebClient WC = new WebClient();
            WC .Headers["Content-type" ] = "application/json";
            //string CallString = this.ParseParameters();

            Stream stream = WC.OpenRead( this.BaseAddress + this .Parameters);

            StreamReader reader = new StreamReader(stream);
            string json = reader.ReadToEnd();
            stream .Close();

            if (json == "[]")
                json = "" ;
            return json;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error in Web Service call: {0}{1}" , this.BaseAddress, this.Parameters);
            Console.WriteLine(ex.Message);
            return "" ;
        }
    }
    protected string GetDeserializedJSON(string rootNode)
    {
        string json = this.GetJSON();
        string xml = "";
        try
        {
            xml = this .DeserializeAsXNode(json, rootNode);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error Deserializing JSON RootNode '{0}' in Web Service call: {1}{2}", rootNode, this.BaseAddress, this.Parameters);
            Console.WriteLine(ex.Message);
            xml = "" ;
        }

        return xml;
    }
    protected string DeserializeAsXNode(string json, string rootNode)
    {
        if (string.IsNullOrEmpty(json)== false)
        {
            XNode node = JsonConvert.DeserializeXNode(json, rootNode);
            return node.ToString();
        }
        else
            return "" ;
    }
    /// <summary>
    /// Used for mal-formed JSON that lacks a root node
    /// </summary>
    /// <param name="json"></param>
    /// <param name="rootNode"></param>
    /// <returns></returns>
    protected string GetDeserializedJSON(string json, string rootNode)
    {
        string xml = "";
        try
        {
            if (string.IsNullOrEmpty(json) == false)
            {
                string RootAndJson = "{\"" + rootNode + "\":" + json + "}";
                System .Xml.XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(RootAndJson, rootNode);
                xml = myXmlNode.OuterXml;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error Deserializing JSON RootNode '{0}' in Web Service call: {1}{2}", rootNode, this.BaseAddress, this.Parameters);
            Console.WriteLine(ex.Message);
            xml = "" ;
        }

        return xml;
    }

    #endregion
}

You'll note that the ProxyBaseREST class makes use of a couple of JsonConvert static methods to convert the JSON format to an XML string. You can change this if you'd like to return XNode or XmlNode, but I prefer strings because I typically use XML to fill a DataSet, which is easily done with an XML string. You can obviously change the methods to return whatever kind of XML you would normally use in your applications.

Now all you have to do is create a sub-class of ProxyBaseREST, add the methods you need to call and you're done. Here's a sample Proxy:

public class MyProxy : ProxyBaseREST
{
    #region Declarations and Constructor

    // constructor
    public MyProxy(string baseAddress) : base(baseAddress)
    {
    }

    #endregion

    #region Methods

    public string GetDataNoParms()
    {
        this.Parameters = "GetData";
        string xml;

        // use one or the other of these two methods
        // comment out (or remove) the one you don't want, obviously

        // this returns a string that is formatted into XML
        xml = this.GetDeserializedJSON("root"); // this "root node" can be called anything

        // this returns a string in the JSON format, just as you've received it from the web service call
        xml = this.GetJSON();

        return xml;
    }
    public string GetDataWithParms(string CustomerName, int CustomerID, bool PreferredCustomer)
    {
        string parms = string.Format("CustomerName={0} CustomerID={1} PreferredCustomer={2}", CustomerName, CustomerID, PreferredCustomer);
        this.Parameters = "GetData?params=" + parms;
        string xml;

        // same two choices as above
        xml = this.GetDeserializedJSON("root");
        xml = this.GetJSON();

        // And here's another situation. You might have mal-formed JSON returned from the web service. 
        // This is fine for just returning the JSON, maybe. But, if you need to serialize it
        // to XML, you'll need to do something extra.
        // The ProxyBaseREST class has a method for that as well, use it in conjunction with the GetJSON() method:
        xml = this.GetDeserializedJSON(this.GetJSON(), "root"); // this "root node" can be called anything

        return xml;
    }

    #endregion
}

And then, you'd make web service calls like this:

public class TestingMyProxy
{
    #region Declarations

    // In real-life, you'd get the address from the appSettings in your config file.
    protected string WebServiceAddress = @"http://192.168.1.161:7777/"; 
    protected MyProxy myProxy;

    #endregion

    #region Constructor

    public TestingMyProxy()
    {
        this.myProxy = new MyProxy(this.WebServiceAddress);
    }

    #endregion

    #region Call Proxy Methods

    public void TestProxyMethods()
    {
        Console.WriteLine("---  GetDataNoParms  ---");
        Console.WriteLine(this.myProxy.GetDataNoParms());
        Console.WriteLine("--- GetDataWithParms ---");
        Console.WriteLine(this.myProxy.GetDataWithParms("CustomerBob", 12345, true));
    }

    #endregion
}

Thursday, October 17, 2013

Easy Windows Services

I have seen a lot of questions on the Forums about Windows Services. The questions run anywhere from “How can I debug my Service?” to “How can I see the MessageBox my Service is showing?” (hint – you can’t do that last one, it’s not possible to use any UI features in a Windows Service).

So, what’s the secret to making Windows Services easy? Well, first of all, begin by hosting your Service(s) in a Console Application. The transition from tinkering with it while you’re developing, to deploying it as a Windows Service, is made a lot easier this way.

Your Console Application project will contain 4 files: app.config, Program.cs, Services.cs and ProjectInstaller.cs. You could, in a real application, have separate files for the Services and for the ServiceHost. I’ve simplified by putting it all in the same file.

The Program.cs starts everything running (as is normally the case with any Console app):

namespace ConsoleApplication1
{
    class Program
    {
        static MyServiceHost oService;

        // Be sure to add a System.ServiceProcess reference and using
        static void Main(string[] args)
        {
            if (Environment.UserInteractive == false)
            {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] 
                { 
                    new MyServiceHost()
                    // others may be added as follows, we only have one
                    // , new MyOtherHost()
                };
                ServiceBase.Run(ServicesToRun);
            }
            else
            {
                if (ConfigurationManager.AppSettings.Count > 0)
                {
                    oService = new MyServiceHost();
                    oService.Start();
                    Console.ReadLine();
                    oService.Stop();
                }
                else
                {
                    Console.WriteLine("Config file is missing ...");
                    Console.ReadLine();
                }
            }
        }
    }
}

Notice in the above code we check to see whether or not we’re running interactively. A Console application would be interactive, a Windows Service would not. You should be able to see how that works from looking at the above code.

Next, the Services and ServiceHost classes:

namespace ConsoleApplication1
{
    // Service classes are just regular classes, that have only one requirement:
    // They must implement a Start and Stop method.
    public class MyServiceOne
    {
        public void Start()
        {
            // startup code here
        }
        public void Stop()
        {
            // stop code here
        }
    }
    public class MyServiceTwo
    {
        public void Start()
        {
            // startup code here

        }
        public void Stop()
        {
            // stop code here
        }
    }

    // Make sure that you add a reference to System.ServiceProcess in your project references
    // I've got threading in this class, be sure to also add a reference to System.Threading
    public partial class MyServiceHost : System.ServiceProcess.ServiceBase
    {
        // This Windows Service can host as many Service classes as you want
        static MyServiceOne ServiceOne;
        static MyServiceTwo ServiceTwo;

        private Thread SqlThread;
        private bool EndLoop = false;
        private string ConnectionString;

        public MyServiceHost()
        {
            this.CanStop = true;
            this.CanShutdown = true;
            this.CanPauseAndContinue = false;
        }
        protected override void OnStart(string[] args)
        {
            // In the case of my Services, I use SqlServer. I need to be sure it's up and running
            // before my Services start. How could this not be the case? Well, machines could have been
            // rebooted because of Windows Updates or for other kinds of maintenance. Whether or not 
            // SqlServer is on the same machine as your Services really doesn't matter. Your Services
            // could start before SqlServer starts. I handle this possiblity by waiting for SqlServer
            // to start first. This is done in the DoWork() method.
            ThreadStart threadStart = new ThreadStart(DoWork);
            this.SqlThread = new Thread(threadStart);
            this.SqlThread.Start();
        }
        protected override void OnStop()
        {
            if (this.EndLoop == false)
                this.EndLoop = true;
            
            // Notice this interesting tidbit (it applies to my app, but depending on what 
            // your services do, it may also apply to yours ... so, consider this just an FYI):
            // When I start my services (in the StartService() method), I start ServiceOne and then ServiceTwo
            // When I stop them, I stop them in the opposite order, first stop ServiceTwo and then ServiceOne.
            if (ServiceTwo != null)
                ServiceTwo.Stop();

            // Sleep for a second if you need a bit of time between service's stopping
            System.Threading.Thread.Sleep(1000);

            if (ServiceOne != null)
                ServiceOne.Stop();
        }
        protected override void OnShutdown()
        {
            // There may be a bug in the .NET Framework in that this method
            // is not being called on system shutdown for SYSTEM account services.
            // Not sure when/if it will be fixed, but I'm putting code here to stop
            // stuff on the off-chance that it will be called eventually.
            if (ServiceTwo != null)
                ServiceTwo.Stop();
            System.Threading.Thread.Sleep(1000);
            if (ServiceOne != null)
                ServiceOne.Stop();
        }
        protected void DoWork()
        {
            this.ConnectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString; ;
            if (string.IsNullOrEmpty(this.ConnectionString))
            {
                Console.WriteLine("No MyConnectionString or No Config File.");
                return;
            }

            while (this.EndLoop == false)
            {
                if (this.SqlServerIsRunning())
                {
                    this.StartService();
                    EndLoop = true;
                }
                else
                {
                    if (Environment.UserInteractive)
                        Console.WriteLine("Waiting for SQL Server ...");
                    Thread.Sleep(30000); // 30 seconds
                }
            }
        }
        protected bool SqlServerIsRunning()
        {
            bool IsConnected = false;

            try
            {
                using (SqlConnection conn = new SqlConnection(this.ConnectionString))
                {
                    conn.Open();
                    IsConnected = true;
                }
            }
            catch
            {
            }

            return IsConnected;
        }
        protected void StartService()
        {
            ServiceOne = new MyServiceOne();
            ServiceTwo = new MyServiceTwo();

            ServiceOne.Start();
            ServiceTwo.Start();
        }

        // These 2 methods are only used when not runnning as a Service, for testing from a Console window.
        public void Start()
        {
            this.OnStart(null);
            Console.WriteLine("Services Started");
        }
        public void Stop()
        {
            Console.WriteLine("Services Stopping ...");
            this.OnStop();
        }
    }
}

OK, well, that was pretty painless, right? Go ahead and run this Console application. If you’d like to expand on ServiceOne and ServiceTwo to actually do something, go ahead and spin off some new threads or something … whatever your services might have to do. You can set breakpoints in Visual Studio and debug to your heart’s content. You’ll notice that as soon as you hit the Enter key in the Console window, the service will stop.

Now, that’s all there is to hosting a Service in a Console Application. Once you’ve got it all debugged and you’re ready to go, you’re going to want to install your service as a Windows Service. This is also not too difficult. You’ll have to add an Installer class to your project. You can right-click your project, “Add New Item” and choose “Installer Class” … however, that adds some stuff that you’ll just have to take out anyway (it adds a Designer.cs class and you really don’t need that). Instead, just right-click and add a new class and copy my Installer class as a starting point and it’s much easier. Here it is:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;

namespace ConsoleApplication1
{
    [RunInstaller(true)]
    public partial class MyServiceInstaller : System.Configuration.Install.Installer
    {
            #region Declarations

        private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
        private System.ServiceProcess.ServiceInstaller serviceInstaller1;
        private System.ServiceProcess.ServiceInstaller serviceInstaller2;

        public string ServiceName
        {
            get { return this.serviceInstaller1.ServiceName; }
            set { this.serviceInstaller1.ServiceName = value; }
        }
        public string ServiceAccount
        {
            set
            {
                switch (value.ToLower())
                {
                    case "user" :
                        this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.User;
                        break;
                    case "localservice" :
                        this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalService;
                        break;
                    case "networkservice" :
                        this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.NetworkService;
                        break;
                }
            }
        }
        public override string HelpText
        {
            get
            {
                return base.HelpText + 
                    "\r\n\r\nSpecific to My Messaging: \r\n\r\n" +
                    "/ServiceName=[servicename] \r\n" + 
                    " Use if installing multiple My Messaging Services. \r\n" +
                    " Defaults to My.MessagingService if switch not used.\r\n\r\n" +
                    "/ServiceAccount [User] |  [LocalService] | [NetworkService] \r\n" + 
                    " Use if not installing under the System account. \r\n\r\n";
            }
        }
        private bool DebugIt = false;

        #endregion

        #region Constructor

        public MyServiceInstaller()
        {
            //InitializeComponent(); // do our own

            this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
            this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
            this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Manual;
            this.serviceInstaller1.ServicesDependedOn = new string[] { "Message Queuing", "Distributed Transaction Coordinator" };
            // 
            // serviceProcessInstaller1
            // 
            this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
            this.serviceProcessInstaller1.Password = null;
            this.serviceProcessInstaller1.Username = null;
            // 
            // ProjectInstaller
            // 
            this.Installers.AddRange(new System.Configuration.Install.Installer[] {
                this.serviceProcessInstaller1,
                this.serviceInstaller1});
        }

        #endregion

        #region Methods

        protected override void OnBeforeInstall(IDictionary savedState)
        {
            base.OnBeforeInstall(savedState);
            this.SetPropertiesFromCommandLineSwitches();
            this.SetDebugService();
        }
        protected override void OnBeforeUninstall(IDictionary savedState)
        {
            base.OnBeforeUninstall(savedState);
            this.SetPropertiesFromCommandLineSwitches();
            this.SetDebugService();
        }
        private void SetPropertiesFromCommandLineSwitches()
        {
            // command line switches: /ServiceName= /ServiceAccount= (and /debug= but not really using debug right now)
            // See HelpText property in the Declarations and the ServiceName and Service account properties

            string name = this.Context.Parameters["ServiceName"];
            if (string.IsNullOrEmpty(name))
                this.ServiceName = "My.MessagingService";
            else
                this.ServiceName = name;

            string account = this.Context.Parameters["ServiceAccount"];
            if (string.IsNullOrEmpty(account) == false)
                this.ServiceAccount = account;

            if (this.Context.Parameters.ContainsKey("debug"))
                this.DebugIt = true;
        }
        private void SetDebugService()
        {
            if (this.DebugIt)
            {
                this.serviceInstaller2 = new System.ServiceProcess.ServiceInstaller();
                this.serviceInstaller2.ServiceName = "My.Debug.Service";
                this.Installers.Add(this.serviceInstaller2);
            }
        }

        #endregion
    }
}

Next, we’ll need just a few lines of code to execute via a Command line. It’s easiest to create two batch files, one for installing and one for uninstalling. The .NET Framework has an Install Utility called “InstallUtil.exe”, located in the c:\Windows\Microsoft.NET\Framework folder. If you have multiple versions of the .NET Framework installed on a machine, you must make sure you use the correct InstallUtil, depending on the .NET version you’ve targeted in your project properties. It’s easy to do with batch files. Here’s a batch file to install the above Service:

@echo off

REM change if yours is a different path
set INSTALL_UTIL_HOME=C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319

set PATH=%PATH%;%INSTALL_UTIL_HOME%


echo .
echo .
echo Installing Service My.MessagingService
echo .
echo .
installutil My.MessagingService.exe

echo .
echo Done.
echo .
pause

To uninstall, your batch file will be essentially the same except you’d echo Uninstalling Service, and you’d use the /u parameter:

@echo off

REM change if yours is a different path
set INSTALL_UTIL_HOME=C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319

set PATH=%PATH%;%INSTALL_UTIL_HOME%


echo .
echo .
echo Uninstalling Service My.MessagingService
echo .
echo .
installutil /u My.MessagingService.exe

echo .
echo Done.
echo .
pause

That’s all there is to it. Have fun and happy coding!  =0)

Saturday, September 28, 2013

Double vs Decimal

I ran into an interesting issue when doing some math with a double rather than a decimal. I’m maintaining some existing code and since part of the original code used doubles, I continued writing my new code using doubles as well. The original author had created a string.ToDouble(defaultVal) extension method to use for such purposes (data is being retrieved from a TextBox.Text, even though it’s numeric data), but NO string.ToDecimal(defaultVal) extension method existed. So I didn’t really give it any thought … and just continued to use the double.

I know that there’s a difference as to when you should use double and when you should use decimal … but it seems that I can never remember which is which. And, all along I thought one was floating point and one was not … but that’s not quite true either. It seems that double (and float also) are floating binary point types, whereas decimal is a floating decimal point type.

I found a really good reply that explains this quite nicely in a StackOverflow thread: Difference Between Decimal Float and Double The very first reply is the one I’m referring to and the gist of it is the following:

A double represent a number like this: 10001.10010110011

Whereas a decimal represents a number like this: 12345.65789

As for what to use when:

  • For values which are "naturally exact decimals" it's good to use decimal. This is usually suitable for any concepts invented by humans: financial values are the most obvious example, but there are others too. Consider the score given to divers or ice skaters, for example.

  • For values which are more artifacts of nature which can't really be measured exactly anyway, float/double are more appropriate. For example, scientific data would usually be represented in this form. Here, the original values won't be "decimally accurate" to start with, so it's not important for the expected results to maintain the "decimal accuracy". Floating binary point types are much faster to work with than decimals.

Read the reply in the linked thread, which has a little more to it than what I excerpted above.

Luckily for me, in my testing I used numbers that would cause this difference to be apparent , otherwise I might never have noticed it, which would have been bad once it was in production! Here’s where I went wrong:

Using Double.TryParse("14.19", out Large) and Double.TryParse("10.00", out Small) ... yields the correct numbers if you look just at Large (14.19) and Small (10.0). However, if you do math on the two, such as Large - Small, you don't get what you'd expect. You'd expect 4.19, but what you get is 4.1899999999999995. Usually not a problem, because it would most likely get rounded along the way … and, in fact does correctly display in the TextBox as 4.19. No harm, no foul … unless you happen to be checking to see if 4.19 <= Large - Small ... it should be true (if rounded), but it won't because it doesn't round at that point (4.19 is definitely NOT less than or equal to 4.1899999999999995)!!! But, cast Large and Small to a decimal before even doing the math and everything is fine.

I immediately wrote my own string.ToDecimal(defaultVal) extension method

Maybe after this little fiasco I won’t forget anymore. ;0)

Monday, August 12, 2013

Persisting A Dictionary By Serialization

I recently helped out a guy on the MSDN forums who wanted to be able to persist his data to an XML file, to be able to be retrieved and restored by his application at application startup. He needed to store his data in a Dictionary. All sounds good so far except he couldn’t figure a good way to serialize the data to XML and then deserialize it in order to load it into a Dictionary.

When I first read his post, my first thought was to serialize the entire dictionary to XML, rather than try and serialize just the data parts. But guess what … a Dictionary cannot be serialized with the XmlSerializer. But, there is a way to do it, and that’s with the DataContractSerializer … turns out that it works just fine! And we don’t even have to decorate our Dictionary with a [DataContract] attribute. Let’s see how to do that:

First, let’s get some test data loaded in a Dictionary:

Dictionary<string, List<string>> Layers = new Dictionary<string, List<string>>();
Layers.Add("ourlayer1", new List<string>());
Layers["ourlayer1"].Add("somerandomthing");
Layers["ourlayer1"].Add("anotherrandomthing");

Layers.Add("ourlayer2", new List<string>());
Layers["ourlayer2"].Add("whatisthis");
Layers["ourlayer2"].Add("whoisthis");

Next, we’ll serialize the Layers Dictionary and write it out to an XML file.

DataContractSerializer dc = new DataContractSerializer(typeof(Dictionary<string, List<string>>));

using (StringWriter sw = new StringWriter())
using (var writer = new XmlTextWriter(sw))
{
    writer.Formatting = Formatting.Indented; // indent the Xml so it's human readable
    dc.WriteObject(writer, Layers);
    writer.Flush();
    File.WriteAllText("Layers.xml", sw.ToString());
}

Here’s what the Layers.xml file looks like:

<ArrayOfKeyValueOfstringArrayOfstringty7Ep6D1 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <KeyValueOfstringArrayOfstringty7Ep6D1>
    <Key>ourlayer1</Key>
    <Value>
      <string>somerandomthing</string>
      <string>anotherrandomthing</string>
    </Value>
  </KeyValueOfstringArrayOfstringty7Ep6D1>
  <KeyValueOfstringArrayOfstringty7Ep6D1>
    <Key>ourlayer2</Key>
    <Value>
      <string>whatisthis</string>
      <string>whoisthis</string>
    </Value>
  </KeyValueOfstringArrayOfstringty7Ep6D1>
</ArrayOfKeyValueOfstringArrayOfstringty7Ep6D1>

And, last but not least, let’s read the file back into the Dictionary:

Layers.Clear();
string s = File.ReadAllText("Layers.xml");
using (StreamReader sr = new StreamReader("Layers.xml"))
{
    Layers = dc.ReadObject(sr.BaseStream) as Dictionary<string, List<string>>;
}

Take a look at your Layers Dictionary in the debugger when this process is done and you’ll see it’s been reserialized correctly. It’s a pretty easy process I think. Here’s the link to the MSDN forum question, if you’re interested:

http://social.msdn.microsoft.com/Forums/en-US/3f1897ab-12a3-4da3-acfe-4b08c2cd74db/trying-to-write-a-simple-program-to-gather-strings-and-save-in-xml-file

Saturday, June 29, 2013

Inheritance and Constructors

I see frequent questions on the Forums where code doesn’t seem to work right and it comes down to the poster’s lack of understanding about the order in which the constructors are executed for the base class and a sub-class.

Here's a common scenario: say you have a base class that does some work (in the example I'll show, it is a generic class to fill a DataSet from SQL, based on the TableName property of the class). Each sub-class of this base class will provide it's own TableName property, because each sub-class will be filling it's own table.

The first attempt at creating these two classes, looks like this:

public class BizObj
{
    protected string TableName = "";
    private DataSet oData;

    public BizObj()
    {
        LoadData();
    }

    public void LoadData()
    {
        SqlConnection oConn = new SqlConnection("...");
        SqlDataAdapter oAdapter = new SqlDataAdapter("SELECT * FROM " + this.TableName, oConn);
        oAdapter.Fill(oData);

    }
}

public class AuthorBizObj : BizObj
{
    public AuthorBizObj()
    {
        this.TableName = "Authors";
    }
}

However, this does not work. Why? Because the BizObj (base class) constructor fires before the AuthorBizObj (sub-class) constructor, not the other way around. And then it's too late to set the TableName at that point.

The trick to fixing this is to use a virtual Property, rather than a member, and to override that Property in each sub-class:

public class BizObj
{
   public string m_TableName="";

   protected virtual string TableName
   {
      get {return this.m_TableName;}
      set {this.m_TableName = value;}
   }

   private DataSet oData;

   public BizObj()
   {
      LoadData();
   }

   public void LoadData()
   {
      SqlConnection oConn = new SqlConnection("...");
      SqlDataAdapter oAdapter = new SqlDataAdapter("SELECT * FROM "+this.TableName,oConn);
      oAdapter.Fill(oData);

   }
}

public class AuthorBizObj : BizObj
{
    protected override string TableName
    {
        get { return "Authors"; }
    }
}

Sunday, May 26, 2013

Comparing Original To Modified In A DataSet

We can easily determine which DataRows in a DataTable have changed. In fact, there are a couple of ways to do that, but it depends on what you intend to do when processing those changes. We can also determine which column of data has changed, but we'll tackle that topic second.

First thing I'll show are two ways to determine DataRow changes.

First option: you can loop through the every row, and determine it’s RowState, which will tell you if the DataRow has been modified or added:

foreach (DataTable dt in MyDataSet.Tables)
{
    foreach (DataRow row in dt.Rows)
    {
        if (row.RowState == DataRowState.Modified || row.RowState == DataRowState.Added)
        {
            // These are the actual rows that have some kind of changes
        }
    }
}

Second Option: If you’re not actually going to do anything with the actual rows, you just need to do some other kind of processing or validation or whatever, you can make use of the DataSet.GetChanges() method. This returns a DataSet containing only the changes (Modified or Added) from your original DataSet. Keep in mind that this is a new DataSet ( a new object) and has no “connection” to your original DataSet. Your code would then look like this:

DataSet dsChanged = MyDataSet.GetChanges();

foreach (DataTable dt in dsChanged.Tables)
{
    foreach (DataRow row in dt.Rows)
    {
        // these are copies of the rows that have some kind of changes
        // either Modified or Added (not the deleted rows)
    }
}

But what about columns that have changed?

Sometimes we want to know which columns have data that has changed. In this case, knowing that the DataRow has changed is not sufficient. That’s a different kettle of fish, but also quite easy to determine. We need to make use of something called a DataRowVersion. My example below will use the dsChanged DataSet from the above example, but the same logic can be applied to the actual MyDataSet object as well (keeping in mind that you need to test the RowState, as I show above).

foreach (DataTable dt in dsChanged.Tables)
{
    foreach (DataRow row in dt.Rows)
    {
        for (int i = 0; i < dt.Columns.Count; i++)
        {
            if (!row[i, DataRowVersion.Current].Equals(row[i, DataRowVersion.Original]))
            {
                // This particular Column has some kind of changes 
            }
        }
    }
}

And that’s it! Hope this helps someone!

Saturday, April 27, 2013

Project item '4294967294' does not represent a file.

Wow, that’s a pretty non-descriptive error message, isn’t it? And the funny thing is, that particular item number is always the same! What the heck is this?

This is an error message you can get in Visual Studio. I don't know if this is specific to SSRS report projects or not, but I suspect it is. I ran into the error when trying to open a solution with a .rptproj.

Googling finds all sorts of stuff about deleting a line out of the rptproj file and rebinding to source control (most mention Source Safe, but I use TFS and still had the issue). Also, this was in VS2005 (because we're using SSRS 2005 … and the reason for that is a story for another day).

It turns out, this guy had the answer all along and it didn't involve mucking about with the .rptproj file!

http://followtheheard.blogspot.com/2008/03/error-opening-reporting-services.html

The issue is caused because someone checked in their .rptproj.user file. That's the only thing wrong! The .user file is specific to a particular user and should never be checked in (I don't know why it was to begin with). The solution is easy ... check out the .user file and then delete it. I couldn't delete it from TFS (because other people had done the same thing and you can't delete a file from TFS if it has pending changes). But, you can just delete it from your own folder, then re-open your solution and all will be fixed!