Exemple #1
0
        /// <summary>
        /// Loads/evaluates C# code into a remote AppDomain and returns a transparent proxy of the
        /// instance of the first class defined in the code.
        /// <para>The returned proxy can be used to unload the AppDomain owning the actual object
        /// the proxy points to.</para>
        /// </summary>
        /// <remarks>
        /// Note, the concrete type of the return value depends on the script class definition.
        /// It the class implement interface then an ordinary type castes proxy object is returned.
        /// However if the class doesn't implement the interface the a dynamically emitted duck-typed
        /// proxy returned instead. Such proxy cannot be built for the types implemented in file-less
        /// (in-memory) assemblies. Thus neither Mono nor Roslyn engines cannot be used with this
        /// technique. Meaning that
        /// <see cref="CSScriptLibrary.CSScript.CodeDomEvaluator"/> needs to be used.
        /// <para>While the script class to be evaluated doesn't have to implement from 'T' interface but
        /// it must inherit <see cref="System.MarshalByRefObject"/> though.</para>
        /// </remarks>
        /// <example>
        ///<code>
        /// // duck-typed proxy; must use CodeDomEvaluator
        /// var script = CSScript.CodeDomEvaluator
        ///                      .LoadCodeRemotely&lt;ICalc&gt;(
        ///                      @"using System;
        ///                        public class Calc : MarshalByRefObject
        ///                        {
        ///                            public int Sum(int a, int b)
        ///                            {
        ///                                return a + b;
        ///                            }
        ///                        }");
        ///
        /// // ordinary type casted proxy
        /// var script2 = CSScript.Evaluator
        ///                       .LoadCodeRemotely&lt;ICalc&gt;(
        ///                       @"using System;
        ///                         public class Calc : MarshalByRefObject : ICalc
        ///                         {
        ///                             public int Sum(int a, int b)
        ///                             {
        ///                                 return a + b;
        ///                             }
        ///                         }");
        ///
        /// int result = script.Sum(15, 3);
        ///
        /// // after the next line call the remote domain with loaded script will be unloaded
        /// script.UnloadOwnerDomain();
        /// </code>
        /// </example>
        /// <typeparam name="T">The interface type the remote object should be casted or aligned (duck-typed) to.</typeparam>
        /// <param name="evaluator">The evaluator.</param>
        /// <param name="scriptCode">The script code that defines the script class to be loaded.
        /// <para>The script class doesn't have to implement from 'T' interface but
        /// it must inherit <see cref="System.MarshalByRefObject"/> though.</para>
        /// </param>
        /// <param name="probingDirs">The probing directories for the assemblies the script
        /// assembly depends on.</param>
        /// <returns></returns>
        public static T LoadCodeRemotely <T>(this IEvaluator evaluator, string scriptCode, params string[] probingDirs) where T : class
        {
            var cx         = RemoteLoadingContext.NewFor(evaluator, scriptCode);
            var searchDirs = probingDirs.ConcatWith(Path.GetDirectoryName(typeof(T).Assembly.Location()));

            var remoteDomain = evaluator.GetRemoteDomain();

            if (remoteDomain == null)
            {
                remoteDomain = AppDomain.CurrentDomain.Clone();
            }

            remoteDomain.Execute(context =>
            {
                try
                {
                    CSScript.GlobalSettings.InMemoryAssembly = context.inMemoryAsm;

                    IEvaluator eval = RemoteLoadingContext.CreateEvaluator(context);

                    context.scriptObj = eval.CompileCode(context.code)
                                        .CreateObject("*");

                    bool implementsInterface = typeof(T).IsAssignableFrom(context.scriptObj.GetType());

                    if (!implementsInterface) //try to align to T
                    {
                        context.scriptObj = context.scriptObj.AlignToInterface <T>(context.scriptObj.GetType().Assembly.Location);
                    }
                }
                catch (Exception e)
                {
                    context.error = e.ToString();
                }
            }, cx, searchDirs);

            if (cx.error != null)
            {
                throw new CompilerException("Exception in the remote AppDomain: " + cx.error);
            }

            var result = (T)cx.scriptObj;

            evaluator.SetRemoteDomain(remoteDomain);
            result.SetOwnerDomain(remoteDomain);

            return(result);
        }
Exemple #2
0
        /// <summary>
        /// Wraps C# code fragment into auto-generated class (type name <c>DynamicClass</c>),
        /// evaluates it and loads the class to the remote AppDomain.
        /// <para>Returns non-typed <see cref="CSScriptLibrary.MethodDelegate"/> of the remote object for
        /// class-less style of invoking.</para>
        /// </summary>
        /// <example>
        /// <code>
        ///
        /// var log = CSScript.Evaluator
        ///                   .CreateDelegateRemotely(
        ///                                   @"void Log(string message)
        ///                                     {
        ///                                         Console.WriteLine(message);
        ///                                     }");
        ///
        /// log("Test message");
        ///
        /// log.UnloadOwnerDomain();
        /// </code>
        /// </example>
        /// <param name="evaluator">The evaluator.</param>
        /// <param name="code">The C# code.</param>
        /// <param name="probingDirs">The probing directories for the assemblies the script
        /// assembly depends on.</param>
        /// <returns> The instance of a 'duck typed' <see cref="CSScriptLibrary.MethodDelegate"/></returns>
        public static MethodDelegate CreateDelegateRemotely(this IEvaluator evaluator, string code, params string[] probingDirs)
        {
            string scriptCode = CSScript.WrapMethodToAutoClass(code, true, false, "MarshalByRefObject");

            var agentDef = @"
                             public class RemoteAgent : MarshalByRefObject, CSScriptLibrary.IRemoteAgent
                             {
                                 public object Method(params object[] parameters)
                                 {
                                      return Implementation(parameters);
                                 }
                                 public CSScriptLibrary.MethodDelegate Implementation {get; set;}
                             }";

            var cx = RemoteLoadingContext.NewFor(evaluator, scriptCode + agentDef);

            var remoteDomain = evaluator.GetRemoteDomain();

            if (remoteDomain == null)
            {
                remoteDomain = AppDomain.CurrentDomain.Clone();
            }

            remoteDomain.Execute(context =>
            {
                try
                {
                    IEvaluator eval = RemoteLoadingContext.CreateEvaluator(context);

                    var script = eval.ReferenceAssemblyOf <CSScript>()
                                 .CompileCode(context.code);

                    //var asm = script.GetType().Assembly.Location;

#if net45
                    string agentTypeName = script.DefinedTypes.Where(t => t.Name == "RemoteAgent").First().FullName;
#else
                    string agentTypeName = script.GetModules()
                                           .SelectMany(m => m.GetTypes())
                                           .Where(t => t.Name == "RemoteAgent")
                                           .First()
                                           .FullName;
#endif
                    var agent            = (IRemoteAgent)script.CreateObject(agentTypeName);
                    agent.Implementation = script.GetStaticMethod();
                    context.scriptObj    = agent;
                }
                catch (Exception e)
                {
                    context.error = e.ToString();
                }
            }, cx, probingDirs);

            if (cx.error != null)
            {
                throw new CompilerException("Exception in the remote AppDomain: " + cx.error);
            }

            var agentProxy = (IRemoteAgent)cx.scriptObj;

            MethodDelegate result = (param) => agentProxy.Method(param);

            evaluator.SetRemoteDomain(remoteDomain);
            result.SetOwnerDomain(remoteDomain)
            .SetOwnerObject(agentProxy);

            return(result);
        }