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

3

9

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;
Khanna answered 30/11, 2011 at 20:30 Comment(7)
Please post only the relevant code. usings are useless for people trying to help you.Graphitize
How do we get people to see this to anwser this?Khanna
See the faq.Graphitize
I'm not yet able to do a bounty so I guess the hope and wait will have to do :D tk for pointing that out..Khanna
Ok I thnk I have a possible solution that I need help with.. to edit this orginal would muddy the question... What is the best why to present this. Just anwser the below? tk -JeremyKhanna
Don't post an answer unless this is the complete solution to your problem. The best way is to edit your question and write the progress you've made. If you're afraid this would muddy your question, ask another one (you can link this question in the new one if necessary).Graphitize
I have updated the examples, I beleive at the moment that the at runtime type creation is the best bet.. just not there yet. :/ Can someone that last bit to get it right?Khanna
K
0

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.

Khanna answered 20/1, 2012 at 3:5 Comment(0)
C
1

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.

Countess answered 7/12, 2011 at 4:10 Comment(7)
Sorry but I think you are way off.. I don't want a custom url route I want to use a string argument to case a namespace or type as the title says. Simplly put I need a dynamic type in C# .net 2.0. Thank you for the try.Khanna
I did a little mockup and was able to get a System.Int32 from the code I have added to my original suggestionCountess
caslte already handles the route as shown in the code above so that is not needed. You'll notice it's not System.Int32 passed or any other FullyQuailfiedName so as in the orginal code you endded up with the same code I said is not working. If you can show an example where it's a wantedtype == <place_types> ie: ending up with <t> as type t equals arg wantedtype, letting the activerecord move thru the typed object, so foreach (place_types place_type in types) then works. As the first method is shown, it works, I just need to make the <place_types> be dynamic. Hope that clears it up.Khanna
looking at your code...Am I right in thinking that you have a bunch of option selectors that are populated by ajax calls based on the type of the field you want to collect an answer for?Countess
Something like that, it's the jquery ui auto-complete and the json feed but since there is like 13-15 of the exact same thing.. so it'd be like taking the working example and coping it and just renaming the 4 spots but otherwise it's exactly the same. Plus knowing how to make a dynamic Type is always a good tool in the box :D .. tk for the help -JKhanna
OK, I have done exactly that using DataServices in a MCV project. I can dig up that code for you if you like...again it's not ActiveRecord, I use Linq2SQL/Entities. but it will give you and idea on how it can be easily done using restful services.Countess
:D if you code has what is needed to make place_types[] ptypes = ActiveRecordBase<place_types>.FindAll(); into t[] ptypes = ActiveRecordBase<t>.FindAll(); .. this really has nothing to do with ActiveRecord as thou it handles the url params automaticly and the object, all that is needed is to have the wantedtype arg become the type of object. Thank you for the help. Cheers -JeremyKhanna
C
1

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

Countess answered 9/12, 2011 at 2:39 Comment(4)
um.. I'm not 100% here but I don't think dynamic cam out till 3.5 and this is 2.0 .. I'll try tk. -JKhanna
I think the important bit is using ActiveRecordBase.FindAll(t); and if dynamic doesn't work use var all_tag = ActiveRecordBase.FindAll(t); also you should consider upgrading to .net 4 if at all possibleCountess
:D oh sorry but upgrading to 4.0+ is not happening, and ActiveRecordBase.FindAll() is the what creates the object thru the database. that should explain the error on ActiveRecordBase.FindAll(t) of "Error 79 'Castle.ActiveRecord.ActiveRecordBase.FindAll(System.Type, NHibernate.Expression.DetachedCriteria, params NHibernate.Expression.Order[])' is inaccessible due to its protection level" also for the dynamic I get the expected error also of "Error 78 The type or namespace name 'dynamic' could not be found (are you missing a using directive or an assembly reference?)" ..Khanna
there was this but I didn't if it may be the trick but weblogs.asp.net/paolopia/archive/2005/06/11/411747.aspx ..Khanna
K
0

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.

Khanna answered 20/1, 2012 at 3:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.