Blog Archives

URL Rewriting/Mapping using Global.asax

Ultimately I wound up using a different method, specified in my other blog post on URL Rewriting on GoDaddy and Shared hosting.

However, the method below is actually very useful if you are trying to do certain validation which cannot be expressed in web.config or RegEx prior to redirect, such as checking if querystring is valid and exists in database values, etc.

        //try out various request types such as absolute path and raw url to see differences
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            string originalPath = HttpContext.Current.Request.Path.ToLower();
            //HttpContext.Current.Request.RawUrl.ToLower();
                //HttpContext.Current.Request.Path.ToLower();
            RewritePaths(originalPath);
        }

        private void RewritePaths(string originalPath)
        {
            Rewrite(originalPath, "default", "index");
            Rewrite(originalPath, "home", "index");
            Rewrite(originalPath, "index");
            Rewrite(originalPath, "login");
        }

        private void Rewrite(string path, string page)
        {
            if (path.Contains("/" + page))
            {
                if (!path.Contains(".aspx"))
                {
                    //Context.RewritePath(path.Replace("/" + page, "/" + page + ".aspx"));
                    Context.RewritePath(page + ".aspx");
                }
            }
        }

        private void Rewrite(string path, string frompage, string topage)
        {
            if (path.Contains("/" + frompage))
            {
                if (!path.Contains(".aspx")) {
                //Context.RewritePath(path.Replace("/" + frompage, "/" + topage + ".aspx"));
                Context.RewritePath(topage + ".aspx");
                }
            }
        }

URL Rewriting on GoDaddy and Shared hosting

After doing a lot of searching through google queries, forums and archives, I was finally able to solve the conundrum of using URL rewriting on GoDaddy.

The site in question is also a subdomain in a sub folder off the root site, meaning web.config rules cascade, which complicated things slightly more and was enough to send GD support over the edge.

So my site/domain/DNS setup was as follows:

//--parent
www.parentsite.com
//--and sub
subsite.parentsite.com
//--where sub is actually cname of
test.othersite.com

//--parent points to root folder
/web.config
/default.aspx
//--and sub points to subsite folder
/subsite/web.config
/subsite/default.aspx
//--desired url
/subsite/default //--should point to /subsite/default.aspx

I could not find a single article which presented a complete solution, including my own URL Mapping solution I presented in a previous article.

The simple solution in my previous article only works on GoDaddy servers if the mapping specifies a file extension on both the url and mapped url, such as:

<urlMappings enabled="true">
            <add url="~/default.aspx" mappedUrl="index.aspx"/>
            <add url="~/index.html" mappedUrl="index.aspx"/>
</urlMappings>

After speaking with GoDaddy support on 3 separate occasions, including callbacks from higher tiers, they informed me the mappings "work" and deferred to the above example..

So I dropped the simple approach of using URL Mappings, and stepped it up to URL Rewriting. According to GoDaddy kbase article, Microsoft URL Rewriting is supported, although for some reason they don't include any examples..

I was able to at least get this working as intended after a little tweaking and reading through some of the references listed further below.

The configuration I am using is IIS7 with .Net 3.5. Haven't tested it on 4.0 though this should work as well.

The solution:

(see code snippets above for domain structure in my scenario)

(( make sure you don't place modules or system.webServer in your web.config more than once.. you'll get a server 500 error :P ))

	<modules runAllManagedModulesForAllRequests="true">

<system.webServer>
    <rewrite>
      <rewriteMaps>
        <rewriteMap name="StaticRedirects">
<!-- this is similar to url mapping, but the user would actually see the aspx extension in the url -->
          <!-- <add key="/subsitefoldername/pagename" value="/pagename.aspx"/> -->
        </rewriteMap>
      </rewriteMaps>
      <rules>
        <rule name="RedirectRule" stopProcessing="true">
          <match url=".*" />
          <conditions>
            <add input="{StaticRedirects:{REQUEST_URI}}" pattern="(.+)" />
          </conditions>
          <action type="Redirect" url="http://test.othersite.com{C:1}" appendQueryString="True" redirectType="Permanent" />
        </rule>
          <rule name="default">
            <match url="default" />
            <action type="Rewrite" url="default.aspx" /> <!-- this hides the extension as intended -->
          </rule>
        <rule name="login">
          <match url="login" />
          <action type="Rewrite" url="login.aspx" />
        </rule>
      </rules>
    </rewrite>

Unfortunately however, the above example can break page validation/viewstate, but that's a topic for another article. :P

There is one other alternative to note that I also tried which also worked on my local server but not on GoDaddy was using Global.asax context rewrite. To avoid lengthiness, see deferred post on URL Rewriting/Mapping using Global.asax.

References
"Simple URL Rewriting/Mapping in IIS7", http://ronniediaz.com/2011/04/06/simple-url-rewritingmapping-in-iis7/
Learn IIS, http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/, http://learn.iis.net/page.aspx/465/url-rewrite-module-configuration-reference/, http://learn.iis.net/page.aspx/761/provide-url-rewriting-functionality/
Stackoverflow, http://stackoverflow.com/questions/416727/url-rewriting-under-iis-at-godaddy
Rackspacecloud, http://cloudsites.rackspacecloud.com/index.php/How_do_I_rewrite_URLs_from_ASP/.NET%3F
Godaddy kbase, http://help.godaddy.com/topic/623/article/5443

Change WPF Toolbar and Window Skin

Took me some Googling to come across some good links to help me find exactly what I was looking to do. Hopefully my post gets enough hits that you’ll come across my title sooner rather than later, and can benefit from my time and research. :)

If you’re new to WPF, or even if you’ve been using WPF for some quite some time, you may or may not have noticed that theming and skinning is not relatively straight forward, and there are many different ways to achieve the end result visually.

If you’re using WPF simply to learn the new technology, understand that there are pro’s and con’s to WPF vs standard Winforms, and although the latter is technically “legacy”, depending on third party controls you may or may not be using, implementation in Winforms can be very fast and may still be a better option for some projects.

Here’s a simple grid I’ve come up with to help you decide which to use:

  WinForms WPF
Supports Skins No Yes
Uses graphics resources to render No Yes
Easily bind controls with data No Yes
Easy to design a form with drag+drop Yes No
Some cross-platform compatibility with Mono Yes No
Easily customize look and feel of controls No Yes
Already comes with most controls/visuals needed for business app Yes No

As you can see from the table above, if you are trying to quickly knock out a business app that is not going to require heavy visual modification or too reliant on databinding, it’s probably faster in WinForms. Also, I have personally deployed WinForms cross-platform (Mac, Linux) using mono, which I could not get to work with WPF.

Overall though, for most environments, WPF is usually the way to go if not for visual flexibility then for databinding (why are you using windows client apps again?:P).

One ways listed above that WPF really comes out on top is in utilizing the computer’s graphics card and other graphics resources to render forms. The WPF objects on the screen are still contained in a form however, and many theming examples override the draw methods on the forms themselves which don’t properly utilize the effectiveness of WPF.

In general, I have found there are at least three different ways to change the look and feel of your application in WPF:

- Using Silverlight Themes
- Using Office Themes
- Using your own Custom Themes

If you download and install the Silverlight toolkit (not to be confused with silverlight SDK or silverlight client), you will automatically get multiple dll references which contain XAML themes that can be re-used in WPF. This is a quick way to make your WPF app look good without too much work.

Office themes are pre-built in, and a common choice for many beginner WPF skinners. They share common visuals which you see in many office apps and give your application a more up-to date look and feel with some recognizability by your users also, similar to how Mac applications all share a common theme.

This is also always an option, but be prepared for a long and ardous task and a few lunch days with your favorite designer. Microsoft expressions studio comes with all the tools needed to make your controls as beautiful as you like, and implementing and inheriting from these visuals is actually relatively simple, but when you apply the time it takes to make one control by the amount of different controls you may have, there is alot of work involved. Also for re-usability, you’ll want to put all your custom controls/skins in their own assembly which increases the time even further. If you’re short on time (who isn’t :P), this is not a good option, but in the long-run this could be very beneficial and give your applications their own gleam.

See references for links on how to implement the above and other information regarding skinning and theming in WPF. (The reference links are in order of my google “stream of consciousness” :P)

References
WPF Skins (this blog), <a href="http://ronniediaz.wordpress.com/wp-admin/post.php?post=1250&action=edit
MSDN Blog, http://social.msdn.microsoft.com/forums/en-us/wpf/thread/c87d508b-9195-4a68-831f-315b64520fcf
Codeproject Article, http://www.codeproject.com/KB/WPF/WPFBusinessAppsPartOne.aspx
Stackoverflow Blog, http://stackoverflow.com/questions/260098/any-free-wpf-themes
Codeplex Article, http://wpfcontrib.codeplex.com/wikipage?title=Themes&referringTitle=Home&ProjectName=wpfcontrib
WPF Tutorial.Net, http://www.wpftutorial.net/Expander.html
Silverlight.Net Blog, http://blogs.silverlight.net/blogs/msnow/archive/2009/02/09/silverlight-tip-of-the-day-91-how-to-apply-themes-from-the-silverlight-toolkit.aspx
MSDN Social, http://social.msdn.microsoft.com/forums/en-US/wpf/thread/3c66adb7-fd26-40c7-8404-85f6fefbd392/
C-sharp Corner Article, http://www.c-sharpcorner.com/Resources/Detail.aspx?ResourceId=667
Browsoft Article, http://www.browsoft.com/tutorials/DefaultTheme.html
Jan-Cornelius Molnar (Blog), http://www.vb-magazin.de/forums/blogs/janm/archive/2006/06/19/4655.aspx
MSDN Official Blog, http://blogs.msdn.com/b/wpfsdk/archive/2008/09/08/custom-window-chrome-in-wpf.aspx

C# and VB Equivalents

VB:

'shorthand object constructors; assigned initial properties
dim p as New Person() With {.FirstName = "john", .LastName="smith"}

'add handler for events
AddHandler context.BeginRequest, AddressOf Applicaton_BeginRequest

C#:

//shorthand object constructors; assigned initial properties
Person p = new Person() with {FirstName = "john", LastName="smith"}

//add handler for events
context.BeginRequest += Application_BeginRequest;

IIF in C#

I always find myself referencing my other projects for this one when I jump between languages, so decided to toss it on the web.

Both examples are in the context of ASP .Net, but syntax also applies np to Winforms

In VB:

<asp:label id="lblmessage" runat="server" visible='<%# iif(1=1,"true","false") %>' />

C# Equivalent:

<asp:label id="lblmessage" runat="server" visible='<%# 1 == 1 ? "true" : "false" %>' />

Serialize and Deserialize classes and objects in .Net

Serialization is a powerful tool and a major factor in many intermediate development technologies such as webservices.

Simply call “SerializeObject” and pass in the class name of your object for the “T” parameters, and your object will be serialized as an xml string which can then be stored in DB or written to disk!

To mark a public variable so it is not serialized, such as a decrypted key value or password, simply mark it with the attribute [XmlIgnore].

Enjoy. ;)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace ApplicationName
{

    /// <summary>
    /// Contains generic static/shared methods accessible throughout the site
    /// </summary>
    public static class XMLSerialization
    {
        /// <summary>
        /// Serialize Object of Type T to XML and return value as string.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pObject"></param>
        /// <returns></returns>
        public static String SerializeObject<T>(T pObject)
        {
            /*try
            */
            String XmlizedString = null;
            MemoryStream memoryStream = new MemoryStream();
            XmlSerializer xs = new XmlSerializer(typeof(T));
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            xs.Serialize(xmlTextWriter, pObject);
            memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
            XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
            return XmlizedString;
            /*}
            catch (Exception e) { System.Console.WriteLine(e); return null; }*/
        }

        public static T DeserializeObject<T>(string URL)
        {
            /*try
            */
            T returnObject;
            XmlSerializer xs = new XmlSerializer(typeof(T));
            XmlTextReader xmlTextReader = new XmlTextReader(URL);
            returnObject = (T)xs.Deserialize(xmlTextReader);
            //xs.Serialize(xmlTextWriter, pObject);
            return returnObject;
            /*}
            catch (Exception e) { System.Console.WriteLine(e); return null; }*/
        }

        public static String UTF8ByteArrayToString(Byte[] characters)
        {

            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

        public static Byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        }
    }
}


Note:
Any snippets may have been condensed from their original sources for brevity. See references for original articles.

All server side code examples are in C# .Net.

References
Original reference misplaced.

Quick Silverlight References

Most of the links below are relatively introductory, but they do serve as a quick refresher if it has been awhile since you have worked with Silverlight.

Though not all of the links are specific to SL4, I would recommend a path of RIA services in conjunction with ADO .Net Entity framework for your business apps as these new process flows simplify the project structure and are improvements upon their predecessors.

For quick “agile” development, Linq to SQL is still the way to go IMO, but ADO .Net is also great nonetheless.

- Walkthrough creating a silverlight business application (4.0 or later) and retrieve data using WCF service.
http://www.silverlight.net/learn/tutorials/silverlight-4/aspnet-and-silverlight/

- Using ADO .Net Entity Model / Framework with Silverlight (4.0 or later)
http://msdn.microsoft.com/en-us/library/ee796239%28v=vs.91%29.aspx

- Silverlight custom data forms (3.0 or later)
http://www.silverlightshow.net/items/Creating-Rich-Data-Forms-in-Silverlight-3-Customization.aspx

- Basic Animation in Silverlight
http://www.silverlight.net/learn/videos/silverlight-videos/basic-animation-silverlight-3/

- General Reference (all versions)
http://www.silverlight.net/learn/

- Run Silverlight on Desktop (Out of Browser Application)
http://www.silverlightshow.net/items/Silverlight-3-as-a-Desktop-Application-Out-of-Browser-Applications.aspx

Bind Control to an Object in Windows Forms

Simple solution for basic binding in Windows Forms app. This would NOT be recommended if you are using ASP .Net, Silverlight, WCF, RIA or any other services to retrieve the data as these project types have much better support for binding to controls.

C#:

static class dataaccess {
static mytype object;
}

//on app load
object = new mytype();

//on form load
tbField1.DataBindings.Add("Text", dataaccess.object.property, "Field1")

Quick .Net Email Reference

I’ve done a bit of encapsulation here to abstract the concept into clearer functionality, IMO.

Make sure to add “using” reference directives for System.Threading and System.Net.Mail accordingly, when necessary.

Note usage of basic boolean “sync lock” style logic in place of static members for thread safety.

(This code is purely illustration of concept and functionality is not assured. Correctness of code is coincidental. :) )

C#:

private Automailer mailer;

private void StartEmailAutomailer() {
      int interval = 100000;
                    System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
                    //set host, port, etc from your data layer
                    List<System.Net.Mail.MailAddress> recipients = DataAccess.MailInfo.recipients;

                    if (mailer == null)
                    {    
                        mailer = new Automailer(interval,client,recipients);
                    }
                    else
                    {
                        mailer.AccessMailInterval = interval;
                        mailer.AccessMailClient = client;
                        mailer.AccessMailRecipients = recipients;
                    }
                    mailer.Start();
}

//contain in job/agent type definitions
public class Automailer
    {
        private System.Timers.Timer mailerthread;

        public bool IsRunning { get; private set; }
        private bool sending { get; set; }

        public double AccessMailInterval
        {
            get
            {
                return mailerthread.Interval;
            }
            set
            {
                if (sending == false)
                {
                    mailerthread.Interval = AccessMailInterval;
                }
                else
                {
                    utils.cout("Cannot modify interval while mail cycle is processing.");
                }
            }
        }

        private SmtpClient MailClient;
        public SmtpClient AccessMailClient { 
            get {
                    return MailClient;
        }
            set
            {
                if (sending == false)
                {
                    MailClient = AccessMailClient;
                }
                else
                {
                    utils.cout("Cannot modify mail client while mail cycle is processing.");
                }
            }
        }

        private List<MailAddress> MailRecipients;
        public List<MailAddress> AccessMailRecipients { 
            get {
                    return MailRecipients;
        } 
            set {
                if (sending == false)
                {
                    MailRecipients = AccessMailRecipients;
                }
                else
                {
                    utils.cout("Cannot modify mail recipients while mail cycle is processing.");
                }

            } 
        }

        /// Must be manually started / stopped.
        public Automailer(double interval,SmtpClient client,List<MailAddress> recipients)
        {
            try
            {
                MailClient = client;
                MailRecipients = recipients;

                sending = false;
                mailerthread = new System.Timers.Timer(interval);
                mailerthread.Elapsed += new System.Timers.ElapsedEventHandler(SendMail);
            }
            catch (Exception ex)
            {
                utils.cout("Error sending email. Details:" + "\r\n" + ex.ToString());
            }
        }

        public void Start() {
            if (IsRunning)
            {
                utils.cout("Automailer agent already running.");
            }
            else
            {
                utils.cout("Starting automailer agent...");
                mailerthread.Start();
                IsRunning = true;
                utils.cout("Initialized.");
            }
        }
        
        public void Stop() {
            if (IsRunning)
            {
                utils.cout("Sending halt and exit command to automailer agent...");
                mailerthread.Stop();
                utils.cout("Stopped.");

                if (sending)
                {
                    utils.cout("Warning: automailer stopped during mail cycle.");
                }
            }
            else
            {
                utils.cout("Automailer agent is not running.");
            }
            
        }

        /// Fires on timer or can be called manually.
        public void SendMail(object source, System.Timers.ElapsedEventArgs e)
        {
            if (sending == false)
            {
                sending = true;
                int successcount = 0;
                try
                {
                    utils.cout("Starting mail cycle...");
                    int rollingcount = 0;
                    foreach (MailAddress address in MailRecipients)
                    {
                        rollingcount += 1;
                        utils.cout(String.Format("Sending email {0} of {1}.", rollingcount, MailRecipients.Count));

                        MailMessage message = new MailMessage();

                        try
                        {
                            message.Body = DataAccess.MailInfo.body;
                            message.IsBodyHtml = DataAccess.MailInfo.ishtml;
                        }
                        catch (Exception ex4)
                        {
                            utils.cout("Could not populate body from template. Message will be sent using defaults. Details:" + "\r\n" + ex4.ToString());
                            message.IsBodyHtml = true;
                            message.Body = String.Format("Thank-you! <br /><br /> \r\n \r\n - {0}",DataAccess.LicenseInfo.company);
                        }

                        try
                        {
                            message.To.Add(address);

                            try
                            {
                                MailClient.Send(message);
                                utils.cout(String.Format("Email sent to {0}.",address.Address));
                                successcount += 1;
                                //async can be used alternatively
                                //MailClient.SendAsync(message,)
                                //MailClient.SendCompleted += new SendCompletedEventHandler(SendMailComplete);
                            }
                            catch (Exception ex2)
                            {
                                utils.cout(String.Format("Could not send to {0}. Details:", address.Address) + "\r\n" + ex2.ToString());
                            }
                        }
                        catch (Exception ex3)
                        {
                            utils.cout(String.Format("Unable to add address {0} to the list. Details:", address.Address) + "\r\n" + ex3.ToString());
                        }

                        message.Dispose();
                    }
                   
                }
                catch (Exception ex)
                {
                    utils.cout("Error sending email. Details:" + "\r\n" + ex.ToString());
                }

                utils.cout(String.Format("Mail cycle complete. {0} sent successful, {1} failed to send.", successcount.ToString(), (MailRecipients.Count - successcount).ToString()));

                sending = false;
            }
        }

        //not used, can be used to engage on asyc calls
        private void SendMailComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            
        }
    }

//data layer
public static class DataAccess {
public static class Mailinfo {
//contains static methods and properties for retrieving data from database or file, etc
}
}

//in a generic lib
public static class utils {
public static void cout(string outputtext) {
//output text to console, window, form, etc
}
}
Follow

Get every new post delivered to your Inbox.