Creating WebControls from fully qualified path (assembly name?) - asp.net

I have a webpage in ASP.NET 3.5 that will be creating WebControls dynamically. The WebControls that it will be creating will be known by their fully qualified path (ie - System.Web.UI.WebControls.whatever). The reason for this is because I am allowing the user to decide what controls will go on the webpage. Of course, there's more complexity than this, but that is it in a nutshell.
Simply put - how do I create a WebControl on a webpage by it's fully qualified path?
I realize that the answer will probably end up using reflection, but I have little experience using reflection and I don't want to shoot myself in the foot by making a newbie mistake.

try to call this way: Activator.CreateInstance(Type.GetType("TypeName"));
where TypeName is fully qualified name, including assembly. in my case it looked this way:
Activator.CreateInstance(Type.GetType("System.Web.UI.WebControls.Label, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"));
to be sure about full name in your case, try to output typeof(System.Web.UI.WebControls.Label).FullName and use it as a pattern

object widget = Activator.CreateInstance ( Assembly.GetType ( name ) );
where name is the string of the fully qualified type

Related

Safe way to get System.Web assembly reference

I am currently using the following line of code in a web server control to get a reference to the loaded System.Web assembly:
var assembly = AppDomain.CurrentDomain.GetAssemblies()
.Single(i => i.FullName.Contains("System.Web,"));
I am a bit concerned that there could be an occasion where the Single method call fails because (1) the assembly can't be found, or (2) more than one assembly is returned. In the debugger, it looks like there is only one assembly that matches the selector (I've included the comma after System.Web as all of the others show as "System.Web.Whatever"), but this doesn't mean that the FullName of all assemblies loaded will never contain this text).
Is there a better way to identify the reference that I'm looking for so I know that it will always find it correctly?
Thanks.
The best way would be to use a type that you know is in the System.Web assembly, e.g.:
var assembly = typeof(System.Web.HttpContext).Assembly;

Using embedded WebResources throughout Webresource.axd

The question's simple: how could one use embedded resources in asp.net applications? What are the steps to include a resource in the assembly, and how to reference it? What are the gotchas that could be encountered?
Edit: For a version without referencing Page and ClientScript, see What is the right way to handle Embedded Resources on a Razor View?
After spending a half of a day I've learned these:
to embed a resource one needs to set it's Build Action to Embedded Resource (in VS Solution Explorer rightclick the file -> Properties)
next AsssemblyInfo.vb must be modified to make this resources available for WebResource queries. Add [Assembly: System.Web.UI.WebResource("MyWebResourceProj.Test.css", "text/css")] to AssemblyInfo.vb located in MyProject folder of the project.
The name consists of root namespace/assembly name +'.'+filename. To be 100% sure of the name, use the following code snippet to look it up:
Dim resNames = Assembly.LoadFile("YourDll.dll").GetManifestResourceNames()
Note that the assembly's Root Namespace must be the same as the Assembly Name (this took me about 4 hours to realize. At least with .Net v4 that is the case)
If there are references inside the css ( <%=WebResource("NS.image.jpg")%> ) than pass PerformSubstitution:=true for that css's WebResource attribute.
Referencing the resource can be done with Page.ClientScript.GetWebResourceUrl(GetType(MyWebResourceProj.ConssumingPage), "MyWebResourceProj.Test.css")
Note that instead of GetType(Typename) one could use Me.GetType(), but again, that won't work if the class is inherited, so beware!
Resources:
Debugging ASP.NET 2.0 Web Resources: Decrypting the URL and Getting the Resource Name
Using embedded resources through WebResource.axd is a pain in the neck, as you can see from your own answer. You have to keep assemblyinfo.vb|cs in sync, and it always seems damn near impossible to get all the namespace & assembly names right in all the right places.
When you finally get it to work, your reward is an include script line that that looks like a core memory dump.
I suggest an alternative. Write yourself a very simple web handler (e.g. MyResourceLoader.ashx. Then add a method to your class that simply serves it's own embedded resources, in whatever way you think is meaningful. You can use reflection to get the classes, like WebResource does, or just hardcode whatever you need into your loader, if it's just for a specific purpose. A public method in your class might look like:
public static Stream GetResource(string resourceName) {
// get the resource from myself, which is easy and doesn't require
// anything in assemblyinfo, and return it as a stream. As a bonus,
// you can parse it dynamically or even return things that aren't
// just embedded, but generated completely in code!
}
Or if you decide to make something more general purpose, you can get all fancy and return more data using a class, e.g.
class ResourceInfo
{
public Stream Data;
public string MimeType;
public string FileName;
}
Now you have the ability to serve up your embedded resources any way you want, e.g.
<script language="javascript" src="/MyResourceLoader.ashx/MyControlScript.js">
I think MS made a mess of that WebResource business. Luckily its' pretty straightforward to do your own thing.

how to call an dll file dynamically from code behind(.cs)

i have an microsoft .office.interop.excel(dll) located at an directory d:\abc. now i do not want to add them as an web reference in my projet and call them
rather call the dll dynamically from my code behind(.cs)
is ther any way we can do dynmically
anyhelp would be great
thank you
Yes, but you will need to use reflection because if you don't add the assembly as reference it won't be known at compile time. Take a look at LoadFrom method.
var assembly = Assembly.LoadFrom(#"d:\abc\microsoft.office.interop.excel.dll");
var someType = assembly.GetType("Namespace.Type");
var instance = Activator.CreateInstance(type);
someType.InvokeMember(... // the reflection pain goes on
Take a look in Assembly.Load() method.
I want to discourage you from doing that. It can definitely be done if read the dll into a byte[] and call AppDomain.CurrentDomain.Load(byte[]). However you will find that you can only work with the types of that assembly through reflection. Otherwise your code behind file will not compile. So if at all possible you should add a reference (not a web reference) to the dll.

How to use reflection to create a class in app_code?

I have a class Customer in app_code folder in asp.net web site, how can I create an instance using reflection, for example using Activator.CreateInstance(assemblyName, typeName)? Because the app_code is dynamically compiled, I don't know the assembly in design time?
Thanks
Fred
The question is should be how get a full name of type in design time, I want to put it in web.config. I have ConfigSection type, it is in app_code folder, I need to declare it in configSection. Thanks
You should be able to use "App_Code" or "__Code" as the assembly name in the web.config
I think you can use Assembly.GetExecutingAssembly() to get a reference to the current assembly.
I have solved a similar problem in this way:
Type[] appCodeTypes = System.Reflection.Assembly.Load("App_Code").GetTypes();
You can also use GetType().Assembly if you know that it will be the same assembly as your currently executing code.

Using generic classes with ObjectDataSource

I have a generic Repository<T> class I want to use with an ObjectDataSource. Repository<T> lives in a separate project called DataAccess. According to this post from the MS newsgroups (relevant part copied below):
Internally, the ObjectDataSource is calling Type.GetType(string) to get the
type, so we need to follow the guideline documented in Type.GetType on how
to get type using generics. You can refer to MSDN Library on Type.GetType:
http://msdn2.microsoft.com/en-us/library/w3f99sx1.aspx
From the document, you will learn that you need to use backtick (`) to
denotes the type name which is using generics.
Also, here we must specify the assembly name in the type name string.
So, for your question, the answer is to use type name like follows:
TypeName="TestObjectDataSourceAssembly.MyDataHandler`1[System.String],TestObjectDataSourceAssembly"
Okay, makes sense. When I try it, however, the page throws an exception:
<asp:ObjectDataSource ID="MyDataSource" TypeName="MyProject.Repository`1[MyProject.MessageCategory],DataAccess" />
[InvalidOperationException: The type specified in the TypeName property of ObjectDataSource 'MyDataSource' could not be found.]
The curious thing is that this only happens when I'm viewing the page. When I open the "Configure Data Source" dialog from the VS2008 designer, it properly shows me the methods on my generic Repository class. Passing the TypeName string to Type.GetType() while debugging also returns a valid type. So what gives?
Do something like this.
Type type = typeof(Repository<MessageCategory);
string assemblyQualifiedName = type.AssemblyQualifiedName;
get the value of assemblyQualifiedName and paste it into the TypeName field. Note that Type.GetType(string), the value passed in must be
The assembly-qualified name of the type to get. See AssemblyQualifiedName. If the type is in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply the type name qualified by its namespace.
So, it may work by passing in that string in your code, because that class is in the currently executing assembly (where you are calling it), where as the ObjectDataSource is not.
Most likely the type you are looking for is
MyProject.Repository`1[MyProject.MessageCategory, DataAccess, Version=1.0.0.0, Culture=neutral, PublicKey=null], DataAccess, Version=1.0.0.0, Culture=neutral, PublicKey=null
I know this is an old post but I have recently had this problem myself. Another solution would be to replace the inheritance with object composition, e.g.
[DataObject]
public class DataAccessObject {
private Repository<MessageCategory> _repository;
// ctor omitted for clarity
// ...
[DataObjectMethod(DataObjectMethodType.Select)]
public MessageCategory Get(int key) {
return _repository.Get(key);
}
}
This way the ObjectDataSource doesn't know about the repository because its hidden within the class. I have a class library in my facade layer that is a perfectly reasonable place to put this code in the project I am working on.
In addition, if you are using Resharper and interfaces, its possible to get Resharper to do the refactoring using Resharpers "Implement using field" function.
Darren,
Many, many thanks for your post. I've been fighting with this all day. Strangely, in my case, I need to double the square brackets, e.g. for your piece of code:
MyProject.Repository`1[[MyProject.MessageCategory, DataAccess, Version=1.0.0.0, Culture=neutral, PublicKey=null]], DataAccess, Version=1.0.0.0, Culture=neutral, PublicKey=null
Roger

Resources