Friday, 30 June 2017

Obsolete Attribute

The obsolete attribute can mark a function in your class as obsolete, it can then be set as deprecated as in you can use it but shouldn't, or marked to create an error.

using System;
using System.Diagnostics;

namespace ConditionalAttributeExample
{
    public class Person
    {
        //You can use it but shouldn't
        [Obsolete("This Property is obsolete, use FirstName and LastName instead", false)]
        public string FullName { get; set; }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime BirthDate { get; set; }

        //You can't use it, will create an error
        [Obsolete("This method is obsolete, use GetAge instead", true)]
        public int GetYearsOld()
        {
            return DateTime.Now.Year - BirthDate.Year;
        }

        public int GetAge()
        {
            var Today = DateTime.Now;
            var age = Today.AddYears(-BirthDate.Year).Year;

            return age;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var p = new Person();
            //will compile with warning
            p.FullName = "Pawel Chooch";

            //will not complie
            p.GetYearsOld();
        }
    }

}

notice that we mark two properties with the Obsolete attribute, we pass a message to both and then a boolean value representing if it should cause a compile time exception. True causes exception, False is a warning.

Thursday, 29 June 2017

Conditional Attribuite

sometimes you may want to run a method only in DEBUG mode, or some other defined condition. if you run the following console app in debug

using System;
using System.Diagnostics;

namespace ConditionalAttributeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            DebugMethod();
            HelloWorld();
        }

        [Conditional("DEBUG")]
        public static void DebugMethod()
        {
            Console.WriteLine("Running in Debug");
        }

        public static void HelloWorld()
        {
            Console.WriteLine("Hello World");
        }
    }
}

You'll get



but in release



 Now if you wanted to create a method that only runs in release you'll quickly learn that there is no RELEASE preprocessor directive, so you'll have to add your own, you can configure it in your project properties, but that's not obvious enough for me. Instead I like to define one at the top of my file:

#define RELEASE
#if DEBUG
#undef RELEASE
#endif

using System;
using System.Diagnostics;

namespace ConditionalAttributeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            DebugMethod();
            ReleaseMethod();
            HelloWorld();
        }

        [Conditional("DEBUG")]
        public static void DebugMethod()
        {
            Console.WriteLine("Running in Debug");
        }

        [Conditional("RELEASE")]
        public static void ReleaseMethod()
        {
            Console.WriteLine("Running in Release");
        }

        public static void HelloWorld()
        {
            Console.WriteLine("Hello World");
        }
    }
}

you can also chain conditional attributes together, so the following

[Conditional("RELEASE"), Conditional("DEBUG")]
public static void ReleaseOrDebugMethod()
{
    Console.WriteLine("Running in Release Or Debug");
}

is completely valid and if the ReleaseOrDebugMethod() is called from the main it'll fire in both the release or Debug Versions.

Wednesday, 28 June 2017

TraceSwitch

The TraceSwitch can be used in your code to specify the level of message you want to display to your user.

Integer value Enumerated value
0 Off
1 TraceError
2 TraceWarning
3 TraceInfo
4 TraceVerbose

If we take a look at the following code for a simple WebForms page

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var ts = new TraceSwitch("mySwitch""");

            //if level explicitly set to 0
            if (ts.Level == 0)
                Response.Write("Nothing<br />");

            //inclusively if level > 0
            if (ts.TraceError)
                Response.Write("Error<br />");

            //inclusively if level > 1
            if (ts.TraceWarning)
                Response.Write("Warning<br />");

            //inclusively if level > 2
            if (ts.TraceInfo)
                Response.Write("Info<br />");

            //inclusively if level > 3
            if (ts.TraceVerbose)
                Response.Write("Verbose<br />");
        }
    }
}

The nice thing is you can set the traceswtich value in the webconfig or appconfig.

<configuration>
  <system.diagnostics>
    <switches>
      <add name ="mySwitch" value ="3"/>
    </switches>
  </system.diagnostics>
</
configuration>

would result in



but if we set the value to 0

<configuration>
  <system.diagnostics>
    <switches>
      <add name ="mySwitch" value ="0"/>
    </switches>
  </system.diagnostics>
</
configuration>

Then instead we'd see

Tuesday, 27 June 2017

Key Management

When you use encryption be it symmetric or asymmetric you have either have a shared secret or a public and private key combo, either way these need to be stored somewhere. If they're strongly type they're near impossible to remember; think along the lines of a GUID as your password.

Luckily there's a ProtectData class, which does pretty much exactly what it sounds like it does. It only has two methods, Protect and Unprotect which also do exactly what they sound they'd do.

now one thing you have to remember is to manually add a reference to the "System.Security" assembly in your solution explorer.

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace pc.ImplementingKeyManagement
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Enter in secret Data");
            var data = Console.ReadLine();

            var EncryptedData = Protect(data);
            var s = Encoding.Default.GetString(EncryptedData);

            Console.WriteLine(s);

            SaveToFile(s);
        }

        static byte[] Protect(string data)
        {
            byte[] userData = Encoding.Default.GetBytes(data);
            return ProtectedData.Protect(userData, null, DataProtectionScope.CurrentUser);
        }

        static void SaveToFile(string data)
        {
            using (var fs = new FileStream(@"c:\secure.txt", FileMode.Create, FileAccess.Write))
            {
                try
                {
                    using (var bw = new BinaryWriter(fs))
                    {
                        try
                        {
                            bw.Write(data);
                        }
                        finally
                        {
                            bw.Close();
                        }
                    }
                }
                finally
                {
                    fs.Close();
                }
            }
        }
    }
}

in the above code, we take in a string encrypt it to the logged in user, then save to a file.



The string is written to our text file



now here's the code to decrypt our string

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace pc.keyManagementReadExample
{
    class Program
    {
        static void Main(string[] args)
        {
            //get contents of secret data
            var s = ReadFile();
            //print encrypted data
            Console.WriteLine("Encrypted data");
            Console.WriteLine(s);

            //print decrypted data
            Console.WriteLine("Decrypted:");
            Console.WriteLine(UnProtect(s));
        }

        static string ReadFile()
        {
            string data = string.Empty;

            using (var fs = new FileStream("c:/secure.txt", FileMode.Open))
                try
                {
                    using (var br = new BinaryReader(fs))
                        try
                        {
                            data = br.ReadString();
                        }
                        finally
                        {
                            br.Close();
                        }

                }
                finally
                {
                    fs.Close();
                }


            return data;
        }

        static string UnProtect(string data)
        {
            byte[] encryptedData = Encoding.Default.GetBytes(data);
            byte[] decryptedData = ProtectedData.Unprotect(encryptedData,
                                    null, DataProtectionScope.CurrentUser);

            return Encoding.Default.GetString(decryptedData);
        }
    }

}

Above we read the encrypted string in from our file and decrypt it. if we try to decrypt if with the same user context we get.



but if we try to decrypt the data under a different user context we get an CryptographicException "Key not valid for use in specified state"