I am trying to deploy a plugin to a customer.
We use MEF, import, export attributes. I use the Export and the client imports it
My application uses DevExpress XtraGrid, XtraEditors and many other DevExpress DLL's(see screenshot), System.Data.Services.
Inspite of providing all these required DLL's and many of their dependencies, the plugin still seems to be requiring DevExpress.ExpressApp. DevExpress.ExpressApp and all its other dependencies are definitely not needed.
Since the client kept complaining that they have a FileNotFound exception, I decided to make a test project to import my own plugin. This is my test code to test the clients theory that he is getting is the following.
System.IO.FileNotFoundException: Could not load file or assembly 'DevExpress.ExpressApp.v14.2, Version=14.2.7.0,
Our Plugin
[Export(typeof (ISomething))]
public class MyClass : ISomething
{
}
TESTER
class Program
{
[ImportMany]
public IEnumerable<ISomething> Somethings { get; set; }
static void Main(string[] args)
{
var rp = new Program();
rp.Run();
}
public void Run()
{
Compose();
}
public void Compose()
{
try
{
AppDomain.CurrentDomain.FirstChanceException += FirstChanceHandler;
AggregateCatalog aggregatecatalogue = new AggregateCatalog();
aggregatecatalogue.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory));
CompositionContainer container = new CompositionContainer(aggregatecatalogue);
CompositionBatch batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);
}
catch (Exception ex)
{
throw ex;
}
}
static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
{
System.Text.StringBuilder msg = new System.Text.StringBuilder();
msg.AppendLine(e.Exception.GetType().FullName);
msg.AppendLine(e.Exception.Message);
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
msg.AppendLine(st.ToString());
msg.AppendLine();
String desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string logFilePath = String.Format("{0}\\{1}", desktopPath, "logfile.txt");
System.IO.File.AppendAllText(logFilePath, msg.ToString());
}
Sure enough, I saw in the output window and found out that it was indeed loading this DLL and some of the dependencies related to ExpressApp from GAC.
Question: How do I figure out where and why is ExpressApp needed?
I can simply just deliver the DLL but then it goes on and on about a TON of dependencies which I have clue why they would be needed.
there are tools for checking managed assembly dependencies. The MS Windows SDK contains the ildasm.exe utility. Chances are you already have it installed in:
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\ildasm.exe
When I had a similar problem (it was dll version mismatch) I have also used cygwin's 'grep' from command line to search for the missing dependency string across all DX and our custom assemblies to locate the actual .dll file referencing the missing dependency dll version. Then opened it in ildasm.exe and double clicked on the MANIFEST tree node. There I've seen the reference to the .dll version I didn't have.
You may follow the same steps to try to track the missing dependency. Run the "DevExpress.ExpressApp" string search against all DX dlls in your project's bin directory then if result is found, open the reported file with ildasm.exe
Note, most probably you don't have 'grep' from the https://www.cygwin.com/ package installed, so use the string search utility which is available to you.
There are also other 3rd party tools for checking dll dependencies but those have to be installed separately, while ildasm.exe is a part of Windows SDK. See this question's answers for other tools refs:
How do I determine the dependencies of a .NET application?
UPDATE:
if you don't have all your DX libs in the bin folder because your app is a plugin and uses DX libs directly from GAC, then you may search for DevExpress.ExpressApp references right in the DX installation folder, in my case:
C:\Program Files (x86)\DevExpress 15.2\Components\Bin\Framework
I've copied the above folder contents to a temp folder, removed all locale subfolders as well as all DevExpress.ExpressApp.* dlls and then ran a command:
grep -nr "DevExpress.ExpressApp"
which produced the following results:
Binary file DevExpress.EasyTest.v15.2.dll matches
Binary file DevExpress.Persistent.Base.v15.2.dll matches
Binary file DevExpress.Persistent.BaseImpl.EF.v15.2.dll matches
Binary file DevExpress.Persistent.BaseImpl.v15.2.dll matches
Binary file DevExpress.Workflow.Activities.v15.2.Design.dll matches
Binary file DevExpress.Workflow.Activities.v15.2.dll matches
See if any of the above dlls is used by either your plugin or the host app where the plugin is to be deployed.
HTH
Related
I am using Java JDK 11.0.8 ("Installed JREs" under Eclipse is set to jdk-11.0.8), Eclipse 2020-06, and Codename One 6.0.0.
I have recently switched from JDK 8 to JDK 11 and noticed that playing sounds option in my app does not work anymore...
Note that I uncheck "Java 8" when I create my app and I am only trying to work things out in the simulator (I am not trying to deploy the app to an actual mobile device).
I want to play a "regular sound" (I want to play a sound from beginning to end, and when it ends I do not need to replay it from the beginning) and also a "looping sound" (the sound should come to its beginning when it ends and hence, I can continuously play it in the background).
Hence I have two questions:
Question1 - About "regular sounds"
I would like to create Media object just once and then re-use it whenever I need to play the same regular sound.
For that purpose I am encapsulating a Media creation inside a class as follows:
public class RegularSound {
private Media m;
public RegularSound(String fileName) {
try{
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/"+fileName);
m = MediaManager.createMedia(is, "audio/wav");
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void play() {
m.setTime(0);
m.play();
}
}
Then I instantiate the RegularSound object and play it as follows:
mySound = new RegularSound("example.wav");
mySound.play();
Please note that example.wav is copied directly under the "src" directory of my project.
This code used to work with JDK 8, but with JDK 11, I get the following build errors:
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: javax/media/ControllerListener
at com.codename1.impl.javase.JavaJMFSEPort$1.run(JavaJMFSEPort.java:67)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.ClassNotFoundException: javax.media.ControllerListener
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at java.base/java.lang.ClassLoader.findSystemClass(ClassLoader.java:1247)
at com.codename1.impl.javase.ClassPathLoader.findClass(ClassPathLoader.java:269)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at com.codename1.impl.javase.ClassPathLoader.loadClass(ClassPathLoader.java:115)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at com.codename1.impl.javase.ClassPathLoader.loadClass(ClassPathLoader.java:107)
... 14 more
Question2- About "looping sounds"
For looping sound I have created another class as follows:
public class LoopingSound implements Runnable{
private Media m;
String fileName;
public LoopingSound(String fileName){
try{
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/"+fileName);
m = MediaManager.createMedia(is, "audio/wav",this);
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void pause()
{
m.pause();
}
public void play()
{
m.play();
}
public void run() {
m.setTime(0);
m.play();
}
}
But I again get build errors when I instantiate an object of LoopingSound and try to play it...
So could you please let me know how to change code for regular and looping sounds so that I do not receive above-mentioned errors when using JDK 11?
UPDATE
Thanks for the reply #shai-almog. I have installed CEF. But I am receiving some messages on the console in runtime and I can't hear the sound playing... I run the following code:
try {
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/example.wav");
Media m = MediaManager.createMedia(is, "audio/wav");
m.play();
} catch (IOException e) {
e.printStackTrace();
}
and I receive the following messages on console when I run this code (it throws an exception at the end):
Adding CEF to classpath
Retina Scale: 2.0
CEF Args: [--disable-gpu, --disable-software-rasterizer, --disable-gpu-compositing, --touch-events=enabled, --enable-media-stream, --device-scale-factor=4, --force-device-scale-factor=4, --autoplay-policy=no-user-gesture-required, --enable-usermedia-screen-capturing]
Using:
JCEF Version = 83.4.0.260
CEF Version = 83.4.0
Chromium Version = 83.0.4103.106
AppHandler.stateHasChanged: INITIALIZING
initialize on Thread[AWT-EventQueue-0,6,main] with library path C:\Users\pmuyan\.codenameone\cef\lib\win64
Added scheme search://
Added scheme client://
Added scheme cn1stream://
DevTools listening on ws://127.0.0.1:8088/devtools/browser/591d3502-6fd6-4997-9131-9a2a352e47b1
AppHandler.stateHasChanged: INITIALIZED
Running ready callbacks
Exception in thread "AWT-EventQueue-0" Address changed to data:text/html,%3C!doctype%20html%3E%3Chtml%3E%3Chead%3E%3Cstyle%20type%3D'text%2Fcss'%3Edocument%2C%20body%20%7Bpadding%3A0%3Bmargin%3A0%3B%20width%3A100%25%3B%20height%3A%20100%25%7D%20video%2C%20audio%20%7Bmargin%3A0%3B%20padding%3A0%3B%20width%3A100%25%3B%20height%3A%20100%25%7D%3C%2Fstyle%3E%3C%2Fhead%3E%3Cbody%3E%3Caudio%20id%3D'cn1Media'%20width%3D'640'%20height%3D'480'%20style%3D'width%3A100%25%3Bheight%3A100%25'%20src%3D'https%3A%2F%2Fcn1app%2Fstreams%2F1'%2F%3E%3Cscript%3Ewindow.cn1Media%20%3D%20document.getElementById('cn1Media')%3Bfunction%20callback(data)%7B%20cefQuery(%7Brequest%3A'shouldNavigate%3A'%2BJSON.stringify(data)%2C%20onSuccess%3A%20function(response)%7B%7D%2C%20onFailure%3Afunction(error_code%2C%20error_message)%20%7B%20console.log(error_message)%7D%7D)%3B%7Dcn1Media.addEventListener('pause'%2C%20function()%7B%20callback(%7B'state'%3A'paused'%7D)%7D)%3Bcn1Media.addEventListener('play'%2C%20function()%7B%20callback(%7B'state'%3A'playing'%7D)%7D)%3Bcn1Media.addEventListener('ended'%2C%20function()%7B%20callback(%7B'state'%3A'ended'%7D)%7D)%3Bcn1Media.addEventListener('durationchange'%2C%20function()%7B%20callback(%7B'duration'%3A%20Math.floor(cn1Media.duration%20*%201000)%7D)%7D)%3Bcn1Media.addEventListener('timeupdate'%2C%20function()%7B%20callback(%7B'time'%3A%20Math.floor(cn1Media.currentTime%20*%201000)%7D)%7D)%3Bcn1Media.addEventListener('volumechange'%2C%20function()%7B%20callback(%7B'volume'%3A%20Math.round(cn1Media.volume%20*%20100)%7D)%7D)%3Bcn1Media.addEventListener('error'%2C%20function()%7B%20var%20msg%20%3D%20'Unknown%20Error'%3B%20try%20%7Bmsg%20%3D%20cn1Media.error.message%20%2B%20'.%20Code%3D'%2Bcn1Media.error.code%3B%7Dcatch(e)%7B%7D%20callback(%7B'error'%3A%20msg%7D)%7D)%3B%3C%2Fscript%3E%20%3C%2Fbody%3E%3C%2Fhtml%3E
UPDATE 2
I could manually add Open JavaFX 11 to Eclipse and to Codename One app running under Eclipse while using JDK 11 as follows:
Step1) Create JavaFX11 user library under Eclipse
Download JavaFX 11 from https://gluonhq.com/products/javafx/
unzip it -> creates javafx-sdk-11.0.2 folder
Create a User Library: Eclipse -> Window -> Preferences -> Java -> Build Path -> User Libraries -> New.
Name it JavaFX11.
Hit "Add External JARs" and include all the jars under javafx-sdk-11.0.2\lib
Step 2) Add the JavaFX11 library to the project:
Right click on project.
Select Build path -> Configure Build Path
Goto Library tab->Add Library->User Library->Check JavaFX11->Apply and Close
Now, I can hear sounds playing in my Codename One application.
However, I need to run my application from command prompt and regular command line to run the apps does not work anymore (the app cannot find the JavaFX related classes from the command prompt and I get the same errors listed above). So could you please tell me how to modify the command line so that Codename One project that uses JavaFX would run from command prompt?
Here is the regular command line I use:
java -cp dist\Proj.jar;JavaSE.jar com.codename1.impl.javase.Simulator com.mycompany.hi.Main
BTW, I have tried to add javafx.media.jar under javafx-sdk-11.0.2\lib to the classpath (-cp) in the command line, but this did not work...
UPDATE 3
We have solved the issue by using the following command line:
java --module-path C:\javafx-sdk-11.0.2\lib\ --add-modules= ALL-MODULE-PATH -cp dist\Proj.jar;JavaSE.jar com.codename1.impl.javase.Simulator com.mycompany.hi.Main
(where C:\javafx-sdk-11.0.2\lib\ is our )
Thanks!
The TL;DR
Either install CEF as explained here or switch to ZuluFX 11 for your VM.
The explanation:
This used to work until we integrated CEF support we would download JavaFX dynamically for JDK 11 installs but this caused a lot of related problems. So we decided to migrate to CEF, this is still in progress and while it's ongoing JavaFX dynamic download is broken. Once it's done CEF will be auto-installed and this will be seamless again.
This impacts browser component and media which are the two components implemented by JavaFX.
We have a DNN module that uses Angular as its client side framework.
I'd like to be able to embed all the resources such as html , js ,css ,images and fonts to my module.(actually our module have more than one dll and every one of them has its own resources so that I don't want to copy all of these resource into main module folder every time I want to make a package)
So far I have tried WebResource.axd which was successful to some extent (Here's what I have done)but then I realized that It is somehow impossible to embed html,images and other stuffs rather than js and css (or it isn't?)
Then I decided to try using VirtualPathProvider and I used this open source project that implements an EmbeddedResourcesVirtualProvider.
I have registered this provider using IRouteMapper interface of DNN. Now that I start testing my project I am getting 404 for all of my resources. I tried to debug the project and put some break points over FileExists ,DirectoryExists and GetFile methods of VirtualProvider but the only virtual path that is being asked from VirtaulProvider is "~/Default.aspx" and nothing else
I would like to ask if it is possible to use VirtualParhProvider with DNN ?
We are using DNN 8.
I think you are over complicating things a bit. If you need a virtual provider for your module to work you are doing it wrong (in my opinion).
A module should be a self-contained package that could be deployed on any DNN installation without having to do anything but install the module.
Normally when you buy or download a free module, it comes in a single zip file with all the necessary files contained in that zip. That could be any type of file (.dll, .js, css, .ascx, .aspx etc) is does not matter as long as it's defined in the .dnn installation file.
You can then link to the files in the ascx of your module.
<script type="text/javascript" src="/DesktopModules/YourModulePath/js/file.js"></script>
or
<img src="/DesktopModules/YourModulePath/images/image.jpg">
With WebResource you can embed anything - images, html, fonts etc., so I would suggest continuing with the approach you've already taken.
I downloaded and installed your module in DDN 8 for testing. So the following assumes that setup.
To embed an image you can do this:
In the library MyFramework:
Add a file called image.png to a new folder \content\images\
Set Build Action to Embedded Resource for this image
Add [assembly: System.Web.UI.WebResource("MyFramework.content.images.image.png", "image/png")] to AssemblyInfo.cs
Add protected string myImageUrl { get; private set; } so we can access the URL in the inheriting class
Add myImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(MyModuleBase), "MyFramework.content.images.image.png"); to your OnInit() method
In the consuming project MyModule:
Add <img src="<%=myImageUrl%>"/> to View.ascx
For HTML and similar content type, you can do basically the same as you have already done for the scripts:
In the library MyFramework:
Add a file called myhtml.html to a new folder \content\html\
(in my file I have: <div style="font-weight: bold;font-size: x-large">Some <span style="color: orange">HTML</span></div>)
Set Build Action to Embedded Resource for the html
Add [assembly: System.Web.UI.WebResource("MyFramework.content.html.myhtml.html", "text/html")] to AssemblyInfo.cs
Add protected string MyHtmlUrl { get; private set; } so we can access the HTML in the inheriting class
Add:
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "MyFramework.content.html.myhtml.html";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream))
{
MyHtmlUrl = reader.ReadToEnd();
}
}
In the consuming project MyModule:
Add <%=MyHtmlUrl%> to View.ascx
I am trying to create an Excel (2007) Add-in that will respond to PivotTable changes, using this code:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Excel.Worksheet sh = this.Application.ActiveSheet;
sh.PivotTableUpdate += new
Excel.DocEvents_PivotTableUpdateEventHandler(sh_PivotTableUpdate);
}
void sh_PivotTableUpdate(Excel.PivotTable TargetPivotTable)
{
MessageBox.Show("sh_PivotTableUpdate event fired");
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
Once the .dll was created, deploying it/generating an .xll file became a challenge; I used this post for guidance there, and do now have an .xll file.
I was able to add this to the Excel spreadsheet (.xlsx file) that I want to respond to the code (via File > Excel Options > Add-Ins > Go... > Browse), but get this err msg on adding the .xll file:
I did see that there is a *.dna file here \packages\ExcelDna.AddIn.0.33.9\content\ExcelDna-Template.dna
...but making a copy of that file and changing the name of it to [projectName].dna (Excel2010AddInForRptRunner-AddIn.dna), and then copying it to the same location as the .xll file with the .xlsx file is not the solution (no pun intended). Changing the PivotTable manually does not fire the event/I see no "sh_PivotTableUpdate event fired" message.
The .dna file does reference the .dll like so:
<ExternalLibrary Path="Excel2010AddInForRptRunner.dll" LoadFromBytes="true" Pack="true" />
So what do I need to do to resolve the err msg I get and get the .xll file to be accepted by the spreadsheet so that its code will run and the PivotTableUpdate event handler is fired?
There are two issues that I see in your snippet:
The first is that you seem to have mixed the VSTO Office stuff with Excel-DNA (I see this from the ThisAddIn_... code, which relates to VSTO). These don't mix at all - you can't use Excel-DNA inside a VSTO add-in project. Any namespaces that start with Microsoft.Office.Tools... indicate there is a problem. This might happen is you start with an "Office Add-In" or "Excel Add-in" as your project type.
There is a also mess in your project related to the NuGet packages - somehow the output files are inside the package directory, or the package directory has been overwritten or changed somehow. You should not have to ever edit anything under packages\...
If everything is correct, then the files you are interested in will be found in bin\Debug and bin\Release under your project directory. Usually you can redistribute only the single ...-AddIn-packed.xll file (which you can also rename if you want to).
I suggest you make a new "Class Library" project (not an Office add-in or anything like that) and install the ExcelDna.AddIn package again. Then follow the instructions in the ReadMe file that pops up to make a simple add-in with a single UDF function, and check that this runs and can be debugged and deployed correctly.
After you have that working perfectly, you can incorporate access the COM object model into your add-in by following these two steps:
Add a reference to the Excel Interop assemblies (Microsoft.Office.Interop.Excel and Office), either directly via "Add Reference", or by installing the ExcelDna.Interop assembly from NuGet.
Get hold of the right Application root object by calling ExcelDnaUtil.Application. The object returned can be cast to a Microsoft.Office.Interop.Excel.Application and used to get to the whole COM object model from there, and hook up your event handlers etc.
I try to make a little application with Prism and MEF in order to learn how it works. I'm stuck on a fairly frustrating problem.
I would like to have a "Modules" subdirectory in my base app directory where I copy all the module's dll as a post build event.
These modules are MVVM app with View and ViewModel.
My problem is : When I copy my module's dll in the main app directory, the views are displayed in the shell, but when my modules are in the subdirectory, nothing is displayer.
My modules and their parts are found but according to fuslogvw the views can't be found :
* Assembly Binder Log Entry (27/11/2015 # 16:45:28) *
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = ModuleB.resources, Version=1.0.0.0, Culture=en-US, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = HelloWorld.vshost.exe
Calling assembly : ModuleB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: All probing URLs attempted and failed.
I don't know why MEF look in "modules\en-US\", I think it's probably why it doesn't find any views, but I couldn't find how to specify otherwise.
My bootstrapper :
public class Bootstrapper : MefBootstrapper
{
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules");
DirectoryCatalog catalog = new DirectoryCatalog(path, "*.dll");
this.AggregateCatalog.Catalogs.Add(catalog);
}
protected override DependencyObject CreateShell()
{
return this.Container.GetExportedValue<MainWindow>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (MainWindow)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
}
My modules :
[ModuleExport(typeof(ModuleAModule))]
public class ModuleAModule : IModule
{
IRegionManager _regionManager;
[ImportingConstructor]
public ModuleAModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion(RegionNames.RightRegion, typeof(ViewA));
}
}
My views :
/// <summary>
/// Interaction logic for ViewA.xaml
/// </summary>
[Export]
public partial class ViewA : UserControl
{
public ViewA()
{
InitializeComponent();
}
}
My viewmodels :
[Export]
public class ViewAViewModel : BindableBase
{
private string _title = "Module A";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
}
Anyone ?
Edit :
Here's the solution for who whould like to take a look : HelloWorldPrismMef
Edit 2 :
The investigation still goes on, I discovered the really handy mefx ! So my problem seems to be :
[Part] ModuleA.ModuleAModule from: DirectoryCatalog (Path="Modules")
[Primary Rejection]
[Export] ModuleA.ModuleAModule (ContractName="Prism.Modularity.IModule")
[Import] ModuleA.ModuleAModule..ctor (Parameter="regionManager", ContractName="Prism.Regions.IRegionManager")
[Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint contract name
ContractName Prism.Regions.IRegionManager
RequiredTypeIdentity Prism.Regions.IRegionManager n'a été trouvée.
at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
Does that mean that I need to Export a IRegionManager class ?
The log you have posted is for an attempt to load a resource .dll, something that MEF will never load (resource .dlls are used to store application resource information, like strings for internationalization). You should look for errors that do not mention resource .dlls.
Also, it seems to me you are attempting to edit the Prism Library HelloWorld example from GitHub. This particular example has tight coupling with ModuleA (by that I mean that ModuleA is used as a project dependency in HelloWorld) and to my knowledge you can not simply move the ModuleA.dll from the main folder to a modules folder and expect it to work.
My suggestion would be to add a new project, set that to output to a modules folder and see if that loads (leaving the ModuleA project alone). Or you could remove the reference from the HelloWorld project and use the post build event.
Now regarding the loading of modules from a directory, in my humble opinion, you are over complicating it. All you need is
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(#".\Modules"));
Or presuming you have a convention that specifies a pattern for module file names that resembles AppName.Modules.[ModuleNameHere].dll (eg: AppName.Modules.LoginModule.dll you could use something like this to load the modules
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(#".\Modules", "AppName.Modules.*Module.dll"));
Although this does not seem the case here, if you ever try to load modules from a zone deemed as untrustworthy, the default security policy is to ignore the module. This would happen if you attempt to run the application over a network connection like Windows Share. For this scenario you need to add these instructions to App.config
<runtime>
<loadFromRemoteSources enabled="true" />
</runtime>
These should be added after <startup /> section.
Hope this helps you.
Edit:
Does that mean that I need to Export a IRegionManager class ?
No, that's just complaining because mefx has not loaded the assembly that exports it (Prism.Wpf.dll I think it is called).
Personally I found mefx.exe to be cumbersome; I prefer the GUI version
Now regarding your code, I took a look at the GitHub repository and made some changes but not that many (had some issues with references with ModuleC so I had to remove and add again Prism.Mef & company):
Removed the PostBuildEvent from Infrastructure project
Changed the PostBuildEvent from the module projects. This needs some explaining:
all macros come appended with the directory delimiter "\" so you do not need to add it (I am reffering to $(OutDir)\Modules => $(OutDir)Modules).
COPY/XCOPY require the destination path to end with a delimiter or the destination path will be intepreted as a destinaiton directory ( $(OutDir)Modules => *$(OutDir)Modules* ).
Destination directory needs to exist (so first command should be MKDIR)
I also commented (lines that start with REM are comments) out the command that copies the .pdb because I do not think it is needed and added the /z flag to XCOPY.
Added ILoggerFacade as a dependency to demonstrate that the modules actually load. If you run the application from the Visual Studio Debugger, you will see some messages in the debug window.
Added <loadFromRemoteSources enabled="true" /> in App.config => <configuration /> => <runtime /> so I can run the app over a mounted partition where the project is stored.
All of this is in the PR.
Now regarding why it will not auto-display the views in the regions, I can not say yet. I will keep investigating during my free time, but you might have better luck asking Brian Lagunas as he is one of the developers of Prism.
Edit 2:
As I was looking at Brian Lagunas's profile I saw he answered this post that luckily solves the issue.
Will also add a PR to GitHub.
I have a Windows Forms project. I have a Resources folder and I wan to use the files there using relative path. Here is a printscreen of my project tree
As you may see I have folder UserControls where I have FileExplorer.cs it contains aa openFileDialog + pictureBox. I use this control in some of my forms which are in Forms folder. The case is that in Resources folder I have this T380.jpg image that I want to load by default but for now I can do it only by inserting the full path to it. Here is my code where I try to load the image:
private void FileExplorer_Load(object sender, EventArgs e)
{
pictureBox1.ImageLocation = #"ShoesUnlimitedAdmin\Resources\T380.jpg";
pictureBox1.Load();
}
I use the Load event of the user control to load my image but it only works when I set the full path to the image like C:\\... and so. How can I point to the Resources folder of the project using relative path?
If these images are small then favor adding them as resources in the executable file so you can use Properties.Resources in your code and don't have to deploy the files on the user's machine. Use Project + Properties, Resources. Click the arrow on the "Add Resource" button and select Add Existing File.
If they are big (more than a couple of megabytes) then you'll indeed want to deploy them as separate files. You can find them back by using the location of the EXE program, here's a helper method, spelled out for clarity:
public static string GetResourcePath(string filename) {
string exepath = System.Reflection.Assembly.GetEntryAssembly().Location;
string exedir = System.IO.Path.GetDirectoryName(exepath);
string resdir = System.IO.Path.Combine(exedir, "Resources");
return System.IO.Path.Combine(resdir, filename);
}