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.
Related
I have a requirement where I need to know the name of the class (ApiController) which has a method (GetMethod) which is called by another method (OtherMethod) from a different class (OtherClass).
To help explain this, I hope the below pseudo-code snippets help.
ApiController.cs
public class ApiController
{
public void GetMethod()
{
OtherMethod();
}
}
OtherClass.cs
public class OtherClass()
{
public void OtherMethod()
{
Console.WriteLine(/*I want to get the value 'ApiController' to print out*/)
}
}
What I've tried:
I've looked at How can I find the method that called the current method? and the answers will get me the calling method (OtherMethod) but not the class (ApiController) which has that method
I tried [CallerMemberName] and using StackTrace properties but these don't get me the method's class name
using System.Diagnostics;
var className = new StackFrame(1).GetMethod().DeclaringType.Name;
Goes to the previous level of the Stack, finds the method, and gets the type from the method. This avoids you needing to create a full StackTrace, which is expensive.
You could use FullName if you want the fully qualified class name.
Edit: fringe cases (to highlight the issues raised in comments below)
If compilation optimizations are enabled, the calling method may be inlined, so you may not get the value you expect. (Credit: Johnbot)
async methods get compiled into a state machine, so again, you may not get what you expect. (Credit: Phil K)
So it can be done like this,
new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().DeclaringType.Name
StackFrame represents a method on the call stack, the index 1 gives you the frame that contains the immediate caller of the currently executed method, which is ApiController.GetMethod() in this example.
Now you have the frame, then you retrieve the MethodInfo of that frame by calling StackFrame.GetMethod(), and then you use the DeclaringType property of the MethodInfo to get the type in which the method is defined, which is ApiController.
You can achieve this by below code
First you need to add namespace using System.Diagnostics;
public class OtherClass
{
public void OtherMethod()
{
StackTrace stackTrace = new StackTrace();
string callerClassName = stackTrace.GetFrame(1).GetMethod().DeclaringType.Name;
string callerClassNameWithNamespace = stackTrace.GetFrame(1).GetMethod().DeclaringType.FullName;
Console.WriteLine("This is the only name of your class:" + callerClassName);
Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
}
}
The instance of stackTrace is depend upon your implementation environment. you may defined it locally or globally
OR
You may use below method without creating StackTrace instance
public class OtherClass
{
public void OtherMethod()
{
string callerClassName = new StackFrame(1).GetMethod().DeclaringType.Name;
string callerClassNameWithNamespace = new StackFrame(1).GetMethod().DeclaringType.FullName;
Console.WriteLine("This is the only name of your class:" + callerClassName);
Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
}
}
Try this may it help you
Why not simply pass the name as constructor parameter? This doesn't hide the dependency, unlike StackFrame/StackTrace.
For example:
public class ApiController
{
private readonly OtherClass _otherClass = new OtherClass(nameof(ApiController));
public void GetMethod()
{
_otherClass.OtherMethod();
}
}
public class OtherClass
{
private readonly string _controllerName;
public OtherClass(string controllerName)
{
_controllerName = controllerName;
}
public void OtherMethod()
{
Console.WriteLine(_controllerName);
}
}
I have a project named A that has a class named ClassA.
ClassA has a method named ReadBlock() which creates a CloudBlockBlob object and calls one of its methods.
CloudBlockBlob is a class which is located in Microsoft.WindowsAzure.Storage.Blob namespace which is in Microsoft.WindowsAzure.Storage.dll.
My project A has a unit testing project named A.Tests.
Now, I want to test method ReadBlock(). To test it, I need to mock the CloudBlockBlob object and intercept the calls to its methods, return custom values and verify that the methods were called.
How can I mock an object that is fully created inside a method?
Can I somehow change project A's dll reference and reference it to a mock dll that creates a mock object instead the real one?
Can I override project A's call for classes inside the Microsoft.WindowsAzure.Storage.Blob with an implementation of my own in A.Tests class?
UPDATE:
The question is whether I can do this without modifying project A's code.
Thanks!
Without modifing class A code you won't be able to UT the ReadBlock method using Moq. You'll be able to UT this method using code weaving tools (MsFakes, Typemock Isolator, etc...)
For example(MsFakes):
[TestMethod]
public void TestMethod1()
{
using (ShimsContext.Create())
{
ShimCloudBlockBlob.AllInstances.<the method you want to override> = (<the method arguments>) => {};
}
}
Inside the using scope you'll be able to override any method CloudBlockBlob has, through the property AllInstances.
In the next section I'm going to discuss all the other options you have...
Option 1:
public class A
{
private IBlockBlob _blockBlob;
public A(IBlockBlob blockBlob)
{
_blockBlob = blockBlob;
}
public void ReadBlock()
{
_blockBlob.DoSomething();
}
}
Since you create a new instance each time call ReadBlock(your method's current behavior) you better inject a factory instead of wrapper and DoSomething should be create; Option 2:
public class A
{
private readonly IFactoryBlockBlob _blobFctory;
public A(IFactoryBlockBlob blobFctory)
{
_blobFctory = blobFctory;
}
public void ReadBlock()
{
var blob = _blobFctory.Create();
}
}
However, based on your question and your comments it seems that your class 'has a dependency' instead of 'needs a dependency'.
(Mark Siemens wrote a great book about DI, this chart was taken from his book)
With this new piece of information your method should be something like; Option 3:
public class A
{
public void ReadBlock(ICloudBlob blob)
{
}
}
But you don't want to change the signature of the method:
public class A
{
public void ReadBlock()
{
ReadBlock(new CloudBlockBlob(<the params bla bla...>));
}
internal void ReadBlock(ICloudBlob blob)
{
}
}
Add InternalsVisibleToAttribute, then verify the behavior of the internal method.
By reading between the lines, it feels to me that your class is a kind of "legacy code" meaning that it can do the job, won't change, and verifying its behavior might be a waste of time. In the past I've posted a chart (in this answer) which may help you to decide the way to handle this case.
Its probably best to create a very simple mockable wrapper for CloudBlockBlob to improve your code's testability and inject it using dependency inversion.
Right now you probably have something like:
public class A
{
public void ReadBlock()
{
var blockBlob = new CloudBlockBlob();
blockBlob.DoSomething();
}
}
Instead, inject your wrapper into A so that the dependency on CloudBlockBlob is not known to A:
public class A
{
IBlockBlob _blockBlob
public A(IBlockBlob blockBlob)
{
_blockBlob = blockBlob;
}
public void ReadBlock()
{
_blockBlob.DoSomething();
}
}
Disclaimer, I work in Typemock.
You can do it without modifying project A's code using Isolator.
There is a simple example how it can be done:
public class Foo
{
public void ReadBlock()
{
var block = new CloudBlockBlob(new Uri("http://myUrl/%2E%2E/%2E%2E"));
var name = block.Name;
}
}
[TestMethod, Isolated]
public void TestReadBlock()
{
//Arrange
var fakeBlock = Isolate.Fake.AllInstances<CloudBlockBlob>();
Isolate.WhenCalled(() => fakeBlock.Name).WillReturn("Name");
//Act
var foo = new Foo();
foo.ReadBlock();
//Assert
Isolate.Verify.WasCalledWithAnyArguments(() => fakeBlock.Name);
}
Hope it helps!
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.
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()
{
}
}
}
C#. I have a base class called FileProcessor:
class FileProcessor {
public Path {get {return m_sPath;}}
public FileProcessor(string path)
{
m_sPath = path;
}
public virtual Process() {}
protected string m_sath;
}
Now I'd like to create to other classes ExcelProcessor & PDFProcessor:
class Excelprocessor: FileProcessor
{
public void ProcessFile()
{
//do different stuff from PDFProcessor
}
}
Same for PDFProcessor, a file is Excel if Path ends with ".xlsx" and pdf if it ends with ".pdf". I could have a ProcessingManager class:
class ProcessingManager
{
public void AddProcessJob(string path)
{
m_list.Add(Path;)
}
public ProcessingManager()
{
m_list = new BlockingQueue();
m_thread = new Thread(ThreadFunc);
m_thread.Start(this);
}
public static void ThreadFunc(var param) //this is a thread func
{
ProcessingManager _this = (ProcessingManager )var;
while(some_condition) {
string fPath= _this.m_list.Dequeue();
if(fPath.EndsWith(".pdf")) {
new PDFProcessor().Process();
}
if(fPath.EndsWith(".xlsx")) {
new ExcelProcessor().Process();
}
}
}
protected BlockingQueue m_list;
protected Thread m_thread;
}
I am trying to make this as modular as possible, let's suppose for example that I would like to add a ".doc" processing, I'd have to do a check inside the manager and implement another DOCProcessor.
How could I do this without the modification of ProcessingManager? and I really don't know if my manager is ok enough, please tell me all your suggestions on this.
I'm not really aware of your problem but I'll try to give it a shot.
You could be using the Factory pattern.
class FileProcessorFactory {
public FileProcessor getFileProcessor(string extension){
switch (extension){
case ".pdf":
return new PdfFileProcessor();
case ".xls":
return new ExcelFileProcessor();
}
}
}
class IFileProcessor{
public Object processFile(Stream inputFile);
}
class PdfFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
class ExcelFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
This should make sure you are using the FileProcessorFactory to get the correct processor, and the IFileProcessor will make sure you're not implementing different things for each processor.
and implement another DOCProcessor
Just add a new case to the FileProcessorFactory, and a new class which implements the interface IFileProcessor called DocFileProcessor.
You could decorate your processors with custom attributes like this:
[FileProcessorExtension(".doc")]
public class DocProcessor()
{
}
Then your processing manager could find the processor whose FileProcessorExtension property matches your extension, and instantiate it reflexively.
I agree with Highmastdon, his factory is a good solution. The core idea is not to have any FileProcessor implementation reference in your ProcessingManager anymore, only a reference to IFileProcessor interface, thus ProcessingManager does not know which type of file it deals with, it just knows it is an IFileProcessor which implements processFile(Stream inputFile).
In the long run, you'll just have to write new FileProcessor implementations, and voila. ProcessingManager does not change over time.
Use one more method called CanHandle for example:
abstract class FileProcessor
{
public FileProcessor()
{
}
public abstract Process(string path);
public abstract bool CanHandle(string path);
}
With excel file, you can implement CanHandle as below:
class Excelprocessor: FileProcessor
{
public override void Process(string path)
{
}
public override bool CanHandle(string path)
{
return path.EndsWith(".xlsx");
}
}
In ProcessingManager, you need a list of processor which you can add in runtime by method RegisterProcessor:
class ProcessingManager
{
private List<FileProcessor> _processors;
public void RegisterProcessor(FileProcessor processor)
{
_processors.Add(processor)
}
....
So LINQ can be used in here to find appropriate processor:
while(some_condition)
{
string fPath= _this.m_list.Dequeue();
var proccessor = _processors.SingleOrDefault(p => p.CanHandle(fPath));
if (proccessor != null)
proccessor.Process(proccessor);
}
If you want to add more processor, just define and add it into ProcessingManager by using
RegisterProcessor method. You also don't change any code from other classes even FileProcessorFactory like #Highmastdon's answer.
You could use the Factory pattern (a good choice)
In Factory pattern there is the possibility not to change the existing code (Follow SOLID Principle).
In future if a new Doc file support is to be added, you could use the concept of Dictionaries. (instead of modifying the switch statement)
//Some Abstract Code to get you started (Its 2 am... not a good time to give a working code)
1. Define a new dictionary with {FileType, IFileProcessor)
2. Add to the dictionary the available classes.
3. Tomorrow if you come across a new requirement simply do this.
Dictionary.Add(FileType.Docx, new DocFileProcessor());
4. Tryparse an enum for a userinput value.
5. Get the enum instance and then get that object that does your work!
Otherwise an option: It is better to go with MEF (Managed Extensibility Framework!)
That way, you dynamically discover the classes.
For example if the support for .doc needs to be implemented you could use something like below:
Export[typeof(IFileProcessor)]
class DocFileProcessor : IFileProcessor
{
DocFileProcessor(FileType type);
/// Implement the functionality if Document type is .docx in processFile() here
}
Advantages of this method:
Your DocFileProcessor class is identified automatically since it implements IFileProcessor
Application is always Extensible. (You do an importOnce of all parts, get the matching parts and Execute.. Its that simple!)