Archive for the 'Asp.NET' Category

Removing the Page directive from you Views in Asp.Net Mvc

Phil Haack shows how you can remove the Page directive from the view, more or less. I have known for a long time that you could register your user controls in your web.config but never thought that this could be possible. It is quite nice.

How to serve the same data in Json, Xml or Html with Asp.Net MVC

A revised version can be found here

About four weeks ago I went to a small event for developers where one of the speakers (christian dalager) compared Ruby on Rails to Asp.Net Mvc. One of the things that really caught my attention in Ruby on Rails was the ability to have an Action serve content in various formats like Json, Xml or Html just by changing the file extension of the requested resource.

I thought it would be cool if you could do something similar in Asp.net MVC and found it to be quite easy, however if you want to serve your content in Xml, you need to download MvcContrib.

To do this, we need to create a new controller that we can inherit from.

The Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/// <summary>
/// A base controller that will enable you to serve your data in either Json, Xml, Html
/// </summary>
public abstract class FormatController : Controller
{
	/// <summary>
	/// The Key to extract the format from Route Data
	/// </summary>
	private const string FORMAT_KEY = "Format";
 
	/// <summary>
	/// The type of files we can server the requested content in
	/// </summary>
	public enum FileFormat { Html, Json, Xml }
 
	protected FormatController()
	{
		// Our Default format
		RequestedFormat = FileFormat.Html;
	}
 
	/// <summary>
	/// The format that has been requested
	/// </summary>
	protected FileFormat RequestedFormat { get; private set; }
 
	/// <summary>
	/// Occurs before an action is executed
	/// </summary>
	/// <param name="filterContext"></param>
	protected override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		base.OnActionExecuting(filterContext);
 
		var routeValues = filterContext.RouteData.Values;
		if (routeValues.ContainsKey(FORMAT_KEY))
		{
			var requestedFormat = routeValues[FORMAT_KEY].ToString();
			if (IsValidFormat(requestedFormat))
			{
				RequestedFormat = (FileFormat)Enum.Parse(typeof(FileFormat), requestedFormat, true);
			}
		}
	}
 
	/// <summary>
	/// Verifies that the requested format is one that can be servered
	/// </summary>
	/// <param name="requestedFormat"></param>
	/// <returns></returns>
	private bool IsValidFormat(string requestedFormat)
	{
		return Enum.GetNames(typeof(FileFormat)).Any(format => format.ToLower() == requestedFormat.ToLower());
	}
 
	/// <summary>
	/// Returns the content in the requested format
	/// </summary>
	/// <param name="viewModel">Viewmodel</param>
	/// <returns>ActionResult</returns>
	protected ActionResult FormatView(object viewModel)
	{
		switch (RequestedFormat)
		{
			case FileFormat.Html:
				return View(viewModel);
			case FileFormat.Json:
				return Json(viewModel);
			case FileFormat.Xml:
				return new XmlResult(viewModel);
			default:
				throw new FormatException(string.Concat("Cannot server the content in the request format: ", RequestedFormat));
		}
	}
}

Setting it up

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Pizza
{
	public int Number { get; set; }
	public string Name { get; set; }
	public string Price { get; set; }
}
 
public class HomeController : FormatController
{
	public ActionResult Index()
	{
		var pizzas = new[]
			{
				new Pizza {Number = 1, Name = "Pizza 1", Price = "$10"},
				new Pizza {Number = 2, Name = "Pizza 2", Price = "$13"},
				new Pizza {Number = 3, Name = "Pizza 3", Price = "$20"}
			};
 
		return FormatView(pizzas);
	}
}
1
2
3
4
5
6
// Add this to Global.asax
routes.MapRoute(
	"Format",
	"{controller}/{action}.{format}/{id}",
	new {id = ""}
);

Fire up your application and then type something like “home/index.xml” or “home/index.json” in the browser.

Finale word

Imaging that on your website you have different categories that contain products, by applying this technique you will be able to create a REST like webservice for your users in no time, everyone will be able to integrate your website into their own.

Sharing data has never been easier, this is so awesome.

I have submittet this piece of code (and some other stuff) to MvcContrib, I hope that it makes into the project.

Further reading
A revised version can be found here
Controllers and Action Methods in MVC Applications

JSON (JavaScript Object Notation)

How to prevent proxy servers from caching your content

A lot of people around the world are sitting behind proxy servers and it can be a good thing, because it reduces the bandwidth costs to a site. However, you don’t really have control over how the proxy server is setup, so you can’t really tell when it will refresh the content. To get around this, you can apply “Cache-Control: private” to the header of the request that is made. Doing so will tell the proxy server (shared cache) that it shouldn’t cache it.

Private - Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache. This allows an origin server to state that the specified parts of the response are intended for only one user and are not a valid response for requests by other users. A private (non-shared) cache MAY cache the response.
- RFC 2616

Weather or not to use this really depends on your site and what you are trying to achieve.

If you have a large, diverse audience, can afford higher bandwidth costs, and have a reputation for high quality, compress your content and use “Cache-Control: private”. This disables proxies but avoids edge case bugs.
- High Performance Web Sites, Steve Souders

If you can’t afford the bandwidth costs then you shouldn’t do it and furthermore there are no guarantees in life and this will only work if the proxy server honors “private”.

Next Page »