How can i load just specific Plugins by MEF? - c#

For my company, I'm developing a simple GUI Framework which can be universally used. I want the GUI Framework to read a config file when starting up, which defines, which Plugins should be loaded, where their GUI elements should be arranged, and so on. But the reading of the config file, and also some writing, should happen through a plugin. So that's why, this plugin should be loaded first, because before others can be loaded, it needs to read out the config file to identify them.
I found out, that I can load just a defined dll like this:
var dirCatalog = new DirectoryCatalog(#"..\..\Extensions\","ProgramConfigManager*");
But I don't want to rely on the filename. My intention is to first load the MEF plugin with the Interface ISAProgramConfigManagerContent:
[Import(typeof(ISAProgramConfigManagerContent))]
SAProgramConfigManagerContent PCM;
After this, the other Plugins, but just the ones in the config file should be loaded into this:
[ImportMany(typeof(IPlugin))]
List<IPlugin> Plugins;
Is there a way, to first just load the special Plugin which handles the config file, by filtering the contracts and just compose the one of type ISAProgramConfigManagerContent ?
Thanks in advance.

When importing from other assemblies, you must tell MEF which in files to have a look. This is either a directory, by file globbing, or any other custom means. Otherwise MEF has no way where to look for the export.
Having said this, you could first setup a catalog to load the plugin manager. And then, based on that, setup another catalog with the entries that you want to load and import the plugins programmatically from that. You can also use an AggregateCatalog to unite several DirectoryCatalogs.
Something like:
var container = new CompositionContainer(aggregateCatalog);
IEnumerable<IPlugin> plugins = container.GetExports<IPlugin>();

Related

Load a different MyExeName.config XML (Project Settings file) to the default one?

I see this question asked many times about the ASP.NET style of application settings where the loading is done and then the code contains calls to ConfigurationManager.AppSettings["MySettingHere"] ..
..but my WinForms app doesnt use this method. Instead it uses the Project Settings route (i.e. I call Properties.Settings.Default.MySettingName to get my value, and I edit my settings by getting properties on the project and choosing the Settings tab)
App.config as a file is present in the root of the project/solution, but there is also Settings.settings and Settings.Designer.cs and I think these are the ones used and transformed into compiled code that gets the data
Essentially Visual Studio provides a type safe wrapper around the settings load/save/value getting process, and what I'd like to do is supply a path of the settings file to load rather than have it stuck at taking the default MyExeName.config file from the application directory
I assume you want to load custom configuration file from desired location rather than loading the default config, then try this,
NOTE : You can't have more than one App.config in a project.The app will use the config file named YourExcecutable.exe.config which is by
default the file App.config. But you can have multipe configuration
files and load then as you need using code. But you can't keep all of
them loaded at the same time. you can only switch between the files as
you need.
System.Configuration.ConfigurationFileMap fileMap = new ConfigurationFileMap("path to new file");
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
OR
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", #"Config file path");
The only solution I have found so far is rather a poor man's solve..
When we use the Settings tab inside a project's properties, the solution will gain a Settings.Settings, Settings.Designer.cs under the project's Properties node and possibly also an app.config in the root of the project. Edits to these files directly seem to be copied/updated /synchronised by VS itself. It also maintains some code in the background to ensure data-typed access to these settings. Likely it's based on Configmanager.AppSetings["propertyName"] but because VS is used to set up the property, and you tell it it's an int (or whatever) then VS can write wrapper code that exposes a namespace/class/member chain of ProjectNamespace.Properties.Settings.Default.PROPERTYNAME
Seemingly this code relies on the settingsfile being called THE_EXE_NAME.exe.config and being stored alongside the EXE itself..
..so I just take the the settings file that I want to use, copy it over the top of the one stored on disk, and call ProjectNamespace.Properties.Settings.Default.Reload() which does reload the values I want to use out of the new file. I can think of countless reasons why this isn't ideal but it's all I've been able to come up with so far

Importing or Including XSLT files from a resource

I'm working on an app where there are a number of XSL stylesheets in use. These stylesheets are stored as resources in the DLL.
I want to include or import another stylesheet in to the running one. Now, I can make this work if the included stylesheet is in the same folder as the running one, but I need to include one in a different folder.
<xsl:include href ="../Folder/transform.xslt"/>
causes an error to be thown when the containing stylesheet is loaded. The server looks to c:\Windows\Folder\transform.xslt which, obviously, isn't there.
Can anyopne suggest how I do this? mI can find next to nothing about running a transform from an enbedded resource and, sadly, I have no choice but to do it this way.
Not sure exactly how it would go, but I theorize it would be done by passing a custom XmlResolver to load the references from resources.
Implement a class that inherits from XmlResolver and looks in resources instead of the filesystem (which would be location the default XmlUrlResolver would look to).
Update: It looks like MSDN has had this problem before. See http://msdn.microsoft.com/en-us/library/aa302284.aspx for an example of how to implement a custom XmlResolver.

Ways to add functionality to a C# app without recompiling

What ways have people found/used to add functionality to a .NET/C# app without recompiling?
The methodology that comes to mind for me is having code that looks for a file to read, parses that file, and then dynamically creates controls and their event handlers, etc., based on what is contained in the file (possibly an xml file).
Or would dynamically loading .DLLs be considered "not recompiling"?
Any ideas/"war stories"?
All you need - MEF - Managed Extensibility Framework
For fairly simple cases with well defined behaviors:
Define an interface for you plugin.
Implement the interface in dlls.
Load dlls with Assembly.LoadFrom.
I'd add a GUID to each dll too so you can tell them apart.
Look at how ASP.Net does it - you can add ASPX/ASPX.cs file while site is running. Short version: ASP.Net listens for file changes and compiles new files into new assemblies, than loads into existing AppDomain to use for rendering new pages.

How can I inject a file into an EXE at runtime and reference the file during program operation?

I'd like a user to download an exe from my website, where (synchronously upon download) an XML file is injected into this application. This XML file contains a public key, and a signature.
How do I inject the file prior to downloading and reference it later during execution?
Ideally I won't be using a shell to inject the file, rather a native .NET api.
You could that easily with Mono.Cecil, you'd just have to write something like:
var module = ModuleDefinition.ReadModule ("Application.exe");
module.Resources.Add (
new EmbeddedResource (
"signature.xml",
ManifestResourceAttributes.Private,
File.ReadAllBytes ("signature.xml")));
module.Write ("Application.exe",
new WriterParameters {
StrongNameKeyPair = new StrongNameKeyPair ("keypair.snk")
});
To inject the signature.xml resource from the signature.xml file, and sign back your assembly with your keypair.snk that you used to sign Application.exe.
And at runtime, you'd just have to use:
var stream = Assembly.GetExecutingAssembly ()
.GetManifestResourceStream ("signature.xml");
To retrieve the resource.
To inject the file add it to your project. Then right-click on it in the solution explorer, go to properties, and change its type to EmbeddedResource.
To load it at run-time use Assembly.GetManifestResourceStream(). Read more here: http://msdn.microsoft.com/en-us/library/xc4235zt.aspx.
From what he writes it seems he's gonna dynamically change the file prior to download.
This really depends on the server-side language you use, And how much control you have over your server/hosting provider account.
Say you have a download.aspx file which generates this exe files and sends for download.
One thing you can do is to put the assembly's source on your server then download.aspx assembles it and send it for download. (The difficult way)
Another way is to put the compiled assembly on server then use e.g cecil ( Programmically embed resources in a .NET assembly ) or whatever to change it then send it for download.
This google result seems promising.
Add the file to your project, typically something along the lines of:
+solution
+project
+Resources
+SomeDirectory
-SomeFile
Then go to your project's properties, go to the resources tab on the left site and select the files resource on the top nav bar. Select to add a resource > add existing file. Browse to the file you just put into your project and select to add it.
The file will now show up under your Resources tab of your project's properties. Change the name of your file in the Resources tab to be more meaningful.
The file is now an embedded resource of your project and you can access it by the following in code:
var MyFile = Properties.Resources.MyFile

Add custom version information to C# application

Application is a C# .Net 3.5 WCF Service.
I'd like during the build process to dynamically add some build information to the final binary and assemblies that can then be read programatically and sent back to the WCF client when it sends a GetVersionInfo request to the web service.
.Net assembly versioning isn't enough. I want to include additional string data that contains the state of the system at the time the application was built.
I'm thinking that I'd do this by adding a post build event to call a script to update the app.config file with the data I want. Does this sound about right, or should I be considering some other approach?
Update
I'd additionally like this string to appear in the "Special Build Description" property of the final exe. I.e. I'd like to right click on the file and see this information in the version tab for the file.
Thanks in advance.
I suspect a pre-build event may be more appropriate than post-build... have you considered adding a buildinfo.xml file (or similar) to be built into the assembly as an embedded resource? You could then load it with Assembly.GetManifestResourceStream. That way you don't need to worry about fitting in with existing files or anything like that - just overwrite buildinfo.xml with a new file in the pre-build step.
You have to decide how important it is that the information you want to exchange is tied to the executable file itself.
Updating the config file during the built is a workable model, but it places the information in a location where it could be altered by anyone with access and a text editor.
Updating information after a build in a compiled assembly is certainly possible, but it's fragile and breaks down if you ever decide to sign the assemblies. It's also a lot of work, since there's no built it support for re-writing assembly files in this manner.
An alternative you should consider, is creating your own custom assembly-level metadata attributes and assigning them during the build process. You could even place them in a separate code file (or append them to AssemblyInfo.cs) as part of you build.
You could also consider creating an embedded resource (an XML file, for instance), and retrieving it from the assembly manifest at runtime.
Either of the above approaches would require you to use a pre-build custom step rather than a post-build step.
Personally, I find the metadata attributes a convenient approach if there isn't a lot of data. Otherwise, I would consider using an embedded resource file.

Categories

Resources