why does AnonymousObjectToHtmlAttributes return a routevaluedictionary - asp.net-mvc

Related to MVC 5.2
Whilst refactoring some code I came across the HtmlHelper method[1]:
public static RouteValueDictionary AnonymousObjectToHtmlAttributes (object htmlAttributes);
I wondered why it returned a RouteValueDictionary rather than a simpler IDictionary<string, object> which is generally used for Html Attributes.
I've assumed that this is unintentional, but wondered if I was actually missing something more profound?
[1] https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.htmlhelper.anonymousobjecttohtmlattributes?view=aspnet-mvc-5.2

Related

ASP.NET MVC - pass htmlAttributes as parameter

I want to pass htmlAttributes as parameter to my HtmlHelper similar as it created in
Html.ActionLink("linktext", "Home", null, new{width="100px"})
How to pass this new{width="100px"} to my method
public static string SelectCategoryAdminWithAllItem(this HtmlHelper htmlHelper, string name, **???**)
{ }
and how to parse it?
Thanks
Always try to look at sources when interested with this kind of questions. From the implementation of HtmlHelper.TextBox
public static MvcHtmlString TextBox(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes)
{
return htmlHelper.TextBox(name, value, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
as you see, type of parameter is object as you cant use anonymous types as parameters to methods, and object is choice. And when parsing it, you can use HtmlHelper.AnonymousObjectToHtmlAttributes Method
I looked through the source for MVC2 when trying to figure this one out. In MVC2 they used an overload of RouteValueDictionary in System.Web.Routing to turn an object to a dictionary rather than having a helper method available like in MVC3.
public static MvcHtmlString TextBox(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes)
{
return htmlHelper.TextBox(name, value, new RouteValueDictionary(htmlAttributes));
}
A bit counter intuitive but that's the standard in 2.
Edit: Updated tags to include mvc2

MVC 3 - Accessing ModelMetaData for IEnumerable Model?

I'm trying to access the ModelMetaData for a Custom HtmlHelper that I'm working on. The HtmlHelper has a signature like so ...
public static MvcHtmlString DataGrid<T>(this HtmlHelper<T> htmlHelper){}
The (Razor) View looks like this ...
#model IEnumerable<LogMyAssets.Models.ContactModel>
....
#Html.DataGrid()
My problem is that I can't access the ModelMetaData for the Model as it's IEnumerable. I thought I
could do the following:
var model = (IEnumerable<T>)htmlHelper.ViewData.Model;
var metaData = model.ElementAt(0).GetMetadata();
public static ModelMetadata GetMetadata<TModel>(this TModel model)
{
return ModelMetadataProviders.Current.GetMetadataForType(null, typeof(TModel));
}
But stangely enough I get the following error:
Unable to cast object of type 'System.Collections.Generic.List`1[LMA.Models.ContactModel]'
to type 'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.IEnumerable`1
I though I could could cast from Generic List to Generic IEnumerable. Am I missing something?
I don't really understand where the T is defined in (IEnumerable<T>), however my Guess is that T is already IEnumerable<something>, which means you're trying to cast to IEnumerable<IEnumerable<something>>

Using Html.ActionLink and Url.Action(...) from inside Controller

I want to write an HtmlHelper to render an ActionLink with pre-set values, eg.
<%=Html.PageLink("Page 1", "page-slug");%>
where PageLink is a function that calls ActionLink with a known Action and Controller, eg. "Index" and "Page".
Since HtmlHelper and UrlHelper do not exist inside a Controller or class, how do I get the relative URL to an action from inside a class?
Update: Given the additional three years of accrued experience I have now, here's my advice: just use Html.ActionLink("My Link", new { controller = "Page", slug = "page-slug" }) or better yet,
<a href="#Url.Action("ViewPage",
new {
controller = "Page",
slug = "my-page-slug" })">My Link</a>
Your extension method may be cute and short, but it adds another untested point-of-failure and a new learning requirement for hires without adding any real value whatsoever. Think of it as designing a complex system. Why add another moving part, unless it adds reliability (no), readability (little, once you read more docs), speed (none) or concurrency (none).
Not sure I actually understood your question clearly, but, let me try.
To create a HtmlHelper extension like you described, try something like:
using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace Something {
public static class PageLinkHelper
{
public static string PageLink(
this HtmlHelper helper,
string linkText, string actionName,
string controllerName, object routeValues,
object htmlAttributes)
{
return helper.ActionLink(
linkText, actionName, controllerName,
routeValues, htmlAttributes);
}
}
}
As for your question on getting a URL from a class, depends on what kind of class you'll implement it. For example, if you want to get the current controller and action from a HtmlHelper extension, you can use:
string currentControllerName = (string)helper.ViewContext
.RouteData.Values["controller"];
string currentActionName = (string)helper.ViewContext
.RouteData.Values["action"];
If you want to get it from a controller, you can use properties/methods from the base class (Controller) to build the URL. For example:
var url = new UrlHelper(this.ControllerContext.RequestContext);
url.Action(an_action_name, route_values);

Custom MVC Error Message Localization

I want to localize my error messages on my model using attributes, such as RequiredAttribute and RangeAttribute. I'm using ASP.NET MVC2 in Visual Studio 2010.
This is really easy if my localized resources were in resx resource files... using ErrorMessageResourceName and ErrorMessageResourceType... however, I need to integrate it against a custom localization framework.
I have set the resourceProviderFactoryType on the globalization section in web.config, but MVC doesn't use this. It tries to access a static property on a resource file which returns the localized string.
This is the call stack...
System.ComponentModel.DataAnnotations.ValidationAttribute.SetResourceAccessorByPropertyLookup() +56576
System.ComponentModel.DataAnnotations.ValidationAttribute.SetupResourceAccessor() +146
System.ComponentModel.DataAnnotations.ValidationAttribute.get_ErrorMessageString() +12
System.ComponentModel.DataAnnotations.ValidationAttribute.FormatErrorMessage(String name) +33
System.Web.Mvc.DataAnnotationsModelValidator.get_ErrorMessage() +31
System.Web.Mvc.RequiredAttributeAdapter.GetClientValidationRules() +46
System.Web.Mvc.Html.ValidationExtensions.<ApplyFieldValidationMetadata>b__0(ModelValidator v) +10
System.Linq.<SelectManyIterator>d__14`2.MoveNext() +238
System.Web.Mvc.Html.ValidationExtensions.ApplyFieldValidationMetadata(HtmlHelper htmlHelper, ModelMetadata modelMetadata, String modelName) +207
System.Web.Mvc.Html.ValidationExtensions.ValidationMessageHelper(HtmlHelper htmlHelper, ModelMetadata modelMetadata, String expression, String validationMessage, IDictionary`2 htmlAttributes) +527
System.Web.Mvc.Html.ValidationExtensions.ValidationMessageFor(HtmlHelper`1 htmlHelper, Expression`1 expression, String validationMessage, IDictionary`2 htmlAttributes) +82
System.Web.Mvc.Html.ValidationExtensions.ValidationMessageFor(HtmlHelper`1 htmlHelper, Expression`1 expression) +75
Does anyone know if it's possible for me to somehow override how MVC retrieves the error message to display?
thanks
k
I would create a custom class attribute that inherits from the standard Mvc HandleError class attribute...
http://blog.dantup.com/2009/04/aspnet-mvc-handleerror-attribute-custom.html
Does this answer help?
How to use DataAnnotations ErrorMessageResourceName with custom Resource Solution

Anonymous type as object, how can I access a property?

I am adding some functionality to the HtmlHelper-class. Basically I want to automatically disable links on a web page based on user privileges e t c.
So I have this function:
public static string ActionLinkWithPrivileges(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues)
{
return LinkExtensions.ActionLink(htmlHelper, linkText, actionName, routeValues);
}
The problem here is the routeValues-argument. Its usually created as an anonymous type so I dont know what to cast it to. This anonymous type often has a property named "id" but just writing routeValue.id gives me a compiler error.
Any help would be appreciated!
This should work :
RouteValueDictionary routeVals = new RouteValueDictionary(routeValues);
var value = routeVals["key"];
//RouteValueDictionary is under System.Web.Routing
either implement an interface or use reflection to get the PropertyInfo and then itterate through the property collection to get the right one.
you would of course need to tell the method the name of the property to get unless it's of a particular type.

Resources