I have built an executable shell that using MEF loads assemblies (MEF Parts) and displays / acts accordingly to the loaded functionality.
I now want to deploy this application as a ClickOnce install. Does anyone have a strategy for this, at the moment I have seen 2 strategies.
Build and installer for the parts and add it as a Redistributal Component to the shell application - this means that the 2 installations are basically welded together and it means that MEF is basically pointless
Build a downloader 开发者_JAVA百科function into the shell, this again means that each MEF part needs to be known about before we start, and making MEF pointless.
Does anyone else know of any other approaches ? Can I build the dependancy the other way around, so a clickonce installer for the MEF parts knows what shell it should use ?
Thanks
What I did was use the Packaging API and make a custom file extension that is mapped to the shell UI. All it does is unzip the package to the ProgramData\MyApp\Extensions folder. Then when the app is restarted, the part shows up.
See this blog post for more info
' Open the Package.
' ('using' statement insures that 'package' is
' closed and disposed when it goes out of scope.)
Using package As Package = package.Open(fileName, FileMode.Open, FileAccess.Read)
tFolder = IO.Path.Combine(tFolder,
MediaToolz.SharedServices.FileSystem.GetSafeFileName(package.PackageProperties.Title))
Dim directoryInfo As New DirectoryInfo(tFolder)
If directoryInfo.Exists Then
directoryInfo.Delete(True)
End If
directoryInfo.Create()
For Each part In package.GetParts()
If part.ContentType = Packages.MediaToolzAddinMimeType Then
ExtractPart(part, tFolder)
End If
Next
package.Close()
End Using
' --------------------------- ExtractPart ---------------------------
''' <summary>
''' Extracts a specified package part to a target folder.</summary>
''' <param name="packagePart">
''' The package part to extract.</param>
''' <param name="targetDirectory">
''' The relative path from the 'current' directory
''' to the targer folder.</param>
Private Shared Sub ExtractPart(ByVal packagePart As PackagePart, ByVal targetDirectory As String)
' Create a string with the full path to the target directory.
Dim pathToTarget As String = targetDirectory
If pathToTarget.EndsWith(IO.Path.DirectorySeparatorChar) = False Then pathToTarget += IO.Path.DirectorySeparatorChar
' Remove leading slash from the Part Uri,
' and make a new Uri from the result
Dim stringPart As String = packagePart.Uri.ToString().TrimStart("/"c)
' I added this line to take off the content pat
stringPart = IO.Path.GetFileName(stringPart)
Dim partUri As New Uri(stringPart, UriKind.Relative)
' Create a full Uri to the Part based on the Package Uri
Dim uriFullPartPath As New Uri(New Uri(pathToTarget, UriKind.Absolute), partUri)
' Create the necessary Directories based on the Full Part Path
'Directory.CreateDirectory(Path.GetDirectoryName(uriFullPartPath.LocalPath))
' Create the file with the Part content
Using fileStream As New FileStream(uriFullPartPath.LocalPath, FileMode.Create)
CopyStream(packagePart.GetStream(), fileStream)
End Using 'Close & dispose fileStream.
End Sub
' --------------------------- CopyStream ---------------------------
''' <summary>
''' Copies data from a source stream to a target stream.</summary>
''' <param name="source">
''' The source stream to copy from.</param>
''' <param name="target">
''' The destination stream to copy to.</param>
Private Shared Sub CopyStream(ByVal source As Stream, ByVal target As Stream)
Const bufSize As Integer = &H1000
Dim buf(bufSize - 1) As Byte
Dim bytesRead As Integer = 0
bytesRead = source.Read(buf, 0, bufSize)
Do While bytesRead > 0
target.Write(buf, 0, bytesRead)
bytesRead = source.Read(buf, 0, bufSize)
Loop
End Sub
精彩评论