I compile a plugin and then create an instance of it in a new AppDomain. Then I want to execute a method in the plugin object but that results in an ArgumentException:
"Object of type System.MarshalByRefObject can not be converted to type Data"
The code below should be compilable and result in the exception above. To make it work you must also sign the Assembly (Project -> Properties -> Signing -> Sign the assembly -> New ...)
IPlugin.cs:
using System;
namespace Plugin
{
[Serializable]
class Data : MarshalByRefObject
{
int value;
}
interface IPlugin
{
void DoStuff(Data data);
}
}
Program.cs:
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Security.Policy;
using System.Security;
using System.Security.Permissions;
using System.Reflection;
namespace Plugin
{
class Program
{
public class Sandbox : MarshalByRefObject
{
const string BaseDirectory = "Untrusted";
const string DomainName = "Sandbox";
private object instance;
public static Sandbox Create()
{
var setup = new AppDomainSetup()
{
ApplicationBase = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaseDirectory),
ApplicationName = DomainName,
DisallowBindingRedirects = true,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true
};
Evidence ev = new Evidence();
ev.AddHostEvidence(new Zone(SecurityZone.Internet));
var permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
StrongName fullTrustAssembly = typeof(Sandbox).Assembly.Evidence.GetHostEvidence<StrongName>();
var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions, fullTrustAssembly);
return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap();
}
public bool CreateInstance(string assemblyPath, string scriptType)
{
new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert();
var assembly = Assembly.LoadFrom(assemblyPath);
CodeAccessPermission.RevertAssert();
Type type = assembly.GetType(scriptType);
if (type == null)
return false;
instance = Activator.CreateInstance(type);
return instance != null;
}
public object Execute(string method, params object[] parameters)
{
Type type = instance.GetType();
MethodInfo info = type.GetMethod(method);
return info.Invoke(instance, parameters);
}
}
private static void CompileToFile(string code, string ifaceFile, string output)
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters p = new CompilerParameters();
p.GenerateInMemory = false;
p.GenerateExecutable = false;
p.OutputAssembly = output;
provider.CompileAssemblyFromSource(p, code, ifaceFile);
}
private static string code = #"
using Plugin;
class MyPlugin : IPlugin
{
public void DoStuff(Data data)
{
}
}
";
static void Main(string[] args)
{
string iface = System.IO.File.ReadAllText(#"C:\Documents and Settings\markus.BLUE\mina dokument\visual studio 2010\Projects\Plugin\Plugin\IPlugin.cs");
string pluginObjectFile = System.IO.Path.GetTempFileName();
CompileToFile(code, iface, pluginObjectFile);
Sandbox s = Sandbox.Create();
s.CreateInstance(pluginObjectFile, "MyPlugin");
Data data = new Data();
s.Execute("DoStuff", data);
}
}
}
It must be a type known at both sides of your communication!
Related
I created a WCF consuming application in WPF by adding service reference.Now its working fine.But now i have a new requirement that is, i want to call the service dynamically by entering the URL,username and password.
You can create a WCF client without adding a service reference with the use of ClientBase, but you will still need a reference to the interface for the compiler to knowwhat functions to call.
It works like this:
public class ServiceClient : System.ServiceModel.ClientBase<IService>, IService {
public ServiceClient() {
}
public ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public void Login(string user, string password) {
return base.Channel.Login(user, password);
}
}
NetNamedPipeBinding binding = new NetNamedPipeBinding();
binding.TransactionFlow = true;
EndpointAddress address = new EndpointAddress(youraddress);
ServiceClient client = new ServiceClient(binding, address);
client.Login("xxx", "yyy");
See this website for a general idea. Create a new VisualStudio Solution and add a WCF Service Application project and an Unit Test Project. Put the following code in the test project (a slightly modified version of the code in the link) and add the missing references to the unit test project. Start the WCF service without debugging, change the portnumber in the test if needed and run the test. As mentioned in the article, the code can still use some adjustments before it could be put into production.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Xml.Linq;
namespace UnitTestProject1
{
public class ServiceDetail
{
public Uri WSDLUri { get; set; }
public Uri ServiceUri { get; set; }
public String ContractName { get; set; }
public string MethodName { get; set; }
}
public class GenericService
{
public object Call(ServiceDetail svc, List<object> payLoads)
{
//Import WSDL
WsdlImporter imptr = ImportWSDL(svc.WSDLUri);
//Extract Service and Data Contract Descriptions
Collection<ContractDescription> svcCtrDesc = imptr.ImportAllContracts();
//Compile the description to assembly
var assembly = GetAssembly(svcCtrDesc);
if (assembly == null) return null;
//Extract all end points available on the WSDL
IDictionary<string, IEnumerable<ServiceEndpoint>> allEP = GetEndPointsOfEachServiceContract(imptr, svcCtrDesc);
IEnumerable<ServiceEndpoint> currentSvcEP;
if (allEP.TryGetValue(svc.ContractName, out currentSvcEP))
{
//Find the endpoint of the service to which the proxy needs to contact
var svcEP = currentSvcEP.First(x => x.ListenUri.AbsoluteUri == svc.ServiceUri.AbsoluteUri);
//Generate proxy
var proxy = GetProxy(svc.ContractName, svcEP, assembly);
//Deserialize each payload argument to object
List<object> pls = new List<object>();
foreach (var pl in payLoads)
{
object clrObj = null;
try
{
clrObj = Deserialize(pl.ToString(), assembly);
}
catch
{
clrObj = pl;
}
pls.Add(clrObj);
}
//Find opration contract on the proxy and invoke
return proxy.GetType().GetMethod(svc.MethodName).Invoke(proxy, pls.ToArray());
}
return null;
}
private Assembly GetAssembly(Collection<ContractDescription> svcCtrDesc)
{
CodeCompileUnit ccu = GetServiceAndDataContractCompileUnitFromWSDL(svcCtrDesc);
CompilerResults rslt = GenerateContractsAssemblyInMemory(new CodeCompileUnit[] { ccu });
if (!rslt.Errors.HasErrors)
return rslt.CompiledAssembly;
return null;
}
private object GetProxy(string ctrName, ServiceEndpoint svcEP, Assembly assembly)
{
Type prxyT = assembly.GetTypes().First(t => t.IsClass && t.GetInterface(ctrName) != null && t.GetInterface(typeof(ICommunicationObject).Name) != null);
object proxy = assembly.CreateInstance(prxyT.Name, false, System.Reflection.BindingFlags.CreateInstance,
null, new object[] { svcEP.Binding, svcEP.Address }, CultureInfo.CurrentCulture, null);
return proxy;
}
private WsdlImporter ImportWSDL(Uri wsdlLoc)
{
MetadataExchangeClient mexC = new MetadataExchangeClient(wsdlLoc, MetadataExchangeClientMode.HttpGet);
mexC.ResolveMetadataReferences = true;
MetadataSet metaSet = mexC.GetMetadata();
return new WsdlImporter(metaSet);
}
private Dictionary<string, IEnumerable<ServiceEndpoint>> GetEndPointsOfEachServiceContract(WsdlImporter imptr, Collection<ContractDescription> svcCtrDescs)
{
ServiceEndpointCollection allEP = imptr.ImportAllEndpoints();
var ctrEP = new Dictionary<string, IEnumerable<ServiceEndpoint>>();
foreach (ContractDescription svcCtrDesc in svcCtrDescs)
{
List<ServiceEndpoint> eps = allEP.Where(x => x.Contract.Name == svcCtrDesc.Name).ToList();
ctrEP.Add(svcCtrDesc.Name, eps);
}
return ctrEP;
}
private CodeCompileUnit GetServiceAndDataContractCompileUnitFromWSDL(Collection<ContractDescription> svcCtrDescs)
{
ServiceContractGenerator svcCtrGen = new ServiceContractGenerator();
foreach (ContractDescription ctrDesc in svcCtrDescs)
{
svcCtrGen.GenerateServiceContractType(ctrDesc);
}
return svcCtrGen.TargetCompileUnit;
}
private object Deserialize(string xml, Assembly assembly)
{
Type ctr = GetDataContractType(xml, assembly);
return Deserialize(xml, ctr);
}
private object Deserialize(string xml, Type toType)
{
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
DataContractSerializer d = new DataContractSerializer(toType);
return d.ReadObject(stream);
}
}
private Type GetDataContractType(string xml, Assembly assembly)
{
var serializedXML = ConvertToXML(xml);
var match = assembly.GetTypes().First(x => x.Name == serializedXML.Root.Name.LocalName);
return match;
}
private XDocument ConvertToXML(string xml)
{
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
return XDocument.Load(stream);
}
}
private CompilerResults GenerateContractsAssemblyInMemory(params CodeCompileUnit[] codeCompileUnits)
{
// Generate a code file for the contracts
CodeGeneratorOptions opts = new CodeGeneratorOptions();
opts.BracingStyle = "C";
CodeDomProvider pro = CodeDomProvider.CreateProvider("C#");
// Compile the code file to an in-memory assembly
// Don't forget to add all WCF-related assemblies as references
CompilerParameters prms = new CompilerParameters(new string[] { "System.dll", "System.ServiceModel.dll",
"System.Runtime.Serialization.dll"});
prms.GenerateInMemory = true;
prms.GenerateExecutable = false;
return pro.CompileAssemblyFromDom(prms, codeCompileUnits);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
// Arrange
var target = new GenericService();
var serviceDetail = new ServiceDetail
{
WSDLUri = new Uri("http://localhost:13152/Service1.svc?singleWsdl"),
ServiceUri = new Uri("http://localhost:13152/Service1.svc"),
ContractName = "IService1",
MethodName = "GetData"
};
var arguments = new List<object> { 5 };
// Act
var result = target.Call(serviceDetail, arguments);
// Assert
Assert.AreEqual("You entered: 5", result);
}
}
}
i have working CompileAssemblyFromSource code. But when i use any code protector like RedGate SmartAssembly or Themida it's stop working and i get error "Could not load file or assembly or one of its dependencies". Can you please help me with that?
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace stringToCode
{
public class Program
{
public static int q = 0;
static void Main(string[] args)
{
try
{
string source = "namespace stringToCode { public class FooClass { public void Execute() { Program.q = 1; } } }";
Console.WriteLine("q=" + q);
using (var foo = new CSharpCodeProvider())
{
var parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
string location = assembly.Location;
if (!String.IsNullOrEmpty(location))
{
parameters.ReferencedAssemblies.Add(location);
}
}
catch (NotSupportedException)
{ }
}
var res = foo.CompileAssemblyFromSource(parameters, source);
var type = res.CompiledAssembly.GetType("stringToCode.FooClass");
var obj = Activator.CreateInstance(type);
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
Console.WriteLine("q=" + q);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);;
}
Console.ReadLine();
}
}
}
sorry for my question. I just understand why it happens)
This is code is example. The main problem i have with code that i get from server.
So when i obfuscate my vars i don't obfuscare them at my "online" code that i use with CompileAssemblyFromSource. So this just can't work. Because vars don't have same names.
i try to use CompileAssemblyFromSource to change 1 value at my main class.
But when i compile i get error "Could not load file or assembly or one of its dependencies" and this only happens when i try change static value of other class. But if i return some output or wrote anything at Console from this FooClass than all work's fine. But how can i change value of other class?
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace stringToCode
{
class Program
{
public static int q = 0;
static void Main(string[] args)
{
string source = "namespace stringToCode { public class FooClass { public void Execute() { Program.q = 1; } } }";
Console.WriteLine("q=" + q);
using (var foo = new CSharpCodeProvider())
{
var parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
string location = assembly.Location;
if (!String.IsNullOrEmpty(location))
{
parameters.ReferencedAssemblies.Add(location);
}
}
catch (NotSupportedException)
{}
}
var res = foo.CompileAssemblyFromSource(parameters ,source);
var type = res.CompiledAssembly.GetType("FooClass"); //<- here i has error
var obj = Activator.CreateInstance(type);
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
Console.WriteLine("q=" + q);
Console.ReadLine();
}
}
}
}
You can't find the type because you have compilation error in your code.You can't access the classes in your current code in this manner. You should at least reference the current assembly in your in-memory assembly.
UPDATE
You have two issues in your code. First, you have to make the class Program public. Then you should specify the full name of type in GetType method.
This code works fine:
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace stringToCode
{
public class Program
{
public static int q = 0;
static void Main(string[] args)
{
string source = "namespace stringToCode { public class FooClass { public void Execute() { Program.q = 1; } } }";
Console.WriteLine("q=" + q);
using (var foo = new CSharpCodeProvider())
{
var parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
string location = assembly.Location;
if (!String.IsNullOrEmpty(location))
{
parameters.ReferencedAssemblies.Add(location);
}
}
catch (NotSupportedException)
{}
}
var res = foo.CompileAssemblyFromSource(parameters ,source);
var type = res.CompiledAssembly.GetType("stringToCode.FooClass"); //<- here i has error
var obj = Activator.CreateInstance(type);
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
Console.WriteLine("q=" + q);
Console.ReadLine();
}
}
}
}
I'm trying to figure out how to save a class object as an assembly, so that I can save that assembly to a local location etc to be used at at a later stage
Example the test class created, I'd like to create an assembly of it after in was instantiated.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
test newtest = new test("someInfo");
//Create assembly from tt
Assembly newAssem = NewAssembly.CreateAssembly(tt);
}
}
public class test
{
public string val {get ;set;}
public test(string v)
{
val = v;
}
}
}
So then in this method I want to create the assembly
public static class NewAssembly
{
public static Assembly CreateAssembly(test tt)
{
Assembly _proxyAssembly;
CodeDomProvider _codeDomProvider = CodeDomProvider.CreateProvider("CS");
CodeCompileUnit _codeCompileUnit = new CodeCompileUnit();
string _proxyCode;
using (StringWriter writer = new StringWriter())
{
CodeGeneratorOptions codeGenOptions = new CodeGeneratorOptions();
codeGenOptions.BracingStyle = "C";
_codeDomProvider.GenerateCodeFromCompileUnit(_codeCompileUnit, writer, codeGenOptions);
writer.Flush();
_proxyCode = writer.ToString();
}
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.OutputAssembly = "some local path \\aName.dll";
CompilerResults results;
results = codeDomProvider.CompileAssemblyFromSource(compilerParams,_proxyCode);
_proxyAssembly = results.CompiledAssembly;
return _proxyAssembly;
}
}
That was the best examples I've been able to get together but I'm not sure if its correct and also don't know what I'm missing like where the actual class gets added and how to finish the method.
Any help would be great, thanks
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.