I read this [useful article] that says I can create a library of inline helpers by putting them in a view in the special folder App_Code. When I moved my #helper functions there, calls to extension helpers I have stopped working. I read [in this SO article] that there's an issue because the #helpers are static but my extensions are not... I tried the 2 different ways but cannot make it work. It fails to recognise the existence of my extension helpers.
'System.Web.WebPages.Html.HtmlHelper' does not contain a definition for 'Image'
my extension helper is called 'Image'. What should I be looking for?
When you write the Helperextension in razor view.
You need to call it like FileName.Method.
eg you have CustomHelpers.cshtml file in app_code and in that you have a method
#helper TruncateString(string input, int length)
{
if (input.Length <= length)
{
#input
}
else
{
#input.Substring(0, length)<text>...</text>
}
}
you can call it from index.cshtml
#CustomHelpers.TruncateString("Example", 8);
As a matter of example, the following code use the "RenderPage" function within a helper library:
#helper GetSection(string sectionName, string sectionTitle, string sectionFileName){
<div id="#sectionName">
<h1>#sectionTitle</h1>
#System.Web.WebPages.WebPageContext.Current.Page.RenderPage("~/Views/Shared/MySections/" + #sectionFileName)
</div>
}
It demonstrate how to retrieve the "current page" (context sensitive) instance.
This code works fine from within your own "common library" Razor helper file (".cshtml") situated in the "*app_code*" subfolder of your project.
ok, my problem had to do with namespace... so I have in \Views\Shared\HtmlHelpers.cs:
public static class Html
{
public static MvcHtmlString Image(this HtmlHelper helper, string src, object htmlAttrs = null)
{
which I generally access from my pages like this:
#Html.Image("/path/to/image")
in App_Code\Helpers.cshtml:
#helper AddButton(string path)
{
var Html = ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html;
#Html.Image(path);
}
but Intellisense would underline the "Image" and complain:
'System.Web.Mvc.HtmlHelper<object>' does not contain a definition for 'Image'
and no extension method 'Image' accepting a first argument of type
'System.Web.Mvc.HtmlHelper<object>' could be found (are
you missing a directive or an assembly reference?)
the reason seemed to be that the Helpers.cshtml needs to have #using for the namespace... on my regular pages the namespace is included in my web.config but this page seems exempt from that mechanism
Related
I'm trying to set a master layout.cshtml page that works consistently for all page except for one or two (typically login and logout). In my layout I'd like to display some elements that I want to not display for these special pages.
I've seen partial views and sections and they all seem to work "backwards" to the way I want - in this case I want the default to be 'display all the elements', but for special pages I want to be able to turn an element off.
I've seen previous code that uses PageData to pass a variable to the layout (which seemed very useful as I could slap a bool in the relevant pages and check it in the layout) but this seems to have been removed. Are there any other ways that work without involving the controller or updating every page to display the bits I want hidden on just 1 page?
There's a number of different ways you can achieve this. If you want to simply "turn off" an area of the page, the simplest approach is probably with ViewData. Something like:
_Layout.cshtml
#if (ViewData["ShowThis"] as bool? ?? true)
{
<!-- HTML here -->
}
This will cause it to default to true (show the HTML) if the ViewData key is not defined, so then in your views where you want to disable it, you'd just need to define it as false:
SomeView.cshtml
#{
ViewData["ShowThis"] = false;
}
Alternatively, you can use sections. This would give you the ability to optionally replace the HTML with something else.
_Layout.cshtml
#if (!IsSectionDefined("Foo"))
{
<!-- HTML here -->
}
else
{
#RenderSection("Foo", required: false)
}
Then, in your view, you simply define the section. If you want to display nothing, you can just define it empty:
SomeView.cshtml
#section Foo {}
Or you can can actually put something in there to replace the area with:
#section Foo
{
<!-- alternate HTML here -->
}
You can try this to pass ViewData in _Layout page in asp.net mvc
public class DynamicMenuAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var result = filterContext.Result as ViewResult;
result.ViewData["key"] = "Hello Bangladesh";
}
}
Add Dependency Injection into Startup.cs file
services.AddMvc(
config =>
{
config.Filters.Add(new DynamicMenuAttribute());
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Now you can you ViewData["key"] in _Layout.cshtml
I am using RC2 of ASP.Net MVC Core.
I have added my using directives to _ViewImports and it is complaining that the namespace is incorrect. I use the exact same namespace in my controller and it works fine but will not work in the views.
The using directive is referencing a class library in the same solution.
#using xxx.Web
#using xxx.Web.Models
#using xxx.Web.Models.AccountViewModels
#using xxx.Web.Models.ManageViewModels
#using Microsoft.AspNetCore.Identity
#using xxx.yyy
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
I have done significant research on the problem but it looks like it really should be as simple as adding the namespace. It even autocompletes in _ViewImports so I am not misspelling it (I have copied and pasted it just in case).
In case it is relevant I do use a "top Level" namespace so my web project is xxx.Web and my class library is xxx.yyy.
If you have the latest version of ASP.NET Core, this could solve your problem:
services.Configure<RazorViewEngineOptions>(options =>
{
var previous = options.CompilationCallback;
options.CompilationCallback = (context) =>
{
previous?.Invoke(context);
context.Compilation = context.Compilation.AddReferences(MetadataReference.CreateFromFile(typeof(hbulens.MyBucketList.Utilities.EnumUtilities).Assembly.Location));
};
});
or you can try:
services.Configure((RazorViewEngineOptions options) =>
{
var previous = options.CompilationCallback;
options.CompilationCallback = (context) =>
{
previous?.Invoke(context);
context.Compilation = context.Compilation.AddReferences(myAssemblies);
};
});
Put this code in the ConfigureServices method of the startup class.
I ran into this exact same problem, and found this question via Google. I solved it by ensuring that my class library was a .NET Core/Class Library rather than a Windows/Class Library (when using the "Add New Project" dialog). I ended up removing my old class library, creating a new project of the correct type, and adding my source files to it.
On this Url there is text i want to mine
http://www.mefik.co.il/provider.asp?provider_id=10757
I'm looking for the class 'big_obj_px_news_page'
tried all kinds of xpath options.
any help ?
I suggest you install Firefox+Firebug+Firepath to validate your xpaths. Your xpaths were close, but not enough.
//div[#class='big_obj_px_news_page']
// or if this div may have more class names
//div[contains(#class, 'big_obj_px_news_page')]
I created a unit test with the following code:
using System;
using System.IO;
using HtmlAgilityPack;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml;
namespace HtmlAgilityPackTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + "\\test.html"));
var item = doc.DocumentNode.SelectNodes("//*[contains(#class, 'big_obj_px_news_page')]");
Assert.IsNotNull(item);
}
}
}
This test passes with the exact html on the page provided. In your code you wrote var item = doc.DocumentNode.SelectNodes(Xpath), are you typing the exact xpath string above, or are you trying to use an xpath object?
If you're using an XPath object, it could be that you are setting up your XPath object incorrectly. The only other option I see is that you are not loading your Html correctly. In the unit test code above "test.html" contains the full html source from the page you provided, and resides in the same directory as the c# source code. In the test.html file properties window in Visual Studio, I've set "Copy to Output Directory" to "copy if newer". It's build action is "Content".
Perhaps if you describe how you're loading your html, we can be of further assistance.
I'm looking for the equivalent of an
#if DEBUG
//view elements to show just for debug builds
#if
for views in MVC3/Razor. What's the idiomatic method for implementing this type of a setup?
That's too messy IMO. Views should be dumb, and focused on rendering HTML, not making build-based decisions.
Set properties in your view model if debug is configured, and render them out in the View.
If the properties are null (e.g non-debug), nothing will get rendered.
You can use HttpContext.Current.IsDebuggingEnabled, it checks debug value in the web.config file.
For instance:
#if(HttpContext.Current.IsDebuggingEnabled) {
//view elements to show just for debug builds
}
The other option is use write your own HttpHelper extension
public static class HtmlHelperExtensions
{
public static bool IsDebug(this HtmlHelper helper)
{
#if DEBUG
return true;
#else
return false;
#endif
}
}
Then in your Razor code you can use it as:
#if (Html.IsDebug())
{
//view elements to show just for debug builds
}
Don't think you can do that in Razor as it doesn't compile the same way as C# code does.
So I'd say the best way to do it would be to do it in your controller and add it to a value in your model.
Edit: Here's some more info. The person here is suggesting an extension method that loads the appropriate code whether it's in debug or not: asp.mvc view enteres #IF DEBUG in release configuration
Since you haven't told us what you'd like to do, i can't give you any 'code' answers.
Preprocessor directives (#if) are a language feature C#, which you can enter by using a razor code block (#{}) and then use a explicit delimited transition (<text></text>) or an explicit line transition (#:) to conditionally add html like this:
#{
#if DEBUG
{
#:<div>Debug Mode</div>
}
#else
{
<text>
<div>
Release Mode
</div>
</text>
}
#endif
}
See Also: Preprocessor directives in Razor
Why doesn't Html.ActionLink work in the below code? This is a page in the app_code folder,
that I am trying to call from index.cshtml
LogOnUserControl.cshtml
#helper DisplayUserControl(){
if (Request.IsAuthenticated ) {
<span>Welcome <strong>#User.Identity.Name</strong>!</span>
<span>[ {#Html.ActionLink("","","")} ]</span>
}
else {
<span>[{#Html.ActionLink("","","") }]</span>
}
}
this is the line of code from index.cshtml. The call itself works, if I remove the Html.ActionLink statements the site loads fine. Is it that you can't use them in a nested page like this? How else can I generate dynamic links?
index.cshtml
#LogOnUserControl.DisplayUserControl()
What's the idea with this action links? Why are you passing empty strings as arguments? I suppose you want to generate SignIn, SignOut links, don't you?
Also if you want to use HTML helpers inside shared helpers that you put in the App_Code folder you will need to pass them as arguments because they are not available:
#using System.Web.Mvc.Html
#helper DisplayUserControl(System.Web.Mvc.HtmlHelper html) {
if (html.ViewContext.HttpContext.User.Identity.IsAuthenticated) {
<span>
Welcome
<strong>
#html.ViewContext.HttpContext.User.Identity.Name
</strong>
!
</span>
<span>[#html.ActionLink("SignOut", "Login")]</span>
}
else {
<span>[#html.ActionLink("SignIn", "Login")]</span>
}
}
and to call the helper:
#LogOnUserControl.DisplayUserControl(Html)
Personally I never use such helpers (the ones you put in the App_Code folder). Can't see any use for them when you have partial views, editor/display templates and Html.Action helpers.
So for example you could define a partial (~/Views/Shared/_LogOnUserControl.cshtml):
#if (User.IsAuthenticated) {
<span>
Welcome
<strong>
#User.Identity.Name
</strong>
!
</span>
<span>[#Html.ActionLink("SignOut", "Login")]</span>
}
else {
<span>[#Html.ActionLink("SignIn", "Login")]</span>
}
which you would include in your layout:
#Html.Partial("_LogOnUserControl")