Good day, everyone,
recently I've come across the Discord.NET Api and was in love with the way Commands were handled. Essentially, to add a new Command that is executed when you write !ping, you can do this:
[Command("ping")]
public async Task Ping()
{
//some logic here
}
And I really liked the easy nature of integrating new commands in an already existing API. So I wanted to recreate what was going on. In the beginning I was absolutely confused by the introduction of metaprogramming, but now feel a little more comfortable, so I tried to start, and designed an Attribute that was only assignable to methods:
[AttributeUsage(AttributeTargets.Method)]
public class Command : Attribute
{
public string Name { get; set; }
public Command(string name)
{
Name = name;
}
public Command()
{
Name = string.Empty;
}
}
Basic idea then is, that when my Console gets a command, I can run a method that has the command attribute and the name of what was entered in the console. So when I enter "ping" in the console, the below method is going to be executed.
[Command("ping")]
public void Ping()
{
//do sth
}
Now to the complicated part. How do I find and especially run that method? That's where I'm stuck right now. I really don't find anything helpful about that question on the .Net documentary or here on stackoverflow. Here is my attempt anyway:
public void Handle(string command)
{
var methods = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.GetCustomAttributes<Command>().Count() > 0
select t;
//run method where command.name = ping
}
The idea behind that being, to iterate through all available methods in the assembly, and then putting those into a List of some kind and then executing the method that has the command.name of what was passed in as an argument to the Handle function. When I get that to work, I of course will initilaize the methods list in the constructor of that class and not everytime call it when Handle is called, but for simplicity in my question I formulated my question independent of that, to have my example minimal. The question now is, how do I iterate through all methods in my assembly, and save those with the command attribute into a collection, and how do I run a method that has a certain value for the command.Name property?
I'am kind of new to that whole reflection stuff, so if I did something else stupid or you have general tips on that topic please let me know!!
Thanks in advance!!
I have written a small demo application that should help you to complete your logic. Overall, of course, it still has room for improvement, but it works:
using System;
using System.Linq;
using System.Reflection;
namespace DemoApp
{
class Program
{
static void Main(string[] args)
{
string command = Console.ReadLine().Trim();
LogicProvider provider = new LogicProvider();
MethodInfo method = provider.GetType().GetMethods().FirstOrDefault((item) => item.GetCustomAttribute<CommandAttribute>().Identifier == command);
method?.Invoke(provider, null);
}
}
public class LogicProvider
{
[Command("DemoCommand")]
public void MyMethod()
{
Console.WriteLine("Here");
}
}
public class CommandAttribute : Attribute
{
public CommandAttribute(string identifier)
{
this.Identifier = identifier;
}
public string Identifier { get; } = null;
}
}
If DemoCommand is entered in the console, then a search is made in the LogicProvider for a matching method. If there is a match, it is executed.
The whole thing also works with methods that have parameters. In the case of method?.Invoke(), this can then be specified.
Related
I think I am a bit mixed up at this point, but I can't seem to be able to solve this issue.
I have an Interface ILinkHandler<T> and 4 other handler classes (inheriting from that interface) that validate different structures of links. From that interface, I have a Task<List<T>> Validate() function that does the validation of links and returns a Task> of results. Depending on T, I return a different model on Validate() (I have 4 different models).
My console app does the following. It calls the Task<List<T>> Validate(); method of every link type and creates some logs after getting results (note that Validate() is async). Every log is a little bit different, since the model is different, so I overrode a method named WriteResults(ModelX results, string name) and from the ModelX type (see end of question, I posted 2 examples), I do some stuff different (not important on this scope I think, but I can provide details if necessary). This method is NOT async.
I wanted to use Generics and my Interface to create a method (ValidateModel<T>) that handles the right call to the overridden method WriteResults from the type of the model and calls the Validate() method from the interface.
The code below is that I did that worked, but the if part resembles what I currently have in my main and I want to avoid.
public void ValidateModel<T>(ILinkHandler<T> handler, string name) where T : class
{
Console.WriteLine($"Validating {name}");
var results = handler.Validate();
if (typeof(T) == typeof(InternalLinksModel))
{
WriteResults(results.Result as List<InternalLinksModel>, name);
}
else // continue with other models
}
Here is what I have in my main:
private static void Main(string[] args)
{
Console.WriteLine("Validating External_Links");
var resultsForExternalLinks = ExternalLinkHandler.Validate();
WriteResults(resultsForExternalLinks.Result, "External_Links");
Console.WriteLine("Validating Image_Links");
var resultsForImageLinks = ImageLinkHandler.Validate();
WriteResults(resultsForImageLinks.Result, "Image_Links");
// and so on
}
I want more something like this if possible, but this does not compile:
public void ValidateModel<T>(ILinkHandler<T> handler, string name) where T : class
{
Console.WriteLine($"Validating {name}");
var results = handler.Validate();
WriteResults<T>(results.Result as List<T>, name);
}
Here is the definition of WriteResults (note that since it's overridden, I have 4 methods with their signature changing in the type of the list):
private void WriteResults(List<InternalLinksModel> results, string filename) { // Logs results into folder to display in jenkins }
private void WriteResults(List<PdfLinksModel> results, string filename) { // Logs results into folder to display in jenkins }
// and so on
EDIT: Adding more code
Interface:
public interface ILinkHandler<T>
{
Task<List<T>> Validate();
}
Example of Handler Class inheriting the interface:
public class InternalLinkHandler : ILinkHandler<InternalLinksModel>
{
public List<InternalLinksModel> InternalLinks = new List<InternalLinksModel>();
public async Task<List<InternalLinksModel>> Validate()
{
// Here set up my tests, call tasks that modifies InternalLinks List and I await for its results
return InternalLinks
}
Main Class (named XmlLinkCheckerValidator) where my code runs currently (and it works):
public class XmlLinkCheckerValidator
{
// References to all modes
public ExternalLinkHandler ExternalLinkHandler => new ExternalLinkHandler();
public ImageLinkHandler ImageLinkHandler => new ImageLinkHandler();
public InternalLinkHandler InternalLinkHandler => new InternalLinkHandler();
public PdfLinkHandler PdfLinkHandler => new PdfLinkHandler();
public void ValidateIPack()
{
InitialSetup();
Console.WriteLine("Validating External_Links");
var resultsForExternalLinks = ExternalLinkHandler.Validate();
WriteResultsForIPacksInCsv(resultsForExternalLinks.Result, "External_Links");
Console.WriteLine("Validating Image_Links");
var resultsForImageLinks = ImageLinkHandler.Validate();
WriteResultsForIPacksInCsv(resultsForImageLinks.Result, "Image_Links");
Console.WriteLine("Validating Internal_Links");
var resultsForInternalLinks = InternalLinkHandler.Validate();
WriteResultsForIPacksInCsv(resultsForInternalLinks.Result, "Internal_Links");
// Console.WriteLine("Validating Pdf Links");
// var results = XmlLinkExtractorFromIPacks.PdfLinkHandler.Validate();
// WriteResultsForIPacks(results, "Pdf Links");
}
private void WriteResultsForIPacksInCsv(List<InternalLinksModel> results, string filename) { logging results }
private void WriteResultsForIPacksInCsv(List<ExternalLinksModel> results, string filename) { logging results }
private void WriteResultsForIPacksInCsv(List<ImageLinksModel> results, string filename) { logging results }
private void WriteResultsForIPacksInCsv(List<PdfLinksModel> results, string filename) { logging results }
private void WriteResultsForIPacksInCsv(List<InternalLinksModel> results, string filename) { logging results }
I finally refactored all my code and it looks much clear. As I said, in the beginning, I think I got a bit mixed up and it all started from one bad design decision I took.
In short, I added a new method, WriteResults(string filename). Doing so, I implemented the method and removed the overridden method (WriteResultsForIPacksInCsv(List<WhateverModelIHad> results, string filename)) from my "Main" class. From that, I changed the Validate method signature in the interface to Task<List<PossibleResults>> Validate() and since every model has that in common, I removed the generic in the interface. I can now call my handlers the following way:
public void Validate(ILinkHandler handler, string filename)
{
Console.WriteLine($"Validating {filename}");
var results = handler.Validate();
SetUpResultsStatistics(results.Result, $"{filename}_Statistics");
handler.WriteResults(filename);
}
I created a function named void SetUpResultsStatistics(List<PossibleResults> results, string filename) which gives statistics of results and it is common to all handlers (thus, to avoid duplication I put it there).
Code is now much clearer and it now does not use any generics nor overridden method. I, however, am still curious as to how should I handle a case like that and will try to formulate it in another question with a much simpler example.
Thank you all for your comments, really appreciated!
I'm making my first "real" C# program and I'm thinking about where I should define error messages? Should I do something like this:
static class Error
{
public static string Example { get { return "Example Error"; } }
}
I could also use values here instead of properties but that would still mean I can't do something like this:
public static string FailedToParse(string filepath, string exmessage)
{
return ("Failed to parse " + filepath + ".\n" + exmessage);
}
So, is that a good idea? Should I make a new class and write a method for each error? How do you guys implement this and why?
I already read
In C#, what's the best way to store a group of constants that my program uses?
The right way to use Globals Constants
I think this is something everything should figure out by themselves.
One like to display nice messages to users another just throw those default generated ones.
Personally I like to have codes for errors.
Something like this:
I create a static class called ExceptionFactory and just pass the code to the method called RaiseException.
public static class ExceptionRegions
{
public static int Internet = 0xA;
public static int FileSystem = 0xB;
}
public class InternetConnectionException : Exception
{
public InternetConnectionException () : base("No internet connection available") { }
}
public class FileSystemAccessException : Exception
{
public FileSystemAccessException () : base("Access to specified path caused an error") { }
}
public static class ExceptionFactory
{
public static void RaiseException(int code)
{
switch(code)
{
case ExceptionRegions.Internet : throw new InternetConnectionException();
...
...
}
}
}
Btw, this is a well known pattern called Factory Pattern. :)
Why I like this, because it allows me to set regions in my application.
Usually an application has many interfaces such as file system, or web services, or database and all I need to do is create a code for each area and the factory will throw a nice message to user without exposing to the user name of database and number of code line or whatever the default generated error message looks alike.
Hi I have a possible design flaw and i need to solve it with an extension method.
Lets say I have a class and it has a property of StringCollection. Example code
public class MyProblematicClass
{
public IDbAccess Db{get;set;}
public StringCollection Errors{get;set;}
public MyProblematicClass(IDbAcces db){ Db=db;}
public int SetItem(Item i)
{
var id = Db.Save(i);
this.Errors = Db.Erros;
return id;
}
}
What I am doing is, in my unit test class I mock IDbAccess. This class validates object according to attributes. If any error occures it doesnt hit to db, it just fills its own Errors collection. For unit test I use another dbclass which just runs validation routines and here is problem i cannot get Error. Let me give you example for further understanding ( I know design is problematic, but for now I want to deal with it without changing anything)
public static class MyDbExtension
{
public static Save(Item i)
{
Validation v = new Validation();
var erros = v.ValidateObject(i);
//Here is problem i cannot pass it to MyProblematicClass
if ( errors.Count > 0 )
return -1;
else
return 1;
/* what I want to is :
var stackTrace = new StackTrace(); get stack trace
var object = stackTrace.GetFrame(1).GetMethod().GetObject() or sth like that. get object
object.GetProperties()[0].SetValue(object,errors,null); find property and set it.
*/
}
}
in my unit test :
public class UnitTest
{
Mock<IDbAccess> _db ;
MyProblematicClass _mpc;
pubic Setup()
{
_db.Setup(x=>x.Save(It.IsAny<Item>).Returns(u =>MyDbExtension.Save(u));
_mpc = new MyProblematicClass(_db.Object);
}
public void SetItem_EmptyObject_Contains3Erros()
{
Item i = new Item();
_mpc.SetItem(i);
//At this point i cannot set _mpc.Errors
}
What I want to achieve is in my DbExtension class can I access caller class and set its Errors property? I tried but it wasn unlikely yet. If anyone has any decent solution I will be appreciative and of course you can comment on design problems.
Edit
I appreciate Alex's answer he just said ignore Save method just mock Erros property and it will be ok. That make sense but what I wonder is in question, is it possible to access Stack Trace and manipulate caller methods object's property?
Thanks in advance.
You need to setup the return value of _db.Errors, something like this:
public class UnitTest
{
Mock<IDbAccess> _db ;
MyProblematicClass _mpc;
StringCollection errors;
pubic Setup()
{
_db.Setup(x=>x.Save(It.IsAny<Item>).Returns(u =>MyDbExtension.Save(u));
_db.Setup(x=>x.Errors).Returns(errors);
_mpc = new MyProblematicClass(_db.Object);
}
public void SetItem_EmptyObject_ContainsError()
{
errors.Add("Expected Error!");
Item i = new Item();
_mpc.SetItem(i);
Assert.AreEqual("Expected Error!", _mpc.Errors[0]);
}
}
I must admit I don't really follow your design, why are you using a static method for save? You could just as easily have the line:
_db.Setup(x=>x.Save(It.IsAny<Item>).Returns(-1);
Then test IDbAccess.Save() independently.
In your 'extension' class the save method has no return value, and MyProblematicClass does not inspect the return value before assigning errors.
Not sure to fully understand the question, but you cannot access the parameters on the stack from a normal program. Runtime metadata is only about static information (method, properties, constants, etc...).
I believe only a debugger (which is considered as a special beast of its own) can do this without changing the program/source, and this has serious performance cost. As a side note, here is a link that explain how to build your own managed debugger (.NET 4): CLR Managed Debugger (mdbg) Sample 4.0
Another solution is to instrument your code (automatically or using a tool) to add some tracing call that can capture the list of parameters on each traced methods. Tools like PostSharp can do this. Here is another link: Non-Invasive Tracing & Logging
You could use unmanaged debugging API to access the call stack and get the object previous function on the stack was called on.
The problem is, the stack may not contain the method you are expecting. In cases such as inlining and tail call optimization, the call stack doesn't contain the previous method called, which means you can't reliably do what you want.
For more information see this answer by Eric Lippert.
This doesn't use the call stack, but might get you some mileage:
class CalledClass
{
public static void PokeCaller()
{
Program._this.Error = "Error!!!";
}
}
class Program
{
public string Error = null;
[ThreadStatic] public static Program _this;
public void Run()
{
_this = this;
CalledClass.PokeCaller();
Console.WriteLine(Error);
Console.ReadKey();
}
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
}
Making Errors be [ThreadStatic] might be a more direct way to do it... or some other variation on that theme. You might also combine it with stack trace checking to see if you were actually called by something that has "Errors" attribute before setting it...
Let's say we have the following piece of code:
public class Event { }
public class SportEvent1 : Event { }
public class SportEvent2 : Event { }
public class MedicalEvent1 : Event { }
public class MedicalEvent2 : Event { }
public interface IEventFactory
{
bool AcceptsInputString(string inputString);
Event CreateEvent(string inputString);
}
public class EventFactory
{
private List<IEventFactory> factories = new List<IEventFactory>();
public void AddFactory(IEventFactory factory)
{
factories.Add(factory);
}
//I don't see a point in defining a RemoveFactory() so I won't.
public Event CreateEvent(string inputString)
{
try
{
//iterate through all factories. If one and only one of them accepts
//the string, generate the event. Otherwise, throw an exception.
return factories.Single(factory => factory.AcceptsInputString(inputString)).CreateEvent(inputString);
}
catch (InvalidOperationException e)
{
throw new InvalidOperationException("Either there was no valid factory avaliable or there was more than one for the specified kind of Event.", e);
}
}
}
public class SportEvent1Factory : IEventFactory
{
public bool AcceptsInputString(string inputString)
{
return inputString.StartsWith("SportEvent1");
}
public Event CreateEvent(string inputString)
{
return new SportEvent1();
}
}
public class MedicalEvent1Factory : IEventFactory
{
public bool AcceptsInputString(string inputString)
{
return inputString.StartsWith("MedicalEvent1");
}
public Event CreateEvent(string inputString)
{
return new MedicalEvent1();
}
}
And here is the code that runs it:
static void Main(string[] args)
{
EventFactory medicalEventFactory = new EventFactory();
medicalEventFactory.AddFactory(new MedicalEvent1Factory());
medicalEventFactory.AddFactory(new MedicalEvent2Factory());
EventFactory sportsEventFactory = new EventFactory();
sportsEventFactory.AddFactory(new SportEvent1Factory());
sportsEventFactory.AddFactory(new SportEvent2Factory());
}
I have a couple of questions:
Instead of having to add factories
here in the main method of my
application, should I try to
redesign my EventFactory class so it
is an abstract factory? It'd be
better if I had a way of not having
to manually add
EventFactories every time I want to
use them. So I could just instantiate MedicalFactory and SportsFactory. Should I make a Factory of factories? Maybe that'd be over-engineering?
As you have probably noticed, I am using a inputString string as argument to feed the factories. I have an application that lets the user create his own events but also to load/save them from text files. Later, I might want to add other kinds of files, XML, sql connections, whatever. The only way I can think of that would allow me to make this work is having an internal format (I choose a string, as it's easy to understand). How would you make this? I assume this is a recurrent situation, probably most of you know of any other more intelligent approach to this. I am then only looping in the EventFactory for all the factories in its list to check if any of them accepts the input string. If one does, then it asks it to generate the Event.
If you find there is something wrong or awkward with the method I'm using to make this happen, I'd be happy to hear about different implementations. Thanks!
PS: Although I don't show it in here, all the different kind of events have different properties, so I have to generate them with different arguments (SportEvent1 might have SportName and Duration properties, that have to be put in the inputString as argument).
I am not sure about the input string question but for the first question you can likely use "convention over configuration"; a combination of reflection, the IEventFActory type and the naming you already have in place, Name.EndsWith("EventFactory") should allow you to instantiate the factories and get them into their Lists with code.
HTH ,
Berryl
The project I am working on requires some executions to be done at a certain time. I am not sure what would be the best way to deal with this situation. The method must be able to survive server restart/maintenance. And method calls must be programmatically.
I am considering going down this path:
I could have a table in database (or even a message queue) called TaskTable which could have TaskID(PK), TaskName(varchar), TaskStatus(enum success,failed, scheduled) and TimeOfExecution. But I need a windows service that periodically polls the database for any unexecuted tasks. Problem I am facing is that: What do I use as the TaskName to save into database? Class name? class and method name ToString? And how can I convert the string back and programmatically invoke the method calls (I don’t want to have a giant switch statement)? A typtical task would look like below. So I ned to be able to get the name of the task "SendIncompleteNotification" and class name save it into database and on retrival invoke programatically
public static Task<string> SendIncompleteNotification
{
get
{
return new Task<string>
(
a => Console.WriteLine("Sample Task")
, "This is a sample task which does nothing."
);
}
}
The problem now is I am having problem saving the method/property name progrmatically.
var type = ApplicationTask.SendIncompleteNotification.GetType();
//type.Name shows "Task`1" rather than SendIncompleteNotification
Is there any better ways of dealing with this situation? Thanks!
Updated:
Sorry my head was spinning. I now realized what I did wrong was to have another method/property to return my Task. What I should have done was to have a new class inhrite from my Task. And there i can easily get the class name and save the string into db and later retireve back and invoke.
Is the database a requirement?
If not, what about a Windows Scheduled Task (they have a tendancy to "just work") which calls into a general console app. The arguments to the console app could be:
A DLL containing the task to execute
The name of a class implementing an interface you define
Other arguments
This way you can put all of your tasks into one assembly, or multiple. Alternatively you could create an attribute, apply that attribute to your tasks to give them a "friendly name", and use reflection over the assembly to find classes with the matching attribute.
Edit: example:
interface ITask
{
void Execute(ExcecutionContext context);
}
[TaskName("Send Emails")
class SendEmailsTask : ITask
{
public void Execute(ExcecutionContext context)
{
// Send emails. ExecutionContext might contain a dictionary of
// key/value pairs for additional arguments needed for your task.
}
}
class TaskExecuter
{
public void ExecuteTask(string name)
{
// "name" comes from the database entry
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
// Check type.GetCustomAttributes for the TaskAttribute, then check the name
}
}
}
Edit 2: This is in answer to your code sample.
class YourClass
{
public static Task<string> SendIncompleteNotification
{
get {
return new Task<string>(
s => Console.WriteLine("Executing task... arguments: {0}", s),
"My task");
}
}
}
interface ITask
{
void Execute(object o);
}
class Task<T> : ITask
{
public Task(Action<T> action, string name)
{
Action = action;
}
public string Name { get; set; }
public Action<T> Action { get; set; }
void ITask.Execute(object o)
{
Action((T)o);
}
}
class Program
{
static void Main(string[] args)
{
// Assume that this is what is stored in the database
var typeName = typeof (YourClass).FullName;
var propertyName = "SendIncompleteNotification";
var arguments = "some arguments";
// Execute the task
var type = Type.GetType(typeName);
var property = type.GetProperty(propertyName);
var task = (ITask)property.GetValue(null, null);
task.Execute(arguments);
Console.ReadKey();
}
}
You might want to look into Windows Workflow. They are designed for long running processes, can be persisted to a database and woken up on event or timer, as far as I know.
Store the assembly FullName, and type FullName and the method name. Assuming the method signature is something predictable (like no parameters and returning void)
1) create an instance of the assembly using the static LoadFrom method of the Assembly type.
2) get a reference to the class type from your assembly using the GetType method
3) get MethodInfo instance from the type using the GetMethod method
4) create an instance of the type using Activator.CreateInstance
5) execute the method using the Invoke of the MethodInfo instance, passing in the class instance from step 4. (sorry that I'm at a public computer without a copy of VS to crank out real code but those 5 steps would do.
Also if you're using SQL 2005 consider using a SqlDependency object and getting "notified" when your talbe changes rather than polling.
Have you looked at Quartz, it works pretty well, and I'm pretty sure it implements all the features you need.