views:

241

answers:

2

I've inherited from an ASP.NET WebControl to add some additional functionality. I tested my control in a blank ASP.NET Web Site (created through File > New Web Site...) and it worked fine. But I can't get it to work when I add it to a Web Application Project (created throgh File > New Project... > Visual Basic > Web > ASP.NET Web Application. I personally prefer Web Sites for ease of development, but the project leadership I'm working with now wants to keep it a Web Application (they like how it pre-compiles all page code-behind into a single DLL in the Bin folder.)

To isolate the issue I tried to reproduce it using the simple MSDN Walkthrough: Developing and Using a Custom Server Control. To my surprise, I had the same issue there: If you build it into an ASP.NET Web Application Project, and then try to access the instance of the control from the page's code-behind, you get the compilation error BC30456: 'WelcomeLabel1' is not a member of 'WebApplication1._Default'. E.g., in Page Load, write:

Me.WelcomeLabel1.Text = "foo"

However, if you simply remove that line of code behind, it compiles properly and the browser shows the page with the label formatted correctly. To me this is a bug in the compiler/framework, because if the control gets injected properly into the page, it should always be available in the code-behind, right?

Any ideas? I suppose I could compile my control into an assembly as suggested further into the walkthrough, but that seems like overkill.

Interestingly, I can use FindControl to get a reference to the WelcomeLabel, but I am unable to cast it to the appropriate type. Doing so causes the error "Unable to cast object of type 'Samples.AspNet.VB.Controls.WelcomeLabel' to type 'WebApplication2.Samples.AspNet.VB.Controls.WelcomeLabel'." I've tried every combination of namespaces and imports that I could think of, even adding declarations to the designer.vb file manually, and I can't get this to work, unless of course I switch to a Web Site project, which I can't do.

UPDATE 1.1:

To clarify, what I was trying to achieve was:

  1. Web Application Project
  2. Inherited web control class file in the same assembly (i.e. not referenced from a separate compiled DLL)
  3. Control added to page through design-time markup
  4. Control instance referenced from page code-behind

EDIT: After re-reading Bryan's comments, I finally understood. It's very simple actually: all you have to do is add Assembly="WebApplication1" to the <%@Register%> directive in the markup, and add the "WebApplication1." prefix to the Namespace directive. So:

<%@ Register Assembly="WebApplication1" TagPrefix="aspSample" Namespace="WebApplication1.Samples.AspNet.VB.Controls" %>

And now you should have no problem instantiating the control through markup and accessing the instance from code-behind, whether you place the control's class file in App_Code or anywhere else.

Jordan Rieger

A: 

Hey,

Sometimes opening the designer gets it to add correctly to the designer.cs file that contains the control references. THat's what is probably missing. Not sure why, works for me fine...

Is there a build error or a compile error, or is the @Page directive showing an error?

HTH.

Brian
When you say it works fine for you, did you actually follow the MSDN article to create the WelcomeLabel class and use it on a page? And did you make sure to create a Web Application Project rather than a Web Site project? Because I've showed this problem to another developer at work, and he was able to reproduce the problem from scratch. The key is that it works fine in a Web Site, but not a Web Application.
Jordan Rieger
OK, you are right, I didn't do that specific example. Where are you locating the files? How are you referencing the specific control so that you can use it in the app? It may be better to put them in a separate project and have your web app reference that project instead. That way, your reference to the project comes from that library.
Brian
I'm locating the files as specified by the MSDN walkthrough: Default.aspx is in /, and WelcomeLabel.vb is in /App_Code. I'm instantiating the control in the markup using <aspSample:WelcomeLabel> as specified by the walkthrough. In the code-behind, I'm referencing the control using the line of code in my original question:Me.WelcomeLabel1.Text = "foo"That line causes the compilation error in my original question, "BC30456: 'WelcomeLabel1' is not a member of 'WebApplication1._Default'."Good idea about switching to design mode. Another dev here suggested that too, but it didn't work.
Jordan Rieger
Well... here's part of the problem. Don't use App_Code for a Web Application Project. That will cause a conflict.
Bryan
Do you know of official documentation for that? I've heard that User Controls don't work in the App_Code folder, but this is not a User Control. And if App_Code is the wrong place to put the class file, why would it still work partially (rendering the control upon Page Load)?
Jordan Rieger
In any case, I tried moving the WelcomeLabel.vb file to the site root, and now I get no compile error. Instead, I get a parser error when trying to view the page: "Unknown server tag 'aspSample:WelcomeLabel'." Probably due to this warning: "Namespace or type specified in the Imports 'Samples.AspNet.VB.Controls' doesn't contain any public member or cannot be found. Make sure the namespace or the type is defined and contains at least one public member. Make sure the imported element name doesn't use any aliases." Arrrgggg, can it really be this hard to add a custom control to a Web App?
Jordan Rieger
See the update on my answer. But to answer this question... use App_Code for a Web *Site* to auto-compile code not associated with an aspx or ascx. For a WAP, all your classes should be compiled into a DLL. If the file is also in App_Code, you run the risk of compiling the code twice and hence a conflict.
Bryan
Where is it documented that putting a class in App_Code "runs the risk of compiling the code twice"? Under what conditions would the code be compiled twice? Sounds like superstition to me. According to http://msdn.microsoft.com/en-us/library/aa983464.aspx, the only thing special about the App_Code folder for Web Application Projects is that all files in their are forcibly set to Build Action: Compiled... If what you say is true, no one would ever be able to add a stand-alone class to a Web Application Project without compiling it into a separate DLL.
Jordan Rieger
APp_Code is a specific compile folder for web site projects; everything gets compiled in web app project, so no need for this. I would recommend anyway to use a separate project, to cleanly separate the control from the UI and to make it more reusable. Much more managable that way IMHO.
Brian
@Bryan In theory I understand what you are saying but do you have some link where the App_Code folder has any special significance anymore, because while I understand why you would say the twice compile, it doesn't seem to me like it really matters the same as web site project.
Brian
If you read the walkthrough you referenced, the section "To prepare the control for compiling and provide a default tag prefix" explains why you don't want this in App_Code. Basically, same as I was saying above.
Bryan
Not to be a pest, but please read it again :-) The section "To prepare the control for compiling and provide a default tag prefix" is _inside_ the section "Compiling the Control into an Assembly." You can prove this by collapsing the "Compiling..." section -- it hides the "To prepare..." section. The text at the beginning of the section shows that compiling the control into a separate assembly is optional. The mention of App_Code is strictly to remind the developer not to leave the control's class file in that folder if it is also being referenced from an external DLL.
Jordan Rieger
Again, the only significance to the App_Code folder in a WAP is that any code files placed in there are automatically compiled, regardless of whether their Build Action is set to Compile.
Jordan Rieger
A: 

You've got something wonky. A couple things to check...

One, make sure your code does not have a CodeFile directive. It should be compiled into the same assembly as your page classes. Make sure the Inherits directive is correct. It sounds very much like you are modifying a class that isn't the one you think it is.

Two, make sure the designer file is using the correct type declaration for your control. If it says "WebControl" or something beside your type, which I suspect, that is a problem. You may need to tell Visual Studio where the code for this control is by setting the application root in Project Properties. That is how Visual Studio knows how to resolve the "~" path at design time.

If that doesn't work... post some code.

UPDATE:
OK, the reason you are getting the original error is that the control is not declared in the designer file. If it's not in the designer file, then it doesn't exist and hence you get this error: "WelcomeLabel1' is not a member of 'WebApplication1._Default'. One reason this can happen is that you are not registering the control, or not registering it properly... so Visual Studio has no idea what to do with it. It's like declaring some random element that has no definition:

<bp:WhatIsThis ID="someID" runat="server">

Visual Studio will not update your .designer file here because it has no clue what this object represents. I'm guessing the same thing is happening here.

UPDATE 2: You must include the .cs file in your project. This step is probably missing from the walk-through because it targets a Web Site, not a WAP. That's why your namespace is empty.

Bryan
I verified that there is no CodeFile directive. Default.aspx does have a CodeBehind directive, but that's required. The designer file doesn't have a declaration for the control at all (even if I open/close the designer view.)If you have a moment, I would be VERY grateful if you could reproduce this issue yourself and play around with it. Simply follow the walkthrough, but create a Web Application Project rather than a Web Site project. And then try to reference the control instance from code-behind. Everyone who's tried this is able to reproduce the compilation error.
Jordan Rieger
I just tried manually adding a declaration to the designer for the control with the appropriate type, but then I got a parser on the page saying that the type in the base class didn't match the control type. The only difference in the type was that the control type had a "WebApplication2." prefix (the project root namespace.) So I changed the project root namespace to blank. After that I rebuilt, but I STILL got a parser error, this time ridiculously telling me that WebApplication2.Samples.AspNet.VB.Controls.WelcomeLabel does not match WebApplication2.Samples.AspNet.VB.Controls.WelcomeLabel!
Jordan Rieger
Try this, with correct Assembly name:<%@ Register TagPrefix="aspSample" Namespace="Samples.AspNet.CS.Controls" Assembly="WebApplication1"%>
Bryan
Please read my comment above. I tried manually adding the control declaration to the designer file, but that created a parser error... If you please, I would SO appreciate if you did the walkthrough yourself with a Web Application Project and saw the error first-hand... All I'm trying to achieve is accessing the inherited control from the code-behind of a page where it's used. It seems absurd that this is not possible with a Web Application Project without creating a separate DLL.
Jordan Rieger
The .cs file (actually .vb in my case) has been included in the project from the beginning. To confirm, I right-clicked on the file and saw that the menu item "Exclude from Project" was present. Actually, it doesn't matter whether I include or exclude it, I get the same result... And if I move the file out of the App_Code folder to the site root, and make sure the Build Action says "Compile" rather than "Content", I get the parser error when I try to load the page, saying it's not a known element.
Jordan Rieger
Read the walkthrough again... it explains in a "Note" section why you need the Assembly tag. Incidentally, I went through the walkthrough earlier, but created a WAP and added the Assembly specification (as above) and it worked fine.
Bryan
Also, you are not creating a separate DLL (unless you want to). The control is contained in the WAP assembly, the same assembly that has all your page classes and anything else compiled in the project.
Bryan
In your WAP project, were you able to access the control instance from the page's code-behind? And you say you did this without compiling a separate DLL? I would *love* to see your project files, as I have been struggling with this for 2 days and been unable to achieve it. Can you please zip up your project files and email them to [email protected]? Or post them on a filesharing site so others viewing this question can view it? ... P.S. Thank you for your persistence!
Jordan Rieger
Bryan, after re-reading your comment about the Namespace="" directive, I finally understand. That was the key. Thank you so much for your help.
Jordan Rieger