i'm seeing a really strange issue with asp.net rendering. i have EXACTLY this in the relevant part of the .aspx (just replaced names of paths and controls):
<div id="header">
<% if (SiteSettings.SiteName.Equals("sx") || SiteSettings.SiteName.Equals("sw"))
{ %>
<sc:sublayout runat="server" renderingid="{B04CFA1A-6B5B-49D3-8000-339DBE9899C1}"
path="/layouts/AX/HeaderSublayout.ascx" id="AXHeader" placeholder="content"></sc:sublayout>
<% }
else
{ %><!-- bla1 --><ax:strangeBehavingControl id="HeaderInclude" runat="server" IncludeType="Header" /><!-- bla2 -->
<% } %>
</div>
the rendered html looks like:
<!-- bla1 -->
""
expected content from strangeBehavingControl
<!-- bla2 -->
the .ascx for strangeBehavingControl is really simple:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="strangeBehavingControl.ascx.cs" Inherits="layouts.strangeBehavingControl" %>
no extra spaces anywhere, checked already many times. the code behind is also really simple:
public partial class strangeBehavingControl: System.Web.UI.UserControl
{
protected override void Render(HtmlTextWriter writer)
{
var filePath = GetFilePath();
if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(Server.MapPath(filePath)))
Response.WriteFile(filePath);
}
}
so i was thinking that the strange "" where inside the rendered included files, but i checked them manually and they start with the expected characters. any idea how can those characters being inserted there?
You are generating markup for your control incorrectly. Your render method should be using the HtmlTextWriter instance given to it, and not using any direct output writing method on Response.
It also looks like a rather strange setup, as you are writing out the contents as a UserControl, meaning it will be rendered within a page. Is it correct to assume you are always outputting either valid HTML or plain text?
I would suggest you change your Render method as follows:
protected override void Render(HtmlTextWriter writer)
{
var filePath = GetFilePath();
if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(Server.MapPath(filePath)))
using (var sr = new StreamReader(filePath))
writer.Write(sr.ReadToEnd());
}
Sometimes the control file has another charset.
Verify that your file does not have extra characters at the start, and if so remove them.
You may have to use a smart text editor that allows you to do that.
I had the same extra space problem, but my control was not implementing a Render() method.
Related
I am new to ASP.NET and user controls. I am trying to generate a javascript array from my C# code.
On the main .aspx page I have this:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="main.aspx.cs" Inherits="main" %>
<%# Register Src="~/table.ascx" TagPrefix="uc1" TagName="myTable" %>
Then on my table.asc.cs I have this:
protected void Page_Load(object sender, EventArgs e)
{
(...)
this.LoadDataFromDB();
(...)
}
private void LoadDataFromDB()
{
(...)
Response.Write(array);
(...)
}
My problem is that the array is being written before the <html> tags. It still works fine, but, how could I put it inside the <head> tags for instance?
Thank you
UPDATE:
I added this to my main.aspx
<asp:Literal ID="Literalarray" runat="server" Mode="PassThrough" Text="" />
and this to my ascx.cs:
Literal Literalarray= new Literal();
Literalarray.Text = output;
What am I missing?
Use a Literal control instead of Response.Write. Place it on your control somewhere and set its Text property.
You have to place it on your control, not on your page and you don't need to reinitalize it.
This code in the ascx.cs:
Literal Literalarray= new Literal();
Literalarray.Text = output;
should be:
Literalarray.Text = output;
Which should be in the Page_Load as a designer file will declare the literal type and allocate the space for it. By declaring a new one, the old one may be hidden. Also, be aware that if you are generating a JavaScript array that you also generate the script tags as part of the output as a literal doesn't do much decorating around the result.
I'd probably suggest putting a literal in the head on the main.aspx and load the data in there that way for one idea.
You could also do dynamic controls so that in the table.ascx.cs you create a Literal like you did previously and then add that to the head of the page assuming the head tag has a "runat=server" attribute so the code behind can use it. I'm pretty sure that in the code behind for the table you could do something like this:
Literal Literalarray= new Literal();
Literalarray.Text = output;
this.Page.head.AddControl(Literalarray);
I've been poking at this all morning and I can't seem to find the way to do this.
I have a web app that has to show a tooltip on one of its div-s. The tooltip's contents come from some DB querying
< div style="height: 10px; clear: both;" title="<%=dbCount %> device(s) with version <%=devVersion %> in this group">
This works fine.
If I try replacing the <%=dbCount %> with an expression:
< div style="height: 10px; clear: both;" title="<%=dbCount > 0 ? ""+dbCount : "No " %> device(s) with version <%=devVersion %> in this group">
then on PageLoad I get an exception CS1518: Expected class, delegate, enum.
It doesn't matter how I structure the expression, if I put parenthesis or not, if I use String.Format or ternary expression - any sort of expression, besides using the variable name only, causes the error.
I tried replacing <%= with <%# and tried <% Response.Write(dbCount>0 ? "some" : "none") %> and I get the same error. This is the only line in the aspx I'm editing so the error is due to it, not elsewhere on the page.
I could use an <% if(...){ construct but then the designer is having trouble with finding the closing div and I don't want to pollute the source with too much junk, I'd rather keep the original version.
Do you know why is the compiler error showing up and how can I prevent it and use the output expression <%= devCount>0?"some":"none" %>?
Do not write code like that.
Aspx files only support that for backward compatibility.
If you really really must do it, Write only public properties that way.
Refer: Embeded code blocks
Embedded code blocks are supported in ASP.NET Web pages primarily to
preserve backward compatibility with older ASP technology. In general,
using embedded code blocks for complex programming logic is not a best
practice, because when the code is mixed on the page with markup, it
can be difficult to debug and maintain. In addition, because the code
is executed only during the page's render phase, you have
substantially less flexibility than with code-behind or script-block
code in scoping your code to the appropriate stage of page processing.
That said, the link does show you how to properly use embeded code.
If you really must do it this way, use Response.Write.
< div style="height: 10px; clear: both;" title="<%
{
string countMessage = dbCount > 0 ? ""+dbCount : "No ";
Response.Write(countMessage );
}
%> device(s) with version <%=devVersion %> in this group">
I've created a test web app and your code (<%=dbCount > 0 ? ""+dbCount : "No " %>) works fine (I'm assuming that "< div" is a mistype). I'm assuming that dbCount is an int and devVersion is a string. Is there something else going on? Is dbCount a public property that calls a method? Is it a public variable?
What is dbCount in your app?
All these variants are running ok here, among the C# samples I include the case you mentioned which is also running fine:
In VB.NET
MarkUp:
<body>
<form id="form1" runat="server">
<div id="<%If dbCount = 1 Then%><%="22"%><%Else%><%="55"%><% End If%>">
<%=dbCount.ToString()%>
</div>
</form>
</body>
Codebehind:
Partial Class varIn
Inherits System.Web.UI.Page
Public dbCount As Short = 0
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
dbCount = 1
End If
End Sub
End Class
In C#
MarkUp:
<div id="<%if (dbCount == 1) { %><%="22"%><%;}else{%><%="55"%><%;}%>">
<%=dbCount.ToString()%>
</div>
Or:
<div id="<%=dbCount > 0 ? ""+dbCount : "No " %>">
<%=dbCount.ToString()%>
</div>
Codebehind:
public partial class _Default : System.Web.UI.Page
{
public short dbCount;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dbCount = 1;
}
}
}
I am using a contentplaceholder control in a master page to allow the content editor to specify the URL of an image used as a background to a div.
<div id="content-left-column"
style="background-image: url('<wc:UrlContentPlaceHolder runat='server' ID='leftContentBackgroundUrl'></wc:UrlContentPlaceHolder>');">
The placeholder is referenced on the content page like:
<asp:Content ID="Content1" ContentPlaceHolderID="leftContentBackgroundUrl" runat="server">/img/left-content.jpg</asp:Content>
The page renders just fine using this approach. However, when I look at the content page in source view, the ContentPlaceHolderId attribute value is underlined and there is a warning "Could not find 'leftContentBackgroundUrl' in the current master page or pages."
Design view will not render the content page due to this error.
Is there a way to use ContentPlaceHolder for attribute values such that no errors are reported in the Visual Studio editor and design surface?
*Note. I am aware of the issues with this approach. If the content editor puts in spaces, carriage returns or performs a document format in visual studio, the rendered attribute value is broken. I have created a subclass of ContentPlaceHolder that trims its values and uses ResolveClientUrl to address these issues. For the sake of discussion I have described the issue which affects a normal ContentPlaceHolder control.
The following stack overflow question addresses the fact that ContentPlaceHolder can be used with attribute values but does not address the design surface issues.
Why can't I use a ContentPlaceholder inside HTML attributes in ASP.NET?
I don't believe that's how ContentPlaceHolders where meant to be used. I would strongly advise you to use inline code for this.
Main.master:
<div id="content-left-column"
style="background-image: url(<%: LeftContentBackgroundURL %>);">
Main.master.cs:
public string LeftContentBackgroundURL { get; set; }
In the ContentPage you then just use the #MasterType directive and set the Property in Codebehind.
Content.aspx:
<%# MasterType VirtualPath="~/Main.master" %>
Content.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
this.Master.LeftContentBackgroundURL = "/img/left-content.jpg";
}
This solution was inspired by #atticae's response.
On the master page, I included a normal ContentPlaceholder control with visible="false". Where I was previously using that ContentPlaceholder as an attribute value, I instead reference a property of the MasterPage, LeftBackgroundImageUrl.
<asp:ContentPlaceHolder runat='server' ID='leftContentBackgroundUrl' Visible="false"/>
<div id="content-left-column" style="background-image: url('<%: LeftBackgroundImageUrl%>');">
Using a subclass of ContentPlaceholder causes errors in the design surface of content pages which is why I went back to using a normal ContentPlaceholder.
The LeftBackgroundImageUrl property code looks like:
ReadOnly Property LeftBackgroundImageUrl As String
Get
Return RenderResolvedUrl(leftContentBackgroundUrl)
End Get
End Property
Private Function RenderedResolvedUrl(control As Control) As String
Dim visible As Boolean = control.Visible
control.Visible = True
Dim result As String = Nothing
Using writer As New System.IO.StringWriter()
Using htmlWriter As New System.Web.UI.HtmlTextWriter(writer)
control.RenderControl(htmlWriter)
htmlWriter.Flush()
End Using
result = Page.ResolveClientUrl(writer.ToString.Trim).Trim
End Using
control.Visible = visible
Return result
End Function
This solution allows the image url to be specified declaratively, and without the user having to add a MasterType directive. This is not perfect in the sense that it does not, at edit/design time, validate that the content the editor provides is just a URL or application relative URL. But, it does keep the user from having to write code.
I have a designer working at the ASPX level. He doesn't do C#, doesn't do code-behinds, doesn't compile, etc. He's a pure designer, working with HTML and server controls.
I need a conditional control -- an If...Then-ish type thing. Normally, I would do this:
<asp:Placeholder Visible='<%# DateTime.Now.Day == 1 %>' runat="server">
It's the first day of the month!
</asp:PlaceHolder>
Is there any way to do something like this without the databinding syntax? Something like:
<asp:If test="DateTime.Now.Day == 1" runat="server">
It's the first day of the month!
</asp:If>
Is there some kind of way to extend a placeholder to allow this? I've fiddled around a bit, but in the end, I have a conditional that I essentially have to compile.
Now, there's nothing wrong with the databinding syntax, but's just one more bit of...weirdness, the a designer is going to have to understand. Additionally, it doesn't give me "else" statements. Something like this would be great...
<asp:If test="DateTime.Now.Day == 1" runat="server">
It's the first day of the month!
<asp:Else>
It's not the first day of the month!
</asp:Else>
</asp:If>
Instead of writing control
asp:If
why not use:
<% if expression
{ %>
Yellow
<% } %>
<% else
{%>
Red
<% } %>
Taking into account that codebehind files are out as the designer probably not got VS, I think a simpler solution with less code may be more preferential:
<%# Page Language="C#"%>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (DateTime.Now.Day == 1)
{
DateTestPanelFirst.visible = true;
DateTestPanelOther.visible = false;
}
}
</script>
<html>
<body>
<asp:panel runat="server" id="DateTestPanelFirst" visible="false">
It's the first day of the month!
<asp:panel>
<asp:panel runat="server" id="DateTestPanelOther">
It's not the first day of the month!
<asp:panel>
</body>
</html>
the <asp:panel> could be changed to another type of web control, like <asp:label> etc. I think almost all dot net controls have the visible property, so you can hide/show them at any time.
The data-binding syntax has two problems: first it's a little weirder for your designer vs. using plain text, and second it requires the designer to remember to invert the "if" test in your "else" block.
The first problem may annoy your designer a little, but the second problem is much more severe, because it forces your designer to think like a programmer (inverting boolean logic!) and makes every if/else block into a possible bug you need to test for after your designer hands over a template.
My suggestion: use data-binding syntax, but fix the more severe problem by creating custom controls that only require data-binding test code on the If control, but not on the Else control. Sure your designers will have to type a few more characters, but the other more severe problems won't apply and your performance won't suffer as it would if you had to dynamically compile code each time your page ran.
Here's an example I coded up to illustrate:
<%# Page Language="C#"%>
<%# Register Assembly="ElseTest" TagPrefix="ElseTest" Namespace="ElseTest"%>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
DataBind();
}
</script>
<html>
<body>
<ElseTest:IfControl runat="server" visible="<%#1 == 1 %>">
This should be visible (in "if" area)
</ElseTest:IfControl>
<ElseTest:ElseControl runat="server">
This should not be visible (in "else" area)
</ElseTest:ElseControl>
<br /><br />
<ElseTest:IfControl runat="server" visible="<%#0 == 1 %>">
This should not be visible (in "if" area)
</ElseTest:IfControl>
<ElseTest:ElseControl runat="server">
This should be visible (in "else" area)
</ElseTest:ElseControl>
</body>
</html>
Here's the underlying controls, which are simply wrappers around asp:Literal:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
[assembly: TagPrefix("ElseTest", "ElseTest")]
namespace ElseTest
{
// simply renames a literal to allow blocks of data-bound-visibility
[ToolboxData("<{0}:IfControl runat=\"server\"></{0}:IfControl>")]
public class IfControl : Literal
{
}
[ToolboxData("<{0}:ElseControl runat=\"server\"></{0}:ElseControl>")]
public class ElseControl : Literal
{
public override bool Visible
{
get
{
// find previous control (which must be an IfControl).
// If it's visible, we're not (and vice versa)
for (int i = Parent.Controls.IndexOf(this)-1; i >= 0; i--)
{
Control c = Parent.Controls[i];
if (c is IfControl)
return !c.Visible; // found it! render children if the if control is not visible
else if (c is Literal)
{
// literals with only whitespace are OK. everything else is an error between if and then
Literal l = c as Literal;
string s = l.Text.Trim();
if (s.Length > 0)
throw new ArgumentException("ElseControl must be immediately after an IfControl");
}
}
throw new ArgumentException("ElseControl must be immediately after an IfControl");
}
set
{
throw new ArgumentException("Visible property of an ElseControl is read-only");
}
}
}
}
If you want it more concise, you can easily shorten the tag name (by changing the class names and/or tag prefix). You can also create a new property (e.g. "test") to use instead of "Visible".
If you really want to get rid of the <%# %>, there are likley many different tricks you can use to leverage CodeDOM or other ways to dynamically compile code, although performance will be a challenge since you'll probably end up dynamically compiling code each time the page runs, it may introduce pesky security issues, and more. I'd stay away from that.
I have a site that features some pages which do not require any post-back functionality. They simply display static HTML and don't even have any associated code. However, since the Master Page has a <form runat="server"> tag which wraps all ContentPlaceHolders, the resulting HTML always contains the ViewState field, i.e:
<input
type="hidden"
id="__VIEWSTATE"
value="/wEPDwUKMjEwNDQyMTMxM2Rk0XhpfvawD3g+fsmZqmeRoPnb9kI="
/>
EDIT: I tried both variants of setting EnableViewState on page level with no luck at all:
<%# Page Language="C#" EnableViewState="false" %>
<%# Page Language="C#" EnableViewState="true" %>
I realize, that when decrypted, this value of the input field corresponds to the <form> tag which I cannot remove because it is on my master page. However, I would still like to remove the ViewState field for pages that only display static HTML. Is it possible?
You could override Render and strip it out with a Regex.
Sample as requested. (NB: Overhead of doing this would almost certainly be greater than any possible benefit though!)
[edit: this function was also useful for stripping all hidden input boxes for using the HTML output as a word doc by changing the MIMEType and file extension]
protected override void Render(HtmlTextWriter output)
{
StringWriter stringWriter = new StringWriter();
HtmlTextWriter textWriter = new HtmlTextWriter(stringWriter);
base.Render(textWriter);
textWriter.Close();
string strOutput = stringWriter.GetStringBuilder().ToString();
strOutput = Regex.Replace(strOutput, "<input[^>]*id=\"__VIEWSTATE\"[^>]*>", "", RegexOptions.Singleline);
output.Write(strOutput);
}
Add following methods to the page:
protected override void SavePageStateToPersistenceMedium(object state)
{
//base.SavePageStateToPersistenceMedium(state);
}
protected override object LoadPageStateFromPersistenceMedium()
{
return null; //return base.LoadPageStateFromPersistenceMedium();
}
protected override object SaveViewState()
{
return null;// base.SaveViewState();
}
Result :
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="" />
In the <% #page... directive at the top of the page, add EnableViewState="False". That will prevent the ViewState for that particular page.
The method suggested by Martin must be used very carefully; because it may cause unexpected behaviors in your pages as Martin pointed in parenthesis. I've actually experienced it. But there is another option to remove viewstate content from page safely.
This option gives you the ability to use viewstate without setting false, it also allows you to remove it from your pages. Please check the articles below:
1- http://www.eggheadcafe.com/articles/20040613.asp
2- http://aspalliance.com/72
There is a solution file zipped under the Peter's article [1] you can download. I recommend that you read the second article also referenced by Peter. This is a perfect solution to remove viewstate content from your page while using its capabilities.
There will always be a ViewState. See this related question:
Why does __VIEWSTATE hidden field gets rendered even when I have the EnableViewState set to false
in .net4 you can just remove the runat="server" from the form tag. But you can't use server controls inside the form tag once you remove it.
ViewState is added only if an asp:Form is present in the page. Remove the Form, and the hidden field will not be rendered.
Beware: By doing this, you are also renouncing to have server-side event handlers, or any kind of PostBack events.
Or just use a simple jQuery line to remove the fields, if you're using AJAX-style postback requests...
$(".aspNetHidden").remove();
This removes the DIV encasing the hidden __VIEWSTATE fields.