ASP.NET Line Breaks in Title Element - asp.net

I'm trying to optimize SEO readability on our websites and one issue I've come across is ASP.NET butchering the title element of my MasterPage. Entered as such in my MasterPage (manually reformatted to remove line breaks caused by the <% %> tags):
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /> - <%=WebsiteSettings.WebsiteName %></title>
This is the output I receive:
<title>
Home
- Website Name</title>
As you can see ASP.NET is adding preceding and trailing line breaks where the <asp:ContentPlaceHolder /> is substitute becaused Visual Studio auto-formats <asp:Content /> to start and end with a line break. Obviously, this can be prevented in the Visual Studio formatting options, but this is not ideal because I only would want to remove that behavior for the TitleContent placeholder and not the rest.
Is there any way I can ensure my Title is trimmed before it is rendered? I am using MVC so code-behind is not an acceptable option.

The following should allow you to keep from copying and pasting code.
Option 1
Since your using MVC create a HTML Helper Like this:
namespace [ProjectName].Web.Views
{
public static class HtmlHelpers
{
public static MvcHtmlString GetFullPageTitle(this HtmlHelper helper, string PageTitle)
{
return MvcHtmlString.Create(PageTitle + " - " + WebsiteSettings.WebsiteName)
}
}
}
Now in your Master Page just put this
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
Then in your pages use this
<asp:Content ID="PageTitleContent" ContentPlaceHolderID="TitleConent" runat="server">
<%=Html.GetFullPageTitle("Some PageTitle")%>
</asp:Content>
Option 2
Note: if you populate Data in your Action then you dont have to Add this to ever page.
Like so:
public ActionResult myAction()
{
ViewData["Title"] = "MyActionTitle";
return View()
}
Then in your Master page you would simply do the following
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /><%= ViewData["Title"] + "-" + WebsiteSettings.WebsiteName %></asp:ContentPlaceHolder></title>
The nice thing about this is if you wanted to you could override what the title says in each page by doing this
<asp:Content ID="PageTitleContent" ContentPlaceHolderID="TitleConent" runat="server">
My Override Title
</asp:Content>

If you are really bothered (and I don't see why you would be given whitespace is not important in HTML) you could try setting it in code-behind something like this:
Page.Title = WebsiteSettings.WebsiteName + " " + Page.Title;

Using regular expressions, as dagray said, is the safest and easiest approach.
This code replaces only the first occurrence of newline/characters in first title tag.
void TrimTitleRegex(ref string content)
{
System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex(#"\<title\>(.*?)\<\/title\>");
var result = rgx.Replace(content,
m =>
{
var codeString = m.Groups[1].Value;
// then you have to evaluate this string
codeString = System.Text.RegularExpressions.Regex.Replace(codeString, #"\r\n?|\n", "");
codeString = String.Format("<title>{0}</title>", codeString);
return codeString.Trim();
}, 1);
content = result;
}

You could try a literal control, though I suspect that won't work in the document header outside the asp.net form. You could also try setting the title via code-behind.

This is a possibility -
Override the rendering routine to remove whitespace with regexp's:
http://madskristensen.net/post/Remove-whitespace-from-your-pages.aspx

Related

Defining where usercontrol output will be

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);

Response.write to <head>

Hopefully this won't be a difficult question for someone to answer, but I am having a lot of trouble finding the solution online. I am trying to add some HTML to my asp.net page from the code behind (It's VB.net). I would like to add the HTML into the head section of my page but can only add to the body currently.
You can put code in the head, just like the body. For example:
<%= CallAMethodThatReturnsAStringOfHtml() %>
You could try creating a property in your code behind and add your html in the Page_Load method:
Public MyHtml As String
then in the head section of your HTML just use the literal notation:
<%= MyHtml %>
Have runat attribute on your head element and you will be able to access it
<head id="someHead" runat="server">
</head>
Now in your codebehind, you can set it like
someHead.InnerHtml="<script src='somelibrary.js' ></script>";
I made this way, and it worked:
on the .aspx file:
...
<%
Response.Write(GetDisclosureText());
%>
...
on the aspx.cs file:
protected string GetDisclosureText()
{
string disclosure = "";
// ...Apply custom logic ...
if (!string.IsNullOrEmpty(disclosure))
{
return disclosure;
}
return "Error getting Disclosure Text";
}
Note the only difference is that I call Response.Write, not just the function.

Creating website template which is independent from source code in asp.net webforms

Im working on an e-commerce platform which supports multiple stores on different domains. The backend is complete (for now) and I'm now starting the front-end part. Since the platform supports multiple stores I need some kind of templating system and I haven't quite figured out what's the best way to do this.
This are my requirements:
I don't want to rebuild my solution to add a new template
Templates are stored in /Templates/TemplateDirectoryName
I want to be able to use (predefined) usercontrols inside the templates.
I use URL routing and only have 1 Default.aspx page which controls which page template and additional code needs to be loaded.
This is what I came up with so far:
In my template directory i have templates created with master pages (A homepage master file, a default master file, and sub-master files referencing the default master file...for product detail, browse, search etc)
My Default.aspx page picks the right template based on routing values
While this way works I don't think it's very practical but the more I think about it the more I come to the conclusion that there are not so many other options to go around this. I think this is what I want to ask: Is there a way to use usercontrols in a template and have the template completely seperated from the application so users can create templates without having to worry about the site's namespace and structure?
Kind regards,
Mark
Since you are referencing a folder for templates, wouldn't it be possible to just change the .aspx files in the folder and asp.net shall pick up the template based on the url path that you've mentioned? I think that is possible in asp.net.
Also, Frameworks like DotNetNuke, Sharepoint, Joomla etc. have the similar concept. You can avail their features.
My proposed solution is below. It has a few constraints, like all master pages need to implement the same set of placeholder controls (not surprising). Take a look and let me know what you think.
I setup my folder structure like this:
Website -> Templates -> TemplateFolder (named same as the template)
Website -> Templates -> UserControls (User controls are stored in a non-template specific folder)
I defined a simple Template configuration class which we can store/save/load a basic template deffinition:
public class Template
{
public string TemplateName { get; set; }
public string UserControlName { get; set; }
public string MasterPageName { get; set; }
public string TemplateFolder
{
get
{
return GetTemplateFolder(TemplateName);
}
}
public string TemplateConfigFile { get { return GetTemplateConfigFile(TemplateName); } }
private static string GetTemplateFolder(string name)
{
return HttpContext.Current.Server.MapPath("~/Templates/" + name + "/");
}
private static string GetTemplateConfigFile(string name)
{
return GetTemplateFolder(name) + "/" + name + ".config";
}
public Template()
{
}
public void Save()
{
XmlSerializer xs = new XmlSerializer(typeof(Template));
if (!Directory.Exists(TemplateFolder)) Directory.CreateDirectory(TemplateFolder);
using (FileStream fs = File.OpenWrite(TemplateConfigFile))
{
xs.Serialize(fs, this);
}
}
public static Template Load(string name)
{
if(!File.Exists(GetTemplateConfigFile(name))) return null;
XmlSerializer xs = new XmlSerializer(typeof(Template));
using (FileStream fs = File.OpenRead(GetTemplateConfigFile(name)))
{
Template t = (Template)xs.Deserialize(fs);
return t;
}
}
}
You can build some bare xml code to get started with by running the code below:
Template t1 = new Template() { TemplateName = "Template1", MasterPageName = "Child1.master", UserControlName = "uc1.ascx" };
Template t2 = new Template() { TemplateName = "Template2", MasterPageName = "Child2.master", UserControlName = "uc2.ascx" };
t1.Save();
t2.Save();
I created a basic master page. This page will probably never be used except to give your default page the basic placeholders. All of your master pages should have the same set of placeholders as your base one so that your pages can use them all interchangably. Notice I left a placeholder for our user control.
<%# Master Language="C#" AutoEventWireup="true" CodeFile="BaseMaster.master.cs" Inherits="Templates_Masters_BaseMaster" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder id="cphHeader" runat="server">
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder id="cpUserControl" runat="server">
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder id="cphFooter" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
Now I create a basic aspx web page that uses the above master page.
<%# Page Title="" Language="C#" MasterPageFile="~/Templates/Masters/BaseMaster.master" AutoEventWireup="true" CodeFile="DefaultTemplated.aspx.cs" Inherits="DefaultTemplated" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="cphHeader" Runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="cpUserControl" Runat="Server">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="cphFooter" Runat="Server">
</asp:Content>
In the codebehind we'll setup the basic templating. This sets the masterpage and adds a pre-defined user control to the content placeholder for user controls. If you wanted you could just make a panel or something and add it to that fixed control, but I thought you might appreciate seeing how to make it work with masterpages.
public partial class DefaultTemplated : System.Web.UI.Page
{
private Template PageTemplate
{
get
{
if (_tLoaded == null)
{
string template = Request.QueryString["template"];
if (string.IsNullOrEmpty(template)) return null;
Template t = Template.Load(template);
_tLoaded = t;
}
return _tLoaded;
}
}
private Template _tLoaded = null;
protected void Page_Load(object sender, EventArgs e)
{
if (PageTemplate != null)
{
//cpUserControl is the name of my usercontrol placeholder
((ContentPlaceHolder)Page.Form.FindControl("cpUserControl")).Controls.Add(
Page.LoadControl("~/Templates/UserControls/" + PageTemplate.UserControlName));
}
}
protected void Page_PreInit(object sender, EventArgs e)
{
if (PageTemplate == null) return;
this.MasterPageFile = "~/Templates/" + PageTemplate.TemplateName + "/" + PageTemplate.MasterPageName;
}
}
If you had a template named "Template1" you could use it by calling "Default.aspx?template=Template1". Since you are using URL rewriting you would use the rewriting to pass the template name as a parameter to the page.
Another option that could be combined with the above would be the use of Page.ParseControl. Using this you could store your raw asp.net designer code (designer only) in a database or raw text file. Then you could instantiate it load it like this:
//where pnl1 is a Panel on the page. Page.ParseControl just returns a control object, so use it anywhere.
pnl1.Controls.Add(Page.ParseControl("raw asp.net designer code here."));
One great thing about this is that nested controls work great too.
I don't know if I understand correctly:
If you don't want to rebuild, then I can tell a CMS concept is best suitable for you.
You can store your templates as an HTML in database and from DB you can fetch it back,
You can give an admin functionality with editor to edit your template online also.

How do I stop <%= from html encoding my script tags?

I am trying to add js dynamically to my view using a custom HTML Helper. The problem I am facing is that the the following server tag is encoding my < and > to &lt and &gt.
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
<%: Model.ProductName %>
<%foreach (var script in Model.DynamicIncludes)
{%>
<%=Html.ScriptTag(Url.Content(script))%>
<%} %>
</asp:Content>
This is what my helper looks like:
public static class ScriptHelper
{
public static string ScriptTag(this HtmlHelper helper, string path)
{
return string.Format("<script src='{0}' type='text/javascript'/>", path);
}
}
When I view the html source the script includes are being written to the reponse stream like so:
<script src='../../Scripts/DataOutEventHandling.js' type='text/javascript'/>
This application is written using the ASP.NET MVC 2.0
Use Html.Raw around your formatted value. You can place this anywhere you find approprate. e.g.
<%=Html.Raw(Html.ScriptTag(Url.Content(script)))%>
http://msdn.microsoft.com/en-us/library/system.web.webpages.html.htmlhelper.raw(v=vs.99).aspx
<%=Html.ScriptTag(Url.Content(script))%> will not encode. You probably use <%:Html.ScriptTag(Url.Content(script))%> which performs the HTML encoding.
Notice the difference between <%= and <%:.
For some reason the script tags were being nested. In my helper I added a closing tag rather than using a self closing script tag and it fixed the problem.
public static string ScriptTag(this HtmlHelper helper, string path)
{
return string.Format("<script src='{0}' type='text/javascript'></script>", path);
}

How can I replicate If...Then logic as a Web control?

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.

Resources