ASP.Net MVC Release Candidate is Available
Scott Guthrie has just announced that the ASP.NET MVC 1.0 Release Candidate is out.
Few of the highlights of this release:
Visual Studio Tooling Improvements
- Add Controller Command
- Add View Command
- Adding and Customizing Scaffold Templates
- Go To Controller / Go To View
- MSBuild Task for Compiling Views
- View Refactoring Support
View Improvements
- Views without Code-Behind Files
- Model Property
- Setting the Title
- Strongly Typed HTML/AJAX Helpers
Form Post Improvements
- [Bind(Prefix=””)] No Longer Required for Common Scenarios
- ModelBinder API Improvements
- IDataErrorInfo Support
Unit Testing Improvements
- ControllerContext changed to no longer derive from RequestContext
- AccountsController Unit Tests
- Cross Site Request Forgery (CSRF) Protection
File Handling Improvements
- FileResult and File() helper method
- File Uploading Support
AJAX Improvements
- jQuery Intellisense Files included within ASP.NET MVC Project Template
- Request.IsAjaxRequest Property
- JavaScriptResult ActionResult and JavaScript() helper method
Download the ASP.Net MVC Release Candidate.
Enjoy!
ASP.Net MVC RSS Feed Action Result
ASP.Net MVC Controller Actions usually returns an object that inherits from the ActionResult class.
public abstract class ActionResult
{
public abstract void ExecuteResult(ControllerContext context);
}
ASP.Net MVC ships with several Action Results:
- ContentResult – Simply writes the returned data to the response.
- EmptyResult – Returns an empty response.
- HttpUnauthorizedResult – Returns Http 401 code for non authorized access.
- JsonResult – Serializes the response to Json.
- RedirectResult – Redirects to another Url.
- RedirectToRouteResult – Redirects to another controller action.
- ViewResultBase (abstract) – Renders an HTML content as a result.
- PartialViewResult (inherits from ViewResultBase) – Renders a partial HTML response.
- BinaryResult (abstract) – Returns a binary response.
- BinaryStreamResult (inherits from BinaryResult) – Writes a binary stream as a result.
If you want to return a RSS Feed as a result, here is what you should do.
Create an Object Model for the RSS Feed
In this samples I created an object model from scratch, but one should use an existing object model from his site.
public class Feed
{
public Feed() { Items = new List<FeedItem>(); }
public string Title { get; set; }
public string Description { get; set; }
public string Url { get; set; }
public string Language { get; set; }
public List<FeedItem> Items { get; set; }
}
public class FeedItem
{
public FeedItem() { Tags = new List<string>(); }
public string Creator { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Url { get; set; }
public DateTime Published { get; set; }
public List<string> Tags { get; set; }
}
With the above object model, a simple test data can be created with the following method:
private Feed GetFeedData()
{
Feed feed = new Feed {
Title = "Guy Burstein's Blog",
Description = "Description of Guy Burstein's Blog",
Language = "en",
Url = "blog.bursteg.net",
Items = {
new FeedItem {
Title = "Post 1",
Creator = "Guy Burstein",
Description = "Body of post 1",
Url = "blogs.bursteg.net/archive/1",
Published = DateTime.Now,
Tags = { "Tag1", "Tag2", "Tag3" }
},
new FeedItem {
Title = "Post 2",
Creator = "Guy Burstein",
Description = "Body of post 2",
Url = "blogs.bursteg.net/archive/2",
Published = DateTime.Now - new TimeSpan(1, 0, 0),
Tags = { "Tag2", "Tag4" }
}
}
};
return feed;
}
Create the RSS Feed Template View
Since the output RSS Feed has its format, we can use the existing View engine to render it. Instead of rendering an HTML, this view will render the RSS feed.
Create a new view called Rss.aspx under the Views\Shared folder. Next, in order to make this view worked with strongly typed model, go to the code-behind file (Rss.Aspx.cs) and let the view inherit from ViewPage<T> where T is the above Feed class.
public partial class Rss : ViewPage<Feed>
{
}
Now, edit the view’s markup and create the template of the RSS Feed, like the following:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Rss.aspx.cs" Inherits="RSSSample.Views.Shared.Rss" %>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title><%=Html.Encode(ViewData.Model.Title) %></title>
<description><%=ViewData.Model.Description %></description>
<link><%=ViewData.Model.Url%></link>
<language><%=ViewData.Model.Language%></language>
<%foreach (FeedItem item in ViewData.Model.Items)
{%>
<item>
<dc:creator><%=Html.Encode(item.Creator)%></dc:creator>
<title><%=Html.Encode(item.Title)%></title>
<description><%=Html.Encode(item.Description)%></description>
<link><%=item.Url %></link>
<pubDate><%=item.Published.ToString("R") %></pubDate>
<% foreach (string tag in item.Tags)
{ %>
<category><%=tag %></category>
<% } %>
</item>
<%
} %>
</channel>
</rss>
Notice that the access to each property of the feed is strongly typed using ViewData.Model.<Property>, and that the values are encoded using the Html helper of the view.
Implementing the Controller to render RSS Action Result
In a controller of our choice, we can add a method that will return the results as RSS Feed.
public ActionResult Rss()
{
// Get Feed Data
Feed f = GetFeedData();
return View(f);
}
This method gets the feed object model populated, and renders the above view passing the feed as the model.
Enjoy!
ASP.Net MVC Route Constraints
ASP.Net MVC has a powerful Routing Engine that allows mapping between URL Routes and Controller Actions. The default route that is created with an empty ASP.Net MVC application is:
{controller}/{action}/{id}
But, according to application requirements, other routes can be used, with parameters not necessarily of type string and int, and may require certain constraints to take place.
For example, my previous post about Anatomy of an ASP.Net MVC Application can be found at: http://blogs.microsoft.co.il/blogs/bursteg/archive/2008/12/21/anatomy-of-an-asp-net-mvc-application.aspx, and has a route similar to:
/blogs/{blogName}/archive/{year}/{month}/{day}/{*permalink}
Each one of the parameters can be checked for validity of format, values and if its value exists in the DB.
Defining Routes and Default Values
If we take a look at the Global.asax file in out ASP.Net MVC application, we can see that the default route is defined using the RegisterRoutes method:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
The first parameter is the name of the route, and it is important for debugging – in order to know which route matches an input url. The second is the route URL with parameters, and the third parameter is default values for the above parameters.
Notice this short way of defining a dictionary with values. An anonymous type that has properties and values is being passed to the constructor of RouteValueDictionary class and using the following code begin transformed into a dictionary:
public class RouteValueDictionary : ...
{
public RouteValueDictionary(object values)
{
this._dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
{
object value = descriptor.GetValue(values);
this._dictionary.Add(descriptor.Name, value);
}
}
}
We can see this form of passing a dictionary of values a lot in the ASP.Net MVC code and usage.
Defining Route Constraints
The MapRoute method has an additional overload that takes the route constrains as an object, just like the defalut values above. For example, if we want to make sure that the controller is from a list of values, and the id has an email format, we can use the following constraints:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "guyb@microsoft.com" },
new
{
controller = new FromValuesListConstraint("Home", "Account"),
id = new EmailFormatConstraint()
}
);
This call assigns two constraints: a FromValuesListConstraint on the controller value, and a EmailFormatConstraint to the id value. Each of those constrains implements the interface IRouteConstraint that has a single method Match that returns true of the value matches the constraint:
public interface IRouteConstraint
{
bool Match(HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection);
}
Implementing a Custom Route Constraint
The ASP.Net URL Routing Engine ships only with a single Route Constraint called HttpMethodConstraint, that validates the Http Method against a list of valid method for an action. This means that this is a place for extensibility and the above 2 samples are custom Route Constraints I created.
public class FromValuesListConstraint : IRouteConstraint
{
public FromValuesListConstraint(params string[] values)
{
this._values = values;
}
private string[] _values;
public bool Match(HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection)
{
// Get the value called "parameterName" from the
// RouteValueDictionary called "value"
string value = values[parameterName].ToString();
// Return true is the list of allowed values contains
// this value.
return _values.Contains(value);
}
}
In order to implement a Custom Route Constraint, you should create a class that inherits from IRouteConstraint, and implement the Match method. In the implementation, get the value from the dictionary by the provided parameter name, and validate id according to your scenario. Don’t forget that you have access to the HttpContext, and you can use the Request, Response and other Http Properties.
Enjoy!