I am working on a custom Html helper extension method with MVC 5.0, and after walking through the source code of the built-in helper method: InputHelper(), I want to use a piece of it in my helper method:
if (String.IsNullOrEmpty(fullName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
}
However, even with the namespace System.Web.Mvc used, I am still getting the error saying: the name 'MvcResources' is not found in the current context.
According to its source code, MvcResources is defined in a .resx file:https://github.com/ASP-NET-MVC/aspnetwebstack/blob/4e40cdef9c8a8226685f95ef03b746bc8322aa92/src/System.Web.Mvc/Properties/MvcResources.resx
And I am sure the source code I shared above is MVC 5.x.
So, can any one help? Thanks.
You can get resources using System.Resources.ResourceManager.
So your Code look like below -
if (String.IsNullOrEmpty(fullName))
{
throw new ArgumentException(System.Resources.ResourceManager(typeof(MyProject.MvcResources)).GetString("name"),"name");//replace `MyProject.MvcResources` by full name (with namspace) of your Resource class
}
You can create and user custom HtmlHelper like below.
Example:
Helper:
public static class HelperClass{
public static string InputHelper<T>(this HtmlHelper html, object key) {
return new System.Resources.ResourceManager(typeof(T)).GetString(key.ToString());
}
}
Use:
#Html.InputHelper<MyProject.Resouce.MyResouce>("name")
Hopefully It's help you.
Yes the post is old, however this came up in a search today whilst I was looking for the the actual resx file for System.Web.Mvc.Properties.MvcResources (so I could replicate a value in it)
The reason that you cannot access System.Web.Mvc.Properties.MvcResources directly is that it's declared as internal.
Related
I am in the phase of building a rendering framework for rendering my models in different formats.
My idea is the following:
public class ResidenceRendererShort : IRender<Residence> {
public string Format() {
return "short";
}
public string Render(Residence content) {
return content.Name; // Could return a whole lot of HTML
}
}
I can have multiple of those with different formats, and they are all injected using Ninject DI into my RenderingService, where I got methods for finding the correct render, using methods like e.g. FindRendererFor(Type type, string format)
Now my question is, how can I create a tag in razor which will use the rendering service and applying the correct render? I have been looking into HtmlHelpers, but they are static methods and I can not inject my RenderingService into this.
I thought I could create something like:
#Model my.namespace.Residence
#Html.RenderObject(Model, "short");
Am I missing something or someone got an idea on how to accomplish this?
You're killing yourself. Just use Display/Editor Templates. If you have a view in ~/Views/Shared/DisplayTemplates or ~/Views/Shared/EditorTemplates named after your class, Residence.cshtml in this case, then Razor will use this view to render your class whenever it's passed to Html.DisplayFor or Html.EditorFor.
I have included Telerik.Web.Mvc assembly and still not able to get ToGridModel() method for export function.
Below are some details about my code
Html.ActionLink(" ", "ExportData", new {..})
public ActionResult ExportData(...)
{
}
issues in code
Not able to define variable with IEnumerable xxx (giving error as it required 1 argument)
Not able to call ToGridModel() method.
Can anybody guide me how should i do this? what I am missing?
Make sure you've brought the extension method into scope by adding the proper using directive pointing to the namespace in which this extension method is defined:
using Telerik.Web.Mvc.Extensions;
Asp.net MVC provides lots of (and very useful) HtmlHelper extensions. But what if I was to provide a micro sub-framework with some extension methods that extend existing ones?
i.e. BeginForm may be rewritten to be more rich (always adding security stuff like anti forgery token and similar.
Question
In order to not rewrite all of the Asp.net MVC's HTML helper methods how can I enforce usage of mine? So that the using usual BeginForm would either throw an exception or not be accessible in the first place. The second choice is likely not possible without removing System.Web.Mvc.Html namespace from view's folder web.config file. This would mean that all of those helpers would need rewriting. And that's something I don't want to do.
The thing is that when this micro sub-framework is used it should prevent usage of standard helpers for security reasons. Period.
What other options are there for me?
Example
Suppose I would only write my own BeginForm that I would call BeginSecureForm so one would use it as:
#using Html.BeginSecureForm() {
...
#Html.EditorFor(m => m.Something)
...
}
As you can see I've used my custom helper and standard EditorFor helper as well. This means that System.Web.Mvc.Html is still included to use non-custom helpers like EditorFor.
Upper code works fine as long as you use my custom helper method... But what if some developer would forget to do so and use the normal one instead?
#using Html.BeginForm() {
...
#Html.EditorFor(m => m.Something)
...
}
Well in this case I would either like to:
Html.BeginForm not being accessible at all
Html.BeginForm throws an exception that the secure version should be used
anything else I don't know can be done to prevent usage of standard BeginForm
One possibility to achieve that is to write a custom WebViewPage and override the Html property with a custom one:
public abstract class MyWebViewPage<T> : WebViewPage<T>
{
public override void InitHelpers()
{
this.Ajax = new AjaxHelper<T>(ViewContext, this);
this.Html = new MyHtmlHelper<T>(ViewContext, this);
this.Url = new UrlHelper(ViewContext.RequestContext);
}
public new MyHtmlHelper<T> Html { get; set; }
}
and here's the custom MyHtmlHelper<T> class in which you will make obsolete the methods that you don't want to be used directly by the developers:
public class MyHtmlHelper<T>: HtmlHelper<T>
{
public MyHtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer)
: base(viewContext, viewDataContainer)
{
}
[Obsolete("Use SecureBeginForm instead", true)]
public MvcForm BeginForm()
{
throw new Exception("Use SecureBeginForm instead.");
}
}
Alright, now all that's left to do is to switch the base type for all Razor views in the application. This could be done inside ~/Views/web.config where you will replace:
<pages pageBaseType="System.Web.Mvc.WebViewPage">
with:
<pages pageBaseType="MyAppName.Mvc.MyWebViewPage">
OK, now you could write your micro framework extension methods to the MyHtmlHelper class and thus providing your custom secure counterparts of the default methods:
public static class MyHtmlHelperExtensions
{
public static MvcForm SecureBeginForm<T>(this MyHtmlHelper<T> html)
{
var rawUrl = html.ViewContext.HttpContext.Request.Url.AbsoluteUri;
var builder = new UriBuilder(rawUrl);
builder.Scheme = Uri.UriSchemeHttps;
var form = new TagBuilder("form");
form.Attributes["action"] = builder.ToString();
form.Attributes["method"] = "post";
html.ViewContext.Writer.Write(form.ToString());
return new MvcForm(html.ViewContext);
}
}
And now inside any Razor view:
#using (Html.SecureBeginForm())
{
...
}
and when you attempt:
#using (Html.BeginForm())
{
...
}
you get a compile-time error (assuming you have enabled compilation of Razor views):
or a runtime exception if you haven't.
You are trying to achieve security in the application by forcing developers to avoid using the Html.BeginForm instead of using the secured one. Let say you somehow tricked the framework not to use Html.BeginForm so what? an young developer who is even not aware of Html.BeginForm can directly write the form HTML in the view and break the rule!
I think security has to be implemented in an application by not forcing someone to use the right tool instead of that it has to be done at the higher level of the application. In the form example itself if all the HTML forms posted to the server should have an anti forgery token then I would do the check at the higher level in the MVC pipeline. If some developer used the normal form still that module won't work and that will be taken care in the testing phase.
I am using Razor view with asp mvc preview 3
I am trying to create some methods which I would like available directly in the views. These are not really Html helper methods so I don't think extending HtmlHelper makes sense?
my goal, be able to call methods in the view i.e.
#HelloWorld(); vs #Html.HelloWorld()
I can get Html.HelloWorld to work by creating an extension method on HtmlHelper
public static class HtmlExtensions
{
public static string HelloWorld(this HtmlHelper helper)
{
return "Hello";
}
}
I would like to do the same thing but for the view; my problem - what type of object is the view?
Note: I was able to get this to work by defining the methods in the .cshtml page
#functions
{
public string HelloWorld()
{
return "Hello";
}
}
#HelloWorld() #* now this works *#
then I tried to put this code my _viewstart.cshtml file thinking it would be available in all views but it was not
if I knew which type the view was I think it could be easily extended, any help appreciated
As remarked by others, Razor Views all ultimately inherit from WebViewPage:
public abstract class WebViewPage<TModel> : WebViewPage
You can therefore simply write your extension methods for WebViewPage without creating a new base class or changing the config files, which has been suggested by other answers. For example:
public static class WebViewPageExtensions
{
public static string HollowWorld(this WebViewPage wvp)
{
return "Memento mori";
}
}
Add a using statement for that namespace to your View and then:
<p>#this.HollowWorld()</p>
it turns out, the asp runtime is going to define the Execute method at runtime, so the custom view base class must also be abstract
using System;
using System.Web.Mvc;
namespace MyMvcWebApp.Extensions
{
public abstract class ViewBase<TModel>
: System.Web.Mvc.WebViewPage<TModel> where TModel : class
{
// now this will be available in any view #HelloWorld()
public string HelloWorld()
{
return "Hello from the ViewBase class";
}
}
}
this should work with strongly typed views, it looks like with razor all views are strongly typed, when you do not define the type 'dynamic' is used and that is the strong type
also, as Clicktricity stated you then update the web.config (the one under the Views directory)
<pages pageBaseType="MyMvcWebApp.Extensions.ViewBase">
The default base class for Razor views is specified in the Web.config located in the views directory. Usually it is:
<pages pageBaseType="System.Web.Mvc.WebViewPage">
I've not tried it, but I would suggest inheriting from this base class and adding your own functionality, then adjust the web.config accordingly.
The best way to call a method with arguments using razor engine is to use helpers.
Example: let you have a helper #MakeNote(string content)
Then in cshtml page you just need to call #MakeNote("Hi") and you should be fine.
I was going crazy when I was having problem then google sent me to this page but it did not help. I was trying to load content in html <select> with L2E using razor.
The secret is to create a helper in app_code then use with cshtml.
I've come across two recommendations for creating custom html helpers: either extend an existing one, or write your own class.
I'd prefer to keep my custom code separated, it seems a bit sloppy to extend helpers for a decent-size application.
But the benefit I see in extending is that 'This HtmlHelper helper' is passed as a parameter, through which I can get ViewContext.HtmlContext.
My question is, how can I roll my own helper class and still have ViewContext.HtmlContext available to me?
Thanks!
Edit:
What I am looking to do, is create "MyHelperClass" which will render some custom objects as html. I don't see a need to "Extend" an Html helper since i'm not using anything that it offers me. The only reason I have to extend htmlhelper currently is to access httpcontext, as you've shown. But my question was, how can i access httpcontext in my own class, without extending an existing helper. thanks
public static class HtmlHelperExtensions
{
public static HttpContextBase GetContext(this HtmlHelper htmlHelper)
{
return htmlHelper.ViewContext.HttpContext;
}
}
You might also use: System.Web.HttpContext.Current.Request.RequestContext