Friday, December 28, 2007

Object Initializers in C# 3.0

C# 3.0 has some cool extensions based on 2.0. Let’s look at one of them, Object Initializing. In 2.0, we used to code either assigning values after instantiation or create custom initializers. Here’s a typical way we used to do:

public class Employee

{

private string _ID;

private string _FirstName;

private string _LastName;

public string ID

{

get { return _ID; }

set { _ID = value; }

}

public string FirstName

{

get { return _FirstName; }

set { _FirstName = value; }

}

public string LastName

{

get { return _LastName; }

set { _LastName = value; }

}

public Employee() { }

public Employee(string id, string firstName, string lastName)

{

ID = id;

FirstName = firstName;

LastName = lastName;

}

}

public sealed class FullTimeEmployee : Employee

{

private decimal _WorkHours;

public decimal WorkHours

{

get { return _WorkHours; }

set { _WorkHours = value; }

}

public FullTimeEmployee() { }

public FullTimeEmployee(string id, string firstName, string lastName, decimal workhours)

: base(id, firstName, lastName)

{

WorkHours = workhours;

}

}

// Instantiation was done like this:

FullTimeEmployee ftEmployee = new FullTimeEmployee();

ftEmployee.ID = "101";

ftEmployee.FirstName = "John";

ftEmployee.LastName = "Doe";

ftEmployee.WorkHours = 40;

// Or with custom initializer

FullTimeEmployee ftEmployee = new FullTimeEmployee("101", "John", "Doe", 40);

//

//

In the 3.0 the whole thing can be simplified to (and you get the idea):

public class Employee

{

public string ID { get; set;}

public string FirstName { get; set;}

public string LastName { get; set;}

public Employee() { }

}

public sealed class FullTimeEmployee : Employee

{

public decimal WorkHours { get; set;}

public FullTimeEmployee() { }

}

// Instantiation can be done like this:

FullTimeEmployee ftEmployee =

new FullTimeEmployee() { ID = "101", FirstName = "John",

LastName = "Doe", WorkHours = 40 };

//

//

And same goes with collections too. It’s much simplified from initializing point of view.

Oh, did you check the C# ?? null coalescing operator? Its cool too. The ?? operator checks if the left side of the expression is null and if null then returns the right side of the expression.

Love coding!

Thursday, December 27, 2007

Overloading in Web Services – How to avoid WSDL name clashes

We know that each method within a WSDL must be unique; which leads to how to use overloading methods in our web services. Well, there is way to do it using the MessageName Property. Let’s look at the document web service example we built earlier here. Suppose we wanted to overload the GetDocument with chunky and chatty interfaces, here would be the signatures look like:

namespace DocumentWebService

{

/// <summary>

/// Gets document with SoapHeader Authentication

/// </summary>

/// <param name="fileName"></param>

/// <returns></returns>

[WebMethod(Description = "Gets document with SoapHeader Authentication", MessageName = "GetDocumentChatty"),

SoapHeader("soapAuthHd")]

public byte[] GetDocument(string fileName)

{

// code goes here

}

/// <summary>

/// Gets document with parameter Authentication

/// </summary>

/// <param name="fileName"></param>

/// <param name="userName"></param>

/// <param name="password"></param>

/// <returns></returns>

[WebMethod(Description = "Gets document with parameter Authentication", MessageName = "GetDocumentChunky")]

public byte[] GetDocument(string fileName, string userName, string password)

{

// code goes here

}

}

This, however, allows the client proxy’s to use the overloaded methods; like in this case GetDocument.

Love coding!

Friday, December 21, 2007

Legacy application SOAP calls – Dynamic web service calls

Many times we see requests coming to find out how to post dynamic web service calls. This is still needed in posting to legacy or proprietary applications that work like web services but are not true web services. Rather, these are applications that are accepting HTTP Posts in SOAP.

The .Net framework makes it a snap to consume web services. In its simplest form, create a proxy and we are almost done. In the case of these dynamic calls, when we can’t create proxies or we don’t have one, we can go back to good old HttpWebRequest in the System.Net namespace module and get our purpose done. Here is a working model that can do this job:

using System.Net;

using System.IO;

using System.Text;

public string HttpSoapCall(string url, string soapMessage, string soapAction)

{

//ASCII Encoding + Bytes:

ASCIIEncoding encoding = new ASCIIEncoding();

byte[] byteData = encoding.GetBytes(soapMessage);

return HttpSoapCall(url, byteData, soapAction);

}

public string HttpSoapCall(string url, byte[] soapMessage, string soapAction)

{

// HttpWebRequest:

HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);

// If you need proxy:

WebProxy myProxy = new WebProxy("123.45.67.8", 1234);

myProxy.UseDefaultCredentials = true;

myHttpWebRequest.Proxy = myProxy;

// set the Request:

myHttpWebRequest.Headers.Add("MessageType", "CALL");

myHttpWebRequest.Headers.Add("SOAPAction", soapAction);

myHttpWebRequest.ContentType = "text/xml";

myHttpWebRequest.ContentLength = soapMessage.Length;

myHttpWebRequest.Method = "POST";

// GetRequestStream, Write till end and Close:

Stream newStream = myHttpWebRequest.GetRequestStream();

newStream.Write(soapMessage, 0, soapMessage.Length);

newStream.Close();

// Get WebResponse and ResponseStream:

WebResponse wRes = myHttpWebRequest.GetResponse();

Stream respStream = wRes.GetResponseStream();

// StreamReader ReadToEnd:

StreamReader reader = new StreamReader(respStream);

string respHTML = reader.ReadToEnd();

respStream.Close();

reader.Close();

wRes.Close();

return respHTML;

}

Well, when in need we do use old methods at times…

Love coding!

Tuesday, December 4, 2007

How to hide WSDL?

.Net Framework default generates friendly WSDL and we could put our custom WSDL if we like to. But how do we protect it from being displayed to public, should we decide to hold it private? A simple way is to set the Web.Config to remove documentation or another is to send the users to a friendly page.

One way is to add remove documentation protocol in the web.config.

<webServices>

<protocols>

<remove name="Documentation"></remove>

</protocols>

</webServices>

Another friendly way is to show a user-friendly page:

<webServices>

<wsdlHelpGenerator href="Sorry.aspx"></wsdlHelpGenerator>

</webServices>

Love coding!


UPDATE:

WCF Services simplifies these and takes it in a whole different direction. I will be posting some about WCF services later, but to the current topic on hiding WSDL in WCF srvices it's done by default. Take a look at serviceMetadata for more information.


Tuesday, October 23, 2007

Post data to popup window

This is one of the most common requirements we deal with... how to post base page data to a popup window? There are many ways we do this like,
  • passing data by query string
  • passing data using session
  • passing data using javascript
The first 2 methods are obvious and simple. So is the third option. Let's look at how we can go about doing it. The idea is simple: get the handle of the popup window and set values of controls. Simple javascipt that does this would look like:
<script language="javascript">
function pops(pageName,windowName)

{
var popWin = null;
var windowstring;
popWin = window.open(pageName, windowName, windowstring);
popWin.focus();
popWin.document.getElementById('txtField1').value = 'My Test Value';
}
<script>

You get the idea...
Love coding!

Wednesday, October 10, 2007

Dynamically adding Meta Tags: An example of Auto-Refresh Page

Have you ever had to add Meta tags dynamically? One easy way to do is to create the HtmlMeta control and add to the list of header controls. Let’s build an example with a page that would refresh every few seconds given in the text box; default to 60 seconds. Here is how we can go about doing it:

Create a text box control like this:

<asp:TextBox ID="tbxRef" runat="server" Text="" OnTextChanged="tbxRef_TextChanged" AutoPostBack="true"></asp:TextBox>

Add this code in tbxRef_TextChanged event:

protected void tbxRef_TextChanged(object sender, EventArgs e)

{

Response.Redirect("~/MyTestPage.aspx?Refresh=" + tbxRef.Text);

}

Now, here is how we could add the Meta tag dynamically:

// Render: <meta http-equiv="Refresh" content="60" />

HtmlMeta meta = new HtmlMeta();

meta.HttpEquiv = "Refresh";

meta.Content = (Request.QueryString["Refresh"] != null ? Request.QueryString["Refresh"].ToString() : "60");

this.Header.Controls.Add(meta);

Love coding!

Wednesday, September 19, 2007

Programmatically reading HTML from any URL

Well, had to put together a quick app today that reads the content of a status web page and send alerts if any errors. There are no services or api’s for me to call to get the status; hence without much thinking went ahead to read the html from the web page and parse through… so had to read html from the url. Here is how I got it done:

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);

using (Stream stream = request.GetResponse().GetResponseStream())

{

using (StreamReader reader = new StreamReader(stream))

{

string response = reader.ReadToEnd();

return response;

}

}

Love coding!

Tuesday, September 18, 2007

Dynamic Paging in ASP.Net – Oracle and SQL Server versions

When dealing with large data paging efficient paging is a must for us. Half the paging challenge is database SQL for the selected range of rows. With SQL Server 2005 we have Row Number function, which existed in Oracle for long. However, there is a difference in how we can use this to our need. Let’s take an example of we wanted to list purchase history of a user on the page that can run into hundreds or thousands of records. Here is an idea on how we can generate a set of records between given rownumbers:

SQL Server

SELECT Column1, Column2, Column3

FROM (SELECT ROW_NUMBER() OVER (ORDER BY Purchase_Date Desc)AS RowN,

Column1, Column2, Column3 FROM myPurchaseHistory Where username = 'myUserName') As PH

WHERE RowN between 26 and 50

Oracle

Select *

From (Select Row_Number() Over (Partition By 'kigo' Order By Purchase_Date Desc) myTops,

Column1, Column2, Column3

From myPurchaseHistory Where username = 'myUserName')

Where myTops Between 26 And 50

--Another Old way

Select *

From (Select RowNum RowN, PH.*

From (Select Column1, Column2, Column3

From myPurchaseHistory Where username = 'myUserName'

Order By Purchase_Date Desc) PH)

Where RowN Between 26 And 50

Having figured out how to go about querying the range, we can create a stored procedure that can do this work for us. Here is an example on how this can be built with dynamic ObjectDataSource:

First, let’s build a class that has two methods (using Oracle here) GetPurchasesCount, GetPurchases and GetAllPurchases.

public class Purchases

{

public int purhcaseID = 0;

public string description = "";

public DateTime purchaseDate;

///

/// Returns the total purchase count

///

///

public static int GetPurchasesCount()

{

string sql = "Select Count(PurchaseID) PurchaseCount From myPurchaseHistory Where username = :username";

OracleParameter[] p = { new OracleParameter(":username", OracleDbType.Varchar2, 50) };

p[0].Value = HttpContext.Current.Profile.UserName;

object obj = myDataHelper.ExecuteScalar(sql, p, CommandType.Text);

int PolicyCount = 0;

int.TryParse(obj.ToString(), out PolicyCount);

return PolicyCount;

}

///

/// Returns range of purchases as list

///

///

public static List<Purchases> GetPurchases(int fromCount, int toCount)

{

string sql = "Select *" +

" From (Select RowNum RowN, PH.*" +

" From (select Column1, Column2, Column3" +

" From myPurchaseHistory Where username = :username " +

" Order By Purchase_Date Desc) PH)" +

" Where RowN Between :fromCount And :toCount ";

OracleParameter[] p = { new OracleParameter(":username", OracleDbType.Varchar2, 50),

new OracleParameter(":fromCount", OracleDbType.Int32),

new OracleParameter(":toCount", OracleDbType.Int32)};

p[0].Value = HttpContext.Current.Profile.UserName;

p[1].Value = fromCount;

p[2].Value = toCount;

OracleDataReader rdr = myDataHelper.ExecuteReader(sql, p, CommandType.Text);

List<Purchases> purchaseHistory = new List<Purchases>();

//Fill purchaseHistory here...

return purchaseHistory;

}

}

Now, let’s say on our ASP.Net page we have a drop down list that the user can choose to change the page size and other standard stuff. We can code a method called BindList and code it like this:

private int CurrentPage

{

get

{

// look for current page in ViewState

object o = this.ViewState["CurrentPage"];

if (o == null)

return 0; // default page index of 0

else

return (int)o;

}

set

{

this.ViewState["CurrentPage"] = value;

}

}

private int PurchasesCount

{

get { return (this.ViewState["PurchasesCount"] != null ?

int.Parse(this.ViewState["PurchasesCount"].ToString()) : GetPurchasesCount());

}

set { this.ViewState["PurchasesCount"] = value; }

}

private int GetPurchasesCount()

{

int myPCount = Purchases.GetPurchasesCount();

PurchasesCount = myPCount;

return myPCount;

}

public void BindList()

{

PagedDataSource objPds = new PagedDataSource();

// Set paging info

objPds.AllowPaging = true;

objPds.AllowCustomPaging = true;

objPds.VirtualCount = PurchasesCount;

objPds.CurrentPageIndex = CurrentPage;

// ddlistPageSize is the dropdown list on our page for choosing page size

switch (ddlistPageSize.SelectedValue)

{

case "":

objPds.PageSize = 5;

break;

case "*":

objPds.AllowPaging = false;

break;

default:

objPds.PageSize = int.Parse(ddlistPageSize.SelectedValue);

break;

}

//

if (objPds.AllowPaging)

objPds.DataSource =

Purchases. GetPurchases((((CurrentPage + 1) * objPds.PageSize) - objPds.PageSize), ((CurrentPage + 1) * objPds.PageSize));

else

objPds.DataSource = Purchases.GetAllPurchases;

//

myGridView.DataSource = objPds;

myGridView.DataBind();

}

Love coding!

Friday, September 7, 2007

A simple document web service – Accessing internal documents from external web site

WSE 3.0 has cool features that allow us to deal with attachments. However, before I go into that I would like to share a simple web service that can give access to a pdf document on the server. The service returns the data in bytes (may be not a good idea, but a simple idea).

Here is scenario I could think we could apply this simple service to:

I have a web site which is accessible publicly. After logging into my website users should be able to view certain documents related to their cases (PDF). But the documents are not available on the web server hosting my web site but on a server that is behind firewall and not accessible to the outside world, including my web site. Now, I could put my web service on an internal box that has access to the internal document server and allow my primary web site boxes to have access to only to that service. Having setup like this, how my service is going to serve the document and how my web app is going to consume it?

Let’s look at the web service side of it first. It’s a simple service that all it does is read the file and return the bytes.

using System;

using System.Data;

using System.Web;

using System.Collections;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.ComponentModel;

using System.IO;

namespace DocumentWebService

{

///

/// Summary description for DocumentService

///

[WebService(Namespace = "http://www.myCompany.com/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[ToolboxItem(false)]

public class DocumentService : System.Web.Services.WebService

{

public AuthSoapHd soapAuthHd;

public class AuthSoapHd : SoapHeader

{

public string userName;

public string password;

}

[WebMethod, SoapHeader("soapAuthHd")]

public byte[] GetDocument(string fileName)

{

if (!(soapAuthHd.userName == "myUSERnAmE" &&

soapAuthHd.password == "myUSERnAmE"))

return null;

docPath = ConfigurationManager.AppSettings["filePath" + pathNum] + "/" + fileName;

if (File.Exists(docPath))

{

byte[] response = null;

response = File.ReadAllBytes(docPath);

return response;

}

}

}

It’s that simple J

Let’s look at how I will consume it:

myWebService.DocumentService docServ = new myWebService.DocumentService();

myWebService.AuthSoapHd authSoapHD = new myWebService.AuthSoapHd();

authSoapHD.userName = "myUSERnAmE";

authSoapHD.password = "myUSERnAmE";

docServ.AuthSoapHdValue = authSoapHD;

byte[] docData = docServ.GetDocument("myFileNAME");

Response.Clear();

Response.AddHeader("content-disposition", "attachment;filename=doc.pdf");

Response.Charset = "";

Response.Cache.SetCacheability(HttpCacheability.NoCache);

Response.ContentType = "application/pdf";

Response.BinaryWrite(docData);

Response.End();

Love coding!