Archive for December 2009

JQuery id with unauthorised characters

December 31, 2009

Yesterday was the second time I’ve found myself staring at the screen trying to figure out what just went wrong there, which in my book is the best trigger for writing a post. The problem is very simple:

In ASP.NET MVC, in order to get a collection (list/array/dictionary etc’) property of your view-model out back to the controller, you need to have your TextBox (or whatever) id attribute looking like this:

<input ... id="MyList[0].Name" ... />

More about it can be found here. Now, all is working nice and tidy until you bring JQuery in, which will not let you select such an object by its id (or any id that contains selector characters such as ‘.’, ‘:’ and so on) , so that the following code will return null:

$("#MyList[0]_Name")

My almighty, kind and generous boss has came up with a bit of code that will override this behviour, which I took liberties to refactor in order to take care of the ‘.’ and ‘:’ cases (even though dots shouldn’t really be a part of the id since the HtmlHelper extension methods in MVC replace dots with an underscore)-

function $$(selector, context) {
 return jQuery(selector.replace(/(\[|\]|:|\.)/g, '\\$1'), context)
}

So that all you need to do is:

$$("#MyList[0]_Name")

tidy! 🙂

Advertisements

Using ASP.NET MVC dynamic SiteMap to simplify User/Role authentication

December 25, 2009

On of the security requirements of the app I’m working on is to let the admin user decide who can access what page. This is a fairly straight forward and rather frequent requirement, which most developers confront.

Now, since we’re working on an ASP.NET MVC project I had to have a look for an MVC SiteMapProvider, and came across this great work by Maarten Balliauw.

What we’ve done was overriding his Provider with a SQL-based one, to make it dynamic and more configurable. First and foremost, we’ve based our security model on a Role (or UserGroup if you prefer) with N Permissions (which translates to a Roles-Permissions many-to-many table). As soon as you establish this relation, when writing your SqlSiteMapProvider, in your BuildSiteMap() method you simply load only the current user Role Permissions property:

IList<Permission> permissions = _authenticationService.GetCurrentUserPermissions(userId);

And then you build your SiteMap graph with all the actions/operations/views the current user is permitted to access. Each Permission object has an Action and a Controller properties, and Maarten’s MvcSiteMapNode takes care of the Url property, using the Action and Controller properties. The Permission would also have a ParentPermission and ChildPermissions (in which case you’d only have to load all orphan- first level- permissions of current user role and eagerly fetch the child permissions bag property). On top of that, the permission Id property could work for the SiteMapNode Key.

What you’ve got now is a dynamic site map constructed according to the current user role/permissions. How do you use it then to know if the user is authorised to access a certain View? Quite simply, in your CustomBaseController, overriding the OnActionExecuting method you add:

if (SiteMap.Provider.CurrentNode == null) throw new AuthenticationException();

That simple 🙂

Filtering queries with AOP?

December 25, 2009

Our client asked us to enable the filtering of certain queries by the profile of the current logged user. For example, a user from a certain region could see information concerning his region only. The first thing that came into my mind was setting the context with AOP; however, using NHibernate, I was kindly directed by Tuna Toksöz (thanks again!) to this truly elegant solution. However, this work only when the context is “prefixed” and known in advanced. When in need to enable a more dynamic approach, where the (admin) users could configure themselves what filters should be enabled on which users, have a look at Ayende’s way of doing this.

One thing you should bear in mind- if your context is an enum, they are mapped by default to a string/nvarchar column by NH today, so that adding the filter parameter type would be:

filterParametersType.Add("current", NHibernateUtil.String);

And the filter enabling in your Interceptor would be

public override void SetSession(ISession session)
 {
 session.EnableFilter("contextFilter").SetParameter("current", Context.Current.ToString());
 }

Getting return values from an SP in NHibernate

December 20, 2009

In order to get a return value from a stored procedure in NHibernate, you’ll need to, depending on the returned value, either (for singular column returned values):

  1. Create your sp in your db.
  2. Call it using the Session.CreateSQLQuery(“exec myStoredProc”)

Or (for ‘complex’, multiple column returned values):

  1. Create your sp
  2. map it.
  3. Call it.

First and foremost, remember always to use SELECT in your SP rather than RETURN.
Now, for the first case, this would look like this:

 CREATE PROCEDURE [dbo].[GetIt]
-- Add the parameters for the stored procedure here

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.

-- Insert statements for procedure here
SELECT 1342
END

This would be then called like this:

int query = session.CreateSQLQuery("exec GetIt").List<int>()[0];

As for the second case, this would look like this:

 ALTER PROCEDURE [dbo].[GetIt]
-- Add the parameters for the stored procedure here

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.

-- Insert statements for procedure here
SELECT 1342 as Id, 'MyName' as Name
END

The mapping would then be:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Examples.FirstProject"  namespace="Examples.FirstProject" >

<sql-query name="GetIt">
<return alias="result">
<return-property column="It" name="Id" />
<return-property column="Name" name="Name" />
</return>
exec GetIt
</sql-query>

</hibernate-mapping>

And finally, this would be executed like this:

IList<User> users = session.GetNamedQuery("GetIt").List<User>();

Beware that the return class referenced in the sql-query mapping should be mapped itself on its own, separately!