Build Custom View Engine to override default views folder in ASP.NET MVC

So here is the situation, I need to build a personalization for the user where they can have different View files based on their user preference or alternatively they can pick their own View folder. To better explain the situation, look at the folder structure below

ViewPersonalisation-FolderStructure

So basically, I don’t want it to be under “Views” folder anymore instead I want my views to be under “Media” folder and by default if the user hasn’t specified which “Views” folder that they want to select then it should use the default one which is “Main” folder

First of all, we need to create our own View Engine that inherits from “RazorViewEngine” and then we need to override the default “ViewLocation“, “PartialViewLocation” and “MasterLocation” with our own default location which is “Media”

Secondly, we need to override “CreateView” method and “CreatePartialView” method to replace the default view location with the one defined in database/user settings

*Note: in the code below “CacheManager.CurrentSite.FolderPath” is storing the “Views” folder that the user has selected in their profile. “UseCustomViewLocation” function is used in this case to not have the personalisation on any of the “Admin Area”

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;</code>

namespace WebUI.Custom.ViewEngine
{
public class WhitelabelViewEngine : RazorViewEngine
{
private const string WHITELABELVIEWFOLDER = "Whitelabel";
private const string MAINFOLDER = "Main";
private const string EXCLUDED_AREA = "admin";

public WhitelabelViewEngine()
{
base.ViewLocationFormats = new[] {
"~/Media/" + MAINFOLDER + "/{1}/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/{1}/{0}.vbhtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.vbhtml"
};

base.MasterLocationFormats = new[] {
"~/Media/" + MAINFOLDER + "/{1}/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/{1}/{0}.vbhtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.vbhtml"
};

base.PartialViewLocationFormats = new[] {
"~/Media/" + MAINFOLDER + "/{1}/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/{1}/{0}.vbhtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.vbhtml"
};
}

protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
IView partialView = base.CreatePartialView(controllerContext, partialPath);

if (UseCustomViewLocation(controllerContext))
{
partialView = base.CreatePartialView(controllerContext, partialPath.Replace(MAINFOLDER, CacheManager.CurrentSite.FolderPath));

if (!File.Exists(controllerContext.HttpContext.Server.MapPath(((RazorView)partialView).ViewPath)))
partialView = base.CreatePartialView(controllerContext, partialPath);
}

return partialView;
}

protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
IView pageView = base.CreateView(controllerContext, viewPath, masterPath);

if (UseCustomViewLocation(controllerContext))
{
pageView = base.CreateView(controllerContext, viewPath.Replace(MAINFOLDER, CacheManager.CurrentSite.FolderPath),
masterPath.Replace(MAINFOLDER, CacheManager.CurrentSite.FolderPath));

 if (!File.Exists(controllerContext.HttpContext.Server.MapPath(((RazorView)pageView).ViewPath)))
pageView = base.CreateView(controllerContext, viewPath, masterPath);
}

return pageView;
}

///
/// to check whether in the custom area or not
///

//////
private bool UseCustomViewLocation(ControllerContext controllerContext)
{
bool useCustomViewLocation = false;

if (controllerContext.RouteData.DataTokens["area"] == null || (controllerContext.RouteData.DataTokens["area"] != null &amp;&amp; controllerContext.RouteData.DataTokens["area"] != EXCLUDED_AREA))
{
useCustomViewLocation = true;
}

return useCustomViewLocation;
}
}
}

Lastly, We also need to register our custom view engine in Global.asax

 public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            BootStrapper.Setup();

            /*Register Whitelabel View Engine logic*/
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new WhitelabelViewEngine());
        }
}

 

MSMQ – Basic Tutorial

I write this article in advance for my technical presentation. MSMQ is a messaging platform by Microsoft and it is built-in on the OS itself.

Installation

1. To install MSMQ, you can go to “Add/Remove program” then go to “Turn Windows features on or off” and then check “Microsoft Message Queue” Server

2. Check in the Services (services.msc), it will install “Message Queuing” service and “Net.Msmq Listener Adapter” and it should be automatically started once you have installed it

3. Make sure that these ports are not blocked by your firewall because MSMQ are using this ports

TCP: 1801
RPC: 135, 2101*, 2103*, 2105*
UDP: 3527, 1801

Basic Operation

1. in order to see your queue, you can go to “computer management – right click my computer and select manage”. Go to Services and Applications node and there will be a sub node called as “Message Queuing”

2. From this console, you can see all the messages that you want to see

3. in my presentation slides there are definitions of private queues and public queues or you can get more detail from MSDN.

4. For this tutorial, please create a private queue called as “Sample Queue” by right clicking the private queue and select “Add”

Coding tutorial

*Please import System.Messaging

1. How to send a message into a queue

Code Snippet
  1. private const string MESSAGE_QUEUE = @”.\Private$\Sample Queue”;
  2.         private MessageQueue _queue;
  3.         private void SendMessage(string message)
  4.         {
  5.             _queue = new MessageQueue(MESSAGE_QUEUE);
  6.             Message msg = new Message();
  7.             msg.Body = message;
  8.             msg.Label = “Presentation at “ + DateTime.Now.ToString();
  9.             _queue.Send(msg);
  10.             lblError.Text = “Message already sent”;
  11.         }

2. Check the queue through MMC console – right click and select refresh

2. Right click on the message and go to Body then you can see that the message is being stored as XML

3. How to process the queue?See the code snippet below

Code Snippet
  1. private const string MESSAGE_QUEUE = @”.\Private$\Sample Queue”;
  2.         private static void CheckMessage()
  3.         {
  4.             try
  5.             {
  6.                 var queue = new MessageQueue(MESSAGE_QUEUE);
  7.                 var message = queue.Receive(new TimeSpan(0, 0, 1));
  8.                 message.Formatter = new XmlMessageFormatter(
  9.                                     new String[] { “System.String,mscorlib” });
  10.                 Console.WriteLine(message.Body.ToString());
  11.             }
  12.             catch(Exception ex)
  13.             {
  14.                 Console.WriteLine(“No Message”);
  15.             }
  16.         }

Queue.Receive is a synchronous process and by passing the timespan into the function, meaning that it will throw exception of Timeout if it hasn’t received any within the duration specified

-The formatter is used to cast back to the original type

-Then you can collect the message by using “Message.Body”

-Once it’s done the message will be removed from your queue

Conclusion

Pros:

Ready to be used – It provides simple queuing for your application without you need to recreate one/reinvent the wheel

Interoperability – It allows other application to collect/process the message from MSMQ

Cons:

-Message poisoning can happen (when a message cannot be process and blocks entire queue)
-Message and queues are in proprietary format which cannot be edited directly
-The only tool is MMC administration console, or you can buy QueueExplorer (3rd party software
)

My Slides:

http://portal.sliderocket.com/vmware/MSMQ-Microsoft-Message-Queue

*DISCLAIMER:this tutorial does not represent the company that I’m working for in any way. This is just a tutorial that I created personally

 

Yield keyword in .NET

I believe some of you already know about this but for me I never used it. Yield keyword has been existed since .NET 2.0 so I decided to look up of what it does and try to understand it

Based on MSDN

Yield is used in an iterator block to provide a value to the enumerator object or to signal the end of iteration, it takes one of the following form

Based on my understanding

Yield is a concatenation for a collection, or in SQL we normally use UNION

Yield break; is used to exit from the concatenation (remember it is not used to skip !)

One practical sample that I can think of is to get the enumerable of exception from inner exception (e.g stack trace)

sample code

Code Snippet
  1. class Program
  2.     {
  3.         ///<summary>
  4.         /// simple function to return IEnumerable of integer
  5.         ///</summary>
  6.         ///<returns></returns>
  7.         private static IEnumerable<int> GetIntegers()
  8.         {
  9.             for (int i = 0; i <= 10; i++)
  10.                 yield return i;
  11.         }
  12.         ///<summary>
  13.         /// simple function to return collection of class
  14.         ///</summary>
  15.         ///<returns></returns>
  16.         private static IEnumerable<MyClass> GetMyNumbers()
  17.         {
  18.             for (int i = 0; i <= 10; i++)
  19.                 if (i > 5)
  20.                     yield break;
  21.                 else
  22.                     yield return new MyClass() { Number = i };
  23.         }
  24.         internal class MyClass
  25.         {
  26.             public int Number { get; set; }
  27.             public string PrintNumber
  28.             {
  29.                 get {
  30.                     return “This is no “ + Number.ToString();
  31.                 }
  32.             }
  33.         }
  34.         static void Main(string[] args)
  35.         {
  36.             Console.WriteLine(“Simple array of integer”);
  37.             foreach (var number in GetIntegers())
  38.                 Console.WriteLine(number.ToString());
  39.             Console.WriteLine();
  40.             Console.WriteLine(“Collection of classes”);
  41.             foreach (var myclass in GetMyNumbers())
  42.                 Console.WriteLine(myclass.PrintNumber);
  43.             Console.ReadLine();
  44.         }
  45.     }

Output

Simple array of an integer
0
1
2
3
4
5
6
7
8
9
10Collection of classes
This is no 0
This is no 1
This is no 2
This is no 3
This is no 4
This is no 5

Using Disposable object

First method is to use the “Using” keyword which is quite clean and simple

using (IDisposable obj = new DataTable())

{

//do your logic with obj variable

}

Second method is to use Try and finally keyword

IDisposable obj = null;

try

{

obj = new DataTable();

}

finally

{

if (obj != null)

{

obj.Dispose();

}

}

Remove UTF8 BOM Character from the file

Normally when you have a UTF8 encoded file then it might have BOM character that will be rendered when you read it using filestream even though when you open the file with the notepad it doesn’t have that character.

I’ve created a function to remove the BOM character from the file

private void removeBoms(string filePattern, string directory)

{

try

{

foreach (string filename in Directory.GetFiles(directory, filePattern))

{

var bytes = System.IO.File.ReadAllBytes(filename);

if (bytes.Length > 2 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)

{

System.IO.File.WriteAllBytes(filename, bytes.Skip(3).ToArray());

}

}

MessageBox.Show(“Files have been processed completely!”);

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

//uncomment this for recursive

//foreach (string subDirectory in Directory.GetDirectories(directory))

//{

//    removeBoms(filePattern, subDirectory);

//}

}

How to call it

private void btnProcess_Click(object sender, EventArgs e)

{

string extension = txtExtensions.Text;

if (extension.Trim().Length > 0 || folderBrowserDialog1.SelectedPath.Trim().Length > 0)

{

if (!extension.StartsWith(“*.”))

{

extension = “*.” + extension;

}

//just process the html files

removeBoms(extension, folderBrowserDialog1.SelectedPath);

}

else

{

if (extension.Trim().Length == 0)

{

txtExtensions.Focus();

MessageBox.Show(“Please specify the extension files”);

}

else if (folderBrowserDialog1.SelectedPath.Trim().Length == 0)

{

MessageBox.Show(“Please select target folder”);

}

}

}

Tag Replacement using Regex in .NET

This snippet of code shows how to do Synchronisation or HTML tag replacement

-My problem is i want to synchronise of tags between 2 HTML document

Issue

-Source.htm

my source.htm has this tag

<xml id=STATIC_CRITERIA_>

  <fields>

    <field fieldID=OPEN_FLAG displayType=checkboxGroup searchType=checkboxGroup underlyingType=int />

    <field fieldID=PARTITION displayType=dropdown searchType=profile profileID=SU_PARTITIONS underlyingType=int />

    <field fieldID=TEMPLATE_IND displayType=checkbox searchType=checkbox underlyingType=int />

    <field fieldID=INCLUDE_DELETED displayType=checkbox searchType=checkbox underlyingType=string />

  </fields>

</xml>

 -Target.htm has this tag

<xml id=STATIC_CRITERIA_>

</xml>

So now the problem is how do I fill the gap in XML tag in target.htm with the value from mySource.htm. We can do this using regex and it’s very simple

 

  string originalDocument = Load(“c:\\MySource.htm”);

                string syncDocument = Load(“c:\\Target.htm”);

 

                MatchCollection mc = Regex.Matches(originalDocument, “<xml([ ]?.*?)>(.*?)</xml>”, RegexOptions.Singleline | RegexOptions.IgnoreCase);

 

                foreach (Match m in mc)

                {

                    string token = “<xml{0}>”;

                    syncDocument = Regex.Replace(syncDocument, String.Format(token, m.Groups[1].Value) + “(.*?)</xml>”,

                                                               String.Format(token, m.Groups[1].Value) + m.Groups[2].Value + “</xml>”,

                                                               RegexOptions.Singleline | RegexOptions.IgnoreCase);

                }

 MatchCollection is used to return all the instances of that regular expression (e.g you might have multiple XML tags with different ID)

What does this tag means

“<xml([ ]?.*?)>(.*?)</xml>”

 ([ ]?.*) means that I don’t care whatever after it (e.g it can be ID or attributes etc). this is the first parameter that we stored on variable

(.*?) means that whatever inside the tag are captured into the second parameter that we stored on variable

You can access the first variable (e.g any attributes after the XML) by doing

m.Groups[1].Value

you can access the value inside the xml bracket by using

m.Groups[2].Value

so what  contains in

m.Groups[0].Value

it contains the whole xml tag that we extracted using regex

 then we can use regex.replace method to replace the tag in target html. When you replace the tag you need to replace the whole xml tag. You can’t just replace the inner part of it

   foreach (Match m in mc)

                {

                    string token = “<xml{0}>”;

                    syncDocument = Regex.Replace(syncDocument, String.Format(token, m.Groups[1].Value) + “(.*?)</xml>”,

                                                               String.Format(token, m.Groups[1].Value) + m.Groups[2].Value + “</xml>”,

                                                               RegexOptions.Singleline | RegexOptions.IgnoreCase);

                }

Reflection GetProperty case sensitive issue

Reflection on .NET by default is case sensitive for the class member. To make it case insensitive you need to pass BindingFlags.IgnoreCase . I’ve passed the ignorecase flag and now it doesn’t return anything!!!


 Dim pi As PropertyInfo = Me.[GetType]().GetProperty(fieldname, BindingFlags.IgnoreCase)

Basically, if you pass one flag then the other flags will be overwritten by default which means all the default flags are disappeared. So to make it case insensitive then you need to pass other binding flags


 Dim pi As PropertyInfo = Me.[GetType]().GetProperty(fieldname, BindingFlags.IgnoreCase Or BindingFlags.Public Or BindingFlags.Instance)

an activex control on this page might be unsafe to interact with other parts of the page. do you want to allow this interaction?

I keep getting this message “an activex control on this page might be unsafe to interact with other parts of the page. do you want to allow this interaction” when I try to access a page that use Javascript to access ActiveX Code. I’ve spent quite sometime to get rid of this error message and I found out that

  1. The code need implement IObjectSafety Interface
  2. You need to digitally sign the code with valid certificate

Step 1 : Detail on how to implement IObjectSafety
-Create an interface file called as IObjectSafety.vb/IObjectSafety.cs

CSharp (IObjectSafety.cs) :

[ComImport()]
[Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IObjectSafety {
   [PreserveSig()]
   int GetInterfaceSafetyOptions(ref Guid riid, out int pdwSupportedOptions, out int pdwEnabledOptions);

   [PreserveSig()]
   int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions);
}
Imports System.Runtime.InteropServices

 _
 _
 _
Interface IObjectSafety
     _
    Function GetInterfaceSafetyOptions(ByRef riid As Guid, ByRef pdwSupportedOptions As Integer, ByRef pdwEnabledOptions As Integer) As Integer

     _
    Function SetInterfaceSafetyOptions(ByRef riid As Guid, ByVal dwOptionSetMask As Integer, ByVal dwEnabledOptions As Integer) As Integer
End Interface

in your ActiveX code you need to implement IObjectSafety

CSharp:


VB.NET:

 _
 _
 _
 _
Public NotInheritable Class ClientUtility
    Implements IObjectSafety


#Region "IObjectSafety Constants"

    Private Const INTERFACESAFE_FOR_UNTRUSTED_CALLER As Integer = &H1
    Private Const INTERFACESAFE_FOR_UNTRUSTED_DATA As Integer = &H2
    Private Const S_OK As Integer = 0

#End Region

#Region "IObjectSafety Methods"

    Public Function GetInterfaceSafetyOptions(ByRef riid As System.Guid, ByRef pdwSupportedOptions As Integer, ByRef pdwEnabledOptions As Integer) As Integer Implements IObjectSafety.GetInterfaceSafetyOptions
        pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER Or INTERFACESAFE_FOR_UNTRUSTED_DATA
        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER Or INTERFACESAFE_FOR_UNTRUSTED_DATA
        Return S_OK
    End Function

    Public Function SetInterfaceSafetyOptions(ByRef riid As System.Guid, ByVal dwOptionSetMask As Integer, ByVal dwEnabledOptions As Integer) As Integer Implements IObjectSafety.SetInterfaceSafetyOptions
        Return S_OK
    End Function

#End Region

CSharp:

[ProgId("Fransiscus.Authentication.ClientUtility")]
[ClassInterface(ClassInterfaceType.AutoDual), ComSourceInterfaces("ControlEvents")]
[Guid("0577147B-6941-4f15-9EFB-2551FEB3D6CC")]
[ComVisible(true)]
public sealed class ClientUtility : IObjectSafety
{


    #region "IObjectSafety Constants"

    private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x1;
    private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x2;
    private const int S_OK = 0;

    #endregion

    #region "IObjectSafety Methods"

    public int GetInterfaceSafetyOptions(ref System.Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
    {
        pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
        return S_OK;
    }

    public int SetInterfaceSafetyOptions(ref System.Guid riid, int dwOptionSetMask, int dwEnabledOptions)
    {
        return S_OK;
    }
#endregion

}

Step 2:
You need to obtain certificate and sign it, You also need Windows Server 2008 SDK to sign your code using SignTool.exe (type Signtool SignWizard in command prompt to follow the wizard and sign your DLL)
For more detail please open verisign website (http://www.verisign.com/support/code-signing-support/code-signing/identity-authentication.html) or click here

Resolve URL functions

This snippet code is credited to Scott’s Hanselman, This Resolve URL function is used where you want to implement it on your business layer.

Methods:


        #region "Image URL helpers"

        public static string ResolveUrl(string originalUrl)
        {
            if (originalUrl == null)
                return null;
            // *** Absolute path - just return
            if (originalUrl.IndexOf("://") != -1)
                return originalUrl;
            // *** Fix up image path for ~ root app dir directory
            if (originalUrl.StartsWith("~"))
            {
                string newUrl = "";
                if (System.Web.HttpContext.Current != null)
                    newUrl = System.Web.HttpContext.Current.Request.ApplicationPath + originalUrl.Substring(1).Replace("//", "/");
                else  // *** Not context: assume current directory is the base directory
                    throw new ArgumentException("Invalid URL: Relative URL not allowed.");
                // *** Just to be sure fix up any double slashes
                return newUrl;
            }
            return originalUrl;
        }

        /// Works like Control.ResolveUrl including support for ~ syntax
        /// but returns an absolute URL.
        /// 
        /// Any Url, either App relative or fully qualified
        /// if true forces the url to use https
        /// 
        public static string ResolveServerUrl(string serverUrl, bool forceHttps)
        {    // *** Is it already an absolute Url?
            if (serverUrl.IndexOf("://") > -1)
                return serverUrl;
            // *** Start by fixing up the Url an Application relative Url
            string newUrl = ResolveUrl(serverUrl);
            Uri originalUri = System.Web.HttpContext.Current.Request.Url;
            newUrl = (forceHttps ? "https" : originalUri.Scheme) + "://" + originalUri.Authority + newUrl;
            return newUrl;
        }

        /// 
        /// This method returns a fully qualified absolute server Url which includes
        /// the protocol, server, port in addition to the server relative Url.
        ///
        /// It work like Page.ResolveUrl, but adds these to the beginning.
        /// This method is useful for generating Urls for AJAX methods
        /// 
        /// Any Url, either App relative or fully qualified
        /// 
        public static string ResolveServerUrl(string serverUrl)
        {
            return ResolveServerUrl(serverUrl, false);
        }

        #endregion

Usage:

 sb.AppendFormat("

", row.WidgetItemClass); sb.AppendFormat("More Info", ProductsService.GetProductUrl(row.ProductID), ResolveServerUrl("~/GetWhiteLabelFile.aspx?whiteLabelFileID=" + row.WidgetItemLinkImageID.ToString())); sb.AppendFormat("

");

Upload Multiple Files to FTP in .NET

I’ve played around with FTP couple of weeks back. My application is required to feed FTP folder with 1000+ files daily. I’ve been googling around and I found one of the methods is to use WebApplication so I decided to put this WebApplication method to upload while iterating every single files in the directory. After 5 files, it keeps giving me error The remote server returned an error: (503) Bad sequence of commands. Strangely the only the first 4 files always uploaded successfully, my thought was the FTP server forcely terminated the connection which is right. After googling I found that we should set KeepAlive property to false which means new connection is always created instead of maintained but unfortunately WebClient class doesn’t have KeepAlive property. Finally, I’ve come up with this code which solves my issue in uploading 1000+ files one after the other by doing Asynchronous Upload

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.IO;

namespace Helpers
{
    public class FtpHelpers
    {
        public class FtpState
        {
            private ManualResetEvent wait;
            private FtpWebRequest request;
            private string fileName;
            private Exception operationException = null;
            string status;

            public FtpState()
            {
                wait = new ManualResetEvent(false);
            }

            public ManualResetEvent OperationComplete
            {
                get { return wait; }
            }

            public FtpWebRequest Request
            {
                get { return request; }
                set { request = value; }
            }

            public string FileName
            {
                get { return fileName; }
                set { fileName = value; }
            }
            public Exception OperationException
            {
                get { return operationException; }
                set { operationException = value; }
            }
            public string StatusDescription
            {
                get { return status; }
                set { status = value; }
            }
        }

        public void AsynchronousUpload(string destinationPath, string sourcePath, string userName, string password)
        {
            // Create a Uri instance with the specified URI string.
            // If the URI is not correctly formed, the Uri constructor
            // will throw an exception.
            ManualResetEvent waitObject;

            Uri target = new Uri(destinationPath);
            string fileName = sourcePath;
            FtpState state = new FtpState();
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(target);
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.KeepAlive = false;
            request.Proxy = null;

            // This example uses anonymous logon.
            // The request is anonymous by default; the credential does not have to be specified.
            // The example specifies the credential only to
            // control how actions are logged on the server.

            if (!(string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(password)))
            {
                request.Credentials = new NetworkCredential(userName, password);
            }

            // Store the request in the object that we pass into the
            // asynchronous operations.
            state.Request = request;
            state.FileName = fileName;

            // Get the event to wait on.
            waitObject = state.OperationComplete;

            // Asynchronously get the stream for the file contents.
            request.BeginGetRequestStream(
                new AsyncCallback(EndGetStreamCallback),
                state
            );

            // Block the current thread until all operations are complete.
            waitObject.WaitOne();

            // The operations either completed or threw an exception.
            if (state.OperationException != null)
            {
                throw state.OperationException;
            }

        }

        private static void EndGetStreamCallback(IAsyncResult ar)
        {
            FtpState state = (FtpState)ar.AsyncState;

            Stream requestStream = null;
            // End the asynchronous call to get the request stream.
            try
            {
                requestStream = state.Request.EndGetRequestStream(ar);
                // Copy the file contents to the request stream.
                const int bufferLength = 2048;
                byte[] buffer = new byte[bufferLength];
                int count = 0;
                int readBytes = 0;
                FileStream stream = File.OpenRead(state.FileName);
                do
                {
                    readBytes = stream.Read(buffer, 0, bufferLength);
                    requestStream.Write(buffer, 0, readBytes);
                    count += readBytes;
                }
                while (readBytes != 0);
                // IMPORTANT: Close the request stream before sending the request.
                requestStream.Close();
                // Asynchronously get the response to the upload request.
                state.Request.BeginGetResponse(
                    new AsyncCallback(EndGetResponseCallback),
                    state
                );
            }
            // Return exceptions to the main application thread.
            catch (Exception e)
            {
                state.OperationException = e;
                state.OperationComplete.Set();
                return;
            }

        }

        // The EndGetResponseCallback method
        // completes a call to BeginGetResponse.
        private static void EndGetResponseCallback(IAsyncResult ar)
        {
            FtpState state = (FtpState)ar.AsyncState;
            FtpWebResponse response = null;
            try
            {
                response = (FtpWebResponse)state.Request.EndGetResponse(ar);
                response.Close();
                state.StatusDescription = response.StatusDescription;
                // Signal the main application thread that
                // the operation is complete.
                state.OperationComplete.Set();
            }
            // Return exceptions to the main application thread.
            catch (Exception e)
            {
                state.OperationException = e;
                state.OperationComplete.Set();
            }
        }

    }
}

Usage:

#Region "Properties"

    Private _ftpUploader As FtpHelpers = Nothing

    Private ReadOnly Property FtpUploader() As FtpHelpers
        Get
            If (_ftpUploader Is Nothing) Then
                _ftpUploader = New FtpHelpers()
            End If

            Return _ftpUploader
        End Get
    End Property

#End Region

Private Sub ProcessFilesToFTP()

        ' make a reference to a directory
        Dim di As New IO.DirectoryInfo(ConfigurationManager.AppSettings("OutputZIPDirectory"))
        Dim jobFiles As IO.FileInfo() = di.GetFiles()

        Console.WriteLine(String.Format("FTP Location: {0}", ConfigurationManager.AppSettings("ftplocation")))

        'list the names of all files in the specified directory
        For Each jobFile As IO.FileInfo In jobFiles

            'process only zip file
            If (jobFile.FullName.Contains("zip")) Then
                Console.WriteLine(String.Format("Upload file {0}", jobFile.Name))

                FtpUploader.AsynchronousUpload(ConfigurationManager.AppSettings("ftplocation") + "/" + jobFile.Name, jobFile.FullName, _
                                   ConfigurationManager.AppSettings("ftpuser"), _
                                   ConfigurationManager.AppSettings("ftppassword"))

            End If

        Next

        Console.WriteLine(String.Format("XML files has been uploaded to {0}", ConfigurationManager.AppSettings("ftplocation")))
    End Sub

The drawback with this code is in the FTP connection where the connection always reinitialized for every single file.