8

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...

DaveRandom
  • 87,921
  • 11
  • 154
  • 174
Graham
  • 413
  • 3
  • 6
  • 10

5 Answers5

9

The suggestions on how to fix worked for me in MVC3. Example usage:

IDictionary<string, object> routeValues = new Dictionary<string, object>();

routeValues.Add("EmployeeID", 1);

@Html.ActionLink("Employee Details", "EmployeeDetails", "Employee", new RouteValueDictionary(routeValues), null);
David Fidge
  • 451
  • 5
  • 6
3

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.

  • This was the answer. This is also the answer when creating a RouteValueDictionary too -- the contructor doesn't treat anything but Dictionary correctly. – Gerard ONeill Dec 08 '15 at 22:02
1

RouteValueDictionary in System.Web.Routing, actually, so yes. This class has a constructor that takes an object, or an IDictionary<string, object>. 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.

Noctis
  • 11,507
  • 3
  • 43
  • 82
Brian Mains
  • 50,520
  • 35
  • 148
  • 257
  • Hi thanks but this doesn't work either. Updated the original with some more information – Graham Mar 13 '10 at 22:17
  • 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 Mains Mar 15 '10 at 00:33
  • menu.Attributes is itself an IDictionary. 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 Mar 15 '10 at 11:29
  • I agree... and that is backed up with this: http://msdn.microsoft.com/en-us/library/cc680124.aspx. – Brian Mains Mar 15 '10 at 13:09
  • Edited the post; I think you need to pass null instead of the last dictionary that you create as a new... – Brian Mains Mar 15 '10 at 21:04
  • Hi, thanks for the update. Unfortunately no, this doesn't work either - the same result. Maybe a bug in MVC? :p – Graham Mar 18 '10 at 17:34
  • 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 Mains Mar 19 '10 at 12:10
0

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.

0

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.

GrahamB
  • 1,368
  • 15
  • 35