Blog to help every programmer to learn good stuff about programming and keep them updated with the latest trend that is happening in the IT industry
Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts
Saturday, November 12, 2011
Friday, September 02, 2011
"The resource cannot be found" error in ASP.NET MVC 3
This week I downloaded the latest version of NerdDinner source code from codeplex for ASP.MVC 3 architecture. Opening the solution and executing, I got "The resource cannot be found" exception. I was clueless as I just downloaded the latest source from the SVN and executed. Googling on it I learned that we can run into a problem when our requests are automatically redirected to a (possibly non-existent) login page.
To fix this, include the following lines in your web.config file:
For MVC 3 beta and MVC 3 RC1:
<appsettings> <add key="autoFormsAuthentication" value="false">
</add></appsettings>
For MVC 3 RC2:
<appsettings> <add
key="enableSimpleMembership" value="false"> </add></appsettings>
To fix this, include the following lines in your web.config file:
For MVC 3 beta and MVC 3 RC1:
<appsettings> <add key="autoFormsAuthentication" value="false">
</add></appsettings>
For MVC 3 RC2:
<appsettings> <add
key="enableSimpleMembership" value="false"> </add></appsettings>
Friday, August 26, 2011
Detecting Mobile Device and Redirecting
Project Description
This project, called "Foundation", is just one of 51Degrees.mobi components for mobile web development. Its provided as a .NET open source class library that detects mobile devices and browsers, enhancing the information available to .NET programmers. Accurate screen sizes, input methods, plus manufacturer and model information is all available. Mobile handsets can optionally be redirected to content designed for mobile devices. Smart phones, tablets and feature phones are all supported.Mobile Optimized Web Sites
Foundation detects the presence of a mobile device, and enables the web request to be directed to web pages designed for mobile. 51Degrees.mobi other products help ASP.NET developers rapidly create fast mobile web pages supporting tablet devices, high end handsets, and basic feature phones. Learn More & Free Trial.How does it work?
Http requests are intercepted by an additional HttpModule before the page handler starts to process the page. The first task of the module is to detect the device making the request and enhance the default properties provided by Microsoft. For example; the Request.Browser.ScreenPixelsWidth property will return the precise value for the mobile device. Finally the module determines if the request should be sent to a mobile home page and performs the redirection. The web.config file can be used to control how detection and redirection operate for your specific web site. For example; some sites may wish to redirect only the very first request to a mobile home page enabling the user to navigate to the traditional home page.To find out more try downloading our detection example web site or reading the operational summary.
Guides and DocumentationExample Projects
Get in Touch |
Friday, August 12, 2011
Creating and Using a CAPTCHA in ASP.NET MVC
A CAPTCHA is a challenge-response system wherein typically a dynamically generated image consisting of random letters and numbers is displayed to the users and the users are asked to re-enter the text in an attempt to verify that both of them match. Any ASP.NET developer would want to prevent spam and automated form submissions in the website being developed and that is where CAPTCHA is extremely useful. The primary purpose of CAPTCHA is to ensure that data is being submitted by humans and not by an automated software system. CAPTCHA is frequently used in user registration and contact forms to prevent spam and abuse of the facility. In this article you will learn how a simple CAPTCHA system can be developed in ASP.NET MVC.

Figure 1: The MVC framework includes several classes
In order to create a CAPTCHA system it is necessary that we emit a dynamically generated image with random text onto the response stream. To meet this requirement you will create a custom Action Result class. The new action result will inherit from ActionResult base class. To create a new action result, add a new class in the Models folder and name it CaptchaImageResult. The following listing shows the empty CaptchaImageResult class.
In the above example, you are using a simplistic approach of generating CAPTCHA images. You can also make use of certain techniques (distorting the characters or emitting two sets of characters for example) that make it even more difficult for the automated software programs to read them.
The ShowCaptchaImage() action method is used in the Index view as shown below:
tag is pointing to the ShowCaptchaImage action method. This way whenever the image is rendered it invokes the ShowCaptchaImage() method and a CAPTCHA image is outputted. The TextBox allows the user to enter the text as seen on the CAPTCHA.
The following figure shows the Index view in action:

Figure 2: The Index View
Basic Steps
Before you delve into further details create a new ASP.NET MVC 3 application with ASPX views. Once created add a new controller named Home into the Controllers folder. You will be adding the required action methods to the Home controller later.Creating a Custom Action Result
An action result indicates the response from an action method and is represented by System.Web.Mvc.ActionResult class. Though most of the action methods can use ActionResult class as their return value you can also create a custom action result class. In fact, the MVC framework includes several classes that inherit from the ActionResult base class. Many of them are shown in the following figure.Figure 1: The MVC framework includes several classes
In order to create a CAPTCHA system it is necessary that we emit a dynamically generated image with random text onto the response stream. To meet this requirement you will create a custom Action Result class. The new action result will inherit from ActionResult base class. To create a new action result, add a new class in the Models folder and name it CaptchaImageResult. The following listing shows the empty CaptchaImageResult class.
public class CaptchaImageResult:ActionResult
{
}
Generating Random Strings
The CaptchaImageResult class needs to display random string values consisting of letters and numbers. To generate such random strings you will need to create a method inside the CaptchaImageResult class that does the job for you. The GetCaptchaString() method as shown below is responsible for creating fixed length strings consisting of alpha-numeric values.public string GetCaptchaString(int length)
{
int intZero = '0';
int intNine = '9';
int intA = 'A';
int intZ = 'Z';
int intCount = 0;
int intRandomNumber = 0;
string strCaptchaString="";
Random random = new Random(System.DateTime.Now.Millisecond);
while (intCount < length)
{
intRandomNumber = random.Next(intZero, intZ);
if (((intRandomNumber >= intZero) && (intRandomNumber <= intNine) || (intRandomNumber >= intA) && (intRandomNumber <= intZ)))
{
strCaptchaString = strCaptchaString + (char)intRandomNumber;
intCount = intCount + 1;
}
}
return strCaptchaString;
}
As you can see, the GetCaptchaString() method accepts a single parameter - length - that indicates the length of the resultant CAPTCHA string. The four variables intZero, intNine, intA and intZ simply store ASCII values for numbers (0-9) and letters (A-Z). Note that we are using only upper case letters in the above logic. You can, of course, add lower case letters if required. Inside the while loop, Random class is used to generate random numbers between a range of 0-9 and A-Z. The random number obtained from the Random class is converted into a character value and stored in strCaptchaString variable. Finally, the complete CAPTCHA string is returned back.Outputting an Image Dynamically in the Response Stream
Generating a random string is just one part of the story. More important is to emit this random string as an image in the response stream. Emitting the random string as an image will make it difficult for automated software programs to read the CAPTCHA string from the HTML source. To generate an image dynamically, you need to override ExecuteResult() method of the ActionResult base class. The ExecuteResult() method is responsible for any custom processing that the child class wants to plug-in. The complete ExecuteResult() method is shown below:public override void ExecuteResult(ControllerContext context)
{
Bitmap bmp = new Bitmap(100, 30);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Navy);
string randomString = GetCaptchaString(6);
context.HttpContext.Session["captchastring"] = randomString;
g.DrawString(randomString, new Font("Courier", 16), new SolidBrush(Color.WhiteSmoke), 2, 2);
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = "image/jpeg";
bmp.Save(response.OutputStream,ImageFormat.Jpeg);
bmp.Dispose();
}
The ExecuteResult() method has one parameter - ControllerContext - that provides the context information in which the method is being called. For example, the HTTP response stream is accessed using the HttpContext provided by the ControllerContext parameter. The method first creates a Bitmap of size 100 X 30. It then washes it with a Navy background. A random CAPTCHA string with a length of 6 characters is generated by calling the GetCaptchaString() method. This random string is then stored in a Session variable so that you can compare the user input later. The DrawString() method of the Graphics object draws the random string onto the image. The image is then saved onto the response stream in JPEG format.In the above example, you are using a simplistic approach of generating CAPTCHA images. You can also make use of certain techniques (distorting the characters or emitting two sets of characters for example) that make it even more difficult for the automated software programs to read them.
Showing a CAPTCHA Image on a View
Next, you need to create an action method in the Home controller as shown below:public CaptchaImageResult ShowCaptchaImage()
{
return new CaptchaImageResult();
}
The ShowCaptchaImage() method simply returns a new instance of CaptchaImageResult class you created earlier. Note that the MVC framework takes care of calling the ExecuteResult() overridden method for you.The ShowCaptchaImage() action method is used in the Index view as shown below:
As you can see, the above markup creates an HTML form. Notice how the src attribute of theCaptcha in ASP.NET MVC
<% using (Html.BeginForm("index", "home")) { %>Please enter the string as shown above: <%= Html.TextBox("CaptchaText")%> <% } %> <%= ViewBag.Message %>
The following figure shows the Index view in action:
Figure 2: The Index View
Verifying the CAPTCHA Value
Before you run the Index view, you need to add Index() action methods as shown below:public ActionResult Index()
{
ViewBag.Message = "A fresh CAPTCHA image is being displayed!";
return View();
}
[HttpPost]
public ActionResult Index(string CaptchaText)
{
if (CaptchaText == HttpContext.Session["captchastring"].ToString())
ViewBag.Message = "CAPTCHA verification successful!";
else
ViewBag.Message = "CAPTCHA verification failed!";
return View();
}
The first Index() action method takes care of GET requests whereas the second one takes care of POST requests (as indicated by [HttpPost] attribute). The first Index() method simply puts a Message in the ViewBag and shows the Index view (Figure 2). When the user enters the CAPTCHA value in the TextBox and submits the form, the second Index() action method compares the submitted value with the value stored in the Session earlier (recollect that ExecuteResult() method stores the CAPTCHA text in a session variable). Depending on the outcome of the comparison either a success or failure message is displayed in the view.Summary
A CAPTCHA is a challenge-response system frequently used to keep away spammers and automated software programs from web pages accepting data from the end users. Common examples of such pages include user registration forms and contact forms. In order to create your own CAPTCHA system in ASP.NET MVC you create a custom ActionResult class that generates a random string value and then emits it as an image on the response stream. You can add more features to the CAPTCHA you developed in this article to make it more difficult for automated software programs to read the CAPTCHA text.Tuesday, August 02, 2011
WebGrid in ASP.NET MVC
Earlier this year Microsoft released ASP.NET MVC version 3 (asp.net/mvc), as well as a new product called WebMatrix (asp.net/webmatrix). The WebMatrix release included a number of productivity helpers to simplify tasks such as rendering charts and tabular data. One of these helpers, WebGrid, lets you render tabular data in a very simple manner with support for custom formatting of columns, paging, sorting and asynchronous updates via AJAX.
In this article, I’ll introduce WebGrid and show how it can be used in ASP.NET MVC 3, then take a look at how to really get the most out of it in an ASP.NET MVC solution. (For an overview of WebMatrix—and the Razor syntax that will be used in this article—see Clark Sell’s article, “Introduction to WebMatrix,” in the April 2011 issue at msdn.microsoft.com/magazine/gg983489).
This article looks at how to fit the WebGrid component into an ASP.NET MVC environment to enable you to be productive when rendering tabular data. I’ll be focusing on WebGrid from an ASP.NET MVC aspect: creating a strongly typed version of WebGrid with full IntelliSense, hooking into the WebGrid support for server-side paging and adding AJAX functionality that degrades gracefully when scripting is disabled. The working samples build on top of a service that provides access to the AdventureWorksLT database via the Entity Framework. If you’re interested in the data-access code, it’s available in the code download, and you might also want to check out Julie Lerman’s article, “Server-Side Paging with the Entity Framework and ASP.NET MVC 3,” in the March 2011 issue (msdn.microsoft.com/magazine/gg650669).
to the view. I’m using the Razor view engine for most of this article, but later I’ll also discuss how the WebForms view engine can be used. My ProductController class has the following action:
The List view includes the following Razor code, which renders the grid shown in Figure 1:
In this article, I’ll introduce WebGrid and show how it can be used in ASP.NET MVC 3, then take a look at how to really get the most out of it in an ASP.NET MVC solution. (For an overview of WebMatrix—and the Razor syntax that will be used in this article—see Clark Sell’s article, “Introduction to WebMatrix,” in the April 2011 issue at msdn.microsoft.com/magazine/gg983489).
This article looks at how to fit the WebGrid component into an ASP.NET MVC environment to enable you to be productive when rendering tabular data. I’ll be focusing on WebGrid from an ASP.NET MVC aspect: creating a strongly typed version of WebGrid with full IntelliSense, hooking into the WebGrid support for server-side paging and adding AJAX functionality that degrades gracefully when scripting is disabled. The working samples build on top of a service that provides access to the AdventureWorksLT database via the Entity Framework. If you’re interested in the data-access code, it’s available in the code download, and you might also want to check out Julie Lerman’s article, “Server-Side Paging with the Entity Framework and ASP.NET MVC 3,” in the March 2011 issue (msdn.microsoft.com/magazine/gg650669).
Getting Started with WebGrid
To show a simple example of WebGrid, I’ve set up an ASP.NET MVC action that simply passes an IEnumerable
- public ActionResult List()
- {
- IEnumerable
model = - _productService.GetProducts();
- return View(model);
- }
- @model IEnumerable
< span="">.Domain.Product> - @{
- ViewBag.Title = "Basic Web Grid";
- }
< span="">>Basic Web Grid
< span="">>- @{
- var grid = new WebGrid(Model, defaultSort:"Name");
- }
- @grid.GetHtml()
(click to zoom)
Figure 1 A Basic Rendered Web Grid
The first line of the view specifies the model type (for example, the type of the Model property that we access in the view) to be IEnumerable
This small amount of code provides rich grid functionality. The grid limits the amount of data displayed and includes pager links to move through the data; column headings are rendered as links to enable paging. You can specify a number of options in the WebGrid constructor and the GetHtml method in order to customize this behavior. The options let you disable paging and sorting, change the number of rows per page, change the text in the pager links and much more. Figure 2 shows the WebGrid constructor parameters and Figure 3 the GetHtml parameters.
Figure 2 WebGrid Constructor Parameters
| Name | Type | Notes |
| source | IEnumerable | The data to render. |
| columnNames | IEnumerable | Filters the columns that are rendered. |
| defaultSort | string | Specifies the default column to sort by. |
| rowsPerPage | int | Controls how many rows are rendered per page (default is 10). |
| canPage | bool | Enables or disables paging of data. |
| canSort | bool | Enables or disables sorting of data. |
| ajaxUpdateContainerId | string | The ID of the grid’s containing element, which enables AJAX support. |
| ajaxUpdateCallback | string | The client-side function to call when the AJAX update is complete. |
| fieldNamePrefix | string | Prefix for query string fields to support multiple grids. |
| pageFieldName | string | Query string field name for page number. |
| selectionFieldName | string | Query string field name for selected row number. |
| sortFieldName | string | Query string field name for sort column. |
| sortDirectionFieldName | string | Query string field name for sort direction. |
Figure 3 WebGrid.GetHtml Parameters
| Name | Type | Notes |
| tableStyle | string | Table class for styling. |
| headerStyle | string | Header row class for styling. |
| footerStyle | string | Footer row class for styling. |
| rowStyle | string | Row class for styling (odd rows only). |
| alternatingRowStyle | string | Row class for styling (even rows only). |
| selectedRowStyle | string | Selected row class for styling. |
| caption | string | The string displayed as the table caption. |
| displayHeader | bool | Indicates whether the header row should be displayed. |
| fillEmptyRows | bool | Indicates whether the table can add empty rows to ensure the rowsPerPage row count. |
| emptyRowCellValue | string | Value used to populate empty rows; only used when fillEmptyRows is set. |
| columns | IEnumerable | Column model for customizing column rendering. |
| exclusions | IEnumerable | Columns to exclude when auto-populating columns. |
| mode | WebGridPagerModes | Modes for pager rendering (default is NextPrevious and Numeric). |
| firstText | string | Text for a link to the first page. |
| previousText | string | Text for a link to the previous page. |
| nextText | string | Text for a link to the next page. |
| lastText | string | Text for a link to the last page. |
| numericLinksCount | int | Number of numeric links to display (default is 5). |
| htmlAttributes | object | Contains the HTML attributes to set for the element. |
The previous Razor code will render all of the properties for each row, but you may want to limit which columns are displayed. There are a number of ways to achieve this. The first (and simplest) is to pass the set of columns to the WebGrid constructor. For example, this code renders just the Name and ListPrice properties:
- var grid = new WebGrid(Model, columnNames: new[] {"Name", "ListPrice"});
- @grid.GetHtml(columns: grid.Columns(
- grid.Column("Name"),
- grid.Column("ListPrice", header:"List Price")
- )
- )
- @grid.GetHtml(columns: grid.Columns(
- grid.Column("Name", format: @
@Html.ActionLink((string)item.Name, - "Details", "Product", new {id=item.ProductId}, null)),
- grid.Column("ListPrice", header:"List Price",
- format: @
@item.ListPrice.ToString("0.00") )- )
- )
Figure 4 A Basic Grid with Custom Columns
Although it looks like there’s some magic going on when I specify the format, the format parameter is actually a Func
Because the item parameter is a dynamic type, you don’t get any IntelliSense or compiler checking when writing your code (see Alexandra Rusina’s article on dynamic types in the February 2011 issue at msdn.microsoft.com/magazine/gg598922). Moreover, invoking extension methods with dynamic parameters isn’t supported. This means that, when calling extension methods, you have to ensure that you’re using static types—this is the reason that item.Name is cast to a string when I call the Html.ActionLink extension method in the previous code. With the range of extension methods used in ASP.NET MVC, this clash between dynamic and extension methods can become tedious (even more so if you use something like T4MVC: bit.ly/9GMoup).
Adding Strong Typing
While dynamic typing is probably a good fit for WebMatrix, there are benefits to strongly typed views. One way to achieve this is to create a derived type WebGridFigure 5 Creating a Derived WebGrid
- public class WebGrid
: WebGrid - {
- public WebGrid(
- IEnumerable
source = null, - ... parameter list omitted for brevity)
- : base(
- source.SafeCast<object>(),
- ... parameter list omitted for brevity)
- { }
- public WebGridColumn Column(
- string columnName = null,
- string header = null,
- Func
, object> format = null, ,- string style = null,
- bool canSort = true)
- {
- Func
, object> wrappedFormat = null; ,- if (format != null)
- {
- wrappedFormat = o => format((T)o.Value);
- }
- WebGridColumn column = base.Column(
- columnName, header,
- wrappedFormat, style, canSort);
- return column;
- }
- public WebGrid
Bind( - IEnumerable
source, - IEnumerable<string> columnNames = null,
- bool autoSortAndPage = true,
- int rowCount = -1)
- {
- base.Bind(
- source.SafeCast<object>(),
- columnNames,
- autoSortAndPage,
- rowCount);
- return this;
- }
- }
- public static class WebGridExtensions
- {
- public static WebGrid
Grid ( - this HtmlHelper htmlHelper,
- ... parameter list omitted for brevity)
- {
- return new WebGrid
( - source,
- ... parameter list omitted for brevity);
- }
- }
The Grid extension method allows you to take advantage of the compiler’s type inference for generic parameters. So, in this example, you can write Html.Grid(Model) rather than new WebGrid
Adding Paging and Sorting
You’ve already seen that WebGrid gives you paging and sorting functionality without any effort on your part. You’ve also seen how to configure the page size via the rowsPerPage parameter (in the constructor or via the Html.Grid helper) so that the grid will automatically show a single page of data and render the paging controls to allow navigation between pages. However, the default behavior may not be quite what you want. To illustrate this, I’ve added code to render the number of items in the data source after the grid is rendered, as shown in Figure 6.Figure 6 The Number of Items in the Data Source
As you can see, the data we’re passing contains the full list of products (295 of them in this example, but it’s not hard to imagine scenarios with even more data being retrieved). As the amount of data returned increases, you place more and more load on your services and databases, while still rendering the same single page of data. But there’s a better approach: server-side paging. In this case, you pull back only the data needed to display the current page (for instance, only five rows).
The first step in implementing server-side paging for WebGrid is to limit the data retrieved from the data source. To do this, you need to know which page is being requested so you can retrieve the correct page of data. When WebGrid renders the paging links, it reuses the page URL and attaches a query string parameter with the page number, such as http://localhost:27617/Product/DefaultPagingAndSorting?page=3 (the query string parameter name is configurable via the helper parameters—handy if you want to support pagination of more than one grid on a page). This means you can take a parameter called page on your action method and it will be populated with the query string value.
If you just modify the existing code to pass a single page worth of data to WebGrid, WebGrid will see only a single page of data. Because it has no knowledge that there are more pages, it will no longer render the pager controls. Fortunately, WebGrid has another method, named Bind, that you can use to specify the data. As well as accepting the data, Bind has a parameter that takes the total row count, allowing it to calculate the number of pages. In order to use this method, the List action needs to be updated to retrieve the extra information to pass to the view, as shown in Figure 7.
Figure 7 Updating the List Action
- public ActionResult List(int page = 1)
- {
- const int pageSize = 5;
- int totalRecords;
- IEnumerable
products = productService.GetProducts( - out totalRecords, pageSize:pageSize, pageIndex:page-1);
- PagedProductsModel model = new PagedProductsModel
- {
- PageSize= pageSize,
- PageNumber = page,
- Products = products,
- TotalRows = totalRecords
- };
- return View(model);
- }
< span="">>- @{
- var grid = new WebGrid
< span="">>(null, rowsPerPage: Model.PageSize, - defaultSort:"Name");
- grid.Bind(Model.Products, rowCount: Model.TotalRows, autoSortAndPage: false);
- }
- @grid.GetHtml(columns: grid.Columns(
- grid.Column("Name", format: @
< span="">>@Html.ActionLink(item.Name, - "Details", "Product", new { id = item.ProductId }, null)),
- grid.Column("ListPrice", header: "List Price",
- format: @
< span="">>@item.ListPrice.ToString("0.00")) - )
- )
Figure 8 Adding Sorting Parameters to the Action Method
- public ActionResult List(
- int page = 1,
- string sort = "Name",
- string sortDir = "Ascending" )
- {
- const int pageSize = 5;
- int totalRecords;
- IEnumerable
products = - _productService.GetProducts(out totalRecords,
- pageSize: pageSize,
- pageIndex: page - 1,
- sort:sort,
- sortOrder:GetSortDirection(sortDir)
- );
- PagedProductsModel model = new PagedProductsModel
- {
- PageSize = pageSize,
- PageNumber = page,
- Products = products,
- TotalRows = totalRecords
- };
- return View(model);
- }
AJAX: Client-Side Changes
WebGrid supports asynchronously updating the grid content using AJAX. To take advantage of this, you just have to ensure the div that contains the grid has an id, and then pass this id in the ajaxUpdateContainerId parameter to the grid’s constructor. You also need a reference to jQuery, but that’s already included in the layout view. When the ajaxUpdateContainerId is specified, WebGrid modifies its behavior so that the links for paging and sorting use AJAX for the updates:
< span=""> id="grid">- @{
- var grid = new WebGrid
< span="">>(null, rowsPerPage: Model.PageSize, - defaultSort: "Name", ajaxUpdateContainerId: "grid");
- grid.Bind(Model.Products, autoSortAndPage: false, rowCount: Model.TotalRows);
- }
- @grid.GetHtml(columns: grid.Columns(
- grid.Column("Name", format: @
< span="">>@Html.ActionLink(item.Name, - "Details", "Product", new { id = item.ProductId }, null)),
- grid.Column("ListPrice", header: "List Price",
- format: @
< span="">>@item.ListPrice.ToString("0.00")) - )
- )
I’m always keen to create pages that degrade gracefully when scripting is disabled, and generally find that the best way to achieve this is through progressive enhancement (basically having a page that functions without scripting that’s enriched with the addition of scripting). To achieve this, you can revert back to the non-AJAX WebGrid and create the script in Figure 9 to reapply the AJAX behavior:
Figure 9 Reapplying the AJAX Behavior
- $(document).ready(function () {
- function updateGrid(e) {
- e.preventDefault();
- var url = $(this).attr('href');
- var grid = $(this).parents('.ajaxGrid');
- var id = grid.attr('id');
- grid.load(url + ' #' + id);
- };
- $('.ajaxGrid table thead tr a').live('click', updateGrid);
- $('.ajaxGrid table tfoot tr a').live('click', updateGrid);
- });
The updateGrid method is set as the event handler and the first thing it does is to call preventDefault to suppress the default behavior. After that it gets the URL to use (from the href attribute on the anchor tag) and then makes an AJAX call to load the updated content into the container element. To use this approach, ensure that the default WebGrid AJAX behavior is disabled, add the ajaxGrid class to the container div and then include the script from Figure 9.
AJAX: Server-Side Changes
One additional point to call out is that the script uses functionality in the jQuery load method to isolate a fragment from the returned document. Simply calling load(‘http://example.com/someurl’) will load the contents of the URL. However, load(‘http://example.com/someurl #someId’) will load the content from the specified URL and then return the fragment with the id of “someId.” This mirrors the default AJAX behavior of WebGrid and means that you don’t have to update your server code to add partial rendering behavior; WebGrid will load the full page and then strip out the new grid from it.In terms of quickly getting AJAX functionality this is great, but it means you’re sending more data over the wire than is necessary, and potentially looking up more data on the server than you need to as well. Fortunately, ASP.NET MVC makes dealing with this pretty simple. The basic idea is to extract the rendering that you want to share in the AJAX and non-AJAX requests into a partial view. The List action in the controller can then either render just the partial view for AJAX calls or the full view (which in turn uses the partial view) for the non-AJAX calls.
The approach can be as simple as testing the result of the Request.IsAjaxRequest extension method from inside your action method. This can work well if there are only very minor differences between the AJAX and non-AJAX code paths. However, often there are more significant differences (for example, the full rendering requires more data than the partial rendering). In this scenario you’d probably write an AjaxAttribute so you could write separate methods and then have the MVC framework pick the right method based on whether the request is an AJAX request (in the same way that the HttpGet and HttpPost attributes work). For an example of this, see my blog post at bit.ly/eMlIxU.
WebGrid and the WebForms View Engine
So far, all of the examples outlined have used the Razor view engine. In the simplest case, you don’t need to change anything to use WebGrid with the WebForms view engine (aside from differences in view engine syntax). In the preceding examples, I showed how you can customize the rendering of row data using the format parameter:
- grid.Column("Name",
- format: @
@Html.ActionLink((string)item.Name, - "Details", "Product", new { id = item.ProductId }, null)),
- grid.Column("Name",
- format: item => Html.ActionLink((string)item.Name,
- "Details", "Product", new { id = item.ProductId }, null)),
Wrapping Up
In this article I showed how a few simple tweaks let you take advantage of the functionality that WebGrid brings without sacrificing strong typing, IntelliSense or efficient server-side paging. WebGrid has some great functionality to help make you productive when you need to render tabular data. I hope this article gave you a feel for how to make the most of it in an ASP.NET MVC application.Ref: http://msdn.microsoft.com/en-us/magazine/hh288075.aspx
Subscribe to:
Posts (Atom)