Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

October 2009 - Posts

Number Parsing in JavaScript

How many times did you have this in your code:

var str = getSomeNumber(); //say, 1212

var num = parseInt(str);

window.alert('Number is: ' + num);  //Number is: 1212

Nothing special about it... or is it?

It happens that JavaScript's parseInt function is smarter than you think (and, probably, smarter that it should): it tries to interpret the string passed as a parameter and returns the result based on its perceived radix, which may not be 10. An example? Try this:

window.alert('Number is: ' + parseInt('010')); //Number is: 8!!

So, what's the solution? Simply pass the appropriate radix as the second parameter for parseInt:

window.alert('Number is: ' + parseInt('010', 10)); //Number is: 10!! Alright!!

Bookmark and Share
Microsoft Sync Framework SDK 2.0 Released

Get it from here. Read about this release on its site.

Bookmark and Share
ADO.NET Data Services and NHibernate

Update: this is based on the old NHContrib LINQ provider; the current one, on the NHibernate core, does not have an NHibernateContext class. Also, ADO.NET Data Services are now called WCF Data Services. For additional information, please read this post.

With the arrival of the LINQ provider for NHibernate, NHibernate now supports ADO.NET Data Services. There are some restrictions, however:

  • Relations must be entities or simple collections of entities (Entity, IList, IList<T>), not sets (ISet<T>, HashSet<T>) or maps (IDictionary, IDictionary<K, V>, HashTable);
  • The ID property must be called either "ID", or end with "ID", for example, CustomerID, otherwise you must apply the DataServiceKeyAttribute to the primary key property;
  • The ID property must have a public setter as well as a public getter;
  • The ID property must be of a base type, such as int or string;
  • The collections to expose must be public properties of type IQueryable<T> or IOrderedQueryable<T>.

Here is an example:

public class Customer

{

    public virtual Int32 ID

    {

        get;

        set;

    }

    public virtual IList<Orders> Orders

    {

        get;

        private set;

    }

}

public class CustomersOrdersContext: NHibernateContext

{

    public CustomersOrdersContext()

    {

    }

    public CustomersOrdersContext(ISession session): base(session)

;nbsp;   {

    }

    public IOrderedQueryable<Orders> Orders

    {

        get

        {

            return(this.Session.Linq<Orders>();

        }

    }

    public IOrderedQueryable<Customers> Customers

    {

        get

        {

            return(this.Session.Linq<Customers>();

        }

    }

}

And, on the ADO.NET Data Services class:

[ServiceBehavior(IncludeExceptionDetailsInFaults = true)] 

public class CustomersOrdersDataService: DataService<CustomersOrdersContext>

{

    public static void InitializeService(DataServiceConfiguration config)

    {

       config.SetEntitySetAccessRule("*", EntitySetRights.All);
       config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
       config.DataServiceBehavior.AcceptCountRequests = true;
       config.DataServiceBehavior.AcceptProjectionRequests = true;
    }

}

The IncludeExceptionDetailInFaults helps debugging any exceptions that may occur, you should remove it in production code. Read this for additional information.

Bookmark and Share
Manually Indexing an Entity with NHibernate Search

Updated: thanks, Ayende!

NHibernate Search, which you can get in source format with SVN from the NHContrib trunk here, is an API that integrates NHibernate with the popular indexer Lucene.NET. Out of the box, it indexes the properties from your entities, the way you want it to (at the moment, only by using attributes), at insert/update/delete time, through the use of listeners. But what if you want to index an entity that already comes from the DB? Let's see how this can be done.

First, out entity:

 

[Indexed]
public class SomeClass
{
	[DocumentId]
	public virtual Int32 Id
	{
		get;
		private set;
	}

	[Field(Index.Tokenized, Store = Store.Yes)]
	public virtual String SomeProperty
	{
		get;
		set;
	}
}

Then, use this code:

Configuration cfg = ...;
ISession session = ...;
SomeClass a = ...;

using (IFullTextSession searchSession = Search.CreateFullTextSession(session))
{
    searchSession.Index(a);
}

And, finally, query it using this:

IList<SomeClass> items = searchSession.CreateFullTextQuery<SomeClass>("SomeProperty:SomeValue").List<SomeClass>();
Bookmark and Share
Finding Dirty Properties in NHibernate

Sometimes there may be a need for finding out if a specific entity, or a property of that entity, was changed, or, better yet, the original value for that property.

Below is a set of extensions for ISession that give you just that.

 

public static class SessionExtensions
	{
		public static Boolean IsDirtyEntity(this ISession session, Object entity)
		{
			String className = NHibernateProxyHelper.GuessClass(entity).FullName;
			ISessionImplementor sessionImpl = session.GetSessionImplementation();
			IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;
			IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(className);
			EntityEntry oldEntry = sessionImpl.PersistenceContext.GetEntry(entity);

			if ((oldEntry == null) && (entity is INHibernateProxy))
			{
				INHibernateProxy proxy = entity as INHibernateProxy;
				Object obj = sessionImpl.PersistenceContext.Unproxy(proxy);
				oldEntry = sessionImpl.PersistenceContext.GetEntry(obj);
			}

			Object [] oldState = oldEntry.LoadedState;
			Object [] currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);
			Int32 [] dirtyProps = persister.FindDirty(currentState, oldState, entity, sessionImpl);
			
			return (dirtyProps != null);
		}

		public static Boolean IsDirtyProperty(this ISession session, Object entity, String propertyName)
		{
			String className = NHibernateProxyHelper.GuessClass(entity).FullName;
			ISessionImplementor sessionImpl = session.GetSessionImplementation();
			IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;
			IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(className);
			EntityEntry oldEntry = sessionImpl.PersistenceContext.GetEntry(entity);

			if ((oldEntry == null) && (entity is INHibernateProxy))
			{
				INHibernateProxy proxy = entity as INHibernateProxy;
				Object obj = sessionImpl.PersistenceContext.Unproxy(proxy);
				oldEntry = sessionImpl.PersistenceContext.GetEntry(obj);
			}

			Object [] oldState = oldEntry.LoadedState;
			Object [] currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);
			Int32 [] dirtyProps = persister.FindDirty(currentState, oldState, entity, sessionImpl);
			Int32 index = Array.IndexOf(persister.PropertyNames, propertyName);

			Boolean isDirty = (dirtyProps != null) ? (Array.IndexOf(dirtyProps, index) != -1) : false;

			return (isDirty);
		}

		public static Object GetOriginalEntityProperty(this ISession session, Object entity, String propertyName)
		{
			String className = NHibernateProxyHelper.GuessClass(entity).FullName;
			ISessionImplementor sessionImpl = session.GetSessionImplementation();
			IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;
			IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(className);
			EntityEntry oldEntry = sessionImpl.PersistenceContext.GetEntry(entity);

			if ((oldEntry == null) && (entity is INHibernateProxy))
			{
				INHibernateProxy proxy = entity as INHibernateProxy;
				Object obj = sessionImpl.PersistenceContext.Unproxy(proxy);
				oldEntry = sessionImpl.PersistenceContext.GetEntry(obj);
			}

			Object [] oldState = oldEntry.LoadedState;
			Object [] currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);
			Int32 [] dirtyProps = persister.FindDirty(currentState, oldState, entity, sessionImpl);
			Int32 index = Array.IndexOf(persister.PropertyNames, propertyName);

			Boolean isDirty = (dirtyProps != null) ? (Array.IndexOf(dirtyProps, index) != -1) : false;

			return ((isDirty == true) ? oldState [ index ] : currentState [ index ]);
		}
	}

Bookmark and Share
.NET Serializers, part 2

There were some things left (well, a lot, actually) from my previous article on .NET serializers. One of these things was the ability to have serializers call specific methods before or after serialization. This can be achieved in two ways:

  • Through implementation of interfaces;
  • Through the use of attributes.

Interface System.Runtime.Serialization.IDeserializationCallback defines a method named OnDeserialization that is called after de deserialization process. You receive the deserialized object as its only argument and you can change it at your will. Only works with IFormatter-based serializers, such as BinaryFormatter and SoapFormatter, not with XmlSerializer.

As for attributes, the following can be applied to methods of your class:

  • System.Runtime.Serialization.OnSerializingAttribute (IFormatter and XmlObjectSerializer)
  • System.Runtime.Serialization.OnSerializedAttribute (IFormatter and XmlObjectSerializer)
  • System.Runtime.Serialization.OnDeserializingAttribute (IFormatter and XmlObjectSerializer)
  • System.Runtime.Serialization.OnDeserializedAttribute (IFormatter and XmlObjectSerializer)

Doesn't matter if the methods are public or private, but they must have the following signature:

void MethodName(StreamingContext ctx)

Through the StreamingContext parameter you can access the properties that will be serialized or deserialized and act upon them.

Please notice that the attribute-based approach is the only one that works with WCF, which uses XmlObjectSerializer-based serializers, as well as IFormatter-based.

Bookmark and Share
.NET Serializers

(UPDATED) 

As of version 3.5 SP1, .NET comes along with the following serializers:

  • System.Runtime.Serialization.Formatters.Binary.BinaryFormatter: binary serializer used in .NET Remoting, type information is included, understands System.Runtime.Serialization.ISerializable;
  • System.Runtime.Serialization.Formatters.Soap.SoapFormatter: SOAP (XML) serializer used in .NET Remoting, includes type information, understands System.Runtime.Serialization.ISerializable;
  • System.Runtime.Serialization.DataContractSerializer: XML serializer used in WCF, does not include type information;
  • System.Runtime.Serialization.Json.DataContractJsonSerializer: JSON serializer used in WCF, does not include type information;
  • System.Runtime.Serialization.NetDataContractSerializer: binary serializer used in WCF, includes type information;
  • System.Xml.Serialization.XmlSerializer: XML serializer used in ASP.NET Web Services (ASMX), type information is not included, understands System.Xml.Serialization.IXmlSerializable; 
  • System.Web.UI.LosFormatter: uses ObjectStateFormatter internally, does not account by itself;
  • System.Web.UI.ObjectStateFormatter: binary or text (base 64 encoded) serializer used in ASP.NET for storing items in view state, control state and session, type information is included, understands System.Runtime.Serialization.ISerializable.

There isn't, however, a common interface for all of these serializers, and, in fact, they have quite different requirements.

The base interfaces are:

  • System.Runtime.Serialization.IFormatter: for BinaryFormatter, SoapFormatter, NetDataContractSerializer and ObjectStateFormatter;
  • System.Runtime.Serialization.XmlObjectSerializer: for DataContractSerializer, DataContractJsonSerializer and NetDataContractSerializer;
  • XmlSerializer doesn't have any interface that specifies its behavior.

The interfaces that can be used to control the serialization process are:

  • System.Runtime.Serialization.ISerializable: for all the IFormatter serializers;
  • System.Xml.Serialization.IXmlSerializable: for XmlSerializer.

Also, there are a couple of attribute classes that can be used to control the serialization process:

  • System.Runtime.Serialization.OptionalFieldAttribute (IFormatter): field may be missing from the serialized content
  • System.Runtime.Serialization.NonSerializedAttribute (IFormatter): field is not serialized
  • System.Xml.Serialization.SoapAttributeAttribute (XmlSerializer)
  • System.Xml.Serialization.SoapElementAttribute (XmlSerializer)
  • System.Xml.Serialization.SoapEnumAttribute (XmlSerializer)
  • System.Xml.Serialization.SoapIgnoreAttribute (XmlSerializer)
  • System.Xml.Serialization.SoapIncludeAttribute (XmlSerializer)
  • System.Xml.Serialization.SoapTypeAttribute (XmlSerializer)
  • System.Xml.Serialization.SoapDocumentServiceAttribute (XmlSerializer): default format is Document
  • System.Xml.Serialization.SoapRpcServiceAttribute (XmlSerializer): default format is RPC
  • System.Xml.Serialization.SoapRpcMethodAttribute (XmlSerializer): method uses SOAP RPC format
  • System.Xml.Serialization.SoapDocumentMethodAttribute (XmlSerializer): method uses SOAP Document format
  • System.Xml.Serialization.XmlAnyAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlAnyElementAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlArrayAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlArrayItemAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlAttributeAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlChoiceIdentifierAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlElementAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlEnumAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlIgnoreAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlIncludeAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlRootAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlTextAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlTypeAttribute (XmlSerializer)
  • System.Xml.Serialization.XmlSchemaProviderAttribute (XmlSerializer): applied on a method that returns the XML schema
  • System.Runtime.Serialization.CollectionDataContractAttribute (XmlObjectSerializer)
  • System.Runtime.Serialization.DataContractAttribute (XmlObjectSerializer)
  • System.Runtime.Serialization.DataMemberAttribute (XmlObjectSerializer)
  • System.Runtime.Serialization.EnumMemberAttribute (XmlObjectSerializer)
  • System.Runtime.Serialization.IgnoreDataMemberAttribute (XmlObjectSerializer)
  • System.Runtime.Serialization.XmlSerializerFormatAttribute (XmlObjectSerializer): choose XmlSerializer instead of DataContractSerializer

Note that the Soap* attributes are only considered if the SoapBindingUse.Encoded is set for the Use property of the binding, in ASP.NET Web Services, otherwise, its the Xml* attributes.

It would be good to see a common interface (perhaps IFormatter, since it's the most common) for all of these serializers.

Bookmark and Share
Generating a Unique Identifier for Each Page Instance

Sometimes there may be a need for identifying each page instance univocally. One ocasion may be, for example, if we want to store something in a session which is specific to a certain page.

What I did was override the Page class' ID property and have it return a unique value for a page that is kept throughout all postbacks. Here is my code:

public override String ID

{

    get

    {

        String id = null;

        if ((this.IsPostBack == true) && (String.IsNullOrEmpty(this.Context.Request.Form["__ID"]) == false))

        {

            id = this.Context.Request.Form["__ID"];

        }

        else if (String.IsNullOrEmpty(this.Context.Items [ "__ID" ] as String) == false)

        {

             id =
this.Context.Items [ "__ID" ] as String;

        }

        else

        {

            id =
Guid.NewGuid().ToString();            this.Context.Items [ "__ID" ] = id;

        }

 

        return (id);

    }

}

protected override void OnPreInit(EventArgs e)

{

    this.ClientScript.RegisterHiddenField("__ID", this.ID);    base.OnPreInit(e);

}

Bookmark and Share
Custom Binding With EntityDataSource

Here's a common scenario: you are using an EntityDataSource control which you are binding to a data control, perhaps a ListView, DataGrid, DataList, Repeater, or GridView. The problem is, you want to do some custom binding. This happens, for example, when viewing a master-detail relationship.

What you typically do then is implement a custom event handler for event ItemDataBound (for ListView, DataGrid, DataList and Repeater) or RowDataBound (for GridView) and do something with the e.Item.DataItem property value (in the former cases) or e.Row.DataItem (in the later one), which is, of course, a pointer to your entity object... or is it? Depending on the way you've set up EntityDataSource on your page, it may or may not be.

If you used the EntitySetName property to indicate the name of your entity, it won't work, because the e.Item.DataItem (or e.Row.DataItem) will instead contain a wrapper object:

<asp:EntityDataSource ID="myEntitiesDataSource" runat="server" ConnectionString="name=MyEntities" EntitySetName="Entity"

DefaultContainerName="MyEntities" />

protected void OnItemDataBound(Object sender, RepeaterItemEventArgs e)

{

    Entity entity = e.Item.DataItem as Entity//null

    entity = this.GetWrappedEntity<Entity>(e.Item.DataItem);  //see code below

}

In this case, you must use this in order to get the actual entity: 

protected TEntity GetWrappedEntity<TEntity>(Object dataItem) where TEntity : class

{

    TEntity entity = dataItem
as TEntity;
    if (entity != null)

    {

        return (entity);

    }

    else

    {

        ICustomTypeDescriptor td = dataItem as ICustomTypeDescriptor;        if (td != null)

        {

            return (td.GetPropertyOwner(null) as TEntity);

        }

        else

        {

            return (null);

        }

    }

}

If, however, you skip the EntitySetName property and instead set the CommandText property, everything works as usual:

<asp:EntityDataSource ID="myEntitiesDataSource" runat="server"

ConnectionString="name=MyEntities" CommandText="SELECT VALUE entity FROM MyEntities.Entities AS entity"

DefaultContainerName="MyEntities" />

protected void OnItemDataBound(Object sender, RepeaterItemEventArgs e)

{

    Entity entity = e.Item.DataItem as Entity//ok

}

Hope this saves you some trouble! :-)

Bookmark and Share
New Version of AJAX Control Toolkit Released

Version 3.0.30930 is out. This release includes two new controls:

  • Seadragon - Seadragon enables you to pan, zoom, and make an image full screen. You can use it, for example, to display interactive product pictures.
  • AsyncFileUpload - This new control enables you to perform file uploads without doing a postback. The control displays a throbber image during upload and raises client and server events when the upload is complete. This control was contributed by Steven Lindsay.

More than 20 bugs were also fixed. See them all live at the samples page.

Get it here. Also check the candidate controls submitted by the community.

Bookmark and Share
More Posts