Monday 26 November 2007

Databinding NHibernate

Had a few problems data-binding lists returned from NHibernate (queries or collections) where the first object in the list was a proxy. We previously 'fixed' this by clearing the session prior to running the query. This then caused further problems as objects were detached and the lazy-lists threw exceptions.

The solution we came to is based on : This posting by Ayende

A TypeDescriptor was created for EntityBase (all our objects returned from NHibernate inherit from EntityBase) which was registered with the web-site in the Global.asax Application_StartUp.

Thursday 22 November 2007

Configuration Error: FairmortRoleProvider

When creating a new site we kept getting spurious errors which seemed to relate to "add name=FairmortRoleProvider...." line of Web.Config.

This was a red herring and the actual error related to Spring Config files and references.  The Salecore assemblies that are to be referenced must be added as a reference AND the relevant config files also added. Either missing reference or config file can cause this spurious error.

Thursday 25 October 2007

VS2005 not rebuilding project

Had an issue with a specific project not being rebuilt when changes made to it and web site being run. The solution contained multiple projects and none of the other projects exhibited this behavior.

 

Appears due to Project being marked as not rebuild for Solution, although this setting was not turned on manually.

Setting access via: Solution (right-click) Properties -> Configuration.

Monday 24 September 2007

NHibernate Criteria aggregate (Sum,Max etc)

It is possible to get NHibernate criteria to perform aggregations using the Projections class:

 


public double SumHours(out double chargeable, out double nonchargeable)
        {
            IList results;
            ICriteria crit = _session.CreateCriteria(typeof(Activity));
            ProjectionList projList = Projections.ProjectionList();
            projList.Add(Projections.Sum("ChargeableHours"));
            projList.Add(Projections.Sum("NonChargeableHours"));

            crit.SetProjection(projList);
            results=crit.List();
            if (results.Count == 0)
            {
                chargeable = 0;
                nonchargeable = 0;
            }
            else
            {
                chargeable = (double)(results[0] as object[])[0];
                nonchargeable = (double)(results[0] as object[])[1];
            }

            return chargeable + nonchargeable;
        }


Thursday 13 September 2007

FileUpload not working ~ no state information on postback

Had a problem where the 'selected file' information was not coming through for a dynamically created FileUpload control. The problem was due to the FileUpload control being inluded on a Ajax UpdatePanel.

FileUpload control will not work with an async postback (Ajax UpdatePanel) because the details of the file to upload are included in the Web Request of a full postback.

See Eilons Liptons Blog for more details.

Solution was to have a dedicated upload page.

Thursday 6 September 2007

Instantiating arrays

Always seem to forget the syntax for instantiating arrays in code:

int [] numbers = new int[] {3,1,4};
string [] names = new string[] {"Tom", "Dick", "Harry"};

Monday 3 September 2007

Validation of viewstate MAC failed... using AJAX UpdatePanel

Was getting the following error after a partial update of a component on an AJAX UpdatePanel:

Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster

It seems the problem occurs because after the partial update the component include a GridView that used DataKeyNames. The use of DataKeyNames requires that view state is encrypted.
I think the error occurred because this encryption was only taking place after the partial postback.

The solution seems to be to always have view state encrypted ~ a page directive.


viewStateEncryptionMode ="Always"

Thursday 30 August 2007

Databind: Object does not match target type

This error sometimes occurs when trying to bind a result from a NHibernate query. It is caused by the first item in the list being a proxy value which causes the DataBind to use reflection of the proxy rather than the real target.

Details and solution taken from Alkampfer's Place.

Possible solution, requires object implements ICloneable:


public IList<T> SafeList<T>(IList<T> input) where T : class, ICloneable {
//Symply check the type of the first element.
if (input.Count > 0) input[0] = (T) input[0].Clone();
return input;
}



If object does not implement IClonable then need to turn off Lazy loading in mapping file.

Final Solution
As it was not pratical to make all objects ICloneable or to turn off lazy loading we finally settled on clearing the cache (Session.Clear) prior to executing queries or criterias.

Wednesday 29 August 2007

LoginStatus - Login page URL

When using LoginStatus control the Login link goes to the page identified in the web.config:


system.web
authentication mode="Forms"
forms loginurl="~/Default.aspx"

Friday 15 June 2007

Problems with Properties showing in Property Editor with custom web server controls

I was creating a custom web sever control which was inherited from CompositeControl, I had removed a couple of editor properties, I then noticed that some properties were not being shown in the property editor after you switched between source and design view of a web page. To fix this I had to add in a new property, compile and use it, then take the new property back out again.
I also had to take the reference of the object out of the web page and stick it back in again.
All in all a pain in the bottom, and a waste of time!

Dear MS why did you make the development of web controls so annoying, like having to put a new control on the screen everytime you make a change, and debugging the component in design mode what were you thinking!

Thursday 7 June 2007

NHibernate:object references an unsaved transient instance

"object references an unsaved transient instance" recieved when performing a save (and transactional commit).
Caused by a related (parent) record not being saved and the entity not set up for cascading save.
e.g. User record has link to Person record but when user is saved the linked person is not saved.
Solution is either to turn on cascading saves for related entity or to explicity save the related record by creating a business object method.

Tuesday 5 June 2007

Ajax Extender Properties Gotchas

When you want to add a property to an Ajax Extender you need to do the following.

Make sure you have installed the Ajax Extender Templates, run AjaxControlExtender.vsi from the AjaxControlExtender directory of your toolkit install.

Create a new item using the ASP.NET Ajax Extender Control Template from my templates.

Note : If you set the namespace to have a . in it e.g. Company.AjaxControls then the Javascript will not be able to find the script as a webresource. If you want to do this then you have to manually change the ClientScriptResource attribute of the extender.


1) Create the C# Property in the controlExtender.cs file

[ExtenderControlProperty]
[RequiredProperty]
public string ExampleControl
{
get { return GetPropertyValue("ExampleControl", ""); }
set { SetPropertyValue("ExampleControl", value); }
}

2) Create the JavaScript Property in the controlBehaviour.js file
  • In the function(element) section, at the top of the page by the todo 1 to declare the property on the JavaScript side

    this._ExampleControl = null;

  • Add the property getter and setters at the bottom of the file

    get_ExampleControl : function() {
    return this._ExampleControl;
    },

    set_ExampleControl : function(value) {
    this._ExampleControl = value;
    },
Note : The getter and setters are named get_(propertyname) and set_(propertyname). the asp.net Ajax controls expect the names in this form.

Monday 21 May 2007

NHibernate, GetType on Proxy

When lazy loading is true the returned type from a db call will be a proxy, so if you call GetType() you will get the proxy type not the underlying class.
To overcome this use NHibernateUtil.GetClass(object-instance).

Friday 11 May 2007

C# Date encoding / parse

DateTime.Parse requires a Culture to be set to use a specific format.
If the format is known then a better alternative is to use new DateTime(year,month,day).

C# Windows dock overlap

Where panels etc are 'docked' in a windows form they can sometimes overlap (eg Left dock overlaps the Fill dock panel). To overcome this the overlapping panel must be 'Sent to Back'

Monday 23 April 2007

Windows 2003 POP3 CatchAll

To facilitate a catch-all address on Windows 2003 you need to run the scripts downloaded from here:

http://isorecorder.alexfeinman.com/catchall.htm

These have been downloaded to Sever1\\Install\Microsoft\Windows2003\MailCatchAll

Wednesday 11 April 2007

PageRequestManagerParserErrorException exporting grid

Had code to export grid but was receiving the error PageRequestManagerParserErrorException.
This appears to be due to the Export button being on a Ajax UpdatePanel and the ScriptManager having PartialUpdates set to false.
There doesn't currently appear to be any work around to fix this other than the button being removed from the UpdatePanel.

Thursday 5 April 2007

NHibernate:Unknown entity class:

Error "Unknown entity class: " occurs when either no mapping file exists for specifed or the mapping file is not flagged as embedded resource.

Tuesday 3 April 2007

AJax Calendar extender date format

The date format of the Calendar extender seesm to be mm/dd/yyyy.
To change it to culture specific:
  • Set Page Culture="auto"
  • Set Page UICulture="auto"
  • Set ScriptManager EnableScriptGlobalization="true"
  • Set ScriptManager EnableScriptLocalization="true"

Wednesday 28 March 2007

GridView : Getting updated cell values

When using a gridview the RowUpdating event arguments has a property (e.)NewValues.
There is a problem if the GridView datasource is not set to s DataSourceObject, these NewValues remain blank.
To populate use the following code:
GridView gv = (GridView)sender;
for (int i = 0; i < gridView.Columns.Count; i++)
{
DataControlFieldCell cell = gv.Rows[e.RowIndex].Cells[i] as DataControlFieldCell;
gv.Columns[i].ExtractValuesFromCell(e.NewValues, cell, DataControlRowState.Edit, true);
}

Monday 26 March 2007

Nhibernate: Date time field null on insert

Receiving exception when trying to save a record the stack tarce identified theproblem as a null value for a DateTime field.
This is caused by either:
  1. Property not marked as nullable (? after Type in property declaration)
  2. Existing record being flushed that contains an invalid null value for datetime.

NHibernate: Object not set to instance on save

When saving I received 'Object not set to instance', from the stack trace the object in question was identified as the VerisionNo.
This was correctly defined for the table in question, after investigation it was identifeid as being a link table that was being flushed which had an existing record with a Null value for the VersionNo.
This record had been either manually entered or entered prior to the versionNo field being defined as NotNull.

Friday 23 March 2007

RowDataBound checking if row is in edit mode

The RowState property of a grid row can hold more than one value using bitwise logic.
If you want to test if a row is in edit mode then use:

if ((e.Row.RowState & DataControlRowState.Edit) > 0)

The RowState will also have a value of DataControlRowState.Alternate for every other row.

Thursday 22 March 2007

GridView : DIsplaying results of function using DataItem as parameter

Instead of just displaying the actual value of a field in a column (<%# Bind("Hours") %>) you can also call a function that uses the value to get another value.
e.g.
If we have ClientID but we want to display ClientName (another tabel in the db) we can assign:
Text='<%# GetClientName(DataBinder.Eval(Container.DataItem, "ClientID")) %>'

We then have a function in the page code:

protected string GetClientName(object iD)
{
return GetClientNameById(iD);
}

Note. the parameter must be defined as object because the actual type is unknown until binding.

Spring: Error instantiating context spring.root

Had the exception "Error instantiating context spring.root" when attempting to create an object.
This was caused by not including the assembly reference that the object belonged to in the web site.

Tuesday 13 March 2007

Updatepanel : Making other panels visble/invisible

Had a problem making multiple panels visible / invisible inside an UpdatePanel. The problem was occurring when I wanted to display different panels based on wether a user was logged in or not.
As an example I created the following user control with two panels which should alternatively be displayed.
When the Top button is clicked the code was storing in a session object that the user is logged in.When the Top button is clicked the code was storing in a session object that the user is logged out. During the Render method of the contorl if the seesion object was set to Logged In then the bottom panel was set visible=true and the top panel set to visible=false (and vice versa when logged out)
This worked, until another UpdatePanel on the page performed a partial postback, then both panels were being displayed.

Assumption of what was happening: The problem seems to be that the setting of the visible=true|false was being made in the wrong place. Setting the values in the Render method mean that they are not then stored on the control state; when a different updatepanel performs a partial postback it appears the control state is used to identify what elements of the page need updating. In the above case both panels has visible=true set in the control state.
Fix: To fix the problem the setting of the panel visibilty was moved to the PreRender method (after PreRender, SaveState is called, the Render).

Validators not working in UpdatePanel after partial postback

There is a problem with Validator controls not being displayed in (Ajax) UpdatePanel after another updatepanel performs a partial postback.

i.e. Validators work fine when page is first loaded; then another UpdatePanel control performs a partial postback; the original validator is no longer displayed.

This is dues to a problem with release v1 of Asp Ajax. A patch is to be released to fix this, alternatively compatible controls can be downloaded

See this link for more details

Monday 12 March 2007

Validators & Multi-view

Validators don't (seem to) work in MultiView view.

May be due to Ajax v1 & validators see above.

Thursday 8 March 2007

NHibernate Flush before Query

Was having a problem with following:
  1. Start Session
  2. Read object/record (presentation layer)
  3. Update record/object im memory (presentation layer)
  4. Run query to check changes valid (biz layer).
  5. If 4 ok commit changes inside transaction (biz layer)
  6. End session
Step 4 was identifying a problem and so steps 5 was not completed (i.e. no explicit Commit was called), the problem was that the record changes were still being written to the database.

This is caused by the FlushMode of the session be set to Auto. When set to auto NHibernate will sometimes flush the persistent obejct prior to performing a query.

There are a few solutions to this:
  • Perform updates to object after query (not applicable in this case due to layers)
  • Disconnect object prior to updating (Evict)
  • Change FlushMode to Commit
The solution decided upon was to change FlushMode to Commit and to also clear the session if a transaction fails and rollback is called.

Tuesday 6 March 2007

Error on DataBind() of DropDownList:, invalid SelectedValue

Getting error:

has a SelectedValue which is invalid because it does not exist in the list of item


The SelectedValue before the databind is set to "" (i.e. blank string)
The error occurs because the data being bound does not include a value of "" (blank string).

To fix it:
  1. Set AppendDataBoundItems=true for control
  2. Clear the list prior to databind; .Items.Clear();
  3. Add a blank item: .Items.Add(new ListItem("", ""));
  4. Call .DataBind();

Monday 5 March 2007

How to map to a Generic IDictionary

Say you have a standard nHibernate Bag that maps to a IList

C# Definition

public virtual IList<UserGroup> Groups;


nHibernate Mapping

<bag name="UserGroups" table="UserGroup">
<key column="UserID"/>
<one-to-many class="UserGroup"/>
</bag>


You can change this to a IDictionary by changing the IList to a IDictionary in the Business Entity, then change the bag to a map,and adding a index setting to the nHibernate mapping.

So the above would be changed to

C# Definition

public virtual IDictionary<int,UserGroup> Groups;


nHibernate Mapping

<map name="UserGroups" table="UserGroup">
<key column="UserID"/>
<index column="GroupID" type="int"/>
<one-to-many class="UserGroup"/>
</map>


Where of course the index column is the column that you will search on, and the type is the type of the column.

NOTE - The Key Column and the Index column cannot be the same, but then thinking about that it would be pointless because the key value would be the same on all the keys of the dictionary.

NHibernate error loading class

Got the error:

Could not load type '...Page, SalecoreContent', check that type and assembly names are correct


Was caused by an incorrect class="Page" reference in one of the object mapping files.

Friday 2 March 2007

nHibernate Get or Load?

Session.Get and Session.Load do very similar things, the difference is.

.Get will return null if a record is not found.
.Save will return an exception if a record is not found, and if it can use a proxy, it will return a proxy, so you won't get the exception until you try to actually use the object.

If you are not sure that a record exists then use .Get and check that the object isn't null.

NHibernate:How do I know a field is dirty?

The problem arose that I needed to know if a field had changed just prior to saving:

  1. Presentation layer reads object/record
  2. Presentation layer changes object field value
  3. Presentation layer calls business layer to update the object/record
  4. Business layer needs to know if a certain field has changed to perform extra processing
When the record is read (in step 4) from the database it actually comes from the (session) cache and therefore holds the values of the changed (but not yet persisted) fields.

The solution seems to be either clear the cache or tell the business object that the field has changed. The clear-the-cache solution was not tried, would have been along the lines of Session.Evict(object).

Tuesday 27 February 2007

HQL Query - as, in errors

Tried to do a simple query:
from Page page

returned error ..expected in...

Tried
from Page as page

return error ..unexpected token:as..

After an hour of frustration realised that the object in C# was not called Page (I had renamed this to SalecorePage as it classed with the asp.net class:page).

The use of the wrong name stemmed from performing the query in SQL Server then porting to HQL.

Configuration - unknown class

Tripped me up a couple of times, the System.Configuration must be manually added as a reference to a project otherwise the Configuration class is unknown.
For some reason I always assume this reference is added by default then spend a while wondering why VS claims Configuration class is not part of System.Configuration!

Monday 26 February 2007

Asp.Net Adding a javascript confimation message box to button click

To add a javascript confimation (message) box to the click of a button add the following to the Page_Load():

btnDelete.Attributes["onclick"] = "return confirm('Are you sure you want to delete this record?');";

NHibernate - Record re-read not showing server updates

Has an issue where re-reading a record the record did not include updates that had happened on the server:
1. Read USER record (e.g. Name=JOHN).
2. Update USER record on server (e.g. set Name=MIKE).
3. Read USER record again. Name is still JOHN.

This implied the record is being read from the cache.
The problem came down to the fact that the Data-access-object was being created as a Singleton which meant the Hibernate Session was not being opened and closed.
The record will only be re-read from the server outside of Session (i.e. Hibernate will read the record from the cache if inside the same session).

Solution was to change the Spring object mapping to not create the DAO as a singleton, this meant the session was being open/closed during page life cycle.

Thursday 22 February 2007

C# Enum, enumerated types

C# Enumerated type info

Declaration:
enum MyType
{
One=1,
Two=2
};



Assignment:

int myVar = (int) MyType.One;
MyType myVar2 = MyType.Two;


Getting name of value:
string enumName = MyType.One.ToString();


Getting all values as string:
string[] enumNames = Enum.GetNames(typeof(MyType));


Getting an Enum value from a string:
MyType myVar = (MyType)Enum.Parse(typeof(MyType),"One",true)

Wednesday 21 February 2007

C# Lazy or full boolean evaluation?

C# allows for both full and lazy evaluation. For full evaluation use the single operators for And/Or (|/&), for lazy evaluation use the double operators for And/Or (&amp;amp;amp;&/||).
e.g.
Full Evaluation
if ((sName==null) | (sName="~empty~"))
...do something

will cause an exception if sName is null as the second comparions (="~empty~") will be performed.

Lazy Evaluation
if ((sName==null) || (sName="~empty~"))
...do something

will not cause an exception if sName is null because as the rest of the expression is an OR the result will be true irrespective of the rest of the expression, and so the rest of the expression is ignored.

Monday 19 February 2007

Grid-View : Select a row without "Select link"

You can use javascript to select a row in a grid-view by setting the rows onMouse and onCLick events:


protected void gvSettings_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onmouseover"] = "this.style.cursor='hand';this.style.textDecoration='underline';";
e.Row.Attributes["onmouseout"] = "this.style.textDecoration='none';";
e.Row.Attributes["onclick"] = ClientScript.GetPostBackClientHyperlink(this.gvSettings, "Select$" + e.Row.RowIndex);
}
}


When DataBind() is called on the grid the events will be set for each row.
Code taken from this Geekzilla article


.... further to this, if 'EnableEventValidation="true"' is on , which it is by default, the postback will cause an error: "Invalid postback or callback argument"


to overcome this you need to register each PostBack event in the Render fn of the page:


foreach (GridViewRow r in gvSettings.Rows)
{
if (r.RowType == DataControlRowType.DataRow)
{
Page.ClientScript.RegisterForEventValidation(this.gvSettings.UniqueID,"Select$" + r.RowIndex);
}
}

Getting a value from a control in the Page Init

The value of a control (e.g. textbox) is not available in PreInit.
As the value may be required (e.g to generate dynamic controls, set theme) it can be retrieved by accessing Http Request:

string selectedValue ;
if (Request.Form["txtNoOfRooms"] != null)
selectedValue = Request.Form["txtNoOfRooms"].ToString();


Uses name of control to retrieve value. Not each control only has 1 value.

Example taken from this article in Code Project

Friday 16 February 2007

Setting a Page Theme

Setting a page theme programmatically can be troublesome as the theme can only be set in the Page PreInit. If the theme value is coming from a control on the page then the controls value is not available in the PreInit.
The following solution was taken from : (K.Scott Allen's) OdetoCode.Com

protected void Page_PreInit(object sender, EventArgs e)
{
if (IsPostBack)
{
string uniqueID = Request[_themeListIDKey];

if (uniqueID != null && Request[uniqueID] != null)
{
Theme = Request[uniqueID];
}
}
}

protected void Page_Load(object sender, EventArgs e)
{
ClientScript.RegisterHiddenField(
_themeListIDKey, _themeList.UniqueID
);
}

const string _themeListIDKey = "_themeListIDKey";

Thursday 15 February 2007

NHibernate - a couple of transaction related issues

A couple of issues with transactional updates

1. Timeout expired.

A timeout expired error was occurring when attempting to update the same record (and field) twice within a single transaction.
This only occurred when the database update was being performed.
Solution: When updating a record multiple times do not perform the Update until all field values have been updated.

2. Illegal attempt to associate a collection with two open sessions
This error was returned when attempting to update child records of a parent record as well as updating the parent record, where the child record was being read independent of the parent record.
e.g
Parent record links to Child1 and Child2
Parent record read (which implicity reads Child1 & Child2 and puts in list Parent.Children)
Child1 record is read independently.
Parent record Updated.
Child1 record Updated.
There is no need to explicity read and update the Child1 instance. The instance (from Parent) should be updated (in memory) instead.

C# Generics typecasting

Error being received:

cannot implicity convert type ilist to list

The error occurs when calling a function that returns an IList.
e.g.

IList myFunction();
....
List myVar = new List;
myVar=myFunction();


the error occurs on the assignment of myVar=myFunction.
The local var myVar should be declared as IList.
In the above instance the new List is not required because myFunction creates the instance.
Correct code:

IList myFunction();
....
IList myVar;
myVar=myFunction();

Wednesday 14 February 2007

NHibernate save error.

Error: "object references an unsaved transient instance...."

This occurred when saving a object that had a 1:M relationship that was represented by a list.



Parent --- child1

--- child2



To fix the error add cascade="all" to the that represents the 1:M relationship in the DB Mapping file.