2016-01-20 14 views
6

Używamy tego komponentu www.codeeffects.com, który pozwala nam tworzyć reguły biznesowe w oparciu o właściwości obiektu.Jak używać dynamicznie generowanego obiektu jako źródła danych generatora CodeEffects

HTML zdania jest tak:

@{ 
    ViewBag.Title = "Post Example"; 

    Html.CodeEffects().Styles() 
     .SetTheme(ThemeType.Gray) 
     .Render(); 
} 
@using (Html.BeginForm("Evaluate", "Post", FormMethod.Post)) 
{ 
    <div class="area"> 
     <h1 class="title">Post Example</h1> 
     <div style="margin-top:10px;"> 
      <span>Info:</span> 
      <span style="color:Red;">@ViewBag.Message</span> 
     </div> 
     <div style="margin-top:10px;"> 
      @{ 
    Html.CodeEffects().RuleEditor() 
     .Id("ruleEditor") 
     .SaveAction("Save", "Post") 
     .DeleteAction("Delete", "Post") 
     .LoadAction("Load", "Post") 
     .Mode(RuleType.Execution) 
     .ContextMenuRules(ViewBag.ContextMenuRules) 
     .ToolBarRules(ViewBag.ToolBarRules) 
     .Rule(ViewBag.Rule) 
     .Render(); 
      } 
     </div> 
    </div> 
    <div class="area"> 
     <h1 class="title" style="margin-top:20px;">Rule Test Form</h1> 
     @{ 
    Html.RenderPartial("_PatientForm"); 
     } 
    </div> 
} 
@{ 
    Html.CodeEffects().Scripts().Render(); 
} 

akcji index w kontrolerze jest tak:

[HttpGet] 
     public ActionResult Index() 
     { 
      ViewBag.Rule = RuleModel.Create(typeof(Patient)); 
      return View(); 
     } 

Klasa Pacjent jest tak:

// External methods and actions 
    [ExternalMethod(typeof(PatientService), "IsToday")] 
    [ExternalAction(typeof(PatientService), "RequestInfo")] 

    // Dynamic Menu Data Sources; details can be found at 
    // http://codeeffects.com/Doc/Business-Rules-Dynamic-Menu-Data-Sources 

    // The getEducationTypes() client-side function declared in /Views/Shared/_Layout.cshtml 
    [Data("Education", "getEducationTypes")] 
    // The List() method declared by the Physician class 
    [Data("Physicians", typeof(Physician), "List")] 
    public class Patient 
    { 
     // C-tor 
     public Patient() 
     { 
      this.ID = Guid.Empty; 
      this.Gender = Gender.Unknown; 
     } 

     // This property will not appear in the Rule Editor - Code Effects component ignores Guids. 
     // Details at http://codeeffects.com/Doc/Business-Rules-Data-Types 
     public Guid ID { get; set; } 

     [Field(DisplayName = "First Name", Description = "Patient's first name", Max = 30)] 
     public string FirstName { get; set; } 

     [Field(DisplayName = "Last Name", Max = 30, Description = "Patient's last name")] 
     public string LastName { get; set; } 

     [Field(DisplayName = "Email Address", ValueInputType = ValueInputType.User, Max = 150, Description = "Email address of the patient")] 
     public string Email { get; set; } 

     [Field(DisplayName = "Date of Birth", DateTimeFormat = "MMM dd, yyyy")] 
     public DateTime? DOB { get; set; } 

     [Field(ValueInputType = ValueInputType.User, Description = "Patient's gender")] 
     public Gender Gender { get; set; } 

     // This field uses the "Physicians" dynamic menu source (declared at class level) 
     [Field(DisplayName = "Physician", DataSourceName = "Physicians", Description = "Patient's primary physician")] 
     public int PhysicianID { get; set; } 

     // This field uses the "Education" client-side dynamic menu source (declared at class level) 
     [Field(DisplayName = "Education", DataSourceName = "Education", Description = "Patient's education level")] 
     public int EducationTypeID { get; set; } 

     [Field(Min = 0, Max = 200, Description = "Current pulse")] 
     public int? Pulse { get; set; } 

     [Field(Min = 0, Max = 200, DisplayName = "Systolic Pressure", Description = "Current systolic pressure")] 
     public int? SystolicPressure { get; set; } 

     [Field(Min = 0, Max = 200, DisplayName = "Diastolic Pressure", Description = "Current Diastolic pressure")] 
     public int? DiastolicPressure { get; set; } 

     [Field(Min = 0, Max = 110, Description = "Current temperature")] 
     public decimal? Temperature { get; set; } 

     [Field(DisplayName = "Headaches Box", Description = "Does the patient have frequent headaches?")] 
     public bool Headaches { get; set; } 

     [Field(DisplayName = "Allergies Box", Description = "Any allergies?")] 
     public bool Allergies { get; set; } 

     [Field(DisplayName = "Tobacco Box", Description = "Does the patient smoke?")] 
     public bool Tobacco { get; set; } 

     [Field(DisplayName = "Alcohol Box", Description = "Alcohol use?")] 
     public bool Alcohol { get; set; } 

     public Address Home { get; set; } 
     public Address Work { get; set; } 

     // This property is used to display outputs of rule actions 
     [ExcludeFromEvaluation] 
     public string Output { get; set; } 

     [Method("Full Name", "Joins together patient's first and last names")] 
     public string FullName() 
     { 
      return string.Format("{0} {1}", this.FirstName, this.LastName); 
     } 

     // Empty overload of the Register method. 
     // No Method attribute is needed here because its 
     // display name is the same as its declared name. 
     [Action(Description = "Registers new patient")] 
     public void Register() 
     { 
      this.Output = "The patient has been registered"; 
     } 

     // Overload of the Register method that takes one param. 
     // Both overloads can be used in Code Effects as two different actions 
     // as long as their display names are different. 
     [Action("Register with a Message", "Registers new patient with additional info")] 
     public void Register([Parameter(ValueInputType.User, Description = "Output message")] string message) 
     { 
      this.Output = message; 
     } 
    } 

Jednak chcemy stworzyć obiekt dinamyc zbudowany przy użyciu odbicia, metoda którą stworzyłem jest następująca:

private static object CreateOurNewObject() 
     { 
      string _xml = "<root>" + 
       "<column name=\"Name\">Miron</column>" + 
       "<column name=\"LastName\">Abramson</column>" + 
       "<column name=\"Blog\">www.blog.mironabramson.com</column>" + 
       "</root>"; 

      XmlDocument xmlDoc = new XmlDocument(); 
      xmlDoc.LoadXml(_xml); 

      // create a dynamic assembly and module 
      AssemblyName assemblyName = new AssemblyName(); 
      assemblyName.Name = "tmpAssembly"; 
      System.Reflection.Emit.AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
      ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule"); 

      // create a new type builder 
      TypeBuilder typeBuilder = module.DefineType("BindableRowCellCollection", TypeAttributes.Public | TypeAttributes.Class); 

      // Loop over the attributes that will be used as the properties names in out new type 
      foreach (XmlNode node in xmlDoc.SelectSingleNode("root").ChildNodes) 
      { 
       string propertyName = node.Attributes["name"].Value; 

       // Generate a private field 
       FieldBuilder field = typeBuilder.DefineField("_" + propertyName, typeof(string), FieldAttributes.Private); 
       // Generate a public property 
       PropertyBuilder property = 
        typeBuilder.DefineProperty(propertyName, 
            PropertyAttributes.None, 
            typeof(string), 
            new Type[] { typeof(string) }); 

       // The property set and property get methods require a special set of attributes: 

       MethodAttributes GetSetAttr = 
        MethodAttributes.Public | 
        MethodAttributes.HideBySig; 

       // Define the "get" accessor method for current private field. 
       MethodBuilder currGetPropMthdBldr = 
        typeBuilder.DefineMethod("get_value", 
               GetSetAttr, 
               typeof(string), 
               Type.EmptyTypes); 

       // Intermediate Language stuff... 
       ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator(); 
       currGetIL.Emit(OpCodes.Ldarg_0); 
       currGetIL.Emit(OpCodes.Ldfld, field); 
       currGetIL.Emit(OpCodes.Ret); 

       // Define the "set" accessor method for current private field. 
       MethodBuilder currSetPropMthdBldr = 
        typeBuilder.DefineMethod("set_value", 
               GetSetAttr, 
               null, 
               new Type[] { typeof(string) }); 

       // Again some Intermediate Language stuff... 
       ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator(); 
       currSetIL.Emit(OpCodes.Ldarg_0); 
       currSetIL.Emit(OpCodes.Ldarg_1); 
       currSetIL.Emit(OpCodes.Stfld, field); 
       currSetIL.Emit(OpCodes.Ret); 

       // Last, we must map the two methods created above to our PropertyBuilder to 
       // their corresponding behaviors, "get" and "set" respectively. 
       property.SetGetMethod(currGetPropMthdBldr); 
       property.SetSetMethod(currSetPropMthdBldr); 
      } 

      // Generate our type 
      Type generetedType = typeBuilder.CreateType(); 

      // Now we have our type. Let's create an instance from it: 
      object generetedObject = Activator.CreateInstance(generetedType); 

      // Loop over all the generated properties, and assign the values from our XML: 
      PropertyInfo[] properties = generetedType.GetProperties(); 

      int propertiesCounter = 0; 

      // Loop over the values that we will assign to the properties 
      foreach (XmlNode node in xmlDoc.SelectSingleNode("root").ChildNodes) 
      { 
       string value = node.InnerText; 
       properties[propertiesCounter].SetValue(generetedObject, value, null); 
       propertiesCounter++; 
      } 

      //Yoopy ! Return our new genereted object. 
      return generetedObject; 
     } 

Jak zastąpić linię w akcji indeksu, aby użyć tego obiektu zamiast Pacjenta? typeof (object), nie działa.

Odpowiedz

1

Używając swojego TypeBuilder, możesz spróbować wkleić istniejący lub niestandardowy interfejs do wygenerowanego typu, a następnie użyć go jako swojego typu.

typeBuilder.AddInterfaceImplementation(typeof(IMyInterface)); 

Teraz utworzeniu (w powyższym przykładzie) obiekt ma typ IMyInterface, które można następnie wykorzystać w swojej Index działania:

ViewBag.Rule = RuleModel.Create(typeof(IMyInterface)); 
+0

który nie działałby, ponieważ nie mogę wykonać typeof (mydinamobject). public ActionResult Index() { IMyInterface myObject = (IMyInterface) ObjectBuilder.CreateOurNewObject(); ViewBag.Rule = RuleModel.Utwórz (typeof (IMyInterface)); return View(); } –

+0

@Didier Czy możesz zaktualizować swój pierwotny wpis kodem, który próbujesz napisać, i podać błąd, który otrzymujesz z kompilatora? Nie jestem pewien, gdzie próbujesz utworzyć 'typof (mydinamobject)'? Jeśli mój poprzedni post był mylący, 'IMyInterface' nie jest prawdziwym interfejsem, tylko symbolem zastępczym. – Chase

+0

proszę sprawdzić to pytanie tutaj http://stackoverflow.com/questions/34929745/could-not-find-or-load-assembly-tmpassembly jego zaktualizowany kod –

3

Extract część z CreateOurNewObject() metoda który zajmuje się tworzeniem typu. Nazywają to CreateType (ciąg xml).

Zmień AssemlbyBuilderAccess.Run na AssemblyBuilderAccess.RunAndSave. Następnie, po utworzeniu typu, wywołaj metodę assemblyBuilder.Save(). Zapisz go w lokalizacji, którą odnajdzie Assembly.Load (np. Bin lub jeden z folderów tymczasowych .net) lub dowolne inne miejsce tak długo w ścieżce wyszukiwania.

Służy do tworzenia typu i tworzenia instancji obiektów.

Następnie w indeksie, zadzwoń

Type myType = CreateType(xml); 
RuleModel.Create(myType); 

Jeśli robisz ocenę poza upewnij się, aby użyć tego samego typu (nie regenerują się to za każdym razem). Co oznacza, że ​​musisz ją najpierw załadować.

Type myType = Assembly.Load(assemblyName); 
object myObject = Activator.CreateInstance(myType); 
//...populate myObject with necessary values based on your xml 
Evaluator ev = new Evaluator(myType, rule); 
bool result = ev.Evaluate(myObject); 

lub można użyć DynamicEvaluator, który po prostu wywołuje myObject.GetType()

DynamicEvaluator ev = new DynamicEvaluator(rule); 
bool result = ev.Evaluate(myObject); 

to powinno działać. Ważne jest tutaj, aby najpierw zapisać swój zespół (nie można go teraz odczytać z pamięci) i że znajduje się on w folderze, który jest częścią ścieżki wyszukiwania, tak aby Assembly.Load (nazwa) mógł go znaleźć.

+2

Genialny! Dziękuję Ci. Miałem inne pytanie dotyczące zasad Code Effects, ale twoja odpowiedź dała mi coś, z czym mógłbym pracować. – Lacash

Powiązane problemy