Thursday, 5 December 2013

Background worker in .Net

We might want to run two or more independent tasks simultaneously rather than running them synchronously. If you talk about asynchronous programming threads concept is the first one to come in our mind. Well its true but Microsoft has given us extra bit of abstraction through background worker. Background worker runs on a different thread and performs tasks asynchronously.

We will show you coding part now.
1. Add reference to System.ComponentModel name space in order to access background worker class.

using System.ComponentModel;

2. Now declare a variable of type Background worker and instantiate it in page_load event of the page as shown below. In addition to that register two events of background worker namely DoWork and RunWorkerCompleted. We will discuss them later in this post.

protected void Page_Load(object sender, EventArgs e)
{
            bWorker = new BackgroundWorker();
            bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
            bWorker.RunWorkerCompleted += new           RunWorkerCompletedEventHandler(bWorker_RunWorkerCompleted);
}

protected void bWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
         
}

protected void bWorker_DoWork(object sender, DoWorkEventArgs e)
{
         
}


3. Now we will write two simple methods namely Task1() and Task2(). We will execute these two methods asynchronously using background worker in later steps.

void Task1()
{
            // Load data from Source1
 }
void Task2()
{
            // Load data from Source2
}

4. Now we want these two methods to be called in page_load. Hence we would change our page_load event as shown below.

protected void Page_Load(object sender, EventArgs e)
{
            bWorker = new BackgroundWorker();
            bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
            bWorker.RunWorkerCompleted += new      RunWorkerCompletedEventHandler(bWorker_RunWorkerCompleted);
            Task1();
            bWorker.RunWorkerAsync();
}

5. Please notice the above code carefully. We made two changes one is we are directly calling Task1(), the second one is we are calling RunWorkerAsync() method of background worker. This RunWorkerAsync() will raise DoWork event of the background worker where we have to call Task2().

protected void bWorker_DoWork(object sender, DoWorkEventArgs e)
{
            Task2();
}

6. We are almost done. You might be having questions regarding RunWorkerCompleted event of the background worker. It is useful to perform operations once after background worker completes processing. For instance hiding the loading popup dialog or some other operations.

7. To sum up everything:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace BlogPosts
{
    public partial class _Default : System.Web.UI.Page
    {

        BackgroundWorker bWorker;

        protected void Page_Load(object sender, EventArgs e)
        {
            bWorker = new BackgroundWorker();
            bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
            bWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bWorker_RunWorkerCompleted);
            Task1();
            bWorker.RunWorkerAsync();
        }

        protected void bWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
         
        }

        protected void bWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Task2();
        }

       void Task1()
       {
            // Load data from Source1
        }
       void Task2()
      {
            // Load data from Source2
       }
    }
}

Thigs to Remember: You can not access UI controls such as labels textboxes etc in DoWork event. For example if you try to set Text property of a label from DoWork event an exception will be thrown because label belongs to UI thread not the background worker's thread. Hence Hence those operations should be performed in  RunWorkerCompleted Event of the background worker.

, , , , ,

Running batch files from .Net with log


We might sometimes need to trigger a batch file which is on the server using .Net. I had to run batch files on server many times and i faced lot of issues while running them using asp.net and I finally got it right, so thought of sharing my code through this post.


For that First add reference to System.Diagnostics name space.
Then create a ProcessStartInfo object and set filename,arguments and WorkingDirectory properties of the same object as shown below.

using System.Diagnostics;


ProcessStartInfo psi = new ProcessStartInfo
{
Arguments = batchFile+ " >log.log",
FileName = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
};
psi.WorkingDirectory = Path.GetDirectoryName(batchFile);


Please note >log.log is used to generate a log file (log file will be generated in same location where batch file is residing) and we are executing batch file using powershell rather than usual command prompt.

Next is to create a process object and set its StartInfo property to the ProcessStarInfo object which we created earlier.
Below code will do exactly that.


Process p = new Process();
p.StartInfo = psi;
p.Start();


To sum up everything:


public static int RunBatch(string batchFile, int timeOut = 10000)
{
ProcessStartInfo psi = new ProcessStartInfo
{
Arguments = batchFile+ " >log.log",
FileName = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
};
psi.WorkingDirectory = Path.GetDirectoryName(batchFile);
psi.UseShellExecute = false;
Process p = new Process();
p.StartInfo = psi;
p.Start();
p.WaitForExit(timeOut); //or p.WaitForExit() to wait until batch completes processing completely.
return p.ExitCode;
}


Well there are some more properites you can set to redirect standard error and output. For instance:


psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
string error=p.StandardError.ReadToEnd();
string output=p.StandardOutput.ReadToEnd();


Please note give full control to "NETWORKSERVICE" user on batch file in order to successfully execute batch file otherwise you may face access issues. Don't forget to disable impersonation in web.config file. Last but not least do not write pause statement in your batch file otherwise it will run forever :).


, , , ,

Wednesday, 4 December 2013

Running Excel Macros from ASP.Net

Today i want to show you how to execute excel macros using asp.net.

First of all we have to add reference to Mirosoft.Office.Interop.Excel dll in Visual studio.
Call the below method to execute macro.


void RunMacro()
{
string excelFile=@"C:\Users\ExMacro.xls";
Microsoft.Office.Interop.Excel.Application excel = Server.CreateObject("Excel.Application") as Microsoft.Office.Interop.Excel.Application;
excel.Visible = false;
Microsoft.Office.Interop.Excel.Workbooks wb = excel.Workbooks;
Microsoft.Office.Interop.Excel.Workbook book = wb.Open(excelFile);
Microsoft.Office.Interop.Excel.Worksheet sheet = book.Sheets[1];
excel.Application.DisplayAlerts = false;
//to hide all the messageboxes (if any)
excel.Run("Initiate_Process"); //Initiate_process is macro name.
book.Save();
excel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
System.Runtime.InteropServices.Marshal.ReleaseComObject(book);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheet);
}


Note: On Some servers to run excel marcos we have to add a folder by the name "desktop" in C:\Windows\SysWOW64\config\systemprofile (if your server is 64 bit) in C:\Windows\System32\config\systemprofile (if your server is 32 bit).
Crazy bug i say:).


The code is simple and self explanatory. First we created Application object and instantiated Workbooks. Using Workbooks reference we opened our sheet by uisng Open method and called Run method to run required macro. Finally we have released all of our objects using ReleaseComObject() method.
, , , ,

.Net Extension Methods

Hello All, Today I want do discuss about an intersting conept Extension Methods introduced in .Net version 3.5. Extension methods are typical static methods but can be called as instance methods. These methods are great because they can reduce our code to a large extent and can be easily re-used.

I would write a simple extension method which will convert an object to string. In other words I am going to write an equivalent method of ToString().


public static string Str(this object obj)
{
return Convert.ToString(obj);
}

Please note "this" keyword is appended to the first parameter in order to call it on that type. In the above example we can call the extension method on any type because the first parameter is of type obj.

Here is the code to call the above method.


int x=123;
string val=x.Str(); //as good as Convert.ToString(x); Str is a static method but it is called as an instance method.


Simple isn't it? Well the above method is a very simple one, you can write more complex methods and can re-use. Further more you can put all of your extension methods in a dll and re-use across your projects.
, , , ,