Type.GetType() returning null [duplicate]
Asked Answered
C

3

10

I have a web application that dynamically creates a web page using usercontrols.

Within my code I have the following:

    private void Render_Modules()
    {
        foreach (OnlineSystemPageCustom.OnlineSystemPageHdr.OnlineSystemPageModule item in custompage.Header.Modules)
        {
            if (item.ModuleCustomOrder != 99 && !item.ModuleOptional)
            {
                string typeName = item.ModuleInternetFile;
                Type child = Type.GetType(typeName);
                webonlinecustombase ctl = (webonlinecustombase)Page.LoadControl("../IPAM_Controls/webtemplatecontrols/" + child.Name.ToString() + ".ascx");
                ctl.Event = Event;
                ctl.custompage = custompage;
                ctl.custommodule = item;
                this.eventprogrammodules.Controls.Add(ctl);
            }
        }
    }

The "typeName" that is being returned (example) is:

IPAMIntranet.IPAM_Controls.webtemplatecontrols.eventorgcommittee

The namespace for the user controls is as follows:

namespace IPAMIntranet.IPAM_Controls

The problem I am having is that Type.GetType(typeName) is returning null. What am I missing here?

Coarsegrained answered 3/1, 2012 at 17:44 Comment(1)
yes sorry my typing error, I meant nullCoarsegrained
P
26

Type.GetType(string) only looks in the currently executing assembly and mscorlib when you don't specify the assembly name within the string.

Options:

If you have an easy way of getting hold of the relevant assembly (e.g. via typeof(SomeKnownType).Assembly) then the second option is probably simpler.

Polygyny answered 3/1, 2012 at 17:46 Comment(22)
assembly-qualified name? where do I get that? These are custom user controls that I created within the web application itself if that helpsCoarsegrained
@mattgcon: You can use Type.AssemblyQualifiedName, but if you know it's for a specific assembly, you could use typeof(SomeClassInTheAssembly).Assembly to get that assembly, then use Assembly.GetType(string). It doesn't matter which class you use from the assembly to get a reference to it.Polygyny
After I get the assembly then what do I do? Do I state Type child = Assembly.GetType(typeName) to get the user control?Coarsegrained
@mattgcon: Yes, exactly... except using the assembly reference instead of just Assembly.Polygyny
ok so I added the following: 'Assembly aqn = typeof(webonlinecustombase).Assembly' then 'Type child = aqn.GetType(typeName)' but it is still returning nullCoarsegrained
@mattgcon: Then it sounds like either your type name is wrong, or that type isn't in the same assembly as webonlinecustombase. (Is that really the name of a type? You might want to look at the .NET naming conventions.)Polygyny
let us continue this discussion in chatCoarsegrained
@mattgcon: Sorry, chat doesn't really work for my lifestyle. Let's stick to comments.Polygyny
Ok not a problem. the type is being returned from a SQL database with a type such as: 'IPAMIntranet.IPAM_Controls.webtemplatecontrols.eventorgcommittee' the usercontrol that I created has a filename of eventorgcommittee.ascx. Both eventorgcommittee.ascx and webonlinecustombase.ascx are located within the same folderCoarsegrained
@mattgcon: I don't know the details of on-the-fly compilation in ASP.NET - I suggest you try to open one of the generated assemblies in Reflector, and see what's in it. Alternatively, try to change your design so that you don't need quite this approach...Polygyny
what I dont understand is, why do I need to call a different assembly if the user control files are not pre compiled from a dll and instead located as files within my web application.Coarsegrained
@mattgcon: Well the types are being created on-the-fly... I'd hoped it would be compiling all of the user controls in one assembly, which would make it work... but if it only compiles them on a "just in time" basis, you'll end up with one assembly per control, which makes it all harder.Polygyny
You are correct in the fact that it is one assembly per control. Here is a question, how would I take that string for the type and do a typeof(class) on it?Coarsegrained
@mattgcon: You can't, because the type reference basically isn't known at compile-time - because it's compiled at execution time.Polygyny
hmmm well that makes things more difficult then. and it has to be done this way.Coarsegrained
@mattgcon: It's not clear exactly what you mean by that. Do you have to use non-precompiled user-controls? (If you precompiled them, they could all be in the same assembly.) Does the logic have to be in those user controls? You could have a class which basically used typeof for each user control you cared about, creating a mapping from string to type - but that would basically force the early compilation anyway.Polygyny
oh what I meant was that the loading of the controls has to be at runtime. The webonlinecustombase is the base usercontrol for all of the dynamically loaded controls if that helpsCoarsegrained
I might have just solved my issue hold on and I will return with my resultsCoarsegrained
Ok this was solved by simply putting stripping off everything except for the control name from typePath and placing it in the LoadControl statement.Coarsegrained
@mattgcon: Ah, excellent - glad you sorted it in the end!Polygyny
@skeet , using Assemly... gives error that "An object reference is required for the non-static field, method, or property 'System.Reflection.Assembly.GetType(string)'Afteryears
@AKS: Hence the "on the appropriate assembly" part. You need to have a reference to the relevant Assembly first...Polygyny
B
4

Type.GetType looks as the calling assembly, and a few system assemblies. For anything else, you must either use assemblyInstance.GetType(typeName), or you must use the "assembly qualified name" of the type, which includes the assembly details in which the type can be found. Otherwise, it wont be found, and will return null. You can get that from:

string aqn = someType.AssemblyQualifiedName;
Beanfeast answered 3/1, 2012 at 17:48 Comment(6)
how do I get the assembly qualified name for the user controlsCoarsegrained
@Coarsegrained I included that in the answerrBeanfeast
if the someType is my typeName, I have to say that typeName is going to be dynamic and I have no idea what it is during design time.Coarsegrained
@matt somewhere, somehow, you have some strings. What I am saying is: store them as the assembly-qualified version. Or: if they all come from the same dll, use Assembly.GetTypeBeanfeast
The thing is these are not precompiled usercontrols that I added with a dll. they are actual usercontrol files within the web application. They are located in a sub folder within the web application.Coarsegrained
@web just create one, and see what the assembly-qualified-name is. IIRC they follow a pattern.Beanfeast
K
0

I had a very similar problem to the original poster, except that I needed to instantiate the code-behind class of my custom user-control in a static utility class rather than an ASPX page, so LoadControl wasn't available to me. Here's what I ended up doing:

public static class Utils
{
    public static string MyFunc(string controlClassName)
    {
        string result = "";
        // get a list of all assemblies in this application domain
        Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
        // the trouble is that we don't know which assembly the class is defined in,
        // because we are using the "Web Site" model in Visual Studio that compiles
        // them on the fly into assemblies with random names
        // -> however, we do know that the assembly will be named App_Web_*
        // (http://msdn.microsoft.com/en-us/magazine/cc163496.aspx)
        foreach (Assembly assembly in assemblies)
        {
            if (assembly.FullName.StartsWith("App_Web_"))
            {
                // I have specified the ClassName attribute of the <%@ Control %>
                // directive in the relevant ASCX files, so this should work
                Type t = assembly.GetType("ASP." + controlClassName);
                if (t != null)
                {
                    // use reflection to create the instance (as a general object)
                    object o = Activator.CreateInstance(t);
                    // cast to the common base type that has the property we need
                    CommonBaseType ctrl = o as CommonBaseType;
                    if (ctrl != null)
                    {
                        foreach (string key in ctrl.PropertyWeNeed)
                        {
                            // finally, do the actual work
                            result = "something good";
                        }
                    }
                }
            }
        }
        return result;
    }
}

It's not pretty and not very efficient, and is liable to break if the App_Web_* naming convention changes (although you could then just look through all of them): but it does work ...

Knecht answered 14/3, 2013 at 19:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.