Optional parameter

Jul 2, 2013 at 9:15 AM
What I want to do:

Define an action where the second parameter is an enum and is optional:
public virtual ActionResult EarningOverview(string id, Frequency frequency = Frequency.Quarterly)
        {     ... }
Use this action in my view without the second parameter:
@Url.Action(Mvc.Contract.Earnings.EarningOverview(Model.Id)
This is the code generated by T4Mvc:
public override System.Web.Mvc.ActionResult EarningOverview(string id, Delen.Common.Contract.Model.Contract.Frequency frequency)
        { ... }
This results in a run-time error:
System.MissingMethodException: Method not found: 'System.Web.Mvc.ActionResult Delen.Rob.Web.Areas.Contract.Controllers.EarningsController.EarningOverview(System.String, Delen.Rob.Web.Models.Frequency)'.
My workaround is to use the action in my view like this:
Url.Action(Mvc.Contract.Earnings.EarningOverview().AddRouteValue("id", Model.Id))
Coordinator
Jul 2, 2013 at 4:07 PM
I'm not able to repro this. See my sample app. Here is the specific change, and it runs fine.

Can you check whether this test app works for you, and if so what cold be different with yours?
Jul 3, 2013 at 7:38 AM
David,

Thank you for taking the time to demonstrate this feature works in the sample app!

It seems I dream about this stuff, because at 3 A.M. this morning I awoke with a realization. About two weeks ago, to speed up development, I had enabled the optimizeCompilations setting in the web.config:
<compilation targetFramework="4.5" debug="true" defaultLanguage="c#" optimizeCompilations="true"/>
Having read the warning and explanation why this setting is not enabled by default, I thought I would never run into that specific situation. Well, I didn't, but there is an other case not mentioned in the 2009 MSDN blog post talking about this switch being introduced in .Net 3.5 SP1, where optional parameters were introduced in .Net 4.

For those unfamiliar with the setting:
  • With optimizeCompilations set to its default "false", the compile cache of the views is emptied when you recompile your controllers.
  • With optimizeCompilations set to "true", views only get recompiled when you change the view.
    --> Removing actions in your controller will then result in a runtime MissingMethodException instead of a compile error, which is not a problem since in both cases you get a helpful error.
    --> Adding an optional parameter to your controller while not changing (thus not recompiling) the views will result in a MissingMethodException. I confirmed this is what happened to me.
The quote from the documentation warning me about a different MissingMethodException case when changing the return type of a method:
Change to a type used in an existing API’s signature

This is the nastiest case. E.g. suppose your Foo() method returns an ‘int’, and you change it to return a ‘short’. Now suppose you have a page that calls ‘Response.Write(o.Foo())’. Let’s compare what happens if you recompile the page vs. if you don’t
1.You recompile the page: everything compiles and runs fine, because the same C# (or VB) code can be used to call the method, no matter what its return type is.
2.You don’t recompile the page: you get a MissingMethodException, because the previously compiled code cannot work with the new method signature.

Undeniably, this case is broken, and is the primary reason that we can’t turn on this optimization by default. Luckily, in practice this situation in not extremely common, which is why the optimization is still very usable for users that are aware of the limitations.
Coordinator
Jul 3, 2013 at 11:44 PM
Yes, optimizeCompilations has some pitfalls and they can show up in tricky ways. And yes, I can see how optional params would do that. Did you notice that that post on optimizeCompilations was from me? :)
Jul 4, 2013 at 12:13 PM
I totally failed to notice that was your post. Shame on me!

Thanks again for taking the time to help me figure this out.