Tuesday, 30 October 2012

Custom CMS using HTTPHandlerFactory




This is a handy chunk of code I want to keep, it allows for the use of the HttpHandlerfactory to return pages that are content managed alongside physical pages.

namespace Web.Helpers {
public class HttpCMSHandlerFactory : IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
    string pageName = Path.GetFileNameWithoutExtension(context.Request.PhysicalPath);
    
    //on Server.Transfer the context is kept, so this just overrides the existing value.
    if (context.Items.Contains("PageName")) 
    {
        context.Items["PageName"] = pageName; } else { context.Items.Add("PageName", pageName); }
        FileInfo fi = new FileInfo(context.Request.MapPath(context.Request.CurrentExecutionFilePath)); 

        //if File is not physical 
        if (fi.Exists == false) 
        {
             //Check if is survey
             if (pageName.IndexOf("Survey", 0, StringComparison.InvariantCultureIgnoreCase) >= 0) 
            { return PageParser.GetCompiledPageInstance(url, context.Server.MapPath("~/Survey.aspx"), context); 
            } 
            else 
           {
            //return page to CMS handler the context containing "PageName" is passed on to this page, which then calls to the database to return the copy.
                return PageParser.GetCompiledPageInstance(url, context.Server.MapPath("~/CMSPage.aspx"),  context); 
            } 
        } 
        else 
        {
            // Returns real page.
            return PageParser.GetCompiledPageInstance(context.Request.CurrentExecutionFilePath, fi.FullName, context); 
        } 
    }
}

All that is then needed is to override the *.aspx handler on the iis site config (which should already be there for an asp.net sites) and also add the following to the web.config:
<httphandlers>
<add path="*.aspx" type="Web.Helpers.HttpCMSHandlerFactory, Web.helpers" verb="*"/>
</httphandlers>

Friday, 26 October 2012

When Session times out before FormsAuthentication is dropped

Just wanted to keep this safe, there are probably better ways of doing this, but I often find that the FormsAuthentication object holds on to your login, after the session has cleared.

This often happens when I am testing a site and making changes, the site will drop it's session but the FormsAuthentication stays populated and logged in causing an error to be thrown until you logout and back into to repopulate the necessary session objects.

So in the OnInit event I add a simple check:
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        var current = Path.GetFileNameWithoutExtension(Request.PhysicalPath);
        if (current.StartsWith("Registration", StringComparison.InvariantCultureIgnoreCase) && Session["Objectx"] == null)
        {
            Response.Redirect("SignIn.aspx");
        }
    }

The above only worries about pages with the word Registration in then page name.

For an entire site you need to be a bit different:
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        var current = Path.GetFileNameWithoutExtension(Request.PhysicalPath);
        if (!current.Equals("SignIn", StringComparison.InvariantCultureIgnoreCase) && Session["Objectx"] == null)
        {
            Response.Redirect("SignIn.aspx");
        }
    }


Wednesday, 3 August 2011

OptGroup with asp:Dropdownlist

Most are aware that the out of the box DropdownList that comes with asp.NET doesnt allow for OptGroups. These are quite handy when it comes to structuring the layout.

One way around this is to use jQuery to insert the items required to make optgroup work.

Define your asp:DropdownList, remember to set the cssclass attribute as this makes it easier to find.

In this case I had a dropdown with the css class of eventDropDown attached.

In the data returned to the Dropdown I make sure 2 extra rows are added to separate the 2 sets of options, in this case one is PE and one is OE.

initially the data is bound with the separators (slightly edited)
<select>
<option>PE</option>
<option>ONE</option>
<option>OE</option>
<option>TWO</option>
</select>

using the :contains selector that comes with the standard jQuery libraray I was able to find the option of PE and OE to be replaced with my optgroup choices.
I have made the assumption that if PE exists, then so does OE. Makes life a bit easier.

<script type="text/ecmascript">
var item = $('.eventDropDown option:contains("PE")');
if (item != null) {
item.replaceWith("<optGroup label='Preferred Events' />");
item = $('.eventDropDown option:contains("OE")');
item.replaceWith("<optGroup label='Other Events' />");
}
</script>

I'm not sure on the accessibility level of what I am doing, but visually this will work for most cases where you want this to happen.

If you do want proper option groups do your site in MVC and make your own custom control, its fun. this is a way out for a control in ASP.NET.

Friday, 15 July 2011

Using LinQ on a DataSet

This is quite straightforward:

Apply the AsEnumerable() extension to your DataTable, allowing you to select the data you want and return it as a collection. By using the extension AsDataView(), the collection is then returned as a friendly DataView object:

for example:
var dv = (from dr in ds.Tables[0].AsEnumerable()
where dr[0] == x
select dr).AsDataView();


Tuesday, 31 May 2011

Grouping with LinQ

Using LinQ to group a set of data by something is quite straightforward.

In the example below I am returning a list of bookings, which is very flat. I wanted to group the data returned by the BookingID

Using group on BookingID, I am able to rearrange the data to "group" sets of data that relate to a specific booking. Brilliant!

var bkgs = dal.GetBookings();

var distinctbkgs = (from x in bkgs
group x by x.BookingID into xx
select new
{
Booking = xx.First(),
RelatedBookings = xx.ToList()
}).ToList();

Monday, 7 March 2011

left join with LinQ comprehension syntax

I was trying to find a way to perform a left join on 2 comparable sets of data using LinQ, but the join keyword only appears to perform an inner join (unless I missed something).

By performing a LinQ statement for the Del entry at the point I create the anonymous type, the following output would act like a left join (returning a null for the Del value when there is no match).

I then go on to select all the null entries using the extension methods and call a delete routine for each entry found.

(from x in Entries
where x.Information["Information3"] == Session["GINumber"].ToString()
select new
{
Pre = x,
Del = (from y in _delegates
where y.EmailAddress == x.Information["Information1"]
select y.EmailAddress).SingleOrDefault()
}).Where(x => x.Del == null).ToList().ForEach(x => Service.DeleteEntry(x.Pre.InformationID));


As an aside I found out that the term for the “from” “in” style of LinQ is called “Query Comprehension Syntax”.

Tuesday, 8 February 2011

Disable asp.net button

adding the following in the page load event in your ASP.NET page. This will setup the ability to disable the button you click, until the submission is complete or an error occurs.

MyButton.Attributes.Add("onclick", "this.disabled=true;" + Page.ClientScript.GetPostBackEventReference(MyButton, "").ToString());