Friday, October 2, 2009

SPSite constructor may break AAM link translation

You can use Alternate Access Mappings (AAM) in SharePoint to host the same content on different URLs.

For example, you could have two web applications in the Default zone with the host names example.local and mysite.local, which you publish to the Internet zone using www.example.com and mysite.example.com respectively.

AAM will normally translate links in the HTML automatically, so if the end user is browsing on www.example.com (the Internet zone) the link to the My Site in the top right of the page will include the mysite.example.com host (as this URL is also from the Internet zone).

However, you may find that the default URLs are displayed in links generated by your custom code in web parts or controls, regardless of which zone you are in.

This will occur if you create a new SPSite object and only specify the URL of the site in the constructor. SharePoint will then treat all content returned from this object as being in the default zone and will not translate the links.

Ensure that when you create SPSite objects you specify the current zone in the constructor. If you don't do this, it will use the default zone (and the links retrieved from that object in Url properties, Image fields, Url fields, HTML content etc. will refer to that zone).

So, instead of doing this:

using (SPSite site = new SPSite(url))
{
...
}

Do this:

SPContext context = SPContext.Current;
// This context only exists when the code is executed from a web application. For code running from from console applications, STSADM extensions, and (potentially) event handlers, you may need to refer to a different context.
using (SPSite site = new SPSite(url, context.Zone))
{
...
}

To Spin or not to Spin and a little PFX

With the advent of multi core computers more developers are getting into spinning threads. I won’t go into how to spin a thread. But it’s getting easier, .NET4 will bring parallel extensions to the framework so you can do parallel “for” loops. Checkout http://blogs.msdn.com/pfxteam/ for more info.

You may think running something on more than one thread won’t be any faster, you will be very surprised with the results.

But just because you can spin a thread it does not mean you should.

A good rule to follow is

Don’t spin if your code is going to be executed by a web service or web site

Web sites / web services by their nature are multi threaded. IIS will decide how many threads to spin to service your content. If you spin extra threads you may add load to the server.

Do spin threads if your code is going to be executed on a desktop machine

Generally your program is not going to have multiple instances that are all very busy doing work for multiple users. So it’s good to spin threads. But do consider the effect of nesting:
If we are going to spin more than one thread for this loop :

public static void DoSubWork()
{
  // We could spin 4 threads for this
  for (int i = 0; i < 5000; i++)
  {
  }
}

And we decide to spin more threads for this loop :

public static void DoLotsOfWork()
{
  // We could spin 4 threads for this
  for (int i = 0; i < 1000000; i++)
  {
  }
}

Then we make DoLotsOfWork() call DoSubWork() we are going to be spinning lots more threads. That’s where PFX comes in. PFX will manage the thread pool count so that is does not exceed a fixed limit. So with PFX your code would look like :

public static void DoLotsOfWork()
{
  Parallel.For(1, 1000000, i; =>
  {
    DoSubWork();
  });
}

public static void DoSubWork()
{
  Parallel.For(1, 1000000, i =>
  {
  });
}

If you call DoLotsOfWork() you will see that it will not spin more than 4 threads. You can view by debugging the code and viewing the thread window (Debug – Windows – Threads) or (CTRL+D,T)

This is my thread list. (just the ones that are doing the looping)

840 ThreadExample.Program.DoLotsOfWork
1880 ThreadExample.Program.DoLotsOfWork.AnonymousMethod
6724 ThreadExample.Program.DoLotsOfWork.AnonymousMethod
4332 ThreadExample.Program.DoSubWork.AnonymousMethod
6176 ThreadExample.Program.DoSubWork.AnonymousMethod

I do think one limitation of PFX (or at least with the CTP) is that you cannot choose how many threads. It will use core count * 2. I can understand the reason for this but if you are spinning more than one thread to download lots of images from a website then you may want to base the number of threads that you spin upon bandwidth rather than CPU resources. (I will have to check .NET4 to see if this has changed)

AOP and Transactions

A project I work on started out as a .NET 1.1 solution, we made a decision to use Serviced Components to handle transactions.

We had our reasons for this, things like :

  • Developers don’t need to worry about transactions, they are handled.
  • In some installations we need to span databases.
  • Transactional Message Queues.

It worked great, but then .NET 2 came along, and we had heard good things about System.Transaction, we wanted to use it, not just because it was cool and new but serviced components did give us a few headaches.

So, we had a fully transactional API, all of our Business classes derived from a common bases class, so.. to make them 'non serviced components' we just removed the base class, but how did we start a transaction for the first call the method and commit it when the last class was disposed.

That’s were AOP comes in, I looked on the web for some examples, I found one that fitted out requirements on MSDN :

http://msdn.microsoft.com/msdnmag/issues/02/03/AOP/default.aspx

This gave me a good start.

We needed AOP as we check each method call for an error, if we get an error we set a bool, then in the dispose we just abort the transaction.

The code below shows how we did this. Note, this code was taken from a production system, I have removed some parts of it, but it should work.

[TransactionSupport()]
public abstract class AOPServicedComponent : ContextBoundObject, IDisposable
{

}

#region AOP Transaction


internal class TransactionSupportedAspect : IMessageSink
{
private IMessageSink m_next;
private bool disposing;

TransactionScope ts;

bool inerror = false;

internal TransactionSupportedAspect(IMessageSink next)
{
// Cache the next sink in the chain
m_next = next;
}

public IMessageSink NextSink
{
get
{
return m_next;
}
}

public IMessage SyncProcessMessage(IMessage msg)
{
IMessage returnMethod;
if (preProcessTransaction(msg) == TransactionParticipation.Suppress)
{
using (new TransactionScope(TransactionScopeOption.Suppress))
{
returnMethod = m_next.SyncProcessMessage(msg);
}
}
else
{
returnMethod = m_next.SyncProcessMessage(msg);
}
postProcessTransaction(msg, returnMethod);
return returnMethod;
}

public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
throw new InvalidOperationException();
}

public static string ContextName
{
get
{
return "TransactionSupported";
}
}

private TransactionParticipation? preProcessTransaction(IMessage msg)
{

// We only want to process method calls
if (!(msg is IMethodMessage)) return null;

IMethodMessage call = msg as IMethodMessage;
Type t = Type.GetType(call.TypeName);

if (t.Name == "IDisposable")
disposing = true;
else
disposing = false;

if (!disposing)
{
// Create the Transaction
ts = new Transaction();
}

// set us up in the callContext
call.LogicalCallContext.SetData(ContextName, this);
return participation;
}

private void postProcessTransaction(IMessage msg, IMessage msgReturn)
{
// We only want to process method return calls
if (!(msg is IMethodMessage) ||
!(msgReturn is IMethodReturnMessage)) return;

IMethodReturnMessage retMsg = (IMethodReturnMessage)msgReturn;

if (disposing)
{
// Commit the transaction
if (!inerror)
{
ts.Complete();
}
// else it will be rolled back when it is disposed

ts.Dispose();
//ts = null;
}
Exception e = retMsg.Exception;
if (e != null) inerror = true;
}
}

public class TransactionSupportedProperty : IContextProperty, IContributeObjectSink
{
public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink next)
{
return new TransactionSupportedAspect(next);
}
public bool IsNewContextOK(Context newCtx)
{
return true;
}
public void Freeze(Context newContext)
{
}
public string Name
{
get
{
return "TransactionSupportedProperty";
}
}
}

[AttributeUsage(AttributeTargets.Class)]
public class TransactionSupportAttribute : ContextAttribute
{
public TransactionSupportAttribute() : base("TransactionSupported") { }
public override void GetPropertiesForNewContext(IConstructionCallMessage ccm)
{
ccm.ContextProperties.Add(new TransactionSupportedProperty());
}
}
[AttributeUsage(AttributeTargets.Method)]
public class TransactionParticipationAttribute : Attribute
{
TransactionParticipation participation = TransactionParticipation.Required;
public TransactionParticipation Participation
{
get
{
return participation;
}
}
public TransactionParticipationAttribute() { }
public TransactionParticipationAttribute(TransactionParticipation participation)
{
this.participation = participation;
}
}
public enum TransactionParticipation
{
UseExisting,
Required,
Suppress
}
#endregion


We didn’t just leave it there, we added code to allow us to control the transactionscope with the use off attributes, just like ServicedComponents. we added code the 'post' method to to-do some tricks with exceptions (I may blog this later).