I know that if you think you found a bug in the .NET framework you are most likely wrong, but that's why I'm writing this question, so please hear me out.
I am fairly certain that there is a difference between the routes in .NET 3.5 and .NET 4.0 when it comes to optional parameters. Specifically if you have more than one optional parameter in your route. I have not been able to find this breaking change noted in any release notes of either .NET 4.0 or MVC 3 so thats why I call it a bug.
EDIT: This bug only manifests itself when you try to build a route url using code like the url or html helpers in mvc. If you actually request the url in a browser, in an actual mvc app, it works just fine. So if my test app below were an actual mvc app there wouldn't be a problem if you tried to request '/root/test1'.
What I need you to do is run the following test program, it should be fairly self-explanatory, but basically it just sets up a route with some optional paramters.
Create a new .NET 4 console application
Change the target framework to '.NET Framework 4' instead of '.NET Framework 4 Client Profile'
Add references to:
System.Web 4.0
System.Web.Routing 4.0
System.Web.Mvc 3.0
Paste following code to the program.cs file, overwriting any previous content:
using System;
using System.IO;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
public class Program
{
static void Main()
{
var httpCtx = new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://localhost/", null), new HttpResponse(new StringWriter())));
var routes = RouteTable.Routes;
routes.MapRoute("Test", "root/{test1}/{test2}/{test3}", new { test2 = UrlParameter.Optional, test3 = UrlParameter.Optional });
var context = new RequestContext(httpCtx , new RouteData());
var url = new UrlHelper(context);
var expected1 = "/root/test1";
var expected2 = "/root/test1/test2";
var expected3 = "/root/test1/test2/test3";
var actual1 = url.RouteUrl("Test", new { test1 = "test1" });
var actual2 = url.RouteUrl("Test", new { test1 = "test1", test2 = "test2" });
var actual3 = url.RouteUrl("Test", new { test1 = "test1", test2 = "test2", test3 = "test3" });
var result1 = actual1 == expected1;
var result2 = actual2 == expected2;
var result3 = actual3 == expected3;
Console.WriteLine("Test 1: {0} ({1})", result1 ? "Success" : "Fail", result1 ? string.Format("'{0}'", actual1) : string.Format("Expected '{0}' but was '{1}'", expected1, actual1 ?? "<null>"));
Console.WriteLine("Test 2: {0} ({1})", result2 ? "Success" : "Fail", result2 ? string.Format("'{0}'", actual2) : string.Format("Expected '{0}' but was '{1}'", expected2, actual2 ?? "<null>"));
Console.WriteLine("Test 3: {0} ({1})", result3 ? "Success" : "Fail", result3 ? string.Format("'{0}'", actual3) : string.Format("Expected '{0}' but was '{1}'", expected3, actual3 ?? "<null>" ));
Console.ReadLine();
}
}
Run program, and note the resulting urls.
On my machine the result is:
Test 1: Fail (expected '/root/test1' but was '<null>')
Test 2: Success ('/root/test1/test2')
Test 3: Success ('/root/test1/test2/test3')
Now change the target framework to .NET 3.5 add references to:
System.Web.Mvc 2.0
System.Web.Routing 3.5
System.Web.Abstrations 3.5
Run the program again and see the 3 test cases all succeed.
This time the result is:
Test 1: Success ('/root/test1')
Test 2: Success ('/root/test1/test2')
Test 3: Success ('/root/test1/test2/test3')
So it seems to me there is a bug in the .NET 4 or MVC 3. If you find the same issue please vote on the following issue in connect: https://connect.microsoft.com/VisualStudio/feedback/details/630568/url-routing-with-two-optional-parameters-unspecified-fails-on-asp-net-mvc3-rc2#details
Feel free to test this out in a regular MVC application if you think theres something wrong in the test program.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…