Wednesday, July 19, 2006

Forms and WIndows based Authentication

For Intranet applications I've done where I want to use NTLM I've done the following:
  1. Create a web application which uses Forms authentication.
  2. Set the loginUrl attribute of the forms element to "AutoLogon/AutoLogon.aspx" and set the .
  3. Create a virtual folder beneath the we app called AutoLogon which is itself an application.
  4. Set the AutoLogon web.config to use the settings you describe above.
  5. Add the following (simplified) code to the page AutoLogon.aspx IPrincipal ip = HttpContext.Current.User; IIdentity id = ip.Identity; FormsAuthentication.Initialize(); FormsAuthentication.SetAuthCookie(id.Name, false); HttpContext.Current.Response.Redirect("../", false); What this gives you is all combination of NTLM authentication without having to authenticate every page using NTLM as you can rely on the forms authentication scheme. You can also easily tie together a custom authorisation scheme with NT/Active Directory groups.

ScottGu's Blog : Recipe: Enabling Windows Authentication within an Intranet ASP.NET Web application

technorati tags:,

Convert char[] to string

char[] is quite convenient if you're reading file data using StreamReader, but it doesn't offer the same functionality as string does. Here's one way I've found of converting:

char[] charBuf = new char[1024]; // Example char array
string s = ""; // Example empty
string s = new string(charBuf); // Create new string passing charBuf into the constructor

C# Programming: Convert char[] to string

Blogged with Flock

Thursday, July 06, 2006

Creating Composite Custom Server Controls

I am in the process of creating a custom composite control.

Please comment on any mistakes or better ways you can think of doing things.

The Composite Control

The idea is to create a selector control. This involves some popping up a nice floating div in an appropriate place complete with appropriate textboxes and dropdowns for criteria selection and a pageable sortable list view underneath. The primary key or perhaps the row is clickable! this closes the box and selects the primary key. A cancel button is required also.

What's it Made of?

Inherit from CompositeControl

[ToolboxData("<{0}:Selector runat=server></{0}:Selector>")]
public class Selector : CompositeControl


The control is made up of a GridView, textboxes, comboboxes and some buttons. A LinkButton over the primary key perhaps.

Using the Control Execution Lifecycle I thought to put all the things that happen once when the control is initialised in OnInit.

Getting the data and putting it into the GridView. Also setting up some of the properties of the GridView.

Events

Right this is slightly hairy. I will describe what I have done but I think it is possible there are other solutions.

I noticed when I clicked a column to try and sort the grid that I got an unhandled event exception. Fair enough!

I went this way. Add a new EventHandler to the Sorting event on the GridView.


selectorGrid.Sorting += new GridViewSortEventHandler(selectorGrid_Sorting);

Visual Studio kindly allows you to press TAB to create the stubs and you end up with

void selectorGrid_Sorting(object sender, GridViewSortEventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}

Now when the column is clicked you end up in the selectorGrid_Sorting method and the "The method or operation is not implemented." exception is thrown.

The sort now has to be handled by the composite. Of course, you cannot use the Sort method on the GridView because you will end up in the Sorting Event and get an Overflow exception.

As the control is loaded every time any state must be preserved manually using the ViewState["myThingIWantToSave"] array.

private GridViewSortEventArgs SortArgs
{
get
{
if (ViewState["SortExpression"] != null && ViewState["SortDirection"] != null)
{
_sortValues.SortExpression = (String)ViewState["SortExpression"];
_sortValues.SortDirection = (SortDirection)ViewState["SortDirection"];
}
return _sortValues;
}
set
{
_sortValues = value;
ViewState["SortExpression"] = _sortValues.SortExpression;
ViewState["SortDirection"] = _sortValues.SortDirection;
}
}

_sortValues is private variable. It means I can have property of the right type and put defaults in. SortDirection is not Serializable either.

My event ends up looking like this:

void selectorGrid_Sorting(object sender, GridViewSortEventArgs e)
{
EnsureChildControls();

//reset to Ascending if changing expression
if (SortArgs.SortExpression != e.SortExpression)
SortArgs.SortDirection = SortDirection.Ascending;
else
//if the expression is the same just toggle the direction
_sortValues.SortDirection = SortArgs.SortDirection == SortDirection.Ascending ? SortDirection.Descending : SortDirection.Ascending;

_sortValues.SortExpression = e.SortExpression;
//Save to ViewState
SortArgs = _sortValues;
//Sort the data in the Grid
SortGrid();
}

Here is SortGrid

private void SortGrid()
{
DataTable dt = ds.Tables[0];
DataView dv = new DataView(dt);
if (SortArgs.SortExpression.Length > 0 )
dv.Sort = SortArgs.SortExpression + " " + (SortArgs.SortDirection == SortDirection.Ascending ? "ASC": "DESC");

selectorGrid.DataSource = dv;
selectorGrid.DataBind();
}

Page Indexing works in a similar way except you don't have to worry about ViewState because the GridView does it internally.

Blogged with Flock