Here is a quick general purpose nhibernate criteria call to retrieve a list of results where the id is in a list. It is written as a generic method that I placed in my base repository and can use it for all of my domain objects. So T resolves to the type of domain object you are retrieving.
public IEnumerable<T> Get(IEnumerable<IdType> ids)
{
var criteria = Session.CreateCriteria<T>()
.Add(Restrictions.In("Id", ids.ToArray()));
return criteria.List<T>();
}
The sql this generates is essentially:
select * from DomainObjectTable
where id in('id1', 'id2', ...)
Here’s two quick methods to get the latitude and longitude of an address. Google takes any address in and tries to find the most appropriate location, regardless of typos. Google also gives you several locations to choose from, say a more northerly point vs a more westerly one.
public bool GetCoordinates(string address, out float latitude, out float longitude)
{
XmlDocument xml = new XmlDocument();
xml.Load(string.Format("http://maps.googleapis.com/maps/api/geocode/xml?address={0}&sensor=false", address));
XmlNode node = xml.DocumentElement;
if (node.Name != "location")
node = FindXmlNode(node, "location");
XmlNode latNode = FindXmlNode(node, "lat");
XmlNode lngNode = FindXmlNode(node, "lng");
if (latNode != null && lngNode != null)
{
bool success;
success = float.TryParse(latNode.InnerText, out latitude);
success = float.TryParse(lngNode.InnerText, out longitude);
return success;
}
else
{
latitude = longitude = 0;
return false;
}
}
public XmlNode FindXmlNode(XmlNode parentNode, string name)
{
foreach (XmlNode node in parentNode.ChildNodes)
{
if (node.Name == name)
return node;
XmlNode foundNode = FindXmlNode(node, name);
if (foundNode != null)
return foundNode;
}
return null;
}
I had a problem today where I needed to prevent mulitple mouse clicks from happen and making duplicate submit requests to the server. Since I don’t like reinventing the wheel, even though I usually do, I search online for examples of what other people were doing in my case. I knew I couldn’t be the only person to come across this issue. However, all solutions I found involved javascript. They offered solutions to disable submit buttons after being clicked and replacing the button with a waiting gif or other icon; or placing a splash page over the entire page to disable any further actions. While I could have accepted this solution and moved on, I wanted to ensure that my application was not processing two requests at the same time.
Thus I went about creating my own solution to lock down the thread per user. Which lead me to the actionfilterattribute class, and using the system.threading.monitor class to mange locks. I had to allow different users to continue processing, while stopping a duplicate form submission from a single user. In the end I did not have the time to figure out how to lock down multiple form submits from the generic principal.
There’s probably room for improvement in this class but I didn’t have to time to figure it out since it is working as is. When there is no user logged in we don’t have a shared object. Otherwise, if they are logged in, we have to find the instance of that user that we locked on, and wait for that lock to release.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Security.Principal;
namespace MyAttributes
{
/// <summary>
/// This class locks a method according to the logged in user.
/// If this is applied to a method with no logged in user, locking will not occur.
/// </summary>
public class LockAttribute : ActionFilterAttribute
{
private static readonly object _firstLock = new object();
private static List<IPrincipal> userLocks = new List<IPrincipal>();
private static Dictionary<IPrincipal, int> lockCounts = new Dictionary<IPrincipal, int>();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// If the user is logged in, we have to track the locking objects.
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
int thisLock;
IPrincipal lockObj = filterContext.HttpContext.User;
// Lock down our list of locking objects so it's modified synchronously.
lock (_firstLock)
{
// If our lock does not contain our user, add it.
if (!userLocks.Contains(filterContext.HttpContext.User))
{
userLocks.Add(filterContext.HttpContext.User);
lockCounts.Add(filterContext.HttpContext.User, 0);
}
// Get the locking object.
thisLock = userLocks.IndexOf(filterContext.HttpContext.User);
lockObj = userLocks[thisLock];
// Increment the lock count.
lockCounts[lockObj]++;
}
System.Threading.Monitor.Enter(lockObj);
}
base.OnActionExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
int thisLock = -1;
IPrincipal lockObj = filterContext.HttpContext.User;
// Clean up our lock; but wait until another lock has finished.
lock (_firstLock)
{
if (userLocks.Contains(filterContext.HttpContext.User))
thisLock = userLocks.IndexOf(filterContext.HttpContext.User);
if(thisLock >= 0)
lockObj = userLocks[thisLock];
// Increment the lock count.
if(lockCounts.ContainsKey(lockObj))
lockCounts[lockObj]--;
if (lockCounts.ContainsKey(lockObj) && lockCounts[lockObj] <= 0)
{
lockCounts.Remove(lockObj);
if(userLocks.Contains(filterContext.HttpContext.User))
userLocks.Remove(filterContext.HttpContext.User);
}
}
System.Threading.Monitor.Exit(lockObj);
}
base.OnResultExecuted(filterContext);
}
}
}
This code is in it’s raw form to show you everything. In my project I created my own classes to handle the increment decrement of the lock counters.
Apply this attribute to a method to force that method to be synchronous. Be careful as this does not sync it the call on a per request basis. So if you have thousands of requests for this method at the same time, they’ll all be waiting.
public class LockAttribute : ActionFilterAttribute
{
private static readonly object _firstLock = new object();
private static readonly object _lockObj = new object();
private static bool isLocked = false;
private bool hasLock = false;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
lock (_firstLock)
{
if (isLocked)
{
System.Threading.Monitor.Enter(_lockObj);
isLocked = hasLock = true;
}
else
{
isLocked = hasLock = System.Threading.Monitor.TryEnter(_lockObj);
}
}
base.OnActionExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if(hasLock)
System.Threading.Monitor.Exit(_lockObj);
base.OnResultExecuted(filterContext);
}
}

Categories
Tag Cloud
Blog RSS
Comments RSS
Last 50 Posts
Back
Void « Default
Life
Earth
Wind
Water
Fire
Light 