How to call a generic method through reflection [duplicate] - c#

This question already has answers here:
Select Right Generic Method with Reflection
(13 answers)
Closed 9 years ago.
is it possible to call with reflection a method with "explict type argument" <S> definition
e.g. oObject.Cast<S>() ?
where is:
IList <P> oObject = new List <P>();
I tried with
oObject.getType().InvokeMember( "Cast", BindingFlags.InvokeMethod, null, oObject, null)
but it does not work, does anyone know why?
Here is the complete test code but still it does not work. The last line produce always exception. Is it possible to make it work ?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace reflection_tester
{
class CBase
{
public string Ja = "I am the base";
}
class MyClass01 : CBase
{
public string _ID;
public string ID
{
get { return _ID; }
set { _ID = value; }
}
}
class Program
{
public static object wrapper()
{
//return a list of classes MyClass01
IList<MyClass01> lstClass01 = new List<MyClass01>();
MyClass01 oClass01a = new MyClass01();
oClass01a.ID = "1";
MyClass01 oClass01b = new MyClass01();
oClass01b.ID = "2";
lstClass01.Add(oClass01a);
lstClass01.Add(oClass01b);
return lstClass01;
}
static void Main(string[] args)
{
MyClass01 oMy1 = new MyClass01();
oMy1._ID = "1";
MyClass01 oMy2 = new MyClass01();
oMy2._ID = "3";
IList<MyClass01> oListType01 = new List<MyClass01>();
oListType01.Add(oMy1);
oListType01.Add(oMy2);
object oObjectType = new object();
oObjectType = oListType01;
/* this works */
IEnumerable<CBase> enumList = oListType01.Cast<CBase>();
MethodInfo mInfo = typeof(System.Linq.Enumerable).GetMethod("Cast", new[] { typeof(System.Collections.IEnumerable) }).MakeGenericMethod(typeof(CBase));
/* this does not work, why ? throws exception */
IEnumerable<CBase> enumThroughObject = (IEnumerable<CBase>)mInfo.Invoke(oObjectType, null);
return;
}
}
}

The Cast extension method lives on the class Enumerable, and you need to call MakeGenericMethod:
typeof(System.Linq.Enumerable)
.GetMethod("Cast", new []{typeof(System.Collections.IEnumerable)})
.MakeGenericMethod(typeof(S))
.Invoke(null, new object[] { oObjectType })
update: Because the method is static, the first parameter to Invoke should be null

I think you're looking for Type.MakeGenericType

Related

Is it possible to convert body of a method to string? [duplicate]

Using the Roslyn API with Visual Studio 2015, can I convert an object instance to source code? Can I create an extension method like ".ToSourceCode()" as shown below?
class Foo { }
class Program
{
static string classSourceCode = "class Foo { }";
static void Main()
{
var instance = new Foo();
var instanceSourceCode = instance.GetType().ToSourceCode();
System.Diagnostics.Debug.Assert(instanceSourceCode == classSourceCode);
}
}
No. However, ILSpy can.
Based on the comments on the question and what I understand about Roslyn, decompilation is not supported. However, thanks to #Bradley's ILSpy tip, there is a solution:
Download the ILSpy binaries from http://ilspy.net/
Reference the following assemblies: ICSharpCode.Decompiler.dll, ILSpy.exe, Mono.Cecil.dll, ILSpy.BamlDecompiler.Plugin.dll
Implement the ".ToSourceCode()" extension method as shown below:
using System;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy;
using Mono.Cecil;
class Foo { }
class Program
{
static string classSourceCode = "using System; internal class Foo { } ";
static void Main()
{
var instance = new Foo();
var instanceSourceCode = instance.GetType().ToSourceCode();
System.Diagnostics.Debug.Assert(instanceSourceCode == classSourceCode);
}
}
static class TypeExtensions
{
public static string ToSourceCode(this Type source)
{
var assembly = AssemblyDefinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);
var type = assembly.MainModule.Types.FirstOrDefault(t => t.FullName == source.FullName);
if (type == null) return string.Empty;
var plainTextOutput = new PlainTextOutput();
var decompiler = new CSharpLanguage();
decompiler.DecompileType(type, plainTextOutput, new DecompilationOptions());
return Regex.Replace(Regex.Replace(plainTextOutput.ToString(), #"\n|\r", " "), #"\s+", " ");
}
}

Using mocking with .NET Reflection [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am trying to attempt mocking on some reflection (code below). I have been advised to use NSubstitue but I am struggling on how to implement this and to get it started.
At the moment my test stubs are simply like the one below, however on the build server these obviously fail as the DLLs are not present.
[TestMethod]
public void CanGetStudentXml()
{
var student = new ReadStudent();
var results = student.GetStudentXml();
Assert.AreNotEqual(string.Empty, results);
}
Can anyone give me any pointers on how I should go about doing this? Do I need to create mock assemblies? If so, based on the one below, how would I achieve that?
Also is Nsubsitute the best for the job, or would moq be better suited? Which would be the best mocking framework to use?
Sample code:
namespace MokPoc
{
using System.Reflection;
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var students = new ReadStudent();
var results = students.GetStudentXml();
var contacts = students.GetTelephoneXml();
}
}
public enum ReflectedAssembyType
{
SimsProcessesTpPersonStudent,
SimsProcessesTpPersonContact
}
internal class ReflectedAssemblyFactory
{
public static ReflectedAssemblyBase GetReflectedAssembly(ReflectedAssembyType reflectedAssembyType)
{
ReflectedAssemblyBase value = null;
switch (reflectedAssembyType)
{
case ReflectedAssembyType.SimsProcessesTpPersonStudent:
value = new SimsProcessesTpPersonStudent("ThirdPartyProcesses.dll");
break;
case ReflectedAssembyType.SimsProcessesTpPersonContact:
value = new SimsProcessesTpPersonContact("PersonContacts.dll");
break;
}
return value;
}
}
internal abstract class ReflectedAssemblyBase
{
private string path = string.Empty;
private string type = string.Empty;
public string Path
{
get { return this.path; }
set { this.path = value; }
}
public string Type
{
get { return this.type; }
set { this.type = value; }
}
public object InvokeFunction(string name, object[] args)
{
var assemblyToLoad = Assembly.LoadFrom(this.path);
var typeToLoad = assemblyToLoad.GetType(this.type);
var methodToInvoke = typeToLoad.GetMethod(name, args.Select(o => o.GetType()).ToArray());
object obj = Activator.CreateInstance(typeToLoad);
return methodToInvoke.Invoke(obj, args);
}
}
internal sealed class SimsProcessesTpPersonStudent : ReflectedAssemblyBase
{
public SimsProcessesTpPersonStudent(string assembly)
{
this.Path = System.IO.Path.Combine(#"C:\Program Files\Zoosk", assembly);
this.Type = "SIMS.Processes.TPPersonStudent";
}
}
public class ReadStudent
{
public string GetStudentXml()
{
var contacts = ReflectedAssemblyFactory.GetReflectedAssembly(ReflectedAssembyType.SimsProcessesTpPersonStudent);
return (string)contacts.InvokeFunction("GetXmlStudents", new object[] { DateTime.Today });
}
public string GetTelephoneXml()
{
var contacts = ReflectedAssemblyFactory.GetReflectedAssembly(ReflectedAssembyType.SimsProcessesTpPersonContact);
return (string)contacts.InvokeFunction("GetXmlTelephone", new object[] { DateTime.Today });
}
}
}
I have refactored you code to understand what you are trying to test, it seems like you had a lot of classes to do something that seems could be the responsibility of one class, the heart of what you are trying to do is in GetStudentAttributes, I would create a test.dll with a class and public method that returns some strings and then run an actual method to test, in that case you are not using a stub or mock but it is a valid test to ensure your code works. You should also test GetTelephoneXml and GetStudentXML but the only thing you are really testing there is that GetStudentAttributes is inkoved with the appropriate parameters, so when GetStudentXML is called you invokeGetStudentAttributes with "ThirdpartyProcesses.dll" and "GetXmlStudents".
Depending on the framework you use the solution to testing will be different, with Rhynomocks you will have to make the methods virtual to allow the proxy to inherit and invoke your methods, but you can certainly test that the method was called and that the parameters are what you expect, I haven't used nSubstitute, so not sure how to do it there but if the framework is decent you should be able to test those calls and the parameters.
One of the first things that you should do when using driven development is to start by writing the tests first, making sure it fails, making it pass and refactor, usually when you try and retrofit tests to existing code it could get really hard, there are some good resources out there about unit testing, this is a great book about it http://www.amazon.com/Test-Driven-Development-By-Example/dp/0321146530, but in my experience when something is hard to test it usually tells you that your code is too complex or something can be improved, once the code is simplified or fixed testing is usually not a problem.
Good luck and hope this helped a bit!
using System;
using System.IO;
using System.Linq;
using System.Reflection;
namespace MokPoc
{
internal class Program
{
private static void Main(string[] args)
{
var students = new ReadStudentsService();
string results = students.GetStudentXml();
string contacts = students.GetTelephoneXml();
}
}
public class ReadStudentsService
{
private const string ProgramFilesZooskDirectory = #"C:\Program Files\Zoosk";
private const string SimsProcessesTppersonstudent = "SIMS.Processes.TPPersonStudent";
public string GetStudentXml()
{
return GetStudentAttributes("ThirdPartyProcesses.dll", "GetXmlStudents");
}
public string GetTelephoneXml()
{
return GetStudentAttributes("ThirdPartyContacts.dll", "GetXmlTelephone");
}
public string GetStudentAttributes(string dllToUse, string methodToExecute)
{
var fullpath = Path.Combine(ProgramFilesZooskDirectory, dllToUse);
var args = new object[] {DateTime.Today};
var assemblyToLoad = Assembly.LoadFrom(fullpath);
var typeToLoad = assemblyToLoad.GetType(SimsProcessesTppersonstudent);
var methodToInvoke = typeToLoad.GetMethod(methodToExecute, args.Select(o => o.GetType()).ToArray());
var obj = Activator.CreateInstance(typeToLoad);
return (string) methodToInvoke.Invoke(obj, args);
}
}
}

Automate class generation from an interface using field/property naming conventions

How would I automate the creation of a default implementation of a class from an interface using conventions. In other words, if I have an interface:
public interface ISample
{
int SampleID {get; set;}
string SampleName {get; set;}
}
Is there a snippet, T4 template, or some other means of automatically generating the class below from the interface above? As you can see, I want to put the underscore before the name of the field and then make the field the same name as the property, but lower-case the first letter:
public class Sample
{
private int _sampleID;
public int SampleID
{
get { return _sampleID;}
set { _sampleID = value; }
}
private string _sampleName;
public string SampleName
{
get { return _sampleName;}
set { _sampleName = value; }
}
}
I am not sure if T4 would be the easiest solution here in terms of readability but you can also use another code generation tool at your disposal: the CodeDom provider.
The concept is very straightforward: code consists of building blocks that you put together.
When the time is ripe, these building blocks are then parsed into the language of choice . What you end up with is a string that contains the source code of your newly created program. Afterwards you can write this to a textfile to allow for further use.
As you have noticed: there is no compile-time result, everything is runtime. If you really want compiletime then you should use T4 instead.
The code:
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Text;
namespace TTTTTest
{
internal class Program
{
private static void Main(string[] args)
{
new Program();
}
public Program()
{
// Create namespace
var myNs = new CodeNamespace("MyNamespace");
myNs.Imports.AddRange(new[]
{
new CodeNamespaceImport("System"),
new CodeNamespaceImport("System.Text")
});
// Create class
var myClass = new CodeTypeDeclaration("MyClass")
{
TypeAttributes = TypeAttributes.Public
};
// Add properties to class
var interfaceToUse = typeof (ISample);
foreach (var prop in interfaceToUse.GetProperties())
{
ImplementProperties(ref myClass, prop);
}
// Add class to namespace
myNs.Types.Add(myClass);
Console.WriteLine(GenerateCode(myNs));
Console.ReadKey();
}
private string GenerateCode(CodeNamespace ns)
{
var options = new CodeGeneratorOptions
{
BracingStyle = "C",
IndentString = " ",
BlankLinesBetweenMembers = false
};
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
CodeDomProvider.CreateProvider("C#").GenerateCodeFromNamespace(ns, writer, options);
}
return sb.ToString();
}
private void ImplementProperties(ref CodeTypeDeclaration myClass, PropertyInfo property)
{
// Add private backing field
var backingField = new CodeMemberField(property.PropertyType, GetBackingFieldName(property.Name))
{
Attributes = MemberAttributes.Private
};
// Add new property
var newProperty = new CodeMemberProperty
{
Attributes = MemberAttributes.Public | MemberAttributes.Final,
Type = new CodeTypeReference(property.PropertyType),
Name = property.Name
};
// Get reference to backing field
var backingRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), backingField.Name);
// Add statement to getter
newProperty.GetStatements.Add(new CodeMethodReturnStatement(backingRef));
// Add statement to setter
newProperty.SetStatements.Add(
new CodeAssignStatement(
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), backingField.Name),
new CodePropertySetValueReferenceExpression()));
// Add members to class
myClass.Members.Add(backingField);
myClass.Members.Add(newProperty);
}
private string GetBackingFieldName(string name)
{
return "_" + name.Substring(0, 1).ToLower() + name.Substring(1);
}
}
internal interface ISample
{
int SampleID { get; set; }
string SampleName { get; set; }
}
}
This produces:
Magnificent, isn't it?
Sidenote: a property is given Attributes = MemberAttributes.Public | MemberAttributes.Final because omitting the MemberAttributes.Final would make it become virtual.
And last but not least: the inspiration of this awesomeness. Metaprogramming in .NET by Kevin Hazzard and Jason Bock, Manning Publications.

How to write extension methods for anonymous types?

I'm trying to create a CSV extension method for my enumerable list and I'm stumped. Here's how I created my simple enumerated list:
var CAquery = from temp in CAtemp
join casect in CAdb.sectors
on temp.sector_code equals casect.sector_code
select new
{
CUSIP = temp.equity_cusip,
CompName = temp.company_name,
Exchange = temp.primary_exchange
};
CAquery.WriteToCSVFile();
This is what I have done so far in creating an extension method (which I think is wrong):
public static class CSVExtensions
{
public static void WriteToCSVFile(this IEnumerable<T> myList)
{
Do you see what I'm doing wrong?
You have to specify the generic type parameter in the method signature:
public static class CSVExtensions
{
public static void WriteToCSVFile<T>(this IEnumerable<T> myList)
{
//your code here
}
}
Are you truly trying to write an extension method that should work on any IEnumerable<T> or is your type more specific? If the later is the case you should replace T with the type you want to support (or add sufficient constraints).
Edit:
In light of comments - you should project to a class instead of an anonymous type in your query - then you can use an extension method for this particular type, i.e.:
class CompanyTicker
{
public string CUSIP {get;set;}
public string CompName {get;set;}
public string Exchange {get;set;}
}
Now your query can be:
var CAquery = from temp in CAtemp
join casect in CAdb.sectors
on temp.sector_code equals casect.sector_code
select new CompanyTicker
{
CUSIP = temp.equity_cusip,
CompName = temp.company_name,
Exchange = temp.primary_exchange
};
And your extension method (which now doesn't need to be generic) becomes:
public static class CSVExtensions
{
public static void WriteToCSVFile(this IEnumerable<CompanyTicker> myList)
{
//your code here
}
}
It is possible to do what you are trying to do using reflection. The performance is going to be somewhat worse than if you write non-generic code however.
Here is a complete code sample:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var seq =
Enumerable.Range(0, 100)
.Select(i => new { Name = "Item" + i, Value = i })
;
seq.WriteCsv(Console.Out);
Console.ReadLine();
}
}
public static class CsvExtension
{
public static void WriteCsv<T>(this IEnumerable<T> seq, TextWriter writer)
{
var type = typeof(T);
MethodInfo[] getters = type.GetProperties().Select(pi => pi.GetGetMethod()).ToArray();
// only supporting simple properties
// indexer properties will probably fail
var args = new object[0];
foreach (var item in seq)
{
for (int i = 0; i < getters.Length; i++)
{
if (i != 0)
writer.Write(",");
Object value = getters[i].Invoke(item, args);
var str = value.ToString();
if (str.Contains(",") || str.Contains("\""))
{
var escaped = str.Replace("\"", "\\\"");
writer.Write("\"");
writer.Write(escaped);
writer.Write("\"");
}
else
{
writer.Write(str);
}
}
writer.WriteLine();
}
}
}

How can I use a string argument to case a namespace or type?

I need to get some JSON output in a .NET 2.0 C# script. The goal is to use one method to output all the JSON feeds I need. All the models have the same id and name properties so I have about 15 namespaces that have the same parts here. In short: since I'm use castle I can call the function like:
/public/get_place_tags.castle
/public/get_place_types.castle
/public/get_place_whichEver.castle
Which in castle is calling each method, ie: the get_place_tags(){} but I want to not have to work where I can call one method to get output from each type like this:
/public/get_json.castle?wantedtype=place_types
Does anyone know how to fix this?
namespace campusMap.Controllers
{
[Layout("home")]
public class PublicController : BaseController
{
/* works and returns */
public void get_pace_type()
{
CancelView();
CancelLayout();
place_types[] types = ActiveRecordBase<place_types>.FindAll();
List<JsonAutoComplete> type_list = new List<JsonAutoComplete>();
foreach (place_types place_type in types)
{
JsonAutoComplete obj = new JsonAutoComplete();
obj.id = place_type.place_type_id;
obj.label = place_type.name;
obj.value = place_type.name;
type_list.Add(obj);
}
string json = JsonConvert.SerializeObject(type_list);
RenderText(json);
}
/* can;t ever find the namespace */
public void get_json(string wantedtype)
{
CancelView();
CancelLayout();
Type t = Type.GetType(wantedtype);
t[] all_tag = ActiveRecordBase<t>.FindAll();
List<JsonAutoComplete> tag_list = new List<JsonAutoComplete>();
foreach (t tag in all_tag)
{
JsonAutoComplete obj = new JsonAutoComplete();
obj.id = tag.id;
obj.label = tag.name;
obj.value = tag.name;
tag_list.Add(obj);
}
string json = JsonConvert.SerializeObject(tag_list);
RenderText(json);
}
}
}
[EDIT]-- (Newest Idea) Runtime type creation.. This I think is the cleanest idea on a way to get it to work...-----
So the goal is really to have at runtime a type used.. right.. so I thought this would work.
http://www.java2s.com/Code/CSharp/Development-Class/Illustratesruntimetypecreation.htm
and based of that here is the method so far. I'm still having issues getting t to get past the error
"The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)" .. not sure where I'm going wrong here. Can't seem to get any of it to work lol..
public void get_json(String TYPE)
{
CancelView();
CancelLayout();
if (String.IsNullOrEmpty(TYPE))
{
TYPE = "place_types";
}
// get the current appdomain
AppDomain ad = AppDomain.CurrentDomain;
// create a new dynamic assembly
AssemblyName an = new AssemblyName();
an.Name = "DynamicRandomAssembly";
AssemblyBuilder ab = ad.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
// create a new module to hold code in the assembly
ModuleBuilder mb = ab.DefineDynamicModule("RandomModule");
// create a type in the module
TypeBuilder tb = mb.DefineType(TYPE, TypeAttributes.Public);
// finish creating the type and make it available
Type t = tb.CreateType();
t[] all_tag = ActiveRecordBase<t>.FindAll();
List<JsonAutoComplete> tag_list = new List<JsonAutoComplete>();
foreach (t tag in all_tag)
{
JsonAutoComplete obj = new JsonAutoComplete();
obj.id = tag.id;
obj.label = tag.name;
obj.value = tag.name;
tag_list.Add(obj);
}
RenderText(JsonConvert.SerializeObject(tag_list));
}
[EDIT]-- (Older idea) Eval code-----
So this attempt to make this happen is to use reflection and stuff to do a eval of sorts based on this http://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=11939
namespace EvalCSCode
{
/// <summary>
/// Interface that can be run over the remote AppDomain boundary.
/// </summary>
public interface IRemoteInterface
{
object Invoke(string lcMethod, object[] Parameters);
}
/// <summary>
/// Factory class to create objects exposing IRemoteInterface
/// </summary>
public class RemoteLoaderFactory : MarshalByRefObject
{
private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
public RemoteLoaderFactory() { }
/// <summary> Factory method to create an instance of the type whose name is specified,
/// using the named assembly file and the constructor that best matches the specified parameters. </summary>
/// <param name="assemblyFile"> The name of a file that contains an assembly where the type named typeName is sought. </param>
/// <param name="typeName"> The name of the preferred type. </param>
/// <param name="constructArgs"> An array of arguments that match in number, order, and type the parameters of the constructor to invoke, or null for default constructor. </param>
/// <returns> The return value is the created object represented as ILiveInterface. </returns>
public IRemoteInterface Create(string assemblyFile, string typeName, object[] constructArgs)
{
return (IRemoteInterface)Activator.CreateInstanceFrom(
assemblyFile, typeName, false, bfi, null, constructArgs,
null, null, null).Unwrap();
}
}
}
#endregion
namespace campusMap.Controllers
{
public class JsonAutoComplete
{
private int Id;
[JsonProperty]
public int id
{
get { return Id; }
set { Id = value; }
}
private string Label;
[JsonProperty]
public string label
{
get { return Label; }
set { Label = value; }
}
private string Value;
[JsonProperty]
public string value
{
get { return Value; }
set { Value = value; }
}
}
[Layout("home")]
public class publicController : BaseController
{
#region JSON OUTPUT
/* works and returns */
public void get_pace_type()
{
CancelView();
CancelLayout();
place_types[] types = ActiveRecordBase<place_types>.FindAll();
List<JsonAutoComplete> type_list = new List<JsonAutoComplete>();
foreach (place_types place_type in types)
{
JsonAutoComplete obj = new JsonAutoComplete();
obj.id = place_type.id;
obj.label = place_type.name;
obj.value = place_type.name;
type_list.Add(obj);
}
string json = JsonConvert.SerializeObject(type_list);
RenderText(json);
}
/* how I think it'll work to have a dynmaic type */
public void get_json(string type)
{
CancelView();
CancelLayout();
/*t[] all_tag = ActiveRecordBase<t>.FindAll();
List<JsonAutoComplete> tag_list = new List<JsonAutoComplete>();
foreach (t tag in all_tag)
{
JsonAutoComplete obj = new JsonAutoComplete();
obj.id = tag.id;
obj.label = tag.name;
obj.value = tag.name;
tag_list.Add(obj);
}*/
StringBuilder jsonobj = new StringBuilder("");
jsonobj.Append(""+type+"[] all_tag = ActiveRecordBase<"+type+">.FindAll();\n");
jsonobj.Append("List<JsonAutoComplete> tag_list = new List<JsonAutoComplete>();{\n");
jsonobj.Append("foreach ("+type+" tag in all_tag){\n");
jsonobj.Append("JsonAutoComplete obj = new JsonAutoComplete();\n");
jsonobj.Append("obj.id = tag.id;\n");
jsonobj.Append("obj.label = tag.name;\n");
jsonobj.Append("obj.value = tag.name;\n");
jsonobj.Append("tag_list.Add(obj);\n");
jsonobj.Append("}\n");
CSharpCodeProvider c = new CSharpCodeProvider();
ICodeCompiler icc = c.CreateCompiler();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.ReferencedAssemblies.Add("Newtonsoft.Json.Net20.dll");
cp.ReferencedAssemblies.Add("Castle.ActiveRecord.dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder sb = new StringBuilder("");
sb.Append("namespace CSCodeEvaler{ \n");
sb.Append("public class CSCodeEvaler{ \n");
sb.Append("public object EvalCode(){\n");
sb.Append("return " + jsonobj + "; \n");
sb.Append("} \n");
sb.Append("} \n");
sb.Append("}\n");
CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString());
System.Reflection.Assembly a = cr.CompiledAssembly;
object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("EvalCode");
object s = mi.Invoke(o, null);
string json = JsonConvert.SerializeObject(s);
RenderText(json);
}/**/
#endregion
}
I know it was suggested that the using is not needed.. I know I don't know them off the top and maybe that is level showing.. But here they are for what I think will work just above.
using System;
using System.Collections;
using System.Collections.Generic;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Queries;
using Castle.MonoRail.Framework;
using Castle.MonoRail.ActiveRecordSupport;
using campusMap.Models;
using MonoRailHelper;
using System.IO;
using System.Net;
using System.Web;
using NHibernate.Expression;
using System.Xml;
using System.Xml.XPath;
using System.Text.RegularExpressions;
using System.Text;
using System.Net.Sockets;
using System.Web.Mail;
using campusMap.Services;
using Newtonsoft.Json;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Linq;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.IO;
using System.Threading;
using System.Reflection;
OK, this is just a suggestion, and I know nothing about castle but it seems to me that you are wanting a custom route.
This is untested and of course you will have to tweak it but have a look at your Global.asax RegisterRoutes method and add this above you default route
routes.MapRoute(
"TypeRoute", // Route name
"Public/{wantedtype}", // URL with parameters
new { controller = "Public", action = "get_json", wantedtype = UrlParameter.Optional } // Parameter defaults
);
something like this might get what you are after.
you might need to fiddle with the action so it matches your castle framework
EDIT
I had some more time to look at this. Using the route I described above and the following method on the controller I got a good result
public void get_json(string wantedtype)
{
Type t = Type.GetType(wantedtype);
// t.Name = "Int32" when "System.Int32 is used as the wanted type
}
http://.../Public/System.Int32 works,
this url doesn't work http://.../Public/Int32
Now if you wanted to use the short version you could use something like MEF or AutoFAC or Castle to do a lookup in your container for the type you are after.
So my answer is use a good route to get the key for the wanted type then build a factory to manage the type mappings and produce an instance of what you are after.
I just had a look at the ActiveRecord API Doco Here
There is a method FindAll(Type targetType) : Array
have you tried replacing
Type t = Type.GetType(wantedtype);
t[] all_tag = ActiveRecordBase<t>.FindAll();
// blah blah blah
with
Type t = Type.GetType(wantedtype);
dynamic all_tag = ActiveRecordBase.FindAll(t);
RenderText(JsonConvert.SerializeObject(all_tag ));
completely untested but see what you think
I tired and tried and tired to so one of these ways. Me and an co-worker came up this with solution. I made 2 files.
Ijson_autocomplete.cs
using System;
namespace campusMap.Models
{
public interface Ijson_autocomplete
{
int id { get; set; }
string name { get; set; }
String get_json_data();
}
}
json_autocomplete.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Castle.ActiveRecord;
using System.Collections.Generic;
using System.Data.SqlTypes;
using Newtonsoft.Json;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Linq;
namespace campusMap.Models
{
public class JsonAutoComplete
{
private int Id;
[JsonProperty]
public int id
{
get { return Id; }
set { Id = value; }
}
private string Label;
[JsonProperty]
public string label
{
get { return Label; }
set { Label = value; }
}
private string Value;
[JsonProperty]
public string value
{
get { return Value; }
set { Value = value; }
}
}
public class json_autocomplete<t> where t : campusMap.Models.Ijson_autocomplete
{
virtual public String get_json_data()
{
t[] all_tag = ActiveRecordBase<t>.FindAll();
List<JsonAutoComplete> tag_list = new List<JsonAutoComplete>();
foreach (t tag in all_tag)
{
JsonAutoComplete obj = new JsonAutoComplete();
obj.id = tag.id;
obj.label = tag.name;
obj.value = tag.name;
tag_list.Add(obj);
}
return JsonConvert.SerializeObject(tag_list);
}
}
}
then when I called the function from the url this is what it ended up as
public void get_json(String TYPE)
{
CancelView();
CancelLayout();
Type t = Type.GetType("campusMap.Models."+TYPE);
Ijson_autocomplete theclass = (Ijson_autocomplete)Activator.CreateInstance(t);
RenderText(theclass.get_json_data());
}
and one off the models
namespace campusMap.Models
{
[ActiveRecord(Lazy=true)]
public class place_types : json_autocomplete<place_types>, campusMap.Models.Ijson_autocomplete
{
private int place_type_id;
[PrimaryKey("place_type_id")]
virtual public int id
{
get { return place_type_id; }
set { place_type_id = value; }
}
private string Name;
[Property]
virtual public string name
{
get { return Name; }
set { Name = value; }
}
private string Attr;
[Property]
virtual public string attr
{
get { return Attr; }
set { Attr = value; }
}
private IList<place> places;
[HasAndBelongsToMany(typeof(place), Lazy = true, Table = "place_to_place_models", ColumnKey = "place_model_id", ColumnRef = "place_id", Inverse = true, NotFoundBehaviour = NotFoundBehaviour.Ignore)]
virtual public IList<place> Places
{
get { return places; }
set { places = value; }
}
}
}
now when you call
/public/get_json.castle?wantedtype=place_types
or
/public/get_json.castle?wantedtype=place_tags
You will get the json output of each model. Tada! :D Thank you everyone for helping.

Categories