|
Dear reader,
at startup of my program I want to find all instances/classes, which support an special interface.
Example:
I have class A, which supports interface "void someFct()"
I have class B, which supports interface "void someFct()"
At startup of my program, I want to call both functions/interfaces without registering them before.
I hope you can understand, what I want?
Have a nice day
############### update ########################
I try to describe my problem better
My app reads a lot of data-sources and then it executes a list of ReportInstances, where each report creates excel-reports/sheets. This takes roughly 10 minutes. Each individual report checks/validates its input/config/... before it executes its own business-logic. In practice it happens, that in worst case the last report detects an error at its validation and the program stops. This is very annoying.
Simplyfied code here:
<pre>void CreateReport( params here ) {
CreateReport_1(par);
CreateReport_2(par);
.......
}
My idea is: Do validation, before starting the single reports
Solution 1: Register all validation-delegates and execute them before starting the reports
This kind of code is
void CreateReport( some params ) {
myValidationList.Add( Reporter_1.GetValidationDelegate());
myValidationList.Add( Reporter_2.GetValidationDelegate());
foreach (validationDelegate in myValidationList) {
execute validationDelegate;
}
CreateReport_1(par);
CreateReport_2(par);
.....
}
This is easy, but it has the disadvantage, that each time I add a new reporter I have to change my "registration-code". It is some kind of maintenance problem.
Solution 2: Do it "more automatic", this is what I am looking for
The kind of code I am looking for is
void CreateReport( some params ) {
myValidationList = GetAllAvailableValidationDelegates()
foreach (validationDelegate in myValidationList) {
execute validationDelegate;
}
CreateReport_1(par);
.....
}
I am looking for the code of "GetAllAvailableValidationDelegates()", which "parses" automatically all available classes/instances in my program and looks for such delegates
modified 29-May-14 0:00am.
|
|
|
|
|
|
I think learning MEF[^] can help you...
I'm not questioning your powers of observation; I'm merely remarking upon the paradox of asking a masked man who he is. (V)
|
|
|
|
|
Frygreen wrote: I want to call both functions/interfaces without registering them before. What does "registering" mean here? Are you referring to the examples of Unity?
You can ask a class which interfaces it implements; you'd still need to have "some place" where you define WHICH interface should be searched for.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Frygreen wrote: at startup of my program I want to find all instances/classes, which support an special interface.
Your requirement as stated in general is difficult.
However if your application is small and/or you limit the search parameters it becomes more reasonable.
As an example of the difficulty involve one wouldn't want to, for example, search all of the Microsoft API classes for your interface since it just won't be there.
So besides using reflection you should determine where you are going to search.
You should also evaluate whether this is really worth while in terms of future plans. It might be easier to look into using Windows Addins (or whatever they are called) or in just hard coding a list or even self registration.
|
|
|
|
|
Not sure why this is downvoted? Perhaps it was very bad pre-edit.
Anyway, what you are asking for is a classic plugin architecture, and that's a well solved problem. There are three steps to it:
- Create a boundary interface that defines what the plugin should do. This interface should be in an assembly available to both the plugin developer (plugins need a compile time reference to the assembly) and the application. In the case of a releasable app or something where the same team develops both sides it can go in the main application assembly.
- Create plugin classes which implement the interface and do the work.
- Write some reflection code in your main application that finds instances of the plugins in relevant assemblies, and registers them.
The exact implementation of that depends on whether you need AppDomain separation between plugins (for example if you want to support plugin update or unloading without restarting the application, or different security contexts), and whether plugins will be in separate assemblies.
In this case the boundary interface is
public interface IReportGenerator {
void Validate();
void Execute();
}
... although I'd expect some form of input to be passed to both methods in reality.
The simplest version of the reflection code (look in a single assembly only) looks like this:
public void RegisterPlugins(Assembly a) {
foreach(Module mod in a.GetLoadedModules()){
foreach(Type ty in mod.GetTypes()){
foreach(Type intf in ty.GetInterfaces()){
if(intf == typeof(IReportGenerator)){
RegisterPlugin((IReportGenerator)Activator.CreateInstance(ty));
}
}
}
}
}
For a full implementation including looking up assemblies in a directory and loading each plugin into an AppDomain, check out my game lobby article[^] (LobbyClient/GameType.cs or LobbyServer/GameTypes.cs). Although don't necessarily copy the coding style in there, that is old code from before I knew what I was doing.
|
|
|
|
|
<pre lang="c#">
string fileToLoad = @"C:\Users\nitin.jain\Documents\visual studio 2012\Projects\ConsoleApplication1\ClassLibrary1\bin\Debug\ClassLibrary1.dll";
string migrationStepsDllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ClassLibrary1.dll");
AppDomainSetup appDomainSetup = new AppDomainSetup() { PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory, ShadowCopyFiles="true" };
Evidence evidence = AppDomain.CurrentDomain.Evidence;
AppDomain appDomain = AppDomain.CreateDomain("ClassLibrary1", evidence, appDomainSetup);
Assembly assembly = Assembly.LoadFile(fileToLoad);
Type type = assembly.GetType("ClassLibrary1.Class1");
object foo = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("CheckAdress");
methodInfo.Invoke(foo, new object[] { "navdeep" });
AppDomain.Unload(appDomain);
Console.WriteLine("App domain unloaded");
Console.ReadLine();
This code is in console application and it works fine in the sense that it loads and unload the assembly in the domain.
But when my console is running and i try to delete the dll it says that dll is opened in console application.
So it is locked by it. How can i make sure that after unloading it, also unlocks the file.
|
|
|
|
|
Assembly assembly = Assembly.LoadFile(fileToLoad);
The assembly object is still in memory, so it is most likely holding an open handle to the file. You could try to dispose of it to see if that releases the file.
|
|
|
|
|
It doesn't look like you've loaded that assembly in the new app domain, hence it will be locked for the duration that your application is running. You can't unload an assembly per se, but you can unload the appdomain which its loaded in.
Have a look at the method AppDomain.CreateInstanceAndUnwrap to instantiate types in a different domain.
Regards,
Rob Philpott.
|
|
|
|
|
Hi,
I wrote an application that is running on multiple systems (>50). As this application gets new features frequently, I want to write a Launcher that is updating the program.
Exchanging the exe file is not a problem, but it get in trouble when the config file of the application changes.
The app.config file is divided into multiple configSections depending on its platform. I use a CustomSection as well, so the config file looks like this:
="1.0"="utf-8"
<configuration>
<configSections>
<section name="Section1" type="App.CustomSection,App"/>
<section name="Section2" type="App.CustomSection,App"/>
</configSections>
<Section1
Attrib1="true"
Attrib2="true"
.
.
.
AttribN="Value"
/>
<Section2
Attrib1="true"
Attrib2="true"
.
.
.
AttribN="Value"
/>
</configuration>
Now the launcher shall detect new attributes (comparing to a file at a file server), and insert them at the correct position (e.g. if an attribute Attrib1.5 is added, between Attrib1 and Attrib2).
The already present attribute values shall not be changed, but remain at their machine specific configuration.
I tried to solve this with the System.Xml namespace, but as I'm not very familiar with it, I was not able to solve my problem.
I also tried a Streamreader. This works partly, but if there are some blank lines on the machine, this does not work and if the order of the attributes has been changed, neither.
Here the code snippet:
private bool syncConfigFiles(string serverConfigFile, string localConfigFile)
{
List<string> _serverFileContent = FileHandler.getFileContent(serverConfigFile);
List<string> _localFileContent = FileHandler.getFileContent(localConfigFile);
for (int i = 0; i < _serverFileContent.Count; i++)
{
if (_serverFileContent[i].Trim() != _localFileContent[i].Trim())
{
string _checkStringServer = _serverFileContent[i].Trim();
string _checkStringLocal = _localFileContent[i].Trim();
if (_checkStringServer.Contains("=") && _checkStringLocal.Contains("="))
{
_checkStringServer = _checkStringServer.Substring(0, _checkStringServer.IndexOf("="));
_checkStringLocal = _checkStringLocal.Substring(0, _checkStringLocal.IndexOf("="));
}
if (_checkStringServer != _checkStringLocal)
{
_localFileContent.Insert(i, _serverFileContent[i]);
}
}
}
FileHandler.writeLines(localConfigFile, _localFileContent, false);
return true;
}
I already googled some hours and used this forum search, but no success.
Can you help me?
Thanks in advance,
Flockston
|
|
|
|
|
When the application launches, read the configuration file from the server and import that into your structure that holds all of your configuration data in your application. You DO have a structure to hold this stuff, correct?!
Then you can use a library, such as this[^], to Merge the machine specific configuration data into your existing configuration object, then serialize the completed structure back out to the machine config.
|
|
|
|
|
Hi,
just wanted you to inform that I have a solution now. I had a closer look into the XML part of .net and came up with the following solution that works pretty well:
private bool syncConfigFiles(string serverConfigFile, string localConfigFile)
{
XmlDocument _localDoc = new XmlDocument();
XmlDocument _serverDoc = new XmlDocument();
_localDoc.Load(localConfigFile);
_serverDoc.Load(serverConfigFile);
XmlNodeList _localNodes = _localDoc.DocumentElement.ChildNodes;
XmlNodeList _serverNodes = _serverDoc.DocumentElement.ChildNodes;
foreach (XmlNode _serverNode in _serverNodes)
{
foreach (XmlNode _localNode in _localNodes)
{
if (_serverNode.Name == _localNode.Name)
{
XmlAttributeCollection _serverAttributes = _serverNode.Attributes;
if (_serverAttributes != null)
{
for (int i = 0; i < _serverAttributes.Count; i++)
{
if (_localNode.Attributes[_serverAttributes[i].Name] == null)
{
XmlNode _newNode = _localNode.OwnerDocument.ImportNode(_serverNode, true);
if (i > 0)
{
_localNode.Attributes.InsertAfter(_newNode.Attributes[_serverAttributes[i].Name], _localNode.Attributes[_serverAttributes[i - 1].Name]);
}
else
{
int _tempI = i;
while (_localNode.Attributes[_serverAttributes[_tempI + 1].Name] == null && _tempI < _serverAttributes.Count)
{
_tempI++;
}
if (_tempI < _serverAttributes.Count)
{
_localNode.Attributes.InsertBefore(_newNode.Attributes[_serverAttributes[i].Name], _localNode.Attributes[_serverAttributes[_tempI + 1].Name]);
}
else
{
_localNode.Attributes.Append(_newNode.Attributes[_serverAttributes[i].Name]);
}
}
}
}
}
}
}
}
XmlWriterSettings _settings = new XmlWriterSettings();
_settings.NewLineOnAttributes = true;
_settings.Indent = true;
_settings.CloseOutput = true;
XmlWriter _writer = XmlWriter.Create(localConfigFile, _settings);
_localDoc.Save(_writer);
_writer.Close();
return true;
}
Log entries and some checks are still missing, but the functionality is given.
Best regards
Flockston
|
|
|
|
|
OK, that looks like it handles attributes only.
What if you throw in a new node on the server config with no attributes?
DON'T make the mistake of thinking that's "never going to happen".
|
|
|
|
|
Thanks for your hint! I did not think about that, because it is very unlikely that there will be new nodes within our environment.
But of course you are right, it CAN happen.
So I'll add the "node handling" to the code and update my post later.
Best Regards
Flockston
|
|
|
|
|
When you go to reuse that code you won't have to add that little feature later.
|
|
|
|
|
Hi ,
Is there a way to make our visual studio output exe to run as Admin always ?. I am running visual studio as Admin and I have a Wix installer project with me.Even if I set the admin flag in the exe manually and then make the setup file , it goes and install it as with out having any permissions. Please help
|
|
|
|
|
You need to add an Application Manifest to the project and set the required privilege level in it.
|
|
|
|
|
how to write custom file properties for a FILE. And retrieve them back.
|
|
|
|
|
I'm all ears - please tell us!
I suggest you read this - How to ask a question[^]
=========================================================
I'm an optoholic - my glass is always half full of vodka.
=========================================================
|
|
|
|
|
See here[^].
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
How to append two different file formats and detach them back to its original form.
|
|
|
|
|
You've posted this on QA. Please do not repost, let it be on QA and wait til someone answers your question. If you didn't get any response, you can improve your question and make it more specific.
Thanks.
Don't mind those people who say you're not HOT. At least you know you're COOL.
I'm not afraid of falling, I'm afraid of the sudden stop at the end of the fall! - Richard Andrew x64
|
|
|
|
|
ZIP them?
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
convert string("from var in dbModel.OM_SHIFT") to system.linq.iqueryable in C#
|
|
|
|
|
No thanks - I don't want to.
How to get an answer[^]
=========================================================
I'm an optoholic - my glass is always half full of vodka.
=========================================================
|
|
|
|