One of the usual needs in an application developers world is to instantiate a  .NET type in a boxed/contained/isolated environment with zero impact to the  current application process space. How do we do that? This article solves this  in an easy manner, adoptable easily.
 Usual Solution
 The immediate answer is to use an Application Domain - create new application  domain and instantiate the type within the new domain. Sounds straight forward.  Sadly nope. If you thought the following lines of code would just work, you are  mistaken. To reconfirm that it does not work, try unloading the app domain and  then deleting the loaded assembly from the windows explorer. It does not let you  delete the assembly file. What happened here? 
//create the application domain and create an instance of the object
AppDomain clientDomain = AppDomain.CreateDomain("ClientTaskDomain");
Object executionObject = clientDomain.CreateInstanceAndUnwrap("ABC.Test", "MyTest");
//find the Execute method and call it.
MethodInfo executionMethod = executionObject.GetType().GetMethod("Execute");
returnData = executionMethod.Invoke(executionObject, null);
 As the type ABC.Test.MyTest was not a MarshalByRefObject descendant, the type  instance gets loaded into the main application domain. Instead if the type  ABC.Test.MyTest did descend from MarshalByRefObject, the type would have been  instantiated in the 'remote' application domain. Thats the way it is  designed.
 Easy Way Out
 Have a proxy type created in your application which descendants from  MarshalByRefObject. Instantiate this object and call a proxy routine on this  proxy object which then instantiates the real type. In this way, as the proxy  type is already created in the new application domain, the real type too would  be created in the new application domain.
AppDomain clientDomain = AppDomain.CreateDomain("ClientTaskDomain");
try
{
AssemblyLoader _aLoader = (AssemblyLoader)clientDomain.CreateInstanceAndUnwrap("XYZ.Test", "XYZ.Test.AssemblyLoader");
returnData = _aLoader.LoadAndRun("ABC.Test", "MyTest");
}
finally
{
AppDomain.Unload(clientDomain);
}
 where AssemblyLoader is defined as an MBR descendant as :
[Serializable]
public class AssemblyLoader : MarshalByRefObject
{
public Object Execute(string assemblyName, string typeName)
{
Assembly _assembly = Assembly.Load(assemblyName);
Type _type =_assembly.GetType(typeName);
MethodInfo _method =_type.GetMethod("Execute");
return _method.Invoke(Activator.CreateInstance(_type), null);
}
}
 Using this method, we have made sure that "MyTest" is always instantiated in  the new application domain. 
 Impersonate for Security
 All good until now, but how do you make sure the executed code executes under  a user supplied account ? Pretty simple if you know how to authenticate a  username/password/domain. Sadly, there is no direct way to perform a windows  authentication in .NET. Not sure why there isnt a "bool  WindowsPrincipal.Authenticate(userName, passWord,domain)" routine ? No clues. We  could go the LogonUser route, but it appears it has certain permission issues in  NT/2000 basedmachines. Hence, lets write one using the NegotiateStream 
public static class SSPIHelper
{
  enum AuthenticationState { Unknown, Success, Failure } ;
  public static WindowsPrincipal LogonUser(NetworkCredential credential)
  {
      string userName, domain, password;
      userName = credential.UserName;
      domain = credential.Domain;
      password = credential.Password;
      TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 0);
      tcpListener.Start();
      WindowsIdentity id = null;
      AuthenticationState authState = AuthenticationState.Unknown;
      IAsyncResult serverResult = tcpListener.BeginAcceptTcpClient(delegate(IAsyncResult asyncResult)
      {
          using (NegotiateStream serverSide = new NegotiateStream(
                   tcpListener.EndAcceptTcpClient(asyncResult).GetStream()))
          {
              try
              {
                  serverSide.AuthenticateAsServer(CredentialCache.DefaultNetworkCredentials,
                       ProtectionLevel.None, TokenImpersonationLevel.Impersonation);
                  id = (WindowsIdentity)serverSide.RemoteIdentity;
                  authState = AuthenticationState.Success;
              }
              catch (Exception e)
              {
                  authState = AuthenticationState.Failure;
              }
          }
      }, null);
      using (NegotiateStream clientSide = new NegotiateStream(new TcpClient("localhost",
                   ((IPEndPoint)tcpListener.LocalEndpoint).Port).GetStream()))
      {
          try
          {
              clientSide.AuthenticateAsClient(new NetworkCredential(userName, password, domain),
                       "", ProtectionLevel.None, TokenImpersonationLevel.Impersonation);
              authState = AuthenticationState.Success;
          }
          catch (Exception E)
          {
              authState = AuthenticationState.Failure;
          }
      }
      while (authState == AuthenticationState.Unknown) ;
      tcpListener.Stop();
      if (authState == AuthenticationState.Success)
          return new WindowsPrincipal(id);
      else
          return null;
  }
}
Ok, we have a windows principal. Now what ? Impersonate to execute the code  using this principal, which happens to be the easy bit.
WindowsIdentity newId = (WindowsIdentity)windowsPrincipal.Identity; //the one received from SSPIHelper
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
This makes sure that the code following the above Impersonate() call uses the  provided identity. Once we want to revert back to the original identity, just do  a Undo() (see below) 
 So effectively what we now have is an isolated and safe execution of a type  provided by the client using the credentials supplied by them. To summarize, the  code should look similar to this: 
//authenticate the client supplied credentials
WindowsPrincipal windowsPrincipal = SSPIHelper.LogonUser(credentials);
WindowsIdentity newId = (WindowsIdentity)windowsPrincipal.Identity;
//impersonate
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
try
{
//create the application domain and create an instance of the object
AppDomain clientDomain = AppDomain.CreateDomain("ClientTaskDomain");
try
{
 //use the proxy MBR object
 AssemblyLoader _aLoader = (AssemblyLoader)clientDomain.CreateInstanceAndUnwrap("XYZ.Test", "XYZ.Test.AssemblyLoader");
 returnData = _aLoader.LoadAndRun("ABC.Test", "MyTest");//call the client's method
}
finally
{
 AppDomain.Unload(clientDomain);
}
}
finally
{
impersonatedUser.Undo();//back to the normal a/c
File.Delete(assemblySaveLocation);//just to clean up things, clean the client's assembly too.
}