Encoding Error When Passing Value in Url
Title: 使用URL傳參數出現亂碼
Use the following to solve the problem.
HttpUtility.UrlEncode()/UrlDecode()
And this method save you from some XSS attacks too ^_^
用下列方法就編碼可以
HttpUtility.UrlEncode()/UrlDecode()
這會同時避開某部份XSS攻擊
Google Map + ASP.NET Series 1
I have made a little web page with google map api. Here are issues I dealed with.
Some of them are of ASP.NET, some of them are of Google Map.
Here are a little features description of my application.
1. Move to one of the marker and zoom in.
2. Pop up info window with information.
3. Showing the mouse Lat. and Lng.
4. Draging marker.
5. Show/hide maker’s name label.
6. Show/hide markers by category.
7. Show information of each station with label.
1-4 are features that provide by Google api.
5-7 are features that needs to work on.


The first thing you need to deal with will be ’s onload and onunload event.
Google’s simple guide is adding an initialize() to onload and adding GUnload() to onunload.
It is not a good idea if you have your on master page and
make it runat=”server”, putting javascript functions to it.
I get around like this. A div with Id=”GMap” and runat=”server”.
In code-behind:
Page.ClientScript.RegisterStartupScript(this.GetType(), "OnLoad", string.Format("AddOnLoadFunctionParam(initialize,\"{0}\");", GMap.ClientID), true);
Page.ClientScript.RegisterStartupScript(this.GetType(), "OnUnload", "GUnload();", true);
In Javascript:
function AddOnLoadFunctionParam(func, containerId) {
$addHandler(window, "load", function() { func(containerId) });
return;
}
function AddOnUnloadFunction(func) {
$addHandler(window, "unload", func);
return;
}
function initialize(id) {
var map = new google.maps.Map2(document.getElementById(id));
map.setCenter(new google.maps.LatLng(37.4419, -122.1419), 13);
//do what you need to do.
}
I pass the div’s Id to the javascript by using the registering it to the page. In that javascript function.
I am using ASP.NET AJAX Client Library function (although nothing AJAX here), to append it as an onload event handler.
This will preserve all other onload event handler. Do the same to onunload with GUnload().
Try it, and write to me if you get any question. Since I have done this quite a while ago.
And write this by memory, and I know my memory is not that good.
Generate Statistic Chart with ZedGraph in ASP.NET
中文翻譯請稍候.
The chart generation work is handled by my former colleague Peter. But he left.
He did the job with his own little chart library which I don’t know how to use it.
So I look for an open source and/or free solution. I find ZedGraph and it looks pretty much 90% what I need.
After experiencing ZedGraph, it is very amazing how easy to use ZedGraph and its features are so complete!
Download ZedGraph first.
If you are not going to make your own version or dive into the source, just download dll only.
Create a Web Application, add both ZedGraph.dll and ZedGraph.Web.dll to the reference.
And then right click on the toolbox, add new server control by adding ZedGraph.Web.dll.
You can now drag the ZedGraph control to your design view.
Remember to *REMOVE* all other tags, just leave
and the ZedGraphWeb control behind.
Result in something like this :
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GenerateLineChart.aspx.cs" Inherits="TaoYuan.HistoryData.ByItemGroup.GenerateLineChart" %>
<%@ Register Assembly="ZedGraph.Web" Namespace="ZedGraph.Web" TagPrefix="zgw" %>
As you can read in their document, ZedGraph works in two modes.
I am not going to explain it since their have nice document on that.
I will show how to use the stream mode to expose a Graph as a url.
Back to the page which we have a ZedGraph control.
We assign an event handler to RenderGraph event which will define how the graph is rendered. Assign like the following :
zedGraphControl.RenderGraph += new ZedGraph.Web.ZedGraphWebControlEventHandler(zedGraphControl_RenderGraph);
public void zedGraphControl_RenderGraph(ZedGraphWeb zgw, Graphics g, MasterPane masterPane){...}
Inside the handler method, you will be given a default master pane.
I maybe talk about master pane later, let’s just use one graph in this post.
What you need to do here is setup the graph style, bind data and done.
I will just show a demo snippet with a little explaination.
//get a graph pane
GraphPane masterPaneDefault = masterPane[0];
//style the title and axises
masterPaneDefault.Title.Text = m_selectedStation.Name;
masterPaneDefault.XAxis.Title.IsVisible = false;
masterPaneDefault.YAxis.Title.Text = m_selectedItemInfo.Name+'('+ m_selectedItemInfo.Unit +')';
//we are going to use line chart here
//use data to make a curve line
PointPairList theLine = new PointPairList();
foreach (DataRow dr in m_DataFound.Rows)
{
DateTime l_date = (DateTime)dr[0];
double x = (double)new XDate(l_date);
double y = 0;
if (!DBNull.Value.Equals(dr[1]))
{
y = (Single)dr[1];
theLine.Add(x, y);
}
}
//set angle of xaxis label
masterPaneDefault.XAxis.Scale.FontSpec.Angle = 45;
//add the line to our graph pane
LineItem theCurve = masterPaneDefault.AddCurve(m_selectedItemInfo.Name, theLine, Color.Red, SymbolType.XCross);
masterPaneDefault.XAxis.Type = AxisType.DateAsOrdinal;
masterPaneDefault.XAxis.Scale.Format = "yyyy/MM/dd HH:mm";
//smooth the curve
//theCurve.Line.IsSmooth = true;
// Make curves thicker
//theCurve.Line.Width = 3.0F;
// Add gridlines to the plot, and make them gray
masterPaneDefault.XAxis.MajorGrid.IsVisible = true;
masterPaneDefault.YAxis.MajorGrid.IsVisible = true;
masterPaneDefault.XAxis.MajorGrid.Color = Color.Gray;
masterPaneDefault.YAxis.MajorGrid.Color = Color.LightGray;
masterPaneDefault.XAxis.MinorGrid.IsVisible = true;
masterPaneDefault.XAxis.MinorGrid.Color = Color.Khaki;
// Move the legend location
masterPaneDefault.Legend.Position = LegendPos.Right;
// Add a background gradient fill to the axis frame
masterPaneDefault.Chart.Fill = new Fill(Color.White, Color.FromArgb(255, 255, 210), -45F);
masterPaneDefault.Fill = new Fill(Color.FromArgb(250, 250, 255));
//masterPaneDefault.XAxis.Scale.MajorStep = 2.5d;
masterPaneDefault.Legend.IsVisible = false;
//calculate the axis scale ranges
masterPaneDefault.AxisChange();
The result will look something like this.

That’s it. There are other great charting tools avaiable.
The MS Chart control and Flot are both great. Check them out if you like.
Customize ImageButton control with image hover/click, with any font style you want.
My first CodeProject article ^^
CodeProject is a place for programmer to share their experience and code. I’ve been there many times but this is the first time I publish an article there.
Keep it MVC. Use templated controls without injecting Eval() in your aspx.
I am quite stubborn in keeping .aspx clean, try to keep only asp and html tag in it.
Until recently I need to use ListView and bind my data to it, almost 90% of the example available are using <%# Eval(“[PropertyName]“) %>.
But I really don’t want to stuff my .aspx with these things, I don’t know if they are VBScript or ASP code, anyway, I want to do that in C# code.
I image that is possible to customize my binding just like I did in Java. After searching and reading articles for a few hours, I finally got it.
I want to share my experience here hoping to save someone a few hours. I will try to give sample code download if I can.
First step, drag a ListView control to your page. There are three things a ListView must have.
1.You must have a <LayoutTemplate> in your ListView.
2.You must have a <PlaceHolder> in your <LayoutTemplate>.
3.Set ItemPlaceholderId to your PlaceHolder Id.
I am using table to display my data. You will result in something that looks like this:
<asp:ListView ID="ltv_users" runat="server" ItemPlaceholderID="plh_userItems" onitemcommand="ltv_users_ItemCommand" ondatabinding="ltv_users_DataBinding" onitemdeleting="ltv_users_ItemDeleting"> <LayoutTemplate> <table class="ListViewTableStyle" border="1"> <thead class="ListViewHeaderStyle"> <tr> <td> </td> <td> Column Header 1 </td> <td> Column Header 2 </td> </tr> </thead> <tbody> <asp:PlaceHolder ID="plh_userItems" runat="server"></asp:PlaceHolder> </tbody> </table> </LayoutTemplate> </asp:ListView>
Second Step is to define your own customize Template to do data binding. Create a class which implement ITemplate interface under System.Web.UI namespace. People usually pass an enumerator to the constructor to indicate what type of template to create. The result looks like this.
public class UserTemplate : ITemplate
{
protected ListViewTemplateType m_templateType;
public UserTemplate(ListViewTemplateType type)
{
m_templateType = type;
}
}
ListViewTemplateType is just an enumerator one to one maps to template available inside ListView tag. Then we implement two methods, InstantiateIn(Control container) which response for creating html tags and data binding method. Here is an example for generating different tags for different template.
public void InstantiateIn(Control container)
{
//for itemtemplate and alternativeitemtemplate
LinkButton l_btnDetail = new LinkButton() { Text = m_DetailBtnText, ID = "btnDetail", CommandName = "Detail", CssClass = "ListViewButton" };
LinkButton l_btnRole = new LinkButton() { Text = m_RoleBtnText, ID = "btnRole", CommandName = "Role", CssClass = "ListViewButton" };
LinkButton l_btnDelete = new LinkButton() { Text = m_DeleteBtnText, ID = "btnDelete", CommandName = "Delete", CssClass = "ListViewButton" };
Label l_lblAccount = new Label() { ID = "lblAccount" };
Label l_lblUserName = new Label() { ID = "lblUserName" };
switch (m_templateType)
{
//ListViewItemType.
case ListViewTemplateType.ItemTemplate:
container.Controls.Add(new LiteralControl("<tr class=\"ListViewItemStyle\"><td>"));
container.Controls.Add(l_btnDetail);
container.Controls.Add(l_btnRole);
container.Controls.Add(l_btnDelete);
container.Controls.Add(new LiteralControl("</td><td>"));
container.Controls.Add(l_lblAccount);
container.Controls.Add(new LiteralControl("</td><td>"));
container.Controls.Add(l_lblUserName);
container.Controls.Add(new LiteralControl("</td></tr>"));
container.DataBinding += new EventHandler(ItemTemplate_DataBinding);
break;
case ListViewTemplateType.AlternatingItemTemplate:
container.Controls.Add(new LiteralControl("<tr class=\"ListViewAlternativeItemStyle\"><td>"));
container.Controls.Add(l_btnDetail);
container.Controls.Add(l_btnRole);
container.Controls.Add(l_btnDelete);
container.Controls.Add(new LiteralControl("</td><td>"));
container.Controls.Add(l_lblAccount);
container.Controls.Add(new LiteralControl("</td><td>"));
container.Controls.Add(l_lblUserName);
container.Controls.Add(new LiteralControl("</td></tr>"));
container.DataBinding += new EventHandler(ItemTemplate_DataBinding);
break;
}
}
We need to define controls id so that we can later bind data to them by their id in ItemTemplate_DataBinding().
public void ItemTemplate_DataBinding(object sender, EventArgs e)
{
ListViewDataItem listViewDataItem = (ListViewDataItem)sender;
string l_account = (string)DataBinder.Eval(listViewDataItem.DataItem, "Account");
string l_userName = (string)DataBinder.Eval(listViewDataItem.DataItem, "FirstName") + (string)DataBinder.Eval(listViewDataItem.DataItem, "LastName");
Guid l_userId = (Guid)DataBinder.Eval(listViewDataItem.DataItem, "Id");
switch (m_templateType)
{
case ListViewTemplateType.ItemTemplate:
case ListViewTemplateType.AlternatingItemTemplate:
((LinkButton)listViewDataItem.FindControl("btnDetail")).CommandArgument = l_userId.ToString();
((LinkButton)listViewDataItem.FindControl("btnRole")).CommandArgument = l_userId.ToString();
//((LinkButton)listViewDataItem.FindControl("btnDelete")).CommandArgument = l_userId.ToString();
LinkButton btnDelete = (LinkButton)listViewDataItem.FindControl("btnDelete");
btnDelete.CommandArgument = l_userId.ToString();
btnDelete.OnClientClick = m_ConfirmScript;
((Label)listViewDataItem.FindControl("lblAccount")).Text = l_account;
((Label)listViewDataItem.FindControl("lblUserName")).Text = l_userName;
break;
}
}
I am using a fall through here because ItemTemplate and AlternatingItemTemplate are binding data in the same way. You can bind textbox for ItemEditTemplate. I am going to show how to use this template class we make just now. How to work under asp page life cycle and use your own data source, and something about default ListView event handling. Read It Now!
Modify Web.Config Programmatically
The gives me a headache for couple of days, and I finally solve this puzzle which everyone else gets no trouble in doing it.
First of all, let me explain some background knowledge on web.config which is the reason why I got into trouble with.
There is a hierarchy on configuration, machine.config->web.config(root)->web.config(app)->web.config(sub)
the latter ones override the previous ones.
machine.config and web.config(root) can be found at
%WINDIR%\Microsoft.NET\Framework\[version]\CONFIG\
[version] is your .NET framework version.
Now, let’s start to dicuss how to modify web.config(app).
System.Configuration.Configuration l_webConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(m_webConfig, m_website, null, Server.MachineName, l_iisUserName, l_iisPassword);
AppSettingsSection l_appSetting = l_webConfig.AppSettings;
ConnectionStringsSection l_connSetting = l_webConfig.ConnectionStrings;+
//Get a setting from appSettings section
string l_appValue = l_appSetting.Settings["key"].value
//Get a connection string from connectionStringsSection
string l_connValue = l_connSetting.ConnectionStrings["ConnectionString"].ConnectionString
//Add a new appSetting
l_appSetting.Settings.Add("key","value")
//Add a new connection string
l_connSetting.ConnectionStrings.Add(new ConnectionStringSettings("name","value"))
//save it
l_webConfig.save(ConfigurationSaveMode.Minimal);
The first line open up a web.config, I am using one of its overload only.
The first parameter is the path where your application web.config locate, usually is “~”.
The second parameter is your website name, default value is “Default Web site”.
The third one is subLocationPath, I am not sure what this is. this might be for web.config(sub).
The fourth one is host name. 5th and 6th parameters is the server administrator account/password.
After modifying your configuration, save it back to the database.
There are three save mode which is self-explanatory.
I get two problems when trying to modify web.config.
The first one is, it will tells you that AllowLocation=false, can not modify web.config.
When this happens, set it to true in your machine.config.
Another one is, when you are not using account/password to open web.config.
If you are running in Visual Studio, it will use ASP.NET account to open it.
If you are running in IIS, it will use IIS account or NETWORK SERVICES account.
Make sure the account that your are using has the permission to modify web.config file.
Add Javascript to page OnLoad event
I used to add start up javascript to a page dynamically by assigning it to body tag OnLoad attribute. But this approach will get in trouble because it runs before all other web elements are rendered. Also it will need to set runat=”server”.
ASP.NET provide a better approach and I discover it just recently.
In your code-behind
Page.ClientScript.RegisterStartUpScript(this.GetType(), "functionName", "TheScript", true);
This function will put your script at the end of that page and run after the page is completely loaded.
Generate Image From Fonts
I have been asked to do this from time to time.
Because web browsers only support very few Chinese font style and designers thinks those fonts suck.
My method is a stupid one. Create a page and write out .png stream. Use this url as image url.
You can use an image file as its background or use a color as its background. I am using the generated image as an ImageButton’s image. The text is aligned to center.
How-To
1. Load the image file
Bitmap bgImg = new Bitmap([ImagePath]);
2. Load font file
PrivateFontCollection privateFontCollection = new PrivateFontCollection(); privateFontCollection.AddFontFile([font path]); FontFamily fontFamily = privateFontCollection.Families[0]; Font font = new Font(fontFamily, l_fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
3. Create a brush
//input is either aarrggbb or color name
if (l_htmlColor.Contains("ff"))
{
l_htmlColor = string.Format("{0:s}{1:s}", "#", l_htmlColor.Substring(2));
l_foreColor = ColorTranslator.FromHtml(l_htmlColor);
}
else
{
l_foreColor = Color.FromName(l_htmlColor);
} SolidBrush myBrush = new SolidBrush([forecolor]);
4. write text to image
Graphics myGraph = Graphics.FromImage(myImage);
myGraph.DrawString(text, font, myBrush, new Rectangle(0, 0, l_btnWidth, l_btnHeight), new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
Save the image to a memory stream and write it out.
That’s it. Please don’t use myXXX to name your variable as in my example. ^^
Treeview as navigation in masterpage with Web.sitemap datasource, which remember collapse state.
I have been struggling with this for a few days. Here is the situation.
I want to use masterpagefor style and layout consistency across pages. I want to use Web.sitemap for navigation because it is .NET feature and handy. Then the client wants to use Treeview for navigation which is fine, because Web.sitemap bind with treeview with one line of code.
Here comes the big question, the client said, why is the treeview collapse all without remembering what they click? Then I try a look like promising solution here on the internet. You can download sample and it works. But that sample is not using Web.sitemap. When you use Web.sitemap as treeview datasource, it binds to treeview each time you are redirected by clicking a tree node. This mechanism makes that solution fail. and I come up with the simplest solution, which is reading the Web.sitemap myself since it is just a xml and adding nodes in my code behind. This gives me even more control over the nodes, I can redirect to a new browser window or do hover image and so on. And also I can use it as an ordinary datasource when I need it to be.
There is only one small problem left. Web.sitemap must have one root node and you don’t want it to be shown most of the time. With SiteMapDataSource you can set ShowStartingNode to false. Now I have to skip this node when I add nodes to my treeview. Here is my crappy code. Put it in the masterpage Page_Load().
XmlDocument l_xmlDoc = new XmlDocument();
XmlTextReader l_xmlRdr = new XmlTextReader("./web.sitemap");
l_xmlRdr.Read();
l_xmlDoc.Load(l_xmlRdr);
XmlNode l_rootNode = null;
foreach (XmlNode node in l_xmlDoc.ChildNodes)
{
//find root node
if (node.Name.Equals("siteMap"))
{
l_rootNode = node;
l_rootNode = l_rootNode.ChildNodes[0];
}
}
//add node to treeview
foreach (XmlNode node in l_rootNode.ChildNodes)
{
TreeNode l_tn = null;
if (node.Attributes["target"] != null)
{
l_tn = new TreeNode(node.Attributes["title"].Value, node.Attributes["url"].Value, "", node.Attributes["url"].Value, node.Attributes["target"].Value);
}
else
{
l_tn = new TreeNode(node.Attributes["title"].Value, node.Attributes["url"].Value);
}
TreeViewMain.Nodes.Add(l_tn);
if (node.ChildNodes.Count > 0)
{
AddNodesToTreeView(node, l_tn);
}
}
Then here is my crappy recurrsive method
private void AddNodesToTreeView(XmlNode node, TreeNode treeNode)
{
//add node to treeview
foreach (XmlNode cnode in node.ChildNodes)
{
//has childnodes,recurrsivly add child, and itself tree
TreeNode l_tn = null;
if (cnode.Attributes["target"] != null)
{
l_tn = new TreeNode(cnode.Attributes["title"].Value, cnode.Attributes["url"].Value, "", cnode.Attributes["url"].Value, cnode.Attributes["target"].Value);
treeNode.ChildNodes.Add(l_tn);
}
else
{
l_tn = new TreeNode(cnode.Attributes["title"].Value, cnode.Attributes["url"].Value);
treeNode.ChildNodes.Add(l_tn);
}
if (cnode.ChildNodes.Count > 0)
{
AddNodesToTreeView(cnode, l_tn);
}
}
}
And then do everything else my reference link teach. I assume here every node in every level directs you to a page. You can use node without redirect by checking url attribute. and also you can turn off the hyperlink by setting treenode SelectionAction property to none.
I am finally done with Treeview navigation, thank god.