How to programatically set meta tags on ASP.Net page

by Viper 5. November 2009 06:19

When we are creating a web site, one of the main goal we all have is that out site should be listed on first page of search engines like Google, Bing, Yahoo, Baidu etc. As we all know that in SEO world, one of the first thing we all look for in the page is meta tags in header of the page. In the past there was no direct way to set the meta tags on a page programatically when developing ASP.Net web site. We all used the work around of adding metaelements in header element of the page. You can read my previous post Adding meta tags to asp.net page dynamically about that technique. With ASP.Net 4.0 microsoft has introduced following two properties on that allow you to set the meta tags on a page.

  • MetaDescription
  • MetaKeywords

Following code snippet shows how it is used in your code.


public partial class _Default : System.Web.UI.Page
{
 protected void Page_Load(object sender, EventArgs e)
 {
  SetMetaTags();
 }
 private void SetMetaTags()
 {
  Title = "Hello Meta";
  MetaDescription = "This is description of my ASP.Net 4.0 page.";
  MetaKeywords = "ASP.Net,.Net4.0,Meta";
 }
}

And it works. You can see from the source of the page as shown below.

<head>
<title>Hello Meta</title>
<meta name="description" content="This is description of my ASP.Net 4.0 page." />
<meta name="keywords" content="ASP.Net,.Net4.0,Meta" />
</head>

Views: 510

Tags:

.Net | ASP.Net

How to implement OWA style new message notifier poup using Silverlight and javascript

by Viper 6. October 2009 14:06
OWA style new message notification popup

Download Demo Projects

This is one of the projects I have been planning to work on for some time. I was looking into building an event notifier in one of my ASP.Net application. I wanted it to be more like Outlook Web Access (OWA) new email notifier pop-up. It is the one that slides up from bottom right corner of your browser when there is a new email in your inbox. I had built it in the past using all javascript solution. Yes, this Microsoft is one of the earliest implementation of so called AJAX applications. I did not want to deal with all the javascript code related to setting up HTTP calls and then dealing with response and rendering the results.

I wanted to leverage Silverlight to do all the heavy lifting. And use light weight javascript implementation on client to do animated sliding and positioning of the popup notifier box. At the end it turned out be quite an elegant solution that worked on major browsers like Internet Explorer, FireFox and Chrome. This article is an attempt to describe How to implement OWA style new email notifier popup using Silverlight and Javascript.

The implementation involved the following technologies and I will describe how each component was implemented

  • ASP.Net web application
  • ASP.Net web service
  • Silverlight application

ASP.Net Web Service

Let's start with discussion of the component that is responsible for communication of data between client and server application. The client requests data from server at certain frequency to check if there are any new messages. So I implemented as simple ASP.Net web service application with few web methods. For this demo I had a simple method with following signature.


[WebMethod]
public string GetGlobalMessages()
{
 List msgs = MockData.GetGlobalMessages();
 return msgs.ToJson();
}

For demo application, I implemented a MockData class that creates a random list of messages and then serializes that collection as JSON and sends it in response. I implemented ToJson as an extension method on List<StatusMessage> object. You will find it in Extension.cs file in ActivityData project.


public static string ToJson(this List<StatusMessage> msgs)
{
 var ser = new DataContractJsonSerializer(msgs.GetType());
 var ms = new MemoryStream();
 ser.WriteObject(ms, msgs);
 var serializedData = System.Text.UTF8Encoding.UTF8.GetString(ms.ToArray());
 return serializedData;
}

You can see there is nothing fancy about this whole implementation to make it work with a Silverlight client. A very simple ASP.Net web service.

Silverlight Application

This is where all the action happens. There are few components of this application, rendering and data access. Lets us first discuss data access. The client application is to talk to server at certain frequency. That means I need some kind of timer going in the application. When this timer ticks at specified interval of time, it send asynchronous request to server to get new messages. I have implemented this whole mechanism in MessageMonitor application. When this class is constructed, it creates an instance of DispatchTimer. You may be asking why DispatchTimer and why not simple Timer application. The problem is that when you are dealing with user interface application, you can only update the controls on the thread on which they were dispatched. Regular timer does not executes on that dispatcher thread. So if you will try to update your user interface on that thread you will get exception complaining about cross threaded access. Here is the code that created DispatcherTimer for my application.


private void CreateMessagePollTimer()
{
 _messagePollTimer = new DispatcherTimer();
 _messagePollTimer.Tick += new EventHandler(MessagePollTimer_Tick);
 _messagePollTimer.Interval = new TimeSpan(0, 0, MessagePollInterval);
}

When the timer ticks it calls MessagePollTimer_Tick method. And that method makes async request to server to get new messages.


void MessagePollTimer_Tick(object sender, EventArgs e)
{
 if (Stopping || MessagePollInProgress) return;
 GetMessages();
}

When async request to server completes, the following method gets called. You can see that now it uses the same JsonSerializer class to de-serialize the response into list of StatusMessage objects. And then it raises event for objects that have subscribed to the event.


void GetGlobalMessagesCompleted(object sender, 
  SiteMessagePanel.ActivityDataServices.GetGlobalMessagesCompletedEventArgs e)
{
if (e.Error != null)
{
 return;
}
 var msgsData = e.Result as String;
 var msgs = msgsData.FromJson();
 System.Diagnostics.Debug.WriteLine(msgs);
 StatusMessageEventArgs args = new StatusMessageEventArgs(msgs);
 OnStatusMessageReceieved(args);
}

Page class that implements user interface for popup, handles this event and renders all the messages.


void Monitor_StatusMessageReceieved(object sender, 
 ByteBlocks.ActivityData.StatusMessageEventArgs arg)
{
 if (arg.Messages.Count == 0)
 {
 msgTextBlock.Text = "No messages received";
 ShowClientPanel(false);
 return;
 }

 msgTextBlock.Text = string.Empty;
 messagesPanel.Children.Clear();
 foreach (var msg in arg.Messages)
 {
  StackPanel sp = new StackPanel();
  TextBlock tb = new TextBlock();
  tb.Text = msg.Title;
  tb.TextWrapping = TextWrapping.Wrap;
  sp.Children.Add(tb);
  messagesPanel.Children.Add(sp);
 }
 ShowClientPanel(true);
}

ASP.Net application and javascript

ASP.Net application acts as a host for the silverlight control that I created to render messages. I have implemented a simple Server Control that hosts it. Then I added that control inside a simple div on the master page. And I have very simple vanilla implementation of the server control. It does not have very complicated implementation. I simply copied the code generated by silverlight wizard for test page into that control


<div id="statusslideup">
<ByteBlocks:StatusPanel runat="server" id="statusPanel" />
</div>

Calling Javascript Method From Silverlight

So far we have implemented two pieces of the application that drive the data and render it. Now comes the fun part. How are we going to trigger the client to show the popup and animate it to come up from bottom. First, it is Silverlight application that is running the timer. So it is the one that has to trigger the client. I implemented some java script code that shows the DIV that hosts silverlight client component. And then small piece of code that implements animation. Silverlight framework provides a very simple mechanism to invoke any Javascript method that is implemented on client side. I implemented a very simple method in silvelight application to call my JS method whenever there are new messages for the user.


private void ShowClientPanel(bool show)
{
 HtmlPage.Window.Invoke("_showStatusPanel", show);
}

It could not be any simpler. And the following Javascript function implements small piece of code that calculates position of popup notifier window based on browser height and height of element containing silverlight control.


setStatusPanelPosition = function() {
 if (_statusdiv) {
 _maxPanelPos = document.body.scrollTop + ($(document).height() - _statusdiv.clientHeight);
 _curPanelPos = $(document).height();
 if (!_isStatusVisible) {
  _sliderInterval = setInterval("_slidePanel()", 5);
 }
 else {
  _statusdiv.style.top = _maxPanelPos + "px";
 }
 _isStatusVisible = true;
 }
}

Demo Project

Attached demo project is a collection of Visual Studio 2010 projects and solution. If you do not have VS2010, you can simply create a new solution and projects in VS2008 and copy the source files in there. You are also going to need to download Silverlight 3 Toolkit because I use theming controls from that toolkit to give some zing to the UI.

I hope this demo project helps you in building cooler implementations of OWA like message and event notifier windows.

Views: 2440

Tags: , ,

ASP.Net | Javascript | JQuery | Silverlight

Unable to start debugging on the web server - Error when starting ASP.Net debugging

by Viper 1. October 2009 13:59

Recently I installed Visual Studio 2010 and was working on a prototype User Activity Monitoring administration application. When I tried to launch the application in Visual Studio IDE, I got the following error message box.

---------------------------
Microsoft Visual Studio
---------------------------
Unable to start debugging on the web server. Debugging failed because integrated 
Windows authentication is not enabled. Please see Help for assistance.
---------------------------
OK   Help   
---------------------------

As the error suggests that I need to enable windows authentication. And that is a pre-requisites for running ASP.Net application under debugger. But thing that was different is that till Visual Studio 2008 when you made the IDE to create Virtual Directory, it used to enable windows authentication in IIS for that virtual directory. It seems that Visual Studio 2010 does things differently. It only enables anonymous access. You will have to explicitly enable windows authentication. It is simple procedure.

  • Launch IIS manager
  • Right click on virtual directory and select Properties menu option
  • Select Directory Security tab on the dialog box.
  • On this view click on Edit button in Anonymous access and authentication control section at top
  • On this dialog box, check the check box at the bottom in front of Integrated Windows Authentication option.
  • Click OK and apply your changes.

Views: 1084

Tags: ,

ASP.Net | IIS | Visual Studio

How to check for loopback IP address on Windows 7

by Viper 2. September 2009 06:02

Transition from Windows XP to Windows 7 has been raising new issues every day during development of desktop as well as web applications. Most of these are not issues per se. They are changes that were introduced during Windows Vista and are part of Windows 7 as well. This piece of information has to do with network protocols on Windows 7. Here is what happened. I am developing a web application. One of the things I had to do in the application is to check if the request URL is from localhost or loopback address then do something different otherwise follow normal routine. So I was comparing Request.UserHostAddress with standard loopback address of 127.0.0.1. It was working fine. Then I started an instance of IE and tried to test the page. Well, nothing seemed to work. When I debugged the code, I saw that value of Request.UserHostAddress was ::1 instead of 127.0.0.1. By looking at the IP address I could tell that it was standard IPv6 loop back IP address. Actually the loopback address on an IPv6 network is 0:0:0:0:0:0:0:1 which is abbreviated as ::1. Then I paid close attention to IPAddress class in .Net framework. There is a method IsLoopback that you can use to test for loopback address. And you will use Parse method to create instance of IPAddress object. After making these changes, my implementation looked as below.


private void GetUserFromIp()
{
 UserGeoLocator geoLocator = new UserGeoLocator();
 _userLocation = null;
 var ip = IPAddress.Parse(Request.UserHostAddress);
 if (IPAddress.IsLoopback(ip) ||
  string.Compare(Request.UserHostAddress, "127.0.0.1", 0) == 0)
 {
  _userLocation = geoLocator.GetUserLocationByIp("68.xxx.xxx.xxx");
 }
 else
 {
  _userLocation = geoLocator.GetUserLocationByIp(Request.UserHostAddress);
 }
}

IPv6 is enabled by default on Windows Vista as well as Windows 7. If you use Visual Studio Development Server to debug your application, you will notice that loopback address is in IPv4 format but if you use IIS to debug your ASP.Net application, the loopback address is in IPv6 format. To avoid any issues like this, using IsLoopback makes the implementation neutral to format because framework will take care of interpretting the IP address correctly when you use Parse to create instance of IPAddress object.

You can diable use of IPv6 on Windows 7 by following instructions in How to disable certain Internet Protocol version 6 (IPv6) components in Windows Vista, Windows 7 and Windows Server 2008. If you are not using any format specific implementation, then you do not have to do that and I would not suggest doing it if you are not comfortable dealing with changing registry entries.

Views: 921

Tags: ,

ASP.Net | Windows 7

ASP.Net version getting set to 4.0 in IIS manager

by Viper 6. August 2009 05:26

I have been working with VS2010 and ASP.Net 4.0 for quite some time now. Every time i create a web application, I just use the handy feature of Visual Studio of creating virtual directory for web application. Last week I was manually creating virtual directory for a web application using IIS manager. Since the application was targeting ASP.Net 2.0, so from ASP.Net tab of IIS, I selected V2.0 framework. Now there is a confirmation dialog box that comes up when you change ASP.Net framework.

Changing the Framework version requires a restart of the W3SVC service. Alternatively, you can change the Framework version without restarting the W3SVC service by running: aspnet_regiis.exe -norestart -s IIS-Viirtual-Path Do you want to continue (this will change the Framework version and restart the W3SVC service)?

Everything is good so far. Moment i accessed the application in browser, I got the following error message.

Server Error in '/Foo' Application.
The application domain or application pool is currently running version 4.0 or later of the .NET Framework. This can occur if IIS settings have been set to 4.0 or later for this Web application, or if you are using version 4.0 or later of the ASP.NET Web Development Server. The <compilation> element in the Web.config file for this Web application does not contain the required 'targetFrameworkMoniker' attribute for this version of the .NET Framework (for example, '<compilation targetFrameworkMoniker=".NETFramework,Version=v4.0">'). Update the Web.config file with this attribute, or configure the Web application to use a different version of the .NET Framework.

I was little surprised because I never configured virtual directory for this application to use ASP.Net 4.0. I fired up IIS manager and went to ASP.Net tab. There it was, the application was configured to use ASP.Net 4.0. So I changed it back to use ASP.Net 2.0. Accessed the application in browser and got the same error again. I experimented with the drop down box for ASP.Net version in IIS manager. The application will get configured to use ASP.Net 4.0 no matter what option I picked from the drop down box. It seems that this is some bug in beta version of Visual Studio 2010 installation.

For now the work around I have been using is to let Visual Studio create virtual directory for my web application. It targets the correct ASP.Net version and modifies IIS meta data correctly.

Views: 1831

Tags: , ,

ASP.Net | IIS

This operation requires IIS integrated pipeline mode - PlatformNotSupportedException

by Viper 22. July 2009 12:31

While experimenting with setting up of Cache-Control headers on Response object, i ran into following exception when I tries to access Headers property of Response object directly.


Exception type: PlatformNotSupportedException 
Exception message: This operation requires IIS integrated pipeline mode.

If i had read the documentation for Headers property I would have not done it at the first place. Here is what documentation says. The Headers property is only supported with the IIS 7.0 integrated pipeline mode and at least the .NET Framework 3.0. So if you are setting an headers in the response on IIS6 or earlier, use AddHeader method of Response object.

Views: 3161

Tags: ,

ASP.Net

How to set correct cache control headers for AJAX response

by Viper 22. July 2009 03:43

I have been developing AJAX enabled applications before the term AJAX was coined. I have been doing it for so long that some of things that I do come kind of naturally. And one of the things that I always do is to make sure that response is not cached to ensure that client is never working on stale response even though it sent new request every few seconds. So I have a small piece of code that I pretty much use in all applications that sets some headers.


Response.ContentType = "text/plain";
Response.Expires = -1;
Response.CacheControl = "no-cache";

These are not just the only headers but gives you an idea how cache was being control. I never ran into any trouble with any applications till last week when I was told that our application is filling up Temporary Internet Files folder of the users. This was the first time ever I was reported such issue and actually this was first time I observed this behavior in my applications. So I fired up Fiddler to see whats going on with my requests. I looked at the response headers and saw the following.

First, I was not expecting to see Cache-Control: private. So that was little out of whack. Second, the expiration time was correct because I always set to an hour behind the response time to make sure that it is stale for caching. I have been using the same caching utility routine for so long that I did not suspect that something is wrong there. Then I looked inside Temporary Internet Files folder again and noticed that this was the only request that was being saved in the folder, others were not. So I looked at the implementation and found that the server side implementation for this request was not using my standard utility to set cache headers. Following is the code snippet that I ad in place. Well why i changed the implementation for this particular call is whole different story.


Response.ContentType = "text/plain";
Response.Expires = -1;

Notice that it is missing Cache-control : no-cache header. That explained everything. After I added this header, everything went back to normal. So I decided to do some experiment to observe behavior of setting different headers.

No Cache-control: no-cache header on any call

You will notice that from my earlier post How to serialize multiple AJAX calls in jQuery, I have two AJAX calls being made. And you can see from snapshot above that both are being saved in Temporary Internet File folder.

Cache-control: no-cache header set on one request only

Now you can see that only one request is being saved in the folder and other has disappeared.

Cache-Control:no-cache header set on all requests

Well, there is nothing to show here in Temporary Internet Files folder because nothing is being saved there any more. But here is the snapshot of response headers as seen in Fiddler.

Now you can see that no-cache header and pragma has been set correctly.

Set cache-control header correctly

As more and more applications are using AJAX or Web2.0 style of implementations, if you do not set these cache control headers correctly, you will see that browser cache folders will accumulate lot of entries. It is not that big of a deal as far as application working goes because this temporary cache will not grow beyond specified limits for a particular browser. But it will hurt performance of other internet sites that you visit because their content will not be found in cache and will have to reloaded from server again. Other performance hit you will take is that now browser has to spend an extra CPU cycle to save these entries on the disk.

Views: 2207

Tags: , , , , ,

AJAX | ASP.Net | JQuery

How to use jQuery to make AJAX requests in ASP.Net?

by Viper 20. July 2009 15:06

Download Sample Project

For one of my current project, I have been using ASP.Net AJAX to make async request into my ASP.Net to get some time related data. First, I am not a big fab of ASP.Net AJAX implementation. I will not go into debate on why. There are plenty of discussions on this topic. I will just spare myself from it. Second, the application was already using jQuery for other javascript related implementation. I was like, if we are already using jQuery why have an overhead of introducing Ajax tool kit. So I started porting the implementation to use jQuery. Through this series of posts, I will describe how you can use jQuery to make AJAX calls in ASP.Net applications. Well, the client side javascript can be used in any browser. So other than the server side implementation, there is no nothing specific to ASP.Net per se.

The sample project for these articles is a time synchronization service. The idea is that I want to display clock on the client machine that will display server time. Well you can say there is no big deal with that implementation. On page load, get the server time. Save in some client side variable and run one second timer on it. Well, that works for most part. There are situations where clients are behind really slow connections that can cause of lot latency in request and response. So in those cases, by the time your response gets to the client side, the server time that you returned to client is already behind by few seconds. For applications that has users who depend very heavily on this server time, this latency of few seconds can be very critical. In this first post I am not going to go into details of algorithm that I implemented to reduce this latency adjustment over time. This first sample does a very simple task. It sends asynchronous request to server every 10 seconds. The server returns its time and then client uses that to display clock.

Server Side Implementation

I have a class ClockData that has DataContract attribute set on it. You can pretty much figure out that I am planning on converting this service to WCF service and use the framework facilities to serialize and de-serialize data as well. So I am populating this class with three pieces of data (server time, latency and a cookie) and then using DataContractJsonSerializer class to serialize the data into JSON format and sending it to client.


private void SerializeServerClockData(ClockData data, Stream strm)
{
 var spSer =
   new DataContractJsonSerializer(typeof(ClockData));
 spSer.WriteObject(strm, data);
}

void SendResponse()
{
 long ms = (long)(_serverTime - new DateTime(1970, 1, 1)).TotalMilliseconds;
 var clockData = new ClockData()
  {ServerTime = ms.ToString(), Latency = _latency, ResponseKey = Guid.NewGuid().ToString("N")};
 Response.ContentType = "text/plain";
 Response.Expires = -1;
 Response.CacheControl = "no-cache";
 SerializeServerClockData(clockData, Response.OutputStream);
 Response.End();
}

From the code snippet above, you can see how plain and simple server side implementation is for this first sample. This will get little complicated as I get more into the actual algorithm of calculation of latency reduction.

Client Side Implementation

Since we are going to be using jQuery to make Ajax call, so we will need to include reference to jQuery javascript file. For this sample, I am going to show the AJAX request you can send using jQuery. The library has method named .getJSON that you can call to send the request. You can set the URL where request is to be sent, set the parameters that needs to be passed with request and set the callback function that should be called when request completes. It is that simple. Here is the implementation from the sample.


function getServerTime() {
 cTime = firstRequest ? -1 : curTime.getTime();
 $.getJSON(clockServiceUrl, { clientTime: cTime, requestKey: respKey }, gotServerTime);
}

function gotServerTime(data) {
 firstRequest = false;
 latency = data.Latency;
 curTime = new Date(parseInt(data.ServerTime));
 if (!clockTicking) createClockTimer();
 createServiceTimer(defaultServiceTimer);
}

function clockTick() {
 clockTicking = true;
 curTime.setTime(curTime.getTime() + 1000);
 elClockDisplay.text(curTime.toString());
 if (latency == -1)
 { elLatencyDisplay.text(""); }
 else
 {elLatencyDisplay.text(latency + " ms");}
}

$(function() {
 elClockDisplay = $('#clockDisplay');
 elLatencyDisplay = $('#latencyDisplay');
 getServerTime();
});

In subsequent posts I will discuss how you can control the request little bit more instead of using .getJSON to use default settings.

Views: 606

Tags: , ,

.Net | ASP.Net | JQuery | AJAX

How to format GridView or DataGrid Using JQuery

by Viper 14. July 2009 14:12
datagrid using jquery

Download Sample Project

This is based on a question asked by one of my blog readers.

I have 2 datagrids. Each Grid has the same amount of columns and each grid has a select column as the last column on the right added from the "gridview/ edit Columns/ CommandField/ Add" sequence. The first GridView has the Select column as a Link The second GridView has the select Column as a button I want to be able to change the text for both the Link and button in cell(4), setting them to the value in cell(1) from the same row using the GridView_RowDataBound event. However, using "cell(4).text = cell(1).text" just overwrites the text value removing the hyperlink and button.

The behavior described in this question is as expected. When you set text of a cell in grid, it directly affects HTML that is going to be rendered. When you set text value of a cell, it means that you are setting innerText of the cell. The column that GridView creates for command fields (Edit, Delete and Select) are a (anchor) or button elements. So you can see what will happen if you set text value in that cell. It will wipe out those link or button controls and replace them with simple text string.

There are properties like EditText, DeleteText and SelectText for CommandField column in grid view. If you try to set these values using a server side method by passing it DataContainer object, you will get following exception thrown.


Databinding expressions are only supported on objects that have a DataBinding event. 
System.Web.UI.WebControls.CommandField does not have a DataBinding event.

After looking at the requirements, i realized that requirements are as simple as replacing text with value from another cell in the same row. There is no need for doing any server side tricks or things like that. I can simple put together a simple client side java script that will take values from cell 1 and put them in whatever cell I want. Abd I came up with this small javascript solution using jQuery. This small code snippet shows how you can manipulate GridView or DataGrid on client side using jQuery. Let me show you the client side javascript that I added on the page. Then I will explain what this code is doing.


<script type="text/javascript">
function updateCommandLinks() {
 var $gridTable = $('#productsGrid');
 var rows = $gridTable.find('tbody > tr');
 var slicedRows = rows.slice(1, rows.length - 2);
 slicedRows.each(function() {
  var cells = $(this).find('td');
  var cellElem1 = cells.get(1);
  var cellElem5 = cells.get(5);
  $(cellElem5).find('a').each(function() {
   $(this).addClass('commandlink').append(" " + cellElem1.innerText);
  });
 });
}

$(document).ready(function() {
  updateCommandLinks();
});
</script>

The above code may look little verbose considering you can write very concise code using jQuery. But for sale of explaining and debugging, I decided to make it little bit verbose. I am sure you can reduce it to half the lines of code that I have written.

The implementation adds a handler for document load event. In that event handler here are the steps it follows:

  1. Finds the element that has id of productsGrid. In our case, that is HTML element ID of our grid view.
  2. In the table, it gets collection of all the rows, identified by tr tag.
  3. Since in my implementation I have header and pager, that adds three rows into the collection. One top row for the header and then the last row itself will contain another table that contains a row for paging elements. To keep it simple, I decided to use slice function to remove first and last 2 rows from collection. You will need to modify this implementation depending on your grid rendering.
  4. It iterates over each row in the collection.
  5. For each row it then finds all cells, identified by td tag.
  6. In my case, I want to replace text in command links with text from second column. So I saved reference to cell at index 1 by using get function.
  7. Then I extracted all elements with tag a from sixth column.
  8. Then it iterates over collection of anchor a tags and appends text from second cell to text in each of the links.

I think that is a simple implementation that serves the purpose without making any changes on the server side. The attached project has the complete implementation for this grid. This is a Visual Studio 2010 project. But you should be able to copy the script from the page to your implementation.

Views: 694

Tags: , , ,

ASP.Net | DataGrid | GridView | JQuery

How to format and modify value in data grid row at run time based on previous row values

by Viper 7. July 2009 14:35
grid view row formatting

Download Sample Project

This was a question was asked by one of my site visitors, Mike. Following is the text of the question:

This is a similar question to one you have already answered in formatting Grid Views. However there are 2 main differences. First: I want to change the value of a column (not the format) in any row if the row preceding it has a certain value in the same column.

This question translates to How do you change value of a data grid column based on values of previous row(s). I generalized this question to cover all previous rows and not just the preceding row. Answer to all such questions relies on handling events like RowDataBound or RowCreated events. When a data grid or grid view renders, RowDataBound fires when row is being data bound and then RowCreated is fired after it has been data bound and row has been created. So depending on at what stage of rendering you want to change behavior of a row, you will subscribe either of these events. In the sample project, I am subscribing to RowDataBound event.

Next step is to access values from previous rows. Here you have choice. One, you can keep some local vaiable that stores values from previous row(s) and then use them in current row event handling. Two, you can access the previous GridRow based on index. In this sample i will discuss the approach of accessing previous row based on index and then extracting values from certain cells.

In RowDataBound event handler, GridViewRowEventArgs provides you access to DataItem associated with current row only. You do not have access to DataItem associated with previous rows. But at this point, previous rows have been prepared for rendering. You have access to all the cell values associated with previous row. You can access GridRow object of previous rows and extract text from cells that you are interested in. In the sample project, I am accessing ListPrice from fourth column and then displaying it in current row along with price associated with current row. Well, this does not sound like something that is very interesting or useful. But it serves the purpose of demonstrating you will accomplish the task.

Here is the code snippet from sample project.


protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
 if (e.Row.RowType == DataControlRowType.DataRow)
 {
  double price = -1.0;
  double prevPrice = -1.0 ;
  // Access the previous row.
  if (e.Row.RowIndex != 0)
  {
   GridViewRow prevRow = this.productsGrid.Rows[e.Row.RowIndex - 1];
   if (null != prevRow && 
    prevRow.RowType == DataControlRowType.DataRow)
   {
    double.TryParse(prevRow.Cells[3].Text, out prevPrice);
   }
  }
  var thisRowData = e.Row.DataItem as DataRowView;
  if (!Convert.IsDBNull(thisRowData["ListPrice"]))
  {
   double.TryParse(thisRowData["ListPrice"].ToString(), out price);
  }
  var ctrl = e.Row.FindControl("prevPriceLabel") as Label;
  if (null != ctrl)
  {
   ctrl.Text = string.Format("{0} - {1}", prevPrice, price);
  }
 }
}

The attached sample project is a VS2010 project. There is no VS2010 or .Net4.0 implementation in the project. So if you are using VS2008 or prior, you should be able to copy the implementation files into your own project.

Feel free to send me any request for any other grid view implementation you would like to be answered or implemented.

Views: 1084

Tags: , ,

.Net | ASP.Net | C# | DataGrid

How to insert google map in DataGrid or GridView

by Viper 2. July 2009 05:08

Download Sample Project

While working on a car dealership listings web site, I was experimenting with inserting google maps into the data grid. The grid will show name and address of top rated car dealers in certain categories. And along side their information, it will show their location on google map. To accomplish this task, I needed the longitude and latitude of car dealership's address or location. Some time back in my earlier post Convert Address and/or IP address to Geo Location I described how you can utilize google map's api to convert a physical address to geo location coordinates. This is the same technique that I used in Backyardtweets to show tweets in a specified location. So use the google map api to get these coordinates and insert these coordinates in the java script.

Now that you have geo location corresponding to an address, your task is to insert that little piece of java script in each row of the data grid. The way google map java script works is that it requires a HTML element where it can insert the map image. So I inserted a div with unique id in a cell in each row and then passed that unique id to java script that is used to render the map. Add an event handler for RowDataBound event and there you can add the element and register a client script for map as well. Here is some code snippet that shows how this all is accomplished.


protected void OnDealerRowDataBound(object sender, GridViewRowEventArgs e)
{
 if (e.Row.RowType == DataControlRowType.DataRow)
 {
	var carDealer = e.Row.DataItem as CarDealer;
	var divId = string.Format("dealloc_{0}", carDealer.Id);
	var mapPanel = e.Row.Cells[2].FindControl("mapPanel") as Panel;
	var div = new HtmlGenericControl("div");
	div.Attributes.Add("id", divId);
	div.Attributes.Add("class", "mapdiv");
	mapPanel.Controls.Add(div);
	string js = GetGoogleMapScript(carDealer, divId);
	ScriptManager.RegisterStartupScript
	  (this.Page, this.GetType(), "_map_" + carDealer.Id, js, true);
 }
}

private string GetGoogleMapScript(CarDealer dealer, string ctlId)
{
 string loc = string.Empty;
 if (!string.IsNullOrEmpty(dealer.State))
 {
	loc = string.Format("{0},", dealer.State);
 }
 loc += dealer.Country;
 decimal longitude, latitude;
 GoogleMapUtility.GetGeoLocationFromGoogle(loc, out longitude, out latitude);
 dealer.Location.Latitude = latitude;
 dealer.Location.Longitude = longitude;
 return GetJScriptForGeoLocations(longitude, latitude, ctlId);
}

public static string GetJScriptForGeoLocations(decimal longitude, decimal latitude, string elemId)
{
 StringBuilder sb = new StringBuilder();
 sb.Append("function initialize_" + elemId + "() {{");
 sb.Append(" if (GBrowserIsCompatible()) {{ ");
 sb.Append(" var map = new GMap2(document.getElementById(\"{0}\"));");
 sb.Append(" map.setCenter(new GLatLng({1}, {2}), 13);");
 sb.Append(" map.setUIToDefault();}}}} initialize_" + elemId + "();");
 return string.Format(sb.ToString(), elemId, latitude, longitude);
}

The attached project with this post has all the implementation for this sample implementation. And this is a Visual Studio 2010 project. I have not used any 2010 specific namespaces or code in this implementation so you should be able to take all the code and move it into a VS2008 or VS2005 project. And you will need to get key for google map api use from google as well.

Views: 4200

Tags: , ,

ASP.Net | DataGrid | GridView

Health Monitoring, Diagnostics, Logging and Instrumentation in ASP.Net

by Viper 18. May 2009 09:20

Troubleshooting, diagnostics and instrumentation is as big a part of the project is as the development of the application itself. Lot of time I have seen projects that do not account for these integral parts of the application development cycle. And when applications run into issue during production, then they do not any means to diagnose the problems quickly and come up with a solution with minimal downtime. In all the projects that I have lead, I put considerable effort in putting lot of diagnostics and health monitoring in place so that when ever there is error in the application we can identify the issue just by looking at log files.

In the past I have used frameworks like log4net and MS Instrumentation ans Logging Blocks to add logging and instrumentation capabilities to ASP.Net applications. Last week while I was researching on a new framework to add logging into an existing application I came across a less known healthMonitoring entry in web.config file of ASP.Net application. When I start digging deep into this I realized that ASP.Net framework already has a very flexible and robust mechanism built into it for logging and instrumentation. I realized that just by adding few entries in web.config file I can get the application to report all unhandled exceptions into a SQL server, Event log or WMI provider. And by writing a custom plugin I can get these to report to my custom repository. Long story short, you really don't need to use any third party plug ins or libraries to add logging capabilities to your ASP.Net applications. Just look at classes offered under System.Web.Management and healthMonitoring entry in web.config file of your ASP.Net applications and you will be able to find lot of information on how to add health monitoring capabilities like logging and instrumentation into your ASP.Net applications.

In next posts and articles I will describe how to use this ASP.Net feature to enable logging and instrumentation for your application and use different providers with it.

Views: 355

Tags: , ,

ASP.Net | Diagnostics

How to enable SQL server based session state for ASP.Net

by Viper 13. May 2009 08:03

For high performance web applications caching of data plays a significant part in improving performance. We all use session or application cache to store data in one form or the other. By default ASP.Net is configured to use InProc session storage mechanism. What this means is that all session data is stored in-memory on web server that is serving ASP.Net application. But when you are developing high availability web applications, you will find your self hosting your web application across web farms or web gardens in network load balanced systems. What this means is that user requests are served from multiple web servers. And load-balancer will pick the web server based on some internal load balancing algorithm. Unless you use stick IPs, you don't have control on what web server will be picked for next request. So if you are using InProc mechanism for session state management, you have a problem. Your session state is saved on one web server where as next request may be served from different server. So you end up loosing session state for that request. This is where you will need to use an external storage for storing session state that can be accessed across multiple servers.

ASP.Net framework provides mechanism to use SQLServer as an option that you can set in sessionState settings in your web application's configuration. Before you can start using sql server to store and server session state, you will need to set up some tables and means to store this data in SQL server. When you install ASP.Net framework on your server, Microsoft provides some SQL scripts along with an installer application that helps you in preparing your SQL Server for session state management.

If you look in WINDOWS\Microsoft.NET\Framework\{Version}, you will find an executable with name aspnet_regsql.exe. This is the same executable that you may have used to install membership and personalization database. If you supply specific command line parameters to this executable it will install required tables and database to manage session state. A very simple command to install session related database and tables can look like as below

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regsql.exe -ssadd -sstype p -E
Start adding session state.
....
Finished.
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>

You will find a new database named ASPState in your SQL server now. You can have more control on creation of this database by using appropriate command line options. Following is list of options that you can use.

-- SESSION STATE OPTIONS --

-ssadd                  Add support for SQLServer mode session state.

-ssremove               Remove support for SQLServer mode session state.

-sstype t|p|c           Type of session state support:

                        t: temporary. Session state data is stored in the "tempdb"
                        database. Stored procedures for managing session are installed in
                        the "ASPState" database. Data is not persisted if you restart
                        SQL. (Default)

                        p: persisted. Both session state data and the stored procedures
                        are stored in the "ASPState" database.

                        c: custom. Both session state data and the stored procedures are
                        stored in a custom database. The database name must be specified.

-d <database>     The name of the custom database to use if -sstype is "c".

Once you have created the database for session state management, modify web.config file of your application to start using SQLServer mode for session state management.

<sessionState 
    mode="SQLServer"
    sqlConnectionString="data source=127.0.0.1;
        user id=<username>;password=<strongpassword>"
    cookieless="false" 
    timeout="20" 
    />

Important step

After you uninstall SQL Server mode session state management configuration, you must restart the w3svc service. To restart the w3svc process, type net start w3svc at a command prompt.

Views: 351

Tags:

ASP.Net

How to add meta tags for a web page dynamically

by Viper 27. February 2009 20:51

If you are using some Content Management System (CMS) for your web site, then there is good chance that all your content along with meta tag content like Title, Description, Keywords etc. is stored in some data source and need to be added to the page dynamically. This all is doable from server side using HtmlMeta html server side control to Controls collection of Header of your page. You just need to add head element to your page and make sure that you have set runat=server for it and you are good to go. See the following snippet how it is done.


protected void Page_Load(object sender, EventArgs e)
{
 if (!IsPostBack)
 {
  this.Header.Title = "My Page Title";
  HtmlMeta meta = new HtmlMeta();
  meta.Content = "my description for this page";
  meta.Name = "description";
  this.Header.Controls.Add(meta);
 }
}

And on the page I have defined the mark up like this.


<head runat="server">
    <title></title>
</head>

Views: 623

Tags:

.Net | ASP.Net | SEO

How to bind a control on page to DataSource directly

by Viper 27. February 2009 19:50

A lot of time we have lot of controls on our ASP.Net page that are directly bound to data object for which page is being rendered. For example you may be implementing a page to display some details of a product. All the data that you want to display comes from a database record. You can directly bind all the information on the page directly with the data source using FormView on the page. If you don't intend to edit and update the data, you don't have to specify EditTemplate etc. You can simply have ItemTemplate for FormView and display data in read only format. Following snippet shows how this can be done.


<asp:FormView ID="FormView1" runat="server" CellPadding="4" 
	DataKeyNames="CategoryID" DataSourceID="SqlDataSource3" ForeColor="#333333">
	<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
	<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
	<ItemTemplate>
		CategoryID:
		<asp:Label ID="CategoryIDLabel" runat="server" 
			Text='<%# Eval("CategoryID") %>' />
		<br />
		CategoryName:
		<asp:Label ID="CategoryNameLabel" runat="server" 
			Text='<%# Bind("CategoryName") %>' />
		<br />
		Description:
		<asp:Label ID="DescriptionLabel" runat="server" 
			Text='<%# Bind("Description") %>' />
		<br />
 </ItemTemplate>
</asp:FormVi

If you have an image to display, you can add Image control inside template and bind ImageUrl property to one of the columns of the data source that contains url for your image.

Views: 528

Tags: ,

ASP.Net | FormView

Blogengine updated to use post and page titles different from Url to make it SEO friendly

by Viper 18. February 2009 05:54

Last week I added a new page to my blog site. The article was very popular and lot of people bookmarked it as well. After 3 days I realized that there is typo in the title that I need to fix. So I made the change. After few minutes of making the change I started getting flood of emails about broken link from the people who bookmarked that article. Then I realized that BlogEngine.net generated URLs for posts and pages based on Title field. So if you change the title of the item, your URL changes as well. Well there are following problems I see with this approach.

  • Biggest problem is that URL changes if title changes. That would mean that you will have keep track of where you have used this URL internally and externally and update them.
  • If i specify a very long title for my post or page, I will have a gigantic URL. This is not something that is recommended in best practices of URL creation.
  • Now to keep the URL to manageable length, I will have to come up with short titles that explain what the page or post is all about. Well, in some cases you want to have a title that is little bit more descriptive for SEO purposes

After thinking through this, I decided to make change in BlogEngine.net to include a new field named MetaTitle for pages and posts.

This new field allows you to enter a title that is different from what is used to create URL of that post or page. And when you want to update title of the item, you just need to update MetaTitle and never have to worry about URL change because you changed title. You can still change Title field, but it will result in a new URL for your page or post.

You can download the updated code from BlogEngine.Net Update 1.5.3. This update requires change in SQL Server tables. The updated script has been appended at the bottom of the page. I will post that update here as well. This update requires addition of new field MetaTitle in be_Pages and be_Posts tables.


/* Script for MetaTitle features */
ALTER TABLE [dbo].[be_Pages]
 ADD
 [MetaTitle] [nvarchar](255) NOT NULL DEFAULT (N'')
GO
 UPDATE [be_Pages]	SET [MetaTitle] = [Title]
GO
ALTER TABLE [dbo].[be_Posts]
 ADD
 [MetaTitle] [nvarchar](255) NOT NULL DEFAULT (N'')
GO
 UPDATE [be_Posts]	SET [MetaTitle] = [Title]
GO

Admin pages Add_Entry and Pages have also been updated to include new text box for MetaTitle field. And all the core code has been updated to account for new database field as well. If you have any feature that you would like implemented or modified, please feel free to contact me. I will be glad to work with you on the changes.


BlogEngine.Net Custom Updates

Views: 631

Tags: ,

ASP.Net | Blog Engine | SEO

New Widgets Added To BlogEngine

by Viper 8. February 2009 11:09

Based on the last update where I added ability to make pages in blogengine first class citizens, it became too much to list most viewed posts/pages, categories of posts and pages separately. They were taking too much vertical space in widget zone. So I decided to create new widgets that use tabbed views. See the following snapshots of most categories and recent items widgets.

These widgets are implemented using Yahoo User Interface (YUI) library. You don't have to worry about carrying these java script files on your server. You can just reference them directly from YUI site. You can add these references in master file of your theme. See site.master file in Blues theme to see how these references were added.

Following code package contains all the updates that were done to BlogEngine since last official code release from original site.

Download Latest BlogEngine (modified) Code (~2MB))

Views: 1343

Tags:

ASP.Net | Blog Engine | Social Networking

Adding Custom Social Link Sharing ASP.Net Control To BlogEngine

by Viper 5. February 2009 12:04

I got little tired of adding these social networking site post sharing links to my themes. And I saw that there were few web sites offering these ShareIt or AddIt buttons. Well, I decided to create my own custom control for it. Please see the following link for more details about the control and how to use it instructions. There is little piece of code that you will need to add to PostView to get to use title of your posts as well as URL. Notice that in following code, I have added a server side script that overrides RenderControl method to set LinkTitle and LinkUrl properties of ShareLink control. If you don't add this piece of code, the control will still work but it will pick up URL and title of page from client side. More details as present in the article.

Custom Link Sharing ASP.Net Control

<script runat="server">
public override void RenderControl(HtmlTextWriter writer)
{
socialShareLink.LinkUrl = Post.AbsoluteLink.AbsoluteUri;
socialShareLink.LinkTitle = Post.Title;
base.RenderControl(writer);
}
</script>

You can download PostView.ascx from the site and see how it is used. All other steps are same as described in article for the control.

Download PostView.ascx (1.60 kb)

Views: 2108

Tags: ,

ASP.Net | Blog Engine | Custom Controls | Social Networking

Blogengine updated to include lot of new features

by Viper 2. February 2009 19:39

I have updated BlogEngine.Net to include following new features.

  • Added ability to assign categories to pages
  • Added new widget PostCategoryList that lists pages by category.
  • Added display of pages by category very much like the way currently posts are displayed by category. The difference is that the page only displays the link to the pages and does not display any details related to the pages. You can click on those links to get to the pages.

You can see all these changes in action on this site itself. Look at bottom right of the page where Articles by Category widget is displayed. This is the new widget that I added with this update.


There were too many changes in the core and web application implementation that I did not see it practical to create a svn patch. Just to keep the whole implementation separate from what is available on BlongEngine site, I have created a fresh package with all the latest code from BlogEngine.Net repository and my changes and named it BlogEngine 1.5.1

I have added changes to SQL script in MSSQLUpgradeTo1.5.0.0From1.4.5.0.sql that is present in "setup/SqlServer" folder.

I will be making more changes to this package to include some more new features and post them here.


Download BlogEngine_1_5_1(1.55 mb)

Views: 6138

Tags:

ASP.Net | Blog Engine

Added Most Viewed Posts Widget In BlogEngine

by Viper 1. February 2009 09:08

Finally i got around to adding new widget to BlogEngine.Net to display most viewed posts. I also added a new field in the database to track views of pages as well. And in a day or two I will add new widget to display most viewed pages as well. Here is list of changes to the code.

  • Updated be_Pages SQL table to include new column Views and two new entries be_Settings table for most viewed posts and page count.
  • Updated BlogSettings.cs to include new properties NumberOfMostViewedPosts and NumberOfMostViewedPages
  • Updated Page.cs file in Data provider project to include new property Views
  • Updated DbBlogProvider.cs to update CRUD metods for Page to manipulate page views count
  • Added new folder MostViewedPosts that contains implementation of new widget.

How to use new widget

Unzip MostViewedPosts.zip file into Widgets folder. Run sql update script to add new field and values in tables. And then apply the code patches.

Following is list of files that you will need to download to add new widget to your existing installation.

SVN Code Patch [BlogEngine_MostViews.patch]

Widget Files [MostViewedPosts.zip (2.44 kb)]

SQL UPdate Script [Sqlupdate.sql (297.00 bytes)]

Views: 2470

Tags:

ASP.Net | Blog Engine

Powered by BlogEngine.NET 1.4.6.1
Theme by Naveen Kohli

Recent

By Categories