MEF & ClickOnce

Dec 17, 2009 at 3:46 PM

Hi all,

As said in the title, I try to use both MEF and ClickOnce technologies (VS 2008).

But it seems that we can only publish main program and referenced dll.

So, with a little test project : one main prog, one contract dll, and two modules dll, only main prog and contract dll (referenced) are published...

How to solve it ???

 

Dec 17, 2009 at 9:07 PM

Not sure what you mean here. Are you saying you are trying to integrate MEF with Click once? Can you show some sample code?


Thanks

Glenn

Dec 18, 2009 at 8:41 AM

Hi,

I tried to use both technologies to test the deployment strategy of an application.

As said before, my solution is composed of:

- a main project generating an exe file

- a "contract" project generating a dll file

- many "unit" project generating each a dll file

The direct references between projects are between the main project and the contract, and between every unit and the contract.

When I try to publish the application with ClickOnce on a web site, i can only publish the exe file and referenced dependances (Contract.dll, System.Composition...). But I want to publish the unit dll too, and want the application set up on a client PC to detect a version modification on every element, main project or unit dll.

Is this more clear ?

At this time, I haven't implemented any part of code into my projects, only start with publishing.

Fabien

Feb 15, 2010 at 7:45 PM

Fabien,

I hear you.  There is more guidance for this in the Silverlight space than WPF.  If you are going to have an application where connectivity is guaranteed, or you can handle the 25 mb local storage limit for the occasionally disconnected app, then I highly recommend Silverlight.

http://csharperimage.jeremylikness.com/2010/01/prism-mef-and-mvvm-part-3-of-3-dynamic.html

If you building a real world LOB app, where connectivity is poor at best or you need access to local system resources, then there are a few things you can do with you ClickOnce WPF solution (Silverlight 4 will give you access to programmatic printing support, programmatic access to the clipboard, rich text editing, support for mouse wheel input, local file system access, and out-of-browser execution).

The easiest is to just add a reference to your “unit” projects to the main project.  Or you can add something like the following to the Post Build event in your unit projects.

xcopy "$(TargetDir)*.*" "$(SolutionDir)Main\bin\$(ConfigurationName)\Units\" /Y

Add the Units directory to your Main project, but don’t add the assemblies to source control. Click on the “Application Files” button on the Publish tab for you main project properties, and set the Publish Status to “Include” and Download Group to “(Required)”.

If you want more control over what “unit” projects get downloaded then you will need to implement something that downloads the “unit” project assemblies and adds them to the catalog.  The code sample at the end is an example using a WCF download manager (http://www.codeproject.com/KB/WCF/WCF_FileTransfer_Progress.aspx).  You also need to make sure the Imports allow recomposition to pick up new matching exports as they appear in the application.

[Import(AllowRecomposition=true)]

 I am still working on how to handle any version issues.  I plan to post a sample project when I get all the details worked out (http://www.devgig.com).

  private void DownloadAssemblies(AggregateCatalog catalog)

        {

            // start service client

            FileTransferServiceClient client = new FileTransferServiceClient();

             foreach (string fileName in SettingsManager.RemoteAssemblyCatalog)

            {

                  // get stream from server

                System.IO.Stream inputStream = null;

                 try

                {

                     long length = client.DownloadFile(fileName, out inputStream);

                     // write server stream to disk

                    using (System.IO.FileStream writeStream = new System.IO.FileStream(SettingsManager.LocalAssemblyCatalogDirectoryPath, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write))

                    {

                        int chunkSize = 2048;

                        byte[] buffer = new byte[chunkSize];

                        do

                        {

                            // read bytes from input stream

                            int bytesRead = inputStream.Read(buffer, 0, chunkSize);

                            if (bytesRead == 0) break;

                            // write bytes to output stream

                            writeStream.Write(buffer, 0, bytesRead);

                         } while (true);

 

                        writeStream.Close();

                    }

                }

                finally

                {

                     // close service client

                    inputStream.Dispose();

                    client.Close();

                }

            }

             catalog.Catalogs.Add(new DirectoryCatalog(SettingsManager.LocalAssemblyCatalogDirectoryPath));

         }

Regards,

Geoff