The easiest way to run code in another appdomain is to execute an assembly entrypoint using AppDomain.ExecuteAssembly() or (starting in v2.0) AppDomain.ExecuteAssemblyByName().
If you want to execute a method other than an assembly entrypoint, call AppDomain.CreateInstance() on a type which extends MarshalByRefObject. Then, call a method on that type which does the Assembly.Load() or whatever work you needed to do there.
An easy way to get that to work is to have your MarshalByRefObject type be in your process exe. Then, call AppDomain.CreateInstanceFrom(Assembly.GetExecutingAssembly().Location, MBROtypeName).
Be sure to not pass any Type/Assembly/etc. instances (besides your MarshalByRefObject type) back to the original appdomain. If you do, it will cause those assemblies to be loaded into the original appdomain. If the appdomain settings are different between the two appdomains, those assemblies may not be loadable there. Plus, even if they are successfully loaded, the assemblies will remain loaded and locked after the target appdomain is unloaded, even if the original appdomain never uses them.
If the reason why you need to pass it back is so that it can interact with some assembly B in that other appdomain, instead, you could pass B to the new appdomain and do all of B’s work there instead of in the original one. For example, for some applications, it’s best if the only work done in the default appdomain is creating the new one and calling CreateInstanceFrom() on it. So, the new appdomain will do all the real work for that application.