Blog

Silverlight 3: Navigation Page and UserControl Inheritance

In a Silverlight 3 application there is by default a limitation to Page and UserControl inheritance. As ASP.net developers we are used to creating BaseControls from which multiple other controls can inherit common functionality. This of course gives us the ability to control/reduce the amount of functionality/code duplication that takes place in our application which also results in making our applications more readable and maintainable.

In order to work around this limitation I have spent hours writing and re-writing code trying to get the inheritance to work as it should within a Silverlight 3 application with no luck. It wasn’t until I saw the ‘Silverlight Class Library’ project and decided that it would be a good idea to move my controls to a separate assembly for reuse in other projects. It was while I was investigating Silverlight class libraries online that I found out we have the ability to not only use the control library to separate out our controls for reuse but we also have the ability to add to the control libraries assembly info definitions for our own Silverlight XML Namespace definitions for the controls we create in the library.

What does this mean to us when it comes to inheritance? It allows us to define our own base classes within the library which inherit from both system provided base classes Page and UserControl. Then once we add the XML Namespace to the assembly info file we can then use any of those base classes as the base classes for all other controls we create inside the library or inside our Silverlight 3 application which references the library  instead of using the system defaults. This of course allows us to place common functionality within these base classes which will then be inherited by all of our derived controls/pages.

To accomplish this you first create a ‘Silverlight Class Library’ project and add to it a new ‘Class’ file (NOT a UserControl or Page) then specify that this new class derives from either ‘UserControl’ or ‘Page’.

namespace SiteBeatControls.BasePages

{

    public class BasePage : Page

    {

    }

}

Once you have create the class you then have to do the most important step of all, this is what allows you to use the base class for inheritance. You need to add to the AssemblyInfo.cs file the following line of course updating the Namespace portion (the second string) to the namespace where your base page lives within the assembly.

[assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "SiteBeatControls.BasePages")]

Once you have done this you can build the assembly reference it in your project and from that point each time you add a UserControl or a Page to your Silverlight 3 project you can then modify it to use your custom base classes and now you have inheritance!

C#: Sending Email

To send email from your application or website do the following:

1. Add this config entry to your (App)(Web).config altering the host to the URL or IP address of your email server with the associated credentials.

    <system.net>

        <mailSettings>

            <smtp from="noreply@medimedia.com">

                <network host="localhost" password="" userName="" />

            </smtp>

        </mailSettings>

    </system.net>

2. Use the following code to create and send a MailMessage

Version:0.9 StartHTML:0000000105 EndHTML:0000007499 StartFragment:0000000105 EndFragment:0000007499

        private void SendEmail()

        {

            MailMessage message = new MailMessage();

            message.From = new MailAddress(_fromEmail);

            foreach (string email in _emailList)

            {

                message.To.Add(new MailAddress(email));

            }

            message.Subject =  _subject;

            message.IsBodyHtml = false;

            message.Priority = MailPriority.High;             

            message.Body = _body;


            try

            {

                SmtpClient client = new SmtpClient();

                client.Send(message);

            }

            catch (Exception ex)

            {

               //TODO: Handle exception

            }

        }

ASP.net: Programmatically Submit Form Post

On occasion it is necessary to post data via an HTTP POST to another page as though that post was submitted by a user but without the user’s interaction. In order to accomplish this use the following code:

        private void PostForm()

        {

            WebRequest request = WebRequest.Create(_targetUrl);

            request.Method = "POST";

            request.ContentType = "application/x-www-form-urlencoded";

            string postContent = string.Format("parameter1={0}&parameter2={1}", _parameter1, _parameter2);

            byte[] postContentBytes = Encoding.ASCII.GetBytes(postContent);

            request.ContentLength = postContentBytes.Length;

            Stream writer = request.GetRequestStream();

            writer.Write(postContentBytes, 0, postContentBytes.Length);

            writer.Close();

            HttpWebResponse testResponse = (HttpWebResponse)request.GetResponse();

            if (!testResponse.StatusDescription.Equals("OK", StringComparison.InvariantCultureIgnoreCase))

            {

                //TODO: Handle failure

            }

        }

C#: Case Insensitive Generic Dictionary

This is a portion of a console app I was using to investigate the Dictionary class and its methods. I was running into issues with Keys not being found within a dictionary that was being auto-generated from incoming web service data, data which I of course had no control over. There were several clients hitting the service which were not using the outlined parameter names with the correct casing. The Dictionary class in .Net uses hashing algorithms to create unique Keys from the key that is entered when the Key/Value pair is added. Because of this hashing the same string with different casing will generate a different unique key. In order to overcome this I found all you have to do is  pass in StringComparer.CurrentCultureIgnoreCase in the constructor of the Dictionary at initialization and from that point on it no longer cares about the casing.

            try

            {

                Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

                dictionary.Add("KeyOne", "Value");

                dictionary.Add("keyone", "Value");

                foreach (KeyValuePair<string, string> valuePair in dictionary)

                {

                    Console.WriteLine(

                        string.Format("Key: {0}, Value: {1}",

                        valuePair.Key,

                        valuePair.Value));

                }

            }

            catch (Exception ex)

            {

                Console.WriteLine(ex.Message);

            }

            Console.ReadLine();

ASP.net: CSS, Images and IIS Virtual Directory Application Deployment

Have you ever tried to deploy an application to a virtual directory in IIS? For example lets say you have your primary website running at http://www.graphicnetdesign.com and you decide it would be nice to have a sub-domain where you can host all of your utility and experimental applications so you create http://dev.graphicnetdesign.com. It is under this sub-domain where you have created virtual directories in IIS to host each of those applications. So you set up a virtual directory for a little application you are playing around with which checks the heart beat of all your websites and web applications and you name it ippoke and your new application’s URL looks like http://dev.graphicnetdesign.com/ippoke.

All excited you quickly FTP your new application to that virtual directory for a little smoke testing. But, sadly, the application which was developing so nicely on your development machine looks like crap. It appears as though your CSS is not loading and if it is it looks like all of the Images embedded in that CSS file are not loading. The Horror! You quickly double check all of your references to the CSS file, you check all of the image URLs within the CSS file and everything looks perfect and it all runs perfectly on your dev machine. What is going on?

After hours of frustration and Google searches you find an article which states that under IIS when using virtual directories to host ASP.net applications IIS does not use the virtual directory as the root of your newly deployed application, instead it uses the root of the main site or http://dev.graphicnetdesign.com. What does that all mean, it means that even though the path to your logo.png file in your ippoke application is ‘/images/logo.png’ and that works on your dev machine and is relative to the root of your application on that machine once deployed to the virtual directory the path required to get that image is has to now be relative to the root of the site under which you created the virtual directory in which your ippoke application is running. In other words the relative path of ‘/images/logo.png’ is no longer a correct path to that image because it is now relative to the root site and resolves to http://dev.graphicnetdesign.com/images/logo.png. In order to make your CSS and images work correctly in the virtual directory you have to change all of your references to resolve from the root so the path needs to be ‘/ippoke/images/logo.png’ instead of ‘/images/logo.png’.

What a pain! So now you have to come up with some way to support the differences between your local dev environment where the site is being developed as a root website in visual studio and what it will eventually be deployed as. In Visual Studio you can actually change the virtual path in the properties of the web application project and there are several other ways you can try to resolve the issue by using separate CSS files for each environment, or by editing the CSS file just before deployment but all of these issues just make more work and make maintenance of the site horrifying. They also do not make the application portable without a lot of editing, for example if I decided to move the application to be its own root site or if I want to change it to a different virtual directory or deploy the site to a completely different server.

The only way I have found to combat the virtual directory CSS and Image bug when it comes to ASP.net applications was to simply create my own custom ASP.net Server Control which is smart enough to know when the application has been deployed as a root site or as a virtual site and armed with that knowledge it creates a copy of the CSS file and updates all image references with the correct virtual directory path so the CSS and Images can be resolved by IIS. This control checks to see if a virtual CSS file exists already and if not it will create one and write it to disk on the first call to the application. If the file already exists it will check to see if the original CSS file has been recently updated and if so the control will create a new version of the virtual CSS in order to capture the changes. Once it has taken care of building the virtual CSS file it then writes out a new tag for the virtual CSS file to the page and that is that. No more missing images, no more missing CSS files and it just works when deployed as either a root site or within a virtual directory.

The code for this control is below, feel free to use it.

Version:0.9 StartHTML:0000000105 EndHTML:0000024318 StartFragment:0000000105 EndFragment:0000024318

using System;

using System.ComponentModel;

using System.IO;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

namespace GraphicNetDesign.ServerControls.Web.UI

{

    [DefaultProperty("Href")]

    [ToolboxItem(true)]

    [ToolboxData("")]

    public class CssVirtualLink : WebControl

    {

        #region Private Fields

        private string _virtualPath;

        private string _originalCssRelativePath;

        private string _originalCssDirectoryPath;

        private string _virtualCssRelativePath;

        private string _virtualCssDirectoryPath;

        private FileInfo _originalCssFile;

        private FileInfo _virtualCssFile;

        #endregion

        #region Public Properties

        [Bindable(true)]

        [Category("Appearance")]

        [DefaultValue("")]

        [Localizable(true)]

        public string Href

        {

            get

            {

                String s = (String)ViewState["href"];

                return (s ?? "[" + ID + "]");

            }

            set

            {

                ViewState["href"] = value;

            }

        }

        #endregion

        #region Protected Methods

        /// 

        /// Renders the contents.

        /// 

        /// The output.

        protected override void RenderContents(HtmlTextWriter output)

        {

            output.WriteBeginTag("link");

            output.WriteAttribute("rel", "stylesheet");

            //Update the CSS file image paths to match virtual directory

            UpdateFile();

            output.WriteAttribute("href", Href);

            output.WriteEndTag("link");

        }

        #endregion

        #region Private Methods

        protected void UpdateFile()

        {

            //Get application's virtual path

            GetApplicationVirtualPath();

            //Get Original CSS file and its actual path

            GetOriginalCssPaths();

            //Build VCSS file path

            GetVirtualCssPaths();

            //Check to see if the CSS file exists

            if (!_originalCssFile.Exists)

                return;

            //Check to see if the Virtual CSS file exists

            if (!_virtualCssFile.Exists || CompareModifiedDates())

                CreateVirtualCssFile();

            //Update Href to the Virtual CSS file

            Href = _virtualCssRelativePath;

        }

        private void GetApplicationVirtualPath()

         {

             _virtualPath = HttpRuntime.AppDomainAppVirtualPath;

             if (!_virtualPath.EndsWith("/"))

                 _virtualPath += "/";

             Page.Trace.Warn("VCSS", "Application Virtual Path: " + _virtualPath);

         }

        private void GetOriginalCssPaths()

        {

            _originalCssRelativePath = (_virtualPath + Href).Replace("//", "/");

            _originalCssDirectoryPath = Page.Server.MapPath(_originalCssRelativePath);

            _originalCssFile = new FileInfo(_originalCssDirectoryPath);

            Page.Trace.Warn("VCSS", "Original CSS Relative Path: " + _originalCssRelativePath);

            Page.Trace.Warn("VCSS", "Original CSS Directory Path: " + _originalCssDirectoryPath);

            Page.Trace.Warn("VCSS", "Original CSS File Exists: " + _originalCssFile.Exists);

        }

        private void GetVirtualCssPaths()

        {

            _virtualCssRelativePath = (_virtualPath + Href.Replace(".css", "_virtual.css")).Replace("//", "/");

            _virtualCssDirectoryPath = Page.Server.MapPath(_virtualCssRelativePath);

            _virtualCssFile = new FileInfo(_virtualCssDirectoryPath);

            Page.Trace.Warn("VCSS", "Virtual CSS Relative Path: " + _virtualCssRelativePath);

            Page.Trace.Warn("VCSS", "Virtual CSS Directory Path: " + _virtualCssDirectoryPath);

            Page.Trace.Warn("VCSS", "Virtual CSS File Exists: " + _virtualCssFile.Exists);

        }

        private bool CompareModifiedDates()

        {

            if (_originalCssFile.LastWriteTime > _virtualCssFile.LastWriteTime)

                return true;

            return false;

        }

        private void CreateVirtualCssFile()

        {

            try

            {

                if (_virtualCssFile.Exists)

                    _virtualCssFile.Delete();

                Page.Trace.Warn("VCSS", "Loading original CSS file for copy.");

                string contents;

                using (FileStream fs = new FileStream(_originalCssDirectoryPath, FileMode.Open, FileAccess.Read))

                {

                    using (StreamReader sr = new StreamReader(fs))

                    {

                        contents = sr.ReadToEnd();

                        sr.Close();

                    }

                    fs.Close();

                }

                Page.Trace.Warn("VCSS", "Original CSS file successfully loaded.");

                Page.Trace.Warn("VCSS", "Creating Virtual CSS file from Original CSS file.");

                using (StreamWriter sw = new StreamWriter(_virtualCssDirectoryPath, false))

                {

                    //Update all URL elements in the CSS file 

                    //to reflect the correct virtual path

                    sw.Write(contents.Replace("url(\"/", "url(\"" + _virtualPath));

                    sw.Close();

                }

                Page.Trace.Warn("VCSS", "Virtual CSS file creation complete.");

            }

            catch (Exception ex)

            {

                Page.Trace.Warn("VCSS", "Exception Thrown: " + ex.Message);

            }

        }

        #endregion

    }

}

C#: Embedding Resources in your DLLs

When you have resources such as images, css files or JavaScript files which you do not want exposed to users, editable, or possibly lost during deployment, a good option is to just embed those resources into your DLL and pull them out as needed.

An example would be an ASP.net custom server control used to handle Session Keep Alive. Lets say we have a .js file which holds our client side JavaScript that needs to be loaded and run on the user’s browser. Lets also say that this file exists within our project in the following directory path next to the .cs files which use it, ProjectName/Web/Utilities/.

To embed the .js file into our DLL you simply need to select the file in Visual Studio and in the ‘Properties’ window there is a option for ‘Build Action’ set it to ‘Embedded Resource’. This will cause the file to be embedded into the DLL the next time the project is built.

Next you need a way to pull that resource out at run time for inclusion in the response to the client. To do this you first need to add a reference to that resource in your ‘AssemblyInfo.cs’ file with is located in the ‘Properties’ folder in the project. Simply go to the bottom of that file and add a WebResource entry as seen below.

[assembly: System.Web.UI.WebResource("GraphicNetDesign.ServerControls.Web.Utilities.KeepAlive.js", "text/js")]

You will notice that the entire path (namespace) to the file needs to be specified. This will be the path you pass in when attempting to access the resource from your code. So now in your code you just do the following to pull the .js file and register it for client use.

Page.ClientScript.RegisterClientScriptResource(typeof(SessionKeepAlive),

                "GraphicNetDesign.ServerControls.Web.Utilities.KeepAlive.js");