Reuse a Variable Multiple Times on an ASP.NET Page - asp.net

I feel somewhat foolish asking such a simple question, but I can't seem to find an answer. I'm new to ASP.NET (C#), but I'm learning by building a simple set of web pages that display a report. I have a variable that represents a company name. I need to output this variable in multiple places on the web page. The only way I have found to output a variable this is with:
company_name.Text = "Acme Windows";
then
<asp:literal id="company_name" runat="server" />
My problem is that I want to use company_name in multiple places on the page. Do I really have to create a separate variable holding the the same value for each time it is placed on the page? If I just copy the above XML code to all the places I want to show the variable it obviously creates a compile error since that ID is already defined.
I feel like I'm missing something very obvious.

The easiest way to do this is to create a string variable or property in your code-behind class and use the <%= %> notation (short for Response.Write) to render it on your page inline:
// You can do this anywhere on your .aspx, as many times as you like.
<%= this.CompanyName %>
// Better yet, html encode the value to protect against various threats,
// such as cross-site script injection (XSS)
<%= HttpUtility.HtmlEncode(this.CompanyName) %>
.NET 4.0 introduces a new shortcut notation (Html Encoding Blocks) to html-encode your output:
<%: this.CompanyName %>
Regarding your original approach, ASP.NET web controls like Literal represent individual parts of a web page - you can't use them multiple times on a page because the object instance company_name refers to the specific part of the HTML generated by the <asp:literal> in your .aspx page.

In this case, you create a property on the page and output that in every place you need it.
public string CompanyName { get { return "Acme Windows"; } }
And in the aspx:
.NET 4.0:
<%:this.CompanyName%>
Before 4.0:
<%=this.companyName%>

You could add the control dynamically:
Literal myLiteral = new Literal();
myLiteral.text = "Acme Windows";
this.Page.Controls.Add(myLiteral);
You can also add the control within a specific control on the page, by changing the this.Page.Controls reference to the particular control you want to add the literal to.

Why is this a community wiki?
Anyway, you have several possibilities to achieve what you want. Placing multiple variables holding the same name is for sure not best practice. If you have it filled with, let's call it, "semi-dynamic" value, I'd not put it hardcoded within your code. What I would do is to use a global resource file.
You create a new resource file in the App_GlobalResources folder and add a key "COMPANY_NAME" with value "Acme Windows". Then within your ASPX code you can do something like
<asp:literal id="company_name" runat="server" Text="<%$ Resources:GlobalResources, Button_Save %>"/>
I've written a blog post some time ago which details this approach. The advantage of the resource file is that you don't have to touch the code.
If you want to further "refactor" then - assuming you have some general company info you have to display on different positions on the page - you could create a separate UserControl which contains the information like company name, phone number, contact info etc. Within that control you have your literal, label, whatever you use to display that information exactly 1 time. This UserControl is then placed on the places on the actual page where you need it, even multiple times.

The simplest answer is you need to define multiple controls.
But a better solution would be to do this:
Create a property on the code behind side of things:
protected CompanyName{get;set;}
Then, in the aspx side of things, reference that with the <%= %> commands
<span><%=CompanyName %></span>

Related

How to Access PagesSection Property in Code-behind of Asp.NET

I'm in the code behind of a user control. I need to access one of the page's properties (EnableSessionState).
Originally, this would be defined something like this in aspx:
<%# Page Language="C#" EnableSessionState="ReadOnly" %>
However, I want to dynamically change this value in the code behind.
I looked at this answer:
PagesSection pages = WebConfigurationManager.OpenWebConfiguration("").GetSection("system.web/pages") as PagesSection;
pages.EnableSessionState = PagesEnableSessionState.ReadOnly;
Unfortunately, I'm just trying to read the header. Also considered this answer:
PagesSection pagesSection = new PagesSection();
pagesSection.EnableSessionState = PagesEnableSessionState.ReadOnly;
But I'm not trying to read default values, I'm trying to set the actual page's values.
Unfortunately, there is no property like this.Page.PagesSection, so is there another way of going about this?
Since the goal was to modify session state behaviour, according to this blog, it is possible to access using the following line:
Context.SetSessionStateBehavior(SessionStateBehavior.ReadOnly);

Multiple CMSEditableRegion in ascx?

I have three CMSEditableRegion controls inside of an ascx which needs to be on an aspx page 3 or more times.
The problem is that each of the region controls will always contain the content of the last set of them.
After doing a little research, I've found out it saves the content of the control in the database under the ID of the control meaning that the first CMSEditableRegion will have its content overwritten by the last CMSEditableRegion's content (since there are at least three with the same server ID - one per ascx). Well, rather, that was for Kentico 5 but what I'm seeing tends to support this. Unfortunately, the solution I found for Kentico 5 does not work in Kentico 10.
How can I have multiple CMSEditableRegion controls in an ascx that is going to be on the aspx page multiple times?
Edit: We are indeed using the portal manager (correctly) and our master is set up using the specified Kentico Documentation.
You need to ensure each CMSEditableRegion's control ID is unique so that the data for each instance is stored separately in the database.
You can achieve this by setting the ID of the control in the codebehind file of your web part ascx.
Place the CMSEditableRegion into your ascx...
<cms:CMSEditableRegion runat="server" ID="cerContent" RegionTitle="WYSIWYG" RegionType="HtmlEditor" />
...and then set the control's ID in the code behind...
cerContent.ID = this.ID + cerContent.ID;
The unique ID is generated here by concatinating the control's ID with this.ID, which is the unique ID of the web part's instance when it is placed on a page.
Works for me in Kentico 10.
Add this to your web-parts code-behind.
public override void OnContentLoaded()
{
base.OnContentLoaded();
if (!this.StopProcessing)
{
theCMSEditableRegion.ID = theCMSEditableRegion.ID + base.ID;
}
}
When you use portal engine you can have as many as you want and that should apply to aspx development model. Did you follow the example?
I would look inside the DB to make sure that XML is saved correctly:
select CONVERT(xml,DocumentContent), * from cms_document where documentid = 123
When you save web parts (in portal engine this is the equivalent of CMSEditableRegion), the xml looks like this:
<content>
<webpart id="editabletext1;fe77e447-3af4-440f-a736-7c1e321cb3fc">456</webpart>
<webpart id="editabletext;3bb22493-8e7d-47c1-9dc0-dfc5aeff3157">123</webpart>
</content>
Yours should look the same or very similar. it might have something to do the IDs or bindings.
I think you are missing Portal Manager:
<cms:CMSPortalManager ID="manPortal" runat="server" EnableViewState="false" />
But easiest way to understand how this works is to open Kentico APX template in CMSTemplates/CorporateSite. In there you will find master page (root.master) with Home page template (HomeASPX.aspx). In master you can see portal manager is placed and in home you can add as many editable regions as you want. I did try this.
Hope this solves your problem.

Accessing app setting from aspx and add concatenated text

I've got a project where I'm tasked with changing hard-coded domain references from one domain to another in a group of legacy C#/VB web projects. I want to parameterize the domains as much as possible instead of just replacing with a different hard-coded value. The problem is that there are over 800 of these references in about 30 different solutions, so creating variables in each code-behind to bind to would take forever.
I have added the new domains to the appSettings section of the web.config file, and this works:
<asp:HyperLink Text="Link" NavigateUrl="<%$appSettings:DomainX %>" runat="server" />
But I need to be able to do something like this:
<asp:HyperLink Text="Link" NavigateUrl="<%$appSettings:DomainX %>/newPage.aspx" runat="server" />
But when I add the "/newPage.aspx" the page doesn't compile anymore. I don't really care if this is done with an asp:HyperLink tag or just a tag.
Any ideas on how I can accomplish this?
Thanks.
I think you have two options. The easiest is to just use a plain old anchor tag, if you're not doing anything with the HyperLink server side:
Link
Alternatively, you could set the NavigateUrl in the Page_Load, since <%= will not work properly within the HyperLink server tag:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
link1.NavigateUrl = string.Concat("http://",
ConfigurationManager.AppSettings["DomainX"], "/newPage.aspx");
}
You could also see if you can make a custom binding, something like $myBinding:DomainX, but I don't know if that's possible off the top of my head (I would assume it is though).
EDIT
That $appSettings:DomainX code is called an ASP.NET Expression, and can you can create custom expressions. This post from Phil Haack covers how to set them up, in case you are interested.
How about something along the lines of:
<%=ConfigurationManager.AppSettings["DomainX"].ToString() + "/newPage.aspx" %>
I would go with one of two different approaches that would save you the need to change the NavigateUrl in the .aspx itself.
One option is to inherit from HyperLink class and overriding the NavigateUrl property, adding the ConfigurationManager.AppSettings["DomainX"] in the getter method. Having this, just change <asp:HyperLink ... to <UC:MyLink ...
Second option is adding small function to each page (can be in one shared place and just called from each page) that will iterate over all the hyperlinks controls and dynamically add the domain. To find all controls of certain type you can use such code for example.

How can I pass arguments on a ContentPlaceHolder?

Ok, so here is the setup. I have a master page. The page is assigned to a aspx file programatically in the PreInit function. This all works as expected.
I have a function that runs through all the controls on the page an looks for ContentPlaceHolder controls with specific IDs. When a specific ID is found the control is processed (specific content is placed there based on the ID and other information). This all works as expected.
I have a situation where I would like to pass information to my processor function from the control. I would like to be able to, based on an attribute, do different things. For example I would like to be able to put something like this on the masterpage:
<asp:ContentPlaceHolder id="CMS_EXTRABLOCK1" type="text" runat="server"></asp:ContentPlaceHolder>
Note that the type="text" attribute is not a standard attribute. I would like to be able to in the c# code do something like where ctrl is the ContentPlaceHolder.
if (ctrl.Attributes["type"] == "text") {} else {}
Now none of that will work as I get a parse error with the added attribute. So is there a way around the problem while still using the ContentPlaceHolder control? If at all possible I would like to continue using the ContentPlaceHolder control type for consistency with the rest of the code. If I can't use the ContentPlaceHolder in any manner then what would be an equally ideal asp control for this type of situation?

How to create HTML output without a) databinding or b) using Response.Write?

Kind of related to my other question - I've only ever used HTMLControls with runat="server" and WebControls grudgingly, preferring to have control over the markup that gets generated (including the ids of the elements, etc.).
What's your suggestion for, say, iterating over the contents of a collection and generating a table or list without resorting to databinding or using Response.Write in a loop from the code-behind? I'm interested in the different approaches for creating clean, maintainable code.
There is nothing to stop you iterating over your collection directly in your aspx page.
<ul>
<% foreach(Person person in this.People) {%>
<li><%=person.Firstname %> <%=person.Lastname %></li>
<% } %>
</ul>
In this example People is a list property on my codebehind. You will find many ASP.NET MVC projects are using this method.
When you say "databinding," are you speaking of binding a database result set to a Gridview or Repeater, etc. via a .Bind() call, or just using any ASP.NET server control (or HTML server control) in general?
Because, if you just want to avoid using server controls in general, but don't want to use Response.Write either, you're seriously limited in your options.
Personally, if you want control over markup, why not just loop through a SqlDataReader or something and then save the results to a Literal control, using HTML where applicable. Then within the page (wherever you want the data to appear) just do:
<asp:Literal ID="ltrResults" runat="server" />
#Brownie... yeah, but those are Response.Write statements... you're just using the shorthand format
Inspired by the first suggestion I've also tried adding a PlaceHolder to the aspx and then adding child controls to it programatically from the code-behind. I'm hoping I can create a user control for the repeating content and then add it to the PlaceHolder in a loop. This will allow the UI code to be nicely encapsulated and should hide all the StringBuilder action.
The repeater control is used for exactly what you want. It is a server control, but you specify what HTML is generated in the templates. You do databind, but isnt that just a shortcut for a manual loop?

Resources