views:

467

answers:

4

All,

Getting to grips with ASP.NET MVC. So far, so good, but this one is a little nuts.

I have a view model that contains a dictionary of attributes for a hyperlink, used like this:

menu = model variable

Html.ActionLink(Html.Encode(menu.Name), Html.Encode(menu.Action), Html.Encode(menu.Controller), menu.Attributes, null)

The problem is the position of "menu.Attributes" expects an object in the form:

new  { Name = "Fred", Age=24 }

From what I can tell, this anonymous object is actually converted to a dictionary via reflection anyway BUT you can't pass a dictionary to it in the first place!!!

The Html generated for the link simply shows the dictionary type.

How on earth do I get round this? The whole point is that its general and the controller can have set the menu.Attributes previously....

Based on a post below I tried the following:

Html.ActionLink(Html.Encode(menu.Name), Html.Encode(menu.Action), Html.Encode(menu.Controller), new RouteValueDictionary(menu.Attributes), new Dictionary<string,object>())

but this still doesn't work (I guess the code internally calls the generic method that takes objects?). The above (and my original solution of passing a dictionary to the 4th paramater produces a HTML similar to this:

<a href="/EditRole?Comparer=System.Collections.Generic.GenericEqualityComparer%601%5BSystem.String%5D&amp;Count=1&amp;Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.String%5D&amp;Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.String%5D">EditDocumentRoles</a>

i.e. it's using reflection and working things out completely wrong...

+1  A: 

Hey,

RouteValueDictionary in System.Web.Routing, actually, so yes. This class has a constructor that takes an object, or an IDictionary. There is one overload that takes this. So you can pass a RouteValueDictionary instead.

EDIT: I think the problem is with this part:

new Dictionary<string,object>()) 

at the end; it should be null. Because, what it will do is extract the public properties of the dictionary and be used incorrectly. Let me know if changing to null fixes the issue.

Brian
Hi thanks but this doesn't work either.Updated the original with some more information
Graham
What is menu.Attributes? It's pulling the properties of the dictionary and using that as the routing parameters, which is why you are getting that error.
Brian
menu.Attributes is itself an IDictionary<string, string>. I understand that is it using reflection to access the properties of the dictionary and getting it wrong.I don't get why the amendment I made above, ie. creating a routevalue from the dictionary, as you suggested, still gets the reflection bit incorrect as I'm passing it a routevaluedictionary
Graham
I agree... and that is backed up with this: http://msdn.microsoft.com/en-us/library/cc680124.aspx.
Brian
Edited the post; I think you need to pass null instead of the last dictionary<string, object> that you create as a new...
Brian
Hi, thanks for the update. Unfortunately no, this doesn't work either - the same result. Maybe a bug in MVC? :p
Graham
Not a bug; you are required to pass in the params in a certain way; I did get this error before, but it was a while ago and I forget all of the reasons I got it. Essentially, it's sucking in the information about the dictionary itself, rather than using the internal values.... and you are right; it would be for the routing parameters value... Microsoft gives you free source code for the MVC framework; you can use this to debug through (have to change all DLL/config references to this local copy, but it works).
Brian
A: 

I am using MVC 2 and I see more than one Html.ActionLink method that takes an IDictionary as a parameter for the Html attributes. Is there some reason you can't use one of those? If you really need a shorter form of that method with some defaults, then you can write an adapter extension method on HtmlHelper.

http://msdn.microsoft.com/en-us/library/system.web.mvc.html.linkextensions.actionlink(VS.90).aspx

Perhaps I don't understand your question.

Space Cow
A: 

Space Cow.. I've lost the original Id I used to post this so cannot answer your question directly.

This was with ASP.NET MVC 1.0.

Although there was an overload that appeared to take a dictonary, the HTML generated was not the contents of the dictionary but the reflected type of the dictionary itself, basically not doing what I'd expect. There was no way in the MVC framework that I could get it to accept a predefined key/value list (e.g. in a dictionary) and for it to generate the HTML href properly. I had to create an anonymous object, which was not possible in my scenario.

Graham
A: 

Graham,

menu.Attributes is an IDictionary<string, string> and the method expects IDictionary<string, object> right? Copy your keys and values into another dictionary where the values are of type object.

Space Cow