Thursday, December 31, 2009

IObservable (T) and IObserver(T) in .Net 4.0: Implemt push based notification using observer pattern

.Net framework 4.0 is going to come up with two new interfaces IObservable and IObserver. These interfaces is going to give a cleaner way to implement observer pattern in your code. In observer design pattern there are two parties involved. One is observer and another is subject.The subject maintains a list of observers and notifies them in case of change in its state.

In .net framework 4 the implementation of observer pattern can be achieved by implementing two interfaces IObservable and IObserver. The class implementing IObservable plays the role of subject and the class implemeniting IObserver acts as observer.

Let us assume that a 'Blog' has some subscribers who want to be notified after every article posted in the 'Blog'. So we can say that here the readers are subscribers to the 'Blog' and they are observer. On the other hand 'Blog' is the subject or observable. When a new article is posted in the blog subscriber will be notified about the article. The following block of codes will help you to understand you can implement this in .net framework 4.0 with two new interfaces.


namespace ObserverExample
{
class Program
{
static void Main(string[] args)
{
Blog blog = new Blog();
/***********Subscribe to the blog********/
blog.Subscribe(new Subscriber { Name = "Alex" , Email="alex@abc.com"});
blog.Subscribe(new Subscriber { Name = "Kevin", Email = "kevin@abc.com" });
blog.Subscribe(new Subscriber { Name = "Kelly", Email="kelly@mail.com"});

blog.PostArticle();
Console.ReadLine();
}
}

public class Article
{
public string Title
{
get;
set;
}
public string Content
{
get;
set;
}

public string Url
{
get;
set;
}
}

public class Blog : IObservable<Article>
{
List<IObserver<Article>> observers = new List<IObserver<Article>>();
Article _article;

#region IObservable<user> Members
public IDisposable Subscribe(IObserver<Article> observer)
{
observers.Add(observer);
return observer as IDisposable;
}
#endregion

public void PostArticle()
{
_article = new Article { Content="Cleaner way to implement observer", Title="Observer pattern in .net 4.0", Url="http://observer.blog.com"};

/*********Save article and then notify observers*****************/
foreach (IObserver<article> observer in observers)
{
observer.OnNext(_article);
}
}
}

public class Subscriber : IObserver<Article>
{
#region IObserver<Article> Members
public string Name
{
get;
set;
}
public string Email
{
get;
set;
}
public void OnCompleted()
{
Console.WriteLine("Finished sending notification.");
}

public void OnError(Exception error)
{
Console.WriteLine("Error sending notification");
}

/****************This is the function which will be called to notify observer***************/
public void OnNext(Article value)
{
/*************Writing to console****************/
/************You should write code here according to your notification mechanism to the subscriber/observer ************/
Console.WriteLine("Name:{0} Email:{1}", this.Name, this.Email);
Console.WriteLine("Title:{0}\n Content:{1}", value.Title,value.Content);
}
#endregion
}
}

Though the example is trivial I hope this one will help anyone to understand how to implement observer pattern in a cleaner way in framewok 4.0.

Thursday, July 30, 2009

Code Contact Article In MSDN Magazine

Melitta Andersen posted a nice article on Code Contact in MSDN magazine. You can find it here.

Wednesday, June 10, 2009

Dynamic Programming With .Net Framework 4.0 and C#

Microsoft have introduced new Dynamic Language Runtime with framework 4.0 . This API supports a new type dynamic which enables dynamic features in statically typed language like C#.

Below are two important findings about dynamic type from MSDN.

1. The type dynamic is a static type but an object of type dynamic bypasses compile time checking.

2.At compile time dynamic variables are compiled into variables of type object.Therefore, type dynamic exists only at compile time not at runtime.

As all of you will find everything detail in MSDN I am Jumping into the code directly.

For the sake of simplicity to show how the dynamic type works in C# I am declaring a naive class MyDateTime which is a skeleton of the .Net Type DateTime.


public class MyDateTime
{
public int Month
{
get { return dateTime.Month;}
}
public int Year
{
get { return dateTime.Year; }
}
public int Day
{
get { return dateTime.Day; }
}


private DateTime dateTime;

public MyDateTime()
{
dateTime = new DateTime();
}

public MyDateTime(int day, int month, int year)
{
dateTime = new DateTime(year, month, day);
}

public override string ToString()
{
return dateTime.ToString("MM/dd/yyyy");
}

public void AddDays(int numberOfDays)
{
dateTime = dateTime.AddDays(numberOfDays);
}
}

Now we can use it like

dynamic dateTime = new MyDateTime(6,9,2009);
Console.WriteLine("Date:{0} ",dateTime);
Console.WriteLine("Month:{0}",dateTime.Month);
Console.WriteLine("Day{0}:",dateTime.Day);
Console.WriteLine("year:{0}",dateTime.Year);


No compile time type checking will occur for the variable dateTime in the above WriteLine methods.

We can also call AddDays function of MyDateTime object through the dynamic type variable dateTime

dateTime.AddDays(7);


But one drawback with this dynamic thing is that you can call any method or access any property which is not actually present in the statically typed object.

So if we call a method SubtractDays for our early dateTime variable

dateTime.SubtractDays(7)

it will not signal us any error at compile time. But at runtime we will fell trap of RuntimeBinderException saying 'MyDateTime does not contain a defination for SubtractDays'.

Reference: MSDN

Tuesday, May 19, 2009

Sql Server Reporting Service : Rendering Report From C# Code & Save The Report

One of the requirement for our last project was after generating the report the report link would be emailed to client. The client will follow the link and download the report in PDF format. So we decided that after generating the report we will save the report in the file system in PDF format.To achieve the goal we have gone through the following steps.

1.Add web reference to the url http://MyServer/ReportServer/ReportExecution2005.asmx
2.Generate a report snapshot which I described here.
3.Call the following function to get stream in your preferred format.

public byte[] GetRenderStream(string historyID, string format)
{
ReportExecutionService reportExecutionService = new ReportExecutionService();
CredentialCache credentials = new CredentialCache();
NetworkCredential serviceCredential = new
NetworkCredential(Settings.Default.ReportUserName, Settings.Default.ReportPassword);
credentials.Add(new Uri(reportExecutionService.Url), "Basic", serviceCredential);

reportExecutionService.Credentials = serviceCredential;

byte[] resultStream = null;
string reportPath = Settings.Default.ReportPath;
string format = format; // PDF,Excel etc;

string encoding;
string mimeType;
string extension;
ReportExecutionService.Warning[] warnings = null;
string[] streamIDs = null;

ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();

try
{
reportExecutionService.ExecutionHeaderValue = execHeader;
execInfo = reportExecutionService.LoadReport(reportPath, historyID);
String SessionId = reportExecutionService.ExecutionHeaderValue.ExecutionID;
resultStream = reportExecutionService.Render(format, null, out extension, out encoding, out mimeType, out warnings, out streamIDs);

return resultStream;
}
catch (Exception ex)
{
throw ex;
}
}


4. Save the returned stream as a file.

string snapshotID = CreateAndGetNewSnapShotID(int year); // this method is described
//here
string format = "PDF";
string fullFileName = @"C:\Reports\Report.pdf";
byte[] responseStream = _reportServiceProxy.GetRenderStream();

try{
FileStream stream = File.OpenWrite(fullFileName);
stream.Write(responseStream, 0, responseStream.Length);
stream.Close();
}
catch(Exception ex)
{
//catch and log exception;
}

Sunday, May 10, 2009

Creating Report Snapshot Using SQL Server 2005 Reporting Service In C#

While working in the project "BI Site For Car Dealers" we need to generate report from our application instead of depending on reporting server scheduler.Here i will describe the steps
that need to be followed to generate report snapshot from c# code.


1. Add an web reference to the url http://MyServer/ReportServer/ReportService2005.asmx.
2. Now call the following function to generate report snapshot.

public string CreateAndGetNewSnapShotID(int year)
{
ReportingService2005 reportingService = new ReportingService2005();

CredentialCache credentials = new CredentialCache();
NetworkCredential serviceCredential = new
NetworkCredential(Settings.Default.ReportUserName, Settings.Default.ReportPassword);
credentials.Add(new Uri(reportingService.Url), "Basic", serviceCredential);

reportingService.Credentials = serviceCredential;

string report = "/myReport";

ReportParameter[] reportParameters;

// I have used only 1 parameter year. It is possible to use multiple parameter as filter.
reportParameters = new ReportParameter[1];
reportParameters[0] = new ReportParameter();
reportParameters[0].Name = "Year";
reportParameters[0].DefaultValues = new string[] { year.ToString() };

try
{
reportingService.SetReportParameters(report, reportParameters);
Warning[] warnings;
return reportingService.CreateReportHistorySnapshot(report,out warnings);
}
catch (Exception ex)
{
throw new Exception(string.Format("Error:Failed To Create New Subscription ErrorMessage:{0}", ex.Message));
}
}


Few things to note here:
1. User name and password is the windows creadential where the reporting server is hosted.
2. To pass the authentication process successfully it is required to configure the host which I described in an earlier post.

Monday, April 6, 2009

Report Viewer 404 Error In Asp.Net Application IIS-7.0 and Sql Server 2008-- File or directory not found

we had to face this problem while we were trying to show reprot in asp.net page with report viewer. Our website was hosted on windows 2008 server and we used Sql Server 2008 reporting service.

To overcome the issue we followed the steps described below.

1.Open IIS Manager
2.double-click on Handler Mappings icon.
3.At the Action pane on your right, click on Add Managed Handler.
4.At the Add Managed Handler dialog, enter the following: Request path: Reserved.ReportViewerWebControl.axd Type: Microsoft.Reporting.WebForms.HttpHandler
Name: Reserved-ReportViewerWebControl-axd Click OK.

Then add the following lines of code in your web config file in the section.

<add name="Reserved-ReportViewerWebControl-axd" path="Reserved.ReportViewerWebControl.axd" verb="*"
type="Microsoft.Reporting.WebForms.HttpHandler" resourceType="Unspecified"/>

Fix 401 error while accessing sql server reporting service with c# code

While working with reporting service in our last project we had to face 401 issue while accessing reporting service from remote computer(using .net code).After lot of digging in the net i found the following solution which worked for me on both windows server 2003 and server 2008.
  1. Click Start, click Run, type regedit, and then click OK.
  2. In Registry Editor, locate and then click the following registry key:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
  3. Right-click Lsa, point to New, and then click DWORD Value.
  4. Type DisableLoopbackCheck, and then press ENTER.
  5. Right-click DisableLoopbackCheck, and then click Modify.
  6. In the Value data box, type 1, and then click OK.
  7. Quit Registry Editor, and then restart your computer.