I am trying to extend a class method that comes from a compiled DLL, and am trying to do this from inside of an MVC project. However, for some reason, it does not pick this up.
This is how i usually extend an instantiated class method, as an example:
public static string CSVEncode(this string original)
{
//.......
}
With this, if i have any string, i can see and call the CSVEncode() method from the object itself, like this as an example:
string temp = "some string goes here";
string csv = temp.CSVEncode();
However, in this latest attempt it simply does not work...
Here's a small definition of the object I am trying to extend for this question's purposes (e.g.: there are more properties and methods that don't need to be iterated here).
namespace SomeOtherDLL.HumanRace
{
public class Human
{
//... some properties...
public Human(){ }
public bool CanAccess(string AppName)
{
//....
}
}
}
In my MVC solution, i have a Common project which includes a class called Extensions. In this class is where i put all my extensions, including the one I am trying to perform for the object above.
However, this does NOT show up in Intellisense anywhere afterwards, and if i try to build or compile, i get an error saying that this method does not exist, and i simply do not understand why?
namespace MyProj.Common
{
public static class Extensions
{
public static bool CanAccess(this HumanRace.Human original, int AppID)
{
//...some code here...
}
}
}
Now from what i can tell of the other object extensions i've done in the past, this should work perfectly...
Here's an example of how i try to use it in a View page:
#model SomeOtherDLL.HumanRace.Human
#using MyProj.Common.Extensions
#Html.Raw(Model.CanAccess(59) ? "<img src='CanAccess.jpg' />" : "<img src='CannotAccess.jpg' />")
.............
This does not resolve in Visual Studio... am I doing something wrong here?
Your Extensions class is in the namespace MyProj.Common, but you don't seem to be including that in your view. Try adding
#using MyProj.Common
to your view.
Related
For a C# Project, I want to include a build step or something integrated in project that should raise build error if any developer is trying to use a specific method from framework classes, instead I want developers to use extension method for same. However I want to impose this as the compile time error. As an example, for a name sake I want developer on given project not to use string.Intern, instead should always use string.SpecialIntern. What are different ways to achieve this? I tried to use Roslyn-code-analysis but could not really write working rule for this, so I am not sure if tha'ts the right solution to this problem. Can someone guide me in details how to solve this with some examples?
This sounds like something you could accomplish with a custom code analyzer. I haven't tried it yet, but I believe it is possible to write your own analyzers.
This article from Microsoft claims to tell you how to do it:
https://learn.microsoft.com/en-us/visualstudio/extensibility/getting-started-with-roslyn-analyzers?view=vs-2017
Here's a direct link to the tutorial referenced in that article:
https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/tutorials/how-to-write-csharp-analyzer-code-fix
AFAIK there's no way to achieve what you're trying to do.
However, a solution would be to simply call the extension method.
public static class Extension
{
public static bool DoStuff(this Class stuff)
{
return false;
}
}
public class Class
{
public bool DontCallMe()
{
return this.DoStuff();
}
}
Class myClass = new Class();
myClass.DontCallMe();
Obviously, that only works if you can change the code of your class (which I suppose you aren't able to)
If that method is marked as virutal, you could create a Wrapper-Class which overrides that method.
public static class Extension
{
public static bool DoStuff(this Class stuff)
{
return false;
}
}
public class Class : Base
{
public override bool DontCallMe()
{
return this.DoStuff();
}
}
public class Base
{
public virtual bool DontCallMe()
{
return false;
}
}
Another approach would be to do what I described in this this post.
I have some code base which has is calling the following:
SetHazardDataService();
namespace Analytics.Foo.DataServices
{
class HDB:IDataService
{
}
}
With a member function declared in another class/file
using Analytics.Foo.DataServices
public void MyDataService()
{
var DbDataSvc = new HDB();
}
originally, I see the same definition used elsewhere but with (no idea if that works):
protected void MyDataService()
I included the public method in my class
I'm now trying to recreate that functionality, but I get the following issue:
The type Analytics.Foo.DataServices.HDB' has no constructors defined
I'm not sure what the issue is - any suggestions for why this is the case. There is no constructor that I can see. Plus I'm not able to see the other code working/but it doesn't give the same issue.
You need to create a constructor to class HDB, like this:
namespace Analytics.Foo.DataServices
{
class HDB:IDataService
{
public HDB()
{
}
}
}
I tried to make this function (and others) and put it in a separate class file in my project that's under "/Helpers/UploadFiles.cs"
namespace Artikelhantering.Helpers
{
public class UploadFiles
{
private void EnsureDirectoriesExist(string SKU)
{
// if the directory doesn't exist - create it.
if (!System.IO.Directory.Exists("//servername/wwwroot/prodimg/" + SKU))
{
System.IO.Directory.CreateDirectory("//servername/wwwroot/prodimg/" + SKU);
}
}
}
Then in the controller I added using Artikelhantering.Helpers;, it's also added to the namespace section of the web.config file and also to global.asa.cx.
Then I figured I could call it from an ActionResult in my controller like this
[ChildActionOnly]
public ActionResult _EnumerateFolder(string SKU)
{
// create directory if it does not exist
EnsureDirectoriesExist(SKU);
ViewBag.SKU = SKU;
var folder = Directory.EnumerateFiles("//servername/wwwroot/prodimg/" + SKU);
return View(folder);
}
But all I get is:
Error 2 The name 'EnsureDirectoriesExist' does not exist in the current context
Tried calling it by writing it as UploadFiles.EnsureDirectoriesExist(); but that doesn't work either. How am I supposed to call these methods without having them all in the same file? I would like to organize this better.
The method is private. You can not access private members of other classes.
Also some other problems here:
The method you wrote is an instance method, so you need to have an instance of the class to call the method.
If you want to call it using UploadFiles.EnsureDirectoryExists(), you need to make it a class method (static).
I'm not sure whether you can create a new directory the way you try to do it. If you are trying to create the directory on the same machine that this code is running on, use local file names.
Sample code for 1):
UploadFiles uf = new UploadFiles();
uf.EnsureDirectoryExists();
Sample code for 2):
public class UploadFiles
{
public static void EnsureDirectoriesExist(string SKU)
{
// if the directory doesn't exist - create it.
if (!System.IO.Directory.Exists("//servername/wwwroot/prodimg/" + SKU))
{
System.IO.Directory.CreateDirectory("//servername/wwwroot/prodimg/" + SKU);
}
}
}
I furthermore suggest that you google for a C# tutorial that provides you with information on what classes are and how they can be used.
First, change the access modifier of EnsureDirectoriesExist to public then
try to change your ActionResult _EnumerateFolder method with the code below:
public ActionResult _EnumerateFolder(string SKU)
{
// create directory if it does not exist
new UploadFiles.EnsureDirectoriesExist(SKU);
ViewBag.SKU = SKU;
var folder = Directory.EnumerateFiles("//servername/wwwroot/prodimg/" + SKU);
return View(folder);
}
First thing that is not correct here is a method accessibility levels. In order to invoke method from outside of the class body it should be public.
Also, way that you are invoking this method is also incorrect. To do it in desired way you should make your class static to avoid creating an instance of a class to invoke method.
So:
public static class Helper
{
public static void EnsureDirectoriesExist(string SKU)
{
...
}
}
Mark your class as static then try this:
public static class UploadFiles
{
public void EnsureDirectoriesExist(string SKU)
{
//your code
}
}
Then:
public ActionResult _EnumerateFolder(string SKU)
{
UploadFiles.EnsureDirectoriesExist(SKU);
//your code
}
make your directory method public and static. Then you can call it something like this
Artikelhantering.Helpers::UploadFiles.EnsureDirectoriesExist(SKU);
If you can't change the signature... you can make a public wrapper method and call it the same way. If you cannot make the method static, then you should create first an instance of your class and finally call the new public wrapper method.
I want to hide public methods from the IntelliSense member list. I have created an attribute that, when applied to a method, will cause the method to be called when its object is constructed. I've done this to better support partial classes. The problem is that in some environments (such as Silverlight), reflection cannot access private members, even those of child classes. This is a problem since all of the work is done in a base class. I have to make these methods public, but I want them to be hidden from IntelliSense, similar to how the Obsolete attribute works. Frankly, because I am anal about object encapsulation. I've tried different things, but nothing has actually worked. The method still shows up in the member drop-down.
How do I keep public methods from showing up in IntelliSense when I don't want them to be called by clients? How's that for a real question, Philistines! This can also apply to MEF properties that have to be public though sometimes you want to hide them from clients.
Update:
I have matured as a developer since I posted this question. Why I cared so much about hiding interface is beyond me.
Using the EditorBrowsable attribute like so will cause a method not to be shown in IntelliSense:
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void MyMethod()
{
}
You are looking for EditorBrowsableAttribute
The following sample demonstrates how to hide a property of a class from IntelliSense by setting the appropriate value for the EditorBrowsableAttribute attribute. Build Class1 in its own assembly.
In Visual Studio, create a new Windows Application solution, and add a reference to the assembly which contains Class1. In the Form1 constructor, declare an instance of Class1, type the name of the instance, and press the period key to activate the IntelliSense drop-down list of Class1 members. The Age property does not appear in the drop-down list.
using System;
using System.ComponentModel;
namespace EditorBrowsableDemo
{
public class Class1
{
public Class1()
{
//
// TODO: Add constructor logic here
//
}
int ageval;
[EditorBrowsable(EditorBrowsableState.Never)]
public int Age
{
get { return ageval; }
set
{
if (!ageval.Equals(value))
{
ageval = value;
}
}
}
}
}
To expand on my comment about partial methods. Try something like this
Foo.part1.cs
partial class Foo
{
public Foo()
{
Initialize();
}
partial void Initialize();
}
Foo.part2.cs
partial class Foo
{
partial void Initialize()
{
InitializePart1();
InitializePart2();
InitializePart3();
}
private void InitializePart1()
{
//logic goes here
}
private void InitializePart2()
{
//logic goes here
}
private void InitializePart3()
{
//logic goes here
}
}
i want to create a wrapper class that will let me use PageData as it was a strongly typed class.
i used this method before in asp.net using HttpContext.Current.Session to define all the items i can store in the session and all the manipulation of the session was done through that class.
example
namespace app.Web
{
public static class Session
{
public string UserName
{
get { return HttpContext.Current.Session["UserName"] as string; }
set { HttpContext.Current.Session["UserName"] = value; }
}
...........
}
}
i want to know how to get the Pagedata in a similar way.
PageData is only available within the page itself, not available anywhere else (like the controller). The best way to do this is with extension methods.
Frederik Vig wrote a blog post showing how this might be done.
Example:
namespace PageData.Extensions
{
public static partial class PageDataExtensions
{
public static string UserName(this PageData page)
{
return page["UserName"] as string;
}
}
}
BTW, you can use the same method for Session as well, which might be cleaner than the method you propose.
Edit:
Based on your comments, there are several other options.
Create your data as a class and add that class as an extension. i.e. Like above, but make it PageData.Utils.UserName this way it adds only a single item to the PageData intellisense and doesn't clutter it too much, and allows you to filter out the PageData methods from extension methods.
Create your static class just like you want to, but use methods instead of properties.
Example:
public static class Utils
{
public static string UserName(IDictionary<object,dynamic> pageData) {
return pageData["UserName"] as string;
}
}
Then in your code just do this (assuming you have the proper #using statements in your view):
#Utils.UserName(PageData)