Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

August 2009 - Posts

Using ASP.NET Providers in Non-ASP.NET Applications

ASP.NET developers are most likely familiar with the rich provider-based modules supplied with ASP.NET. These are the Role Provider, the Membership Provider, the Profile Provider, the Personalization Provider, the Web Events Provider, the Site Map Provider, the Session State Provider and the Protected Configuration Provider. For detailed information on all of these modules, you should read this. The providers that I will talk about are the Role, Membership and Profile, which are the ones that may be used in non-ASP.NET applications.

These post is targeted at Windows Forms users, since ASP.NET ones are probably familiar with all these concepts. 

What's the purpose of using these providers in your applications? Well, they implement some typical requirements of enterprise-level applications, so you don't have to develop your own:

  • User creation, management, authentication and monitoring (Membership Provider)
  • Role creation and assignment to users (Role Provider)
  • Per-user configuration (Profile Provider)

The concepts involved are:

  1. A user has certain well-known settable properties, such as a password, a question and an answer, an approval flag, an e-mail and some comments and some implicit properties, like the creation date, last login date, last activity date, logged-in flag, online flag, last lockout date and last password changing date
  2. A user may belong to none or some roles, a role may be associated with many users
  3. A user may have particular values for system-wide defined properties

I will not get into details on all of these providers, and I won't also talk about rolling out your own providers, which is actually quite simple. The default providers are registed in the global Machine.config file, located in %WINDIR%\Microsoft.NET\Framework\v2.0.50727\Config with their default settings. All providers inherit indirectly from System.Configuration.Provider.ProviderBase.

The default implementations, which are the ones I will talk about, require an SQL Server database, so we need to create it. We do so with the aspnet_regsql command, which you can find on %WINDIR%\Microsoft.NET\Framework\v2.0.50727. After you run it, you are prompted for the location of the SQL Server to use, and after that a number of tables and stored procedures are created. Don't forget to set it's connection string in App.config:

<connectionStrings>

  <add name="SomeConnectionStringName" connectionString="Data Source=localhost;Integrated Security=SSPI;Initial Catalog=SomeDatabaseName" providerName="System.Data.SqlClient"/>

  <add name="AuthorizationStoreConnectionName" connectionString="msxml://~/SomeAutorizationStore.xml" />

</connectionStrings>

Oracle has an identical set of providers, with the sole difference that they work with Oracle databases, which may come in handy if you really need to have Oracle instead of SQL Server. They are part of Oracle Data Access Components, and you can get it from the Oracle site, here.

Now, let's move on to the providers. 

Membership Provider 

For the Membership Provider, the class that actually implements it is System.Web.Security.SqlMembershipProvider. The methods for the Membership Provider are defined in the abstract base class System.Web.Security.MembershipProvider. These are:

  • ChangePassword
  • ChangePasswordQuestionAndAnswer
  • CreateUser
  • DeleteUser
  • FindUsersByEmail
  • FindUsersByName
  • GetAllUsers
  • GetNumberOfUsersOnline
  • GetPassword
  • GetUser (overloaded)
  • GetUserNameByEmail
  • ResetPassword
  • UnlockUser
  • UpdateUser
  • ValidateUser

The configuration properties are:

  • ApplicationName
  • EnablePasswordReset
  • EnablePasswordRetrieval
  • MaxInvalidPasswordAttempts
  • MinRequiredNonAlphanumericCharacters
  • MinRequiredPasswordLength
  • PasswordAttemptWindow
  • PasswordFormat
  • PasswordStrengthRegularExpression
  • RequiresQuestionAndAnswer
  • RequiresUniqueEmail

And the single fired event is:

  • ValidatingPassword

The Membership Provider is configured through the <system.web><membership> section of the App.config file (because we are developing a Windows Forms applications, otherwise it would be, of course, Web.config). In order to use it, you must configure a default provider on the configuration file, like this:

<membership defaultProvider="SqlMembershipProvider">

  <providers>

    <add name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="SomeConnectionStringName" enablePasswordRetrieval="false" enablePasswordReset="true  requiresQuestionAndAnswer="false" applicationName="SomeApplicationName" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"   passwordStrengthRegularExpression="" />

  </providers>

</membership>

Then you can access it in code:

MembershipUser user = null;

try

{

  user = System.Web.Security.
Membership.CreateUser("ricardoperes", "somepassword");

}

catch

{

  //user already exists

  user = System.Web.Security.
Membership.GetUser("ricardoperes");

}

//perform operations on user and don't forget to call UpdateUser when finished:

System.Web.Security.Membership.UpdateUser(user);

Role Provider

The Role Provider implementation class is System.Web.Security.SqlRoleProvider, and the abstract base class that defines its operations is System.Web.Security.RoleProvider. These operations are:

  • AddUsersToRoles
  • CreateRole
  • DeleteRole
  • FindUsersInRole
  • GetAllRoles
  • GetRolesForUser
  • GetUsersInRole
  • IsUserInRole
  • RemoveUsersFromRoles
  • RoleExists

And the sole property is:

  • ApplicationName

You configure the Role Provider through section <system.web><roleManager>:

<roleManager enabled="true" defaultProvider="SqlRoleProvider">

  <providers>

    <add name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="SomeConnectionStringName" />

    <add name="AuthorizationStoreRoleProvider" type="System.Web.Security.AuthorizationStoreRoleProvider" connectionStringName="AuthorizationStoreConnectionName" applicationName="SomeApplicationName" cacheRefreshInterval="60" scopeName="" />

  </providers>

</roleManager>

You may notice that I configured two Role providers. The second one, AuthorizationStoreRoleProvider, allows us to use AzMan for the definition of the roles, instead of Windows NT groups, and may be usefull if you want to have roles that differ from you machine's or Active Directory's groups.

This is how you would use the Role Provider:

if (System.Web.Security.Roles.RoleExists("Bloggers") == false)

{

  System.Web.Security.
Roles.CreateRole("Bloggers");

}

String [] roles = System.Web.Security.Roles.GetRolesForUser("ricardoperes");if (roles.Length == 0)

{

  System.Web.Security.
Roles.AddUsersToRole(new String [] { "ricardoperes" }, "Bloggers");

}

Profile Provider

The Profile Provider is implemented in System.Web.Profile.SqlProfileProvider; the base class is System.Web.Profile.ProfileProvider. It's methods are:

  • DeleteInactiveProfiles
  • DeleteProfiles (overloaded)
  • FindInactiveProfilesByUserName
  • FindProfilesByUserName
  • GetAllInactiveProfiles
  • GetAllProfiles
  • GetNumberOfInactiveProfiles

Both the Profile Provider and the system-wide properties must be configured on App.config. Note that you cannot use property groups, they don't work in non-ASP.NET applications:

<profile enabled="true" automaticSaveEnabled="true" defaultProvider="SqlProfileProvider">

  <providers>

    <add name="SqlProfileProvider" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="SomeConnectionStringName" />

  </providers>

  <properties>     <add name="Birthday" type="System.DateTime" />

    <add name="Url" type="System.String" />

    <add name="Married" type="System.Boolean" defaultValue="false" />

    <add name="Collection" type="SomeNamespace.SomeCollection, SomeAssembly" />   </properties>

</profile>

And to use it:

ProfileBase profile = System.Web.Profile.DefaultProfile.Create("ricardoperes", true);

 

DateTime birthday = (DateTime) profile.GetPropertyValue("Birthday");profile.SetPropertyValue("Birthday", new DateTime(1975, 8, 19));

profile.Save();

Bookmark and Share

Posted: Aug 29 2009, 09:29 AM by Ricardo Peres | with 1 comment(s)
Filed under: ,
Fluent NHibernate 1.0 Released

Get it from here, read about it in the wiki.

Bookmark and Share
Blog Post Hijack

Some guy at http : // www . ilovenet . com . ar has published some of my blog posts without quoting me, without a link to my blog and without even mentioning my name. I don't know about the other blog posts, but at least two of them were written by me. I can find no contact on the blog and the comments require approval.

They say plagiarism is the sincerest form of flattery but I can only think of other words to describe this.

Bookmark and Share
Posted: Aug 24 2009, 10:54 PM by Ricardo Peres | with 2 comment(s)
Filed under:
.NET Collections
Sometimes, the proper choice of a collection can greatly impact the performance of your application. For example, there are collection types that are more appropriate for insertions, others that allow faster lookups, and so on. Plus, you must decide if you want indexed collections or not, and if you want to have generic collections, in order to have compile-time type checking. The .NET BCL comes with several general-purpose collection classes. Here is a list of all the collection classes in .NET 3.5 SP1 and their intended use.

Purpose Types Description
Fixed size System.Array Can have multiple dimensions
FIFOs (Queues) System.Collections.Queue, System.Collections.Generic.Queue<T>
LIFOs (Stacks) System.Collections.Stack, System.Collections.Generic.Stack<T>
Linked lists System.Collections.Generic.LinkedList<T> Random inserts and deletes
Array-based System.Collections.ArrayList, System.Collections.Generic.List<T>
Customizable System.Collections.ObjectModel.Collection<T> can override InsertItem, RemoveItem, SetItem and ClearItems to implement custom algorithms
Thread-safe System.Collections.Generic.SynchronizedCollection<T>, System.Collections.Generic.SynchronizedReadOnlyCollection<T>
Read-only System.Collections.ObjectModel.ReadOnlyCollection<T>, System.Collections.Generic.SynchronizedReadOnlyCollection<T>, System.Collections.ObjectModel. ReadOnlyObservableCollection<T> Wrap existing (not read-only collections)
Sorted System.Collections.SortedList, System.Collections.Generic.SortedList<K,V>, System.Collections.Generic.SortedDictionary<K,V>
Sets System.Collections.Generic.HashSet<T> no repetition of elements
Keyed System.Collections.Specialized.ListDictionary (for <=10 items), System.Collections.Generic.Dictionary<K,V>, System.Collections.Hashtable (index by hash), System.Collections.Generic.KeyedByTypeCollection<T> (index by type), System.Collections.Specialized.HybridDictionary (changes depending on number of elements, ListDictionary -> Hashtable), System.Collections.Specialized.OrderedDictionary (access by key or index)
Multiple values for a single key System.Collections.Specialized.NameValueCollection
Bits System.Collections.BitArray, System.Collections.BitVector32 (up to 32 bits only)
Strings System.Collections.Specialized.StringDictionary, System.Collections.Specialized.StringCollection
Observable System.Collections.ObjectModel.ObservableCollection<T>, System.Collections.ObjectModel. ReadOnlyObservableCollection<T> Identical to System.Collections.ObjectModel.Collection<T>, fires events upon adding, removing, modifying or clearing


Of course, you should not expose a collection class directly, instead you should use collection interfaces, that all these classes implement (at least, one of them). These interfaces are:
Purpose Types
Enumerate, count System.Collections.ICollection, System.Collections.Generic.ICollection<T>
Indexed access, add/remove System.Collections.IList, System.Collections.Generic.IList<T>
Keyed System.Collections.IDictionary, System.Collections.IOrderedDictionary, System.IDictionary<K,V>
Enumerate only System.Collections.IEnumerable, System.Collections.IEnumerable<T>


There are some useful constructs missing, most notably, ISet and ISet<T>, however, a set implementation exists, as of .NET 3.5: HashSet<T>. Some recommendations for using collections:
  • Collections that rely on object identity may need proper implementation of Equals or GetHashCode methods
  • For customized object equality comparison, a custom implementation of System.Collections.IEqualityComparer<T> or System.Collections.IEqualityComparer may be passed on the constructor
  • For sorted collections, a custom implementation of System.Collections.IComparer<T> or System.Collections.IComparer may be passed on the constructor (System.Collections.Comparer, System.Collections.CaseInsensitiveComparer are default implementations)
  • If number of elements is known beforehand, use the constructor that specifies the initial capacity
  • Avoid using value types, except for keys

And that's it.

Bookmark and Share

Posted: Aug 24 2009, 08:50 PM by Ricardo Peres | with 2 comment(s)
Filed under:
NHibernate Performance Optimization

Today Fabio Maulo (of NHibernate fame) posted on NHibernate performance optimization. Unfortunately, he didn't include the source code or the DB creation scripts, but I hope he will do it. The post is, however, very interesting, and it certainly shows that NHibernate performance can dramatically change if one knows what to do. 

Bookmark and Share
Using NHibernate Validator 1.0 with NHibernate 2.1

If you want to use NHibernate Validator with the latest version of NHibernate and you are tired of waiting for the new version of NHibernate Validator which works with NHibernate 2.1 and you also don't want to recompile the whole thing, here's what to do: you must tell the CLR to redirect requests for the old version of NHibernate and Iesi.Collections to the new versions. Add these lines to your App.config or Web.config, inside the <configuration> section:

<runtime>

  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

    <dependentAssembly>

      <assemblyIdentity name="Iesi.Collections" publicKeyToken="aa95f207798dfdb4"/>

      <bindingRedirect oldVersion="1.0.0.3" newVersion="1.0.1.0"/>

    </dependentAssembly>

    <dependentAssembly>

      <assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4"/>

      <bindingRedirect oldVersion="2.0.1.4000" newVersion="2.1.0.4000"/>

    </dependentAssembly>

  </assemblyBinding>

</runtime>

Bookmark and Share
.NET O/RM Performance Comparison

With the launch of the ORMBattle.NET site, a new discussion started on the blogosphere; later on, this post by Gergely Orosz added more ashes to the fire. The subject seems to be, is it possible to blindly compare O/RM tools, disregarding all differences between them, in simple yet not plausible scenarios, such as loading/saving/updating N entities in a loop?

Oren Eini wrote about it, and so did Davy Brion, both dismissing the way tests were conducted and the general usefulness of these kinds of (well, useless) tests. I tend to agree with both, but I don't know why the performance of these OR/M tools (which all implement the Unit of Work pattern), properly configured of course, can't be configured in simple but common scenarios, such as loading entities by id, loading an amount of entities at the same time, entity materialization, entity saving and updating, SQL generation quality, and so on. Of course, a more interesting test would be implementing a simple application with well known requirements with each technology, something like the PetShop application. Or, why don't we just forget about LINQ (NHibernate's implementation, at least, is not very mature), which seems to me just a trendy subject, and focus instead on things like:

  • Cache support
  • Available mapping types
  • Support for multiple tiers
  • Query language quality (or existence)
  • Possibility to pre-compile queries
  • Support for stored procedures
  • Memory and CPU consumption
  • Existence and quality of supporting tools (automatic entity generation, for example)
  • ...
Bookmark and Share
More Posts