// Constructor. internal BaseVsaEngine(String language, String version, bool supportDebug) { applicationPath = String.Empty; assemblyVersion = version; compiledRootNamespace = null; engineMoniker = String.Empty; engineName = String.Empty; engineSite = null; errorLocale = CultureInfo.CurrentCulture.LCID; executionEvidence = null; failedCompilation = false; genDebugInfo = false; haveCompiledState = false; isClosed = false; isDebugInfoSupported = supportDebug; isEngineCompiled = false; isEngineDirty = false; isEngineInitialized = false; isEngineRunning = false; loadedAssembly = null; rootNamespace = String.Empty; scriptLanguage = language; startupClass = null; startupInstance = null; vsaItems = null; }
public virtual void Run(){ this.TryObtainLock(); try{ Preconditions(Pre.EngineNotClosed | Pre.EngineNotRunning | Pre.RootMonikerSet | Pre.SiteSet | Pre.RootNamespaceSet); // managed engines cannot support the AppDomain property so we always use the current one AppDomain appDomain = System.AppDomain.CurrentDomain; if (this.haveCompiledState){ // make sure the RootNamespace hasn't been changed since the compilation if (this.rootNamespace != this.compiledRootNamespace) throw new VsaException(VsaError.RootNamespaceInvalid); this.loadedAssembly = this.LoadCompiledState(); appDomain.SetData(this.engineMoniker, this.loadedAssembly); }else{ // if Compile returned false last time it was called, quit before cache lookup or callback if (this.failedCompilation) throw new VsaException(VsaError.EngineNotCompiled); this.startupClass = null; this.loadedAssembly = appDomain.GetData(this.engineMoniker) as Assembly; if (this.loadedAssembly == null){ // assembly is not in the cache, so callback to the site for compiled state // prevent multiple callbacks which could result in duplicate assemblies being loaded into the AppDomain string mutexName = this.engineMoniker + "/" + appDomain.GetHashCode().ToString(CultureInfo.InvariantCulture); Mutex compiledStateCallbackMutex = new Mutex(false, mutexName); if (compiledStateCallbackMutex.WaitOne()){ try{ // see if there was another callback before we got the lock this.loadedAssembly = appDomain.GetData(this.engineMoniker) as Assembly; if (this.loadedAssembly == null){ byte[] pe; byte[] pdb; this.engineSite.GetCompiledState(out pe, out pdb); if (pe == null) throw new VsaException(VsaError.GetCompiledStateFailed); this.loadedAssembly = Assembly.Load(pe, pdb, this.executionEvidence); appDomain.SetData(this.engineMoniker, this.loadedAssembly); } }finally{ compiledStateCallbackMutex.ReleaseMutex(); compiledStateCallbackMutex.Close(); } } } } // update the _Startup class Type object (if needed) try{ if (this.startupClass == null) this.startupClass = this.loadedAssembly.GetType(this.rootNamespace + "._Startup", true); }catch(Exception e){ // the _Startup class was not in the RootNamespace throw new VsaException(VsaError.BadAssembly, e.ToString(), e); } // set the engine to running, callback for global and event instances, then run global code try{ this.startupInstance = (BaseVsaStartup)Activator.CreateInstance(this.startupClass); this.isEngineRunning = true; this.startupInstance.SetSite(this.engineSite); this.startupInstance.Startup(); }catch(Exception e){ throw new VsaException(VsaError.UnknownError, e.ToString(), e); } }finally{ this.ReleaseLock(); } }
public virtual void Run() { this.TryObtainLock(); try{ Preconditions(Pre.EngineNotClosed | Pre.EngineNotRunning | Pre.RootMonikerSet | Pre.SiteSet | Pre.RootNamespaceSet); // managed engines cannot support the AppDomain property so we always use the current one AppDomain appDomain = System.AppDomain.CurrentDomain; if (this.haveCompiledState) { // make sure the RootNamespace hasn't been changed since the compilation if (this.rootNamespace != this.compiledRootNamespace) { throw new VsaException(VsaError.RootNamespaceInvalid); } this.loadedAssembly = this.LoadCompiledState(); appDomain.SetData(this.engineMoniker, this.loadedAssembly); } else { // if Compile returned false last time it was called, quit before cache lookup or callback if (this.failedCompilation) { throw new VsaException(VsaError.EngineNotCompiled); } this.startupClass = null; this.loadedAssembly = appDomain.GetData(this.engineMoniker) as Assembly; if (this.loadedAssembly == null) { // assembly is not in the cache, so callback to the site for compiled state // prevent multiple callbacks which could result in duplicate assemblies being loaded into the AppDomain string mutexName = this.engineMoniker + "/" + appDomain.GetHashCode().ToString(CultureInfo.InvariantCulture); Mutex compiledStateCallbackMutex = new Mutex(false, mutexName); if (compiledStateCallbackMutex.WaitOne()) { try{ // see if there was another callback before we got the lock this.loadedAssembly = appDomain.GetData(this.engineMoniker) as Assembly; if (this.loadedAssembly == null) { byte[] pe; byte[] pdb; this.engineSite.GetCompiledState(out pe, out pdb); if (pe == null) { throw new VsaException(VsaError.GetCompiledStateFailed); } this.loadedAssembly = Assembly.Load(pe, pdb, this.executionEvidence); appDomain.SetData(this.engineMoniker, this.loadedAssembly); } }finally{ compiledStateCallbackMutex.ReleaseMutex(); compiledStateCallbackMutex.Close(); } } } } // update the _Startup class Type object (if needed) try{ if (this.startupClass == null) { this.startupClass = this.loadedAssembly.GetType(this.rootNamespace + "._Startup", true); } }catch (Exception e) { // the _Startup class was not in the RootNamespace throw new VsaException(VsaError.BadAssembly, e.ToString(), e); } // set the engine to running, callback for global and event instances, then run global code try{ this.startupInstance = (BaseVsaStartup)Activator.CreateInstance(this.startupClass); this.isEngineRunning = true; this.startupInstance.SetSite(this.engineSite); this.startupInstance.Startup(); }catch (Exception e) { throw new VsaException(VsaError.UnknownError, e.ToString(), e); } }finally{ this.ReleaseLock(); } }