Call me crazy but I'm developing an ASP.NET MVC4 site in F#. Here's my first roadblock; in the controller I submit a dictionary, this way:
[<HandleError>]
type FooController() =
inherit Controller()
member this.Index () =
this.ViewData.Add("Foo", "Bar")
this.ViewData.Add("Baz", dict [ (0, 0); (1, 3); (2, 2); ] )
this.View() :> ActionResult
Now I want to iterate through the values in the Razor template, how to do it? I've tried this:
@foreach (var time in @ViewBag.Baz.Keys)
{
<hr /><p>Time is @time, and value is @ViewBag.Baz[time]</p>
}
But it throws this error:
Line 119: Total: <span class="highlight">6449</span> kW/h.
Line 120: </p>
Line 121: @foreach (var time in (@ViewBag.Baz).Keys)
Line 122: {
Line 123: <hr /><p>Time is @time, and value is @ViewBag.Baz[time]</p>
[RuntimeBinderException: 'object' does not contain a definition for 'Keys']
CallSite.Target(Closure , CallSite , Object ) +280
System.Dynamic.UpdateDelegates.UpdateAndExecute1(CallSite site, T0 arg0) +924
ASP._Page_Views_lobby_Index_cshtml.Execute() in c:\Users\knocte\documents\visual studio 2012\projects\fsolar\conclavesolarweb\conclavesolarwebwebapi\Views\Lobby\Index.cshtml:121
System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +280
System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +126
System.Web.WebPages.StartPage.ExecutePageHierarchy() +143
System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +181
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +378
System.Web.Mvc.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17() +33
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +853420
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +265
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +837892
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +28
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +65
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +51
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +42
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +51
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288
In MVC, when we want to transfer the data from the controller to view, we use ViewData. It is a dictionary type that stores the data internally. ViewData contains key-value pairs which means each key must be a string in a dictionary. The only limitation of ViewData is, it can transfer data from controller to view.
ViewData is a dictionary of objects that are stored and retrieved using strings as keys. It is used to transfer data from Controller to View. Since ViewData is a dictionary, it contains key-value pairs where each key must be a string. ViewData only transfers data from controller to view, not vice-versa.
ViewData itself cannot be used to send data from View to Controller and hence we need to make use of Form and Hidden Field in order to pass data from View to Controller in ASP.Net MVC Razor.
So the problem you are experiencing is a know limitation of the dynamic keyword and explicit interface implementations. Unfortunately Map
will have this problem too. If you really want to use a ViewBag like this, you could use an actual Dictionary<int,int>
.
Ultimately, however you should play to F#'s strengths, which is static typing and low ceremony type creation. Create lightweight types in your F# code and use the @model keyword in your views.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With