0

XMLファイル内の変数に基づいて電子メールを送信するC#で記述されたWindowsサービスがあります。これには、XMLファイルで提供される接続文字列を介したSQLまたはMySQLデータベースへのアクセスが含まれます。また、C#またはVB.NETコードを評価する「カスタムフィールド」と呼ばれる機能を提供します。これにより、ユーザーはカスタムコードの結果をXMLファイルに入力して、電子メールの生成に使用することもできます。ここで、カスタムコードで、ユーザーがコードから呼び出すことができる一連のヘルパー関数を提供します。この関数は、フィールドの値を取得し、必要に応じて操作できます。

基本的に、XMLでは、ユーザーはアクセスする各データベースへの参照を設定し、次にそのデータベース内の各テーブル、次にそのテーブル内の各フィールドに、テーブル内の各データベース内で「0」(ゼロ)ベースのIEであるIDが与えられます。 idは(ゼロ)から始まり、各テーブル内でもフィールドは「0」(ゼロ)から始まります

特定のフィールドへの参照は、私がブレッドクラムと呼んでいるものでは次のようにフォーマットされています。

0,2,6(データベースID 0、データベースID0内のテーブルID2、データベースID0内のテーブルID2内のフィールドID6)

また

0,3,6(データベースID 0、データベースID0内のテーブルID3、データベースID0内のテーブルID3内のフィールドID6)

ユーザーは、カスタムコード内でヘルパー関数を呼び出すことができます。ヘルパー関数は、次のようなXMLファイルで参照した任意のフィールドの場合に応じて1つまたは複数の値を取得します。

    <customFields>
    <field id="0" language="VB">
                    <name>Member Program Week</name>
                    <code><![CDATA[Dim FullName As String
FullName = MailEngine.GetFieldValue(0,0,1) + &quot; &quot; + MailEngine.GetFieldValue(0,0,1)
Return FullName]]></code>
                </field>
    </customFields>

このカスタムコードでわかるように、2つのフィールドが参照されています。1つはフィールドブレッドクラム「0,0,1」(データベースID 0、データベースID0内のテーブルID0、データベースID0内のテーブルID0内のフィールドID1)です。 )およびフィールドブレッドクラムが「0,0,2」の2つ(データベースID 0、データベースID0内のテーブルID0、データベースID0内のテーブルID0内のフィールドID2)

これらのブレッドクラムは、XMLで提供されるスキーマへの参照です。例:

...
<databases nextid="1" mainDataTable="0,0">
    <database id="0">
        <name>Fake Company Databse</name>
        <schema>fakeCompany</schema>
        <tables nextid="1">
            <table id="0" primaryKey="member_id" schema="dbo">
                <name>Members</name>
                <schema>members</schema>
                <fields nextid="3">
                    <field id="0">
                        <schema>member_id</schema>
                        <name>Member ID</name>
                    </field>
                    <field id="1">
                        <schema>member_firstname</schema>
                        <name>Member Firstname</name>
                    </field>
                    <field id="2">
                        <schema>member_lastname</schema>
                        <name>Member Lastname</name>
                    </field>
                    <field id="3">
                        <schema>member_email</schema>
                        <name>Member Email</name>
                    </field>
                </fields>
            </table>
        </tables>
    </database>
</databases>
...

基本的に、そのカスタムコードは、「FullName」という名前の文字列変数を作成し、メンバーの名と姓を取得して「」(スペース)文字で結合し、結果を「FullName」変数に格納してから結果を返します。 。その後、customCodeは、「C、0」C=Customなどのメッセージ内から呼び出すことができます。

ここに私の質問があります:

データベースフィールドなどのすべての処理はサービス自体の中で行われるため、Reflectionsを使用してサービス内からもカスタムコードが呼び出されます。ヘルパー(MailEngine)クラスから、サービスで使用される関数と変数にアクセスできます。ヘルパー(MailEngine)クラスが、サービスとは異なるコンテキストにあるカスタムコードに含まれていること。

たとえば、MailEngineクラスに次のような関数がある場合

public static string GetValueForField(int DatabaseID, int TableID, int FieldID)
{

}

この関数またはこのクラスの他の関数内から、関数を呼び出したり、サービス内にある変数を取得したりできるようにするには、何をする必要がありますか。

これは可能ですか、それともxmlドキュメントを再解析してデータベースに再接続し、すべてのフィールド値を再収集してそこから移動する必要がありますか...

どうすればもっと良いことを本当に聞くことができるのかわかりません。うまくいけば、これを理解し、提案をすることができます。

あなたが与えることができるどんな助けにも感謝します。

クリス

編集:

public class EvalVBCode{

        private string _Code;
        private CompilerErrorCollection m_oCompilerErrors = new CompilerErrorCollection();
        private Dictionary<String, String> _ReferencedAssemblies = new Dictionary<String, String>();
        private List<EvalInputObject<dynamic>> _RuntimeVariables = new List<EvalInputObject<dynamic>>();

        public string Code
        {
            get
            {
                return this._Code;
            }

            set
            {
                this._Code = value;
            }
        }

        public CompilerErrorCollection CompilerErrors{ 
            get
            {
                return m_oCompilerErrors;
            }

            set
            {
                m_oCompilerErrors = value;
            }
        }


        public Dictionary<String, String> ReferencedAssemblies
        {
            get
            {
                return this._ReferencedAssemblies;
            }
        }

        public List<EvalInputObject<dynamic>> RuntimeVariables
        {
            get
            {
                return this._RuntimeVariables;
            }
        }

        public delegate void EvalErrorEventHandler(Object sender, EvalErrorEventArgs e);
        public event EvalErrorEventHandler EvalError;

        protected virtual void onEvalError(EvalErrorEventArgs e)
        {
            if (EvalError != null)
                EvalError(this, e);
        }

        public static Object Evaluate(string code)
        {
            EvalVBCode EvalObj = new EvalVBCode();
            EvalObj.Code = code;
            return EvalObj.Evaluate();
        }

        public static Object Evaluate(string code, params EvalInputObject<dynamic>[] parameters)
        {
            EvalVBCode EvalObj = new EvalVBCode();
            EvalObj.Code = code;
            return EvalObj.Evaluate(parameters);
        }

        public static Object Evaluate(string code, EvalErrorEventHandler errorEventHandler)
        {
            EvalVBCode EvalObj = new EvalVBCode();
            EvalObj.Code = code;
            EvalObj.EvalError = errorEventHandler;
            return EvalObj.Evaluate();
        }

        public static Object Evaluate(string code, EvalErrorEventHandler errorEventHandler, params EvalInputObject<dynamic>[] parameters)
        {
            EvalVBCode EvalObj = new EvalVBCode();
            EvalObj.Code = code;
            EvalObj.EvalError = errorEventHandler;
            return EvalObj.Evaluate(parameters);
        }

        public Object Evaluate(params Object[] parameters){

            AppDomainSetup loSetup = new AppDomainSetup();
            loSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
            AppDomain loAppDomain = AppDomain.CreateDomain("MyAppDomain", null, loSetup);

             VBCodeProvider oCodeProvider = new VBCodeProvider();
            //Obsolete in 2.0 framework
            //oICCompiler ICodeCompiler = oCodeProvider.CreateCompiler

            CompilerParameters oCParams = new CompilerParameters();
            CompilerResults oCResults; 
            System.Reflection.Assembly oAssy;
            Object oExecInstance = null;
            Object oRetObj  = null;
            MethodInfo oMethodInfo;
            Type oType;

            try{
                //Setup the Compiler Parameters  
                //Add any referencedsemblies
                oCParams.ReferencedAssemblies.Add("system.dll");
                oCParams.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
                oCParams.ReferencedAssemblies.Add("Mscorlib.dll");

                //oCParams.ReferencedAssemblies.Add("system.xml.dll");
                //oCParams.ReferencedAssemblies.Add("system.data.dll");

                //Add User Assemblies
                foreach (String Assembly in _ReferencedAssemblies.Keys)
                {
                    if (!oCParams.ReferencedAssemblies.Contains(Assembly))
                        oCParams.ReferencedAssemblies.Add(Assembly);
                }

                oCParams.CompilerOptions = "/t:library";
                oCParams.GenerateInMemory = true;

                //Generate the Code Framework
                StringBuilder sb  = new StringBuilder();

                sb.Append("Imports System " + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append("Imports Microsoft.VisualBasic" + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append("Imports System.Math" + Microsoft.VisualBasic.Constants.vbCrLf);

                foreach (String Import in _ReferencedAssemblies.Values.Distinct(StringComparer.InvariantCultureIgnoreCase))
                {
                    if (!Import.IsIn(StringComparer.InvariantCultureIgnoreCase, "SYSTEM", "MICROSOFT.VISUALBASIC", "SYSTEM.MATH"))
                        sb.AppendFormat("Imports {0}" + Microsoft.VisualBasic.Constants.vbCrLf, Import);
                }
                //sb.Append("Imports System.Xml" + Microsoft.VisualBasic.Constants.vbCrLf);
                //sb.Append("Imports System.Data" + Microsoft.VisualBasic.Constants.vbCrLf);

                //Build a little wrapper code, with our passed in code in the middle 
                sb.Append("Namespace EvalVBCode " + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append("Class EvalVBCodeClass " + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append("Public Function Eval(");

                if (RuntimeVariables.Count > 0)
                {
                    List<String> MethodParams = new List<String>();
                    foreach (EvalInputObject<dynamic> InputObject in _RuntimeVariables.Distinct())
                    {
                        MethodParams.Add(String.Format("{0} {1}", InputObject.Type.ToString(), InputObject.Name));
                    }
                    sb.Append(String.Join(", ", MethodParams));
                }
                sb.Append(") As Object " + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append(this._Code + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append("End Function " + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append("End Class " + Microsoft.VisualBasic.Constants.vbCrLf);
                sb.Append("End Namespace " + Microsoft.VisualBasic.Constants.vbCrLf);
                //Response.Write("<br />" + sb.ToString() + "<br />");

                try{
                    //Compile and get results 
                    //2.0 Framework - Method called from Code Provider
                    oCResults = oCodeProvider.CompileAssemblyFromSource(oCParams, sb.ToString());
                    //1.1 Framework - Method called from CodeCompiler Interface
                    //cr = oICCompiler.CompileAssemblyFromSource (cp, sb.ToString)

                    //Check for compile time errors 
                    if(oCResults.Errors.Count > 0){
                        onEvalError(new EvalErrorEventArgs(this._Code, this._ReferencedAssemblies, this._RuntimeVariables, new Exception(oCResults.Errors[0].ErrorText)));
                        return null;
                    }else{
                        //No Errors On Compile, so continue to process...
                        oAssy = oCResults.CompiledAssembly;
                        oExecInstance = oAssy.CreateInstance("EvalVBCode.EvalVBCodeClass");

                        oType = oExecInstance.GetType();
                        oMethodInfo = oType.GetMethod("Eval");
                        if (parameters.Length > 0)
                        {
                            oRetObj = oMethodInfo.Invoke(oExecInstance, parameters);
                        }
                        else if(RuntimeVariables.Count > 0)
                        {
                            List<Object> RuntimeVariableValues = new List<Object>();
                            foreach(EvalInputObject<dynamic> Variable in _RuntimeVariables)
                            {
                                RuntimeVariableValues.Add(Variable.Value);
                            }
                            oRetObj = oMethodInfo.Invoke(oExecInstance, RuntimeVariableValues.ToArray<Object>());
                        }
                        else
                            oRetObj = oMethodInfo.Invoke(oExecInstance, null);

                        /*if (oRetObj != null)
                            Response.Write("<br />" + oRetObj.GetType().ToString() + " - " + Convert.ToString(oRetObj) + "<br />");*/
                        return oRetObj;
                    }
                }catch(Exception ex){
                    //Compile Time Errors Are Caught Here
                    //Some other weird error 
                    onEvalError(new EvalErrorEventArgs(this._Code, this._ReferencedAssemblies, this._RuntimeVariables, ex));
                    return null;
                }
            }catch(Exception ex){
                onEvalError(new EvalErrorEventArgs(this._Code, this._ReferencedAssemblies, this._RuntimeVariables, ex));
                return null;
            }
            return oRetObj;
        }
    }

    public class EvalErrorEventArgs
    {
        private string code;
        private Dictionary<String, String> _ReferencedAssemblies;
        private List<EvalInputObject<dynamic>> _RuntimeVariables;
        private Exception exception;

        public EvalErrorEventArgs(string Code, Dictionary<String, String> ReferencedAssemblies, List<EvalInputObject<dynamic>> RuntimeVariables, Exception Exception)
        {
            this.code = Code;
            this._ReferencedAssemblies = ReferencedAssemblies;
            this._RuntimeVariables = RuntimeVariables;
            this.exception = Exception;
        }

        public string Code
        {
            get
            {
                return this.code;
            }
        }

        public Dictionary<String, String> ReferencedAssemblies
        {
            get
            {
                return this._ReferencedAssemblies;
            }
        }

        public ReadOnlyCollection<EvalInputObject<dynamic>> RuntimeVariables
        {
            get
            {
                return this._RuntimeVariables.AsReadOnly();
            }
        }

        public Exception Exception
        {
            get
            {
                return this.exception;
            }
        }
    }
4

1 に答える 1

0

ダイナミクスは非常に強力で、実行時にインスタンスを作成するときに現在のAppDomainを静的ファクトリメソッドに渡すことをお勧めします。「評価」の上のコードは新しいAppDomain(コンテキスト)を作成するため、直接アクセスすることはできません。Evaluateメソッド内にデバッグブレークポイントを挿入して、System.Reflection.Assembly.GetEntryAssembly()。FullNameにアクセスできるかどうかを確認します。そうすると、同じドメインで実行され、AppDomainの「新しい」インスタンスではなくSystem.Threading.Thread.GetDomainとして設定できます。

動的アセンブリをインスタンス化したメソッドのインスタンスへの参照を取得する限り、次のようになります。

1)ダイナミックのctorへの参照を渡すのが最も簡単です2)パブリックメンバープロパティへの参照を渡します3)シングルトンパターンまたは静的コンストラクターを使用して、探している参照を返す「呼び出し」を行います。

ダイナミクスを扱う場合、これらの概念はすべてかなり複雑です。しかし、いくつかのドキュメントを読んで上記の1を実行する方法を見つけることができれば、問題はありません。

于 2011-04-04T00:52:26.237 に答える